diff --git a/dist/index.cjs b/dist/index.cjs deleted file mode 100644 index 5ca5bb1c..00000000 --- a/dist/index.cjs +++ /dev/null @@ -1,2 +0,0 @@ -"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"),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 getAbsolutePath(e){return path.isAbsolute(e)?path.normalize(e):path.resolve(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}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&&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&&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||"[validation] Validation error"} - 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;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(n),enableFileLogging(o,r,i)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}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:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","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"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",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"}}}};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","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===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.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["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()},validators={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),validation: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:validators.args(e)}).partial(),HighchartsSchema=e=>zod.z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>zod.z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>zod.z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>zod.z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>zod.z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>zod.z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>zod.z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>zod.z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>zod.z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>zod.z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>zod.z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>zod.z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=zod.z.object({requestId:validators.requestId(),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({requestId:validators.requestId(),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:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.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 _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}.`}}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 globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(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)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}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 _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&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]||null;return e}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 _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}async function get$1(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}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{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),"utf8");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=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{fs.writeFileSync(path.join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const n=e.cdnUrl||cache.cdnUrl,i=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${n}/${r}/${e}`:`${n}/${e}`,i,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${n}/maps/${r}/modules/${e}`:`${n}/maps/modules/${e}`:r?`${n}/${r}/modules/${e}`:`${n}/modules/${e}`,i,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${n}/stock/${r}/indicators/${e}`:`${n}/stock/indicators/${e}`,i,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,i)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),fs.writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(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 get$1(`${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.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new httpsProxyAgent.HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(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 setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:n,wrap:i}=Highcharts;Highcharts.setOptionsObj=n(!1,{},o()),window.isRenderComplete=!1,i(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=n(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,o])})),i(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=n(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=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 launch and 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){const 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:getAbsolutePath(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(pageTemplate,{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,o){const r=[];try{let n=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;n=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const i=await _getChartSize(e,n,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(i.chartHeight||t.height)),c=Math.abs(Math.ceil(i.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:n?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),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 _getChartSize(e,t,o){return t?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(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}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,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,e.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,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`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);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),n=await puppeteerExport(t.page,e.export,e.customLogic);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(t.workCount=e.pool.workLimit+1,t.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.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(n):new ExportError(`[pool] ${e.requestId?`Request [${e.requestId}] - `:""}Error encountered during export: ${r()}ms.`).setError(n);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}ms.`),{result:n,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({export:e.export,customLogic:e.customLogic},(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({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((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{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),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=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("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.options=null,t.export.instr=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.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),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),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}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||"png"}`}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 _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:n}=isAllowedConfig(e.globalOptions)||!1,{chart:i,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||n?.sourceHeight||r?.height||s?.sourceHeight||i?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||n?.sourceWidth||r?.width||s?.sourceWidth||i?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||n?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0),e.resources=validateOption("resources",e.resources)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}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){let r=e;r||(e="resources.json");const n=["js","css","files"];let i=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(fs.readFileSync(getAbsolutePath(e),"utf8"),!1,o):(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 _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(fs.readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(fs.readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=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.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}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){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const n=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==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.maxRequests} 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)}}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 ExportError("[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();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 ExportError(`[validation] Request [${r}] - 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 ExportError(`[validation] Request [${r}] - 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 ExportError(`[validation] Request [${r}] - 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"}.${t.type||"png"}`,type:t.type,constr: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] Request [${i}] - Got an incoming HTTP request.`),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 ExportError(`[export] Request [${i}] - 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"),"utf8")),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:getHcVersion(),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){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),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{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[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 ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const n=e.params.newVersion;if(!n)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(n)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${n}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e={}){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),n=multer({storage:r,limits:{fieldSize:o}});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:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(n.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=fs.readFileSync(path.join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=fs.readFileSync(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),exportRoutes(app),healthRoutes(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){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}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=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(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()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};exports.default=index,exports.initExport=initExport; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvbG9nZ2VyLmpzIiwiLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzIiwiLi4vbGliL3ZhbGlkYXRpb24uanMiLCIuLi9saWIvZXJyb3JzL0V4cG9ydEVycm9yLmpzIiwiLi4vbGliL2NvbmZpZy5qcyIsIi4uL2xpYi9mZXRjaC5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L2Nzcy5qcyIsIi4uL3RlbXBsYXRlcy9zdmdFeHBvcnQvc3ZnRXhwb3J0LmpzIiwiLi4vbGliL2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3RpbWVyLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy9lcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzIiwiLi4vbGliL3NlcnZlci9taWRkbGV3YXJlcy92YWxpZGF0aW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvdWkuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy92ZXJzaW9uQ2hhbmdlLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvcmVzb3VyY2VSZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHV0aWxpdHkgbW9kdWxlIHByb3ZpZGVzXHJcbiAqIGEgY29tcHJlaGVuc2l2ZSBzZXQgb2YgaGVscGVyIGZ1bmN0aW9ucyBhbmQgY29uc3RhbnRzIGRlc2lnbmVkIHRvIHN0cmVhbWxpbmVcclxuICogYW5kIGVuaGFuY2UgdmFyaW91cyBvcGVyYXRpb25zIHJlcXVpcmVkIGZvciBIaWdoY2hhcnRzIGV4cG9ydCB0YXNrcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBpc0Fic29sdXRlLCBub3JtYWxpemUsIHJlc29sdmUgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG4vLyBUaGUgZGlyZWN0b3J5IHBhdGhcclxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcclxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xyXG4gKiB3aGl0ZXNwYWNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gY2xlYXJUZXh0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgdGhlICcvXFxzXFxzKy9nJyBSZWdFeHAuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXHJcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgdGhlICcgJyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBjbGVhclRleHQodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSB7XHJcbiAgcmV0dXJuIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZGVlcENvcHlcclxuICpcclxuICogQHBhcmFtIHsoT2JqZWN0fEFycmF5KX0gb2JqQXJyIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxBcnJheSl9IFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBkZWVwQ29weShvYmpBcnIpIHtcclxuICAvLyBJZiB0aGUgYG9iakFycmAgaXMgbnVsbCBvciBub3Qgb2YgdGhlIGBvYmplY3RgIHR5cGUsIHJldHVybiBpdFxyXG4gIGlmIChvYmpBcnIgPT09IG51bGwgfHwgdHlwZW9mIG9iakFyciAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmpBcnI7XHJcbiAgfVxyXG5cclxuICAvLyBQcmVwYXJlIGVpdGhlciBhIG5ldyBhcnJheSBvciBhIG5ldyBvYmplY3RcclxuICBjb25zdCBvYmpBcnJDb3B5ID0gQXJyYXkuaXNBcnJheShvYmpBcnIpID8gW10gOiB7fTtcclxuXHJcbiAgLy8gUmVjdXJzaXZlbHkgY29weSBlYWNoIHByb3BlcnR5XHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqQXJyKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iakFyciwga2V5KSkge1xyXG4gICAgICBvYmpBcnJDb3B5W2tleV0gPSBkZWVwQ29weShvYmpBcnJba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNvcGllZCBvYmplY3RcclxuICByZXR1cm4gb2JqQXJyQ29weTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGV4cEJhY2tvZmZcclxuICpcclxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuIFRoZSBkZWZhdWx0IHZhbHVlXHJcbiAqIGlzIGAwYC5cclxuICogQHBhcmFtIHsuLi51bmtub3dufSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHVua25vd24+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0XHJcbiAqIG9mIHRoZSBmdW5jdGlvbiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gVGhyb3dzIGFuIGBFcnJvcmAgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZXhwQmFja29mZihmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpIHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlcGVhdCwgdGhyb3cgYW4gZXJyb3JcclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcclxuICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxyXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcclxuXHJcbiAgICAvLy8gVE8gRE86IENvcnJlY3RcclxuICAgIC8vIC8vIEluZm9ybWF0aW9uIGFib3V0IHRoZSByZXNvdXJjZSB0aW1lb3V0XHJcbiAgICAvLyBsb2coXHJcbiAgICAvLyAgIDMsXHJcbiAgICAvLyAgIGBbdXRpbHNdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBvZiBJRDogJHthcmdzWzBdfS5gXHJcbiAgICAvLyApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gcGF0aCBpcyByZWxhdGl2ZSBvciBhYnNvbHV0ZSBhbmQgcmV0dXJucyB0aGUgY29ycmVjdGVkLFxyXG4gKiBhYnNvbHV0ZSBwYXRoLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gYmUgY2hlY2tlZCBvbi5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGguXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QWJzb2x1dGVQYXRoKHBhdGgpIHtcclxuICByZXR1cm4gaXNBYnNvbHV0ZShwYXRoKSA/IG5vcm1hbGl6ZShwYXRoKSA6IHJlc29sdmUocGF0aCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBpbnB1dCBkYXRhIHRvIGEgQmFzZTY0IHN0cmluZyBiYXNlZCBvbiB0aGUgZXhwb3J0IHR5cGUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRCYXNlNjRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIGlucHV0IHRvIGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmb3JtYXQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgQmFzZTY0IHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0QmFzZTY0KGlucHV0LCB0eXBlKSB7XHJcbiAgLy8gRm9yIHBkZiBhbmQgc3ZnIHR5cGVzIHRoZSBpbnB1dCBtdXN0IGJlIHRyYW5zZm9ybWVkIHRvIEJhc2U2NCBmcm9tIGEgYnVmZmVyXHJcbiAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcclxuICAgIHJldHVybiBCdWZmZXIuZnJvbShpbnB1dCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBGb3IgcG5nIGFuZCBqcGVnIGlucHV0IGlzIGFscmVhZHkgYSBCYXNlNjQgc3RyaW5nXHJcbiAgcmV0dXJuIGlucHV0O1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyBzdHJpbmdpZmllZCBkYXRlIHdpdGhvdXQgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldE5ld0RhdGUoKSB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cclxuICByZXR1cm4gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgc3RvcmVkIHRpbWUgdmFsdWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0TmV3RGF0ZVRpbWVcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXROZXdEYXRlVGltZSgpIHtcclxuICByZXR1cm4gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNPYmplY3RcclxuICpcclxuICogQHBhcmFtIHt1bmtub3dufSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFJldHVybnMgYHRydWVgIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNPYmplY3QoaXRlbSkge1xyXG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoaXRlbSkgPT09ICdbb2JqZWN0IE9iamVjdF0nO1xyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc09iamVjdEVtcHR5XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGl0ZW0gaXMgYW4gZW1wdHkgb2JqZWN0LCBgZmFsc2VgXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc09iamVjdEVtcHR5KGl0ZW0pIHtcclxuICByZXR1cm4gKFxyXG4gICAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxyXG4gICAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gICAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwXHJcbiAgKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gUmV0dXJucyBgdHJ1ZWAgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgYGZhbHNlYFxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChpdGVtKSB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIGBwcm9jZXNzLmhydGltZSgpYCBtZXRob2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBtZWFzdXJlVGltZVxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RnVuY3Rpb259IEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWUgaW4gbWlsbGlzZWNvbmRzLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1lYXN1cmVUaW1lKCkge1xyXG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XHJcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiByb3VuZE51bWJlclxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSBUaGUgcm91bmRlZCBudW1iZXIuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gcm91bmROdW1iZXIodmFsdWUsIHByZWNpc2lvbiA9IDEpIHtcclxuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcclxuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQGZ1bmN0aW9uIHRvQm9vbGVhblxyXG4gKlxyXG4gKiBAcGFyYW0ge3Vua25vd259IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB0b0Jvb2xlYW4oaXRlbSkge1xyXG4gIHJldHVybiBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6ICEhaXRlbTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZGVlcENvcHksXHJcbiAgZXhwQmFja29mZixcclxuICBnZXRBYnNvbHV0ZVBhdGgsXHJcbiAgZ2V0QmFzZTY0LFxyXG4gIGdldE5ld0RhdGUsXHJcbiAgZ2V0TmV3RGF0ZVRpbWUsXHJcbiAgaXNPYmplY3QsXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG1lYXN1cmVUaW1lLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgQSBtb2R1bGUgZm9yIG1hbmFnaW5nIGxvZ2dpbmcgZnVuY3Rpb25hbGl0eSB3aXRoIGN1c3RvbWl6YWJsZVxyXG4gKiBsb2cgbGV2ZWxzLCBjb25zb2xlIGFuZCBmaWxlIGxvZ2dpbmcgb3B0aW9ucywgYW5kIGVycm9yIGhhbmRsaW5nIHN1cHBvcnQuXHJcbiAqIFRoZSBtb2R1bGUgYWxzbyBlbnN1cmVzIHRoYXQgZmlsZS1iYXNlZCBsb2dzIGFyZSBzdG9yZWQgaW4gYSBzdHJ1Y3R1cmVkXHJcbiAqIGRpcmVjdG9yeSwgY3JlYXRpbmcgdGhlIG5lY2Vzc2FyeSBwYXRocyBhdXRvbWF0aWNhbGx5IGlmIHRoZXkgZG8gbm90IGV4aXN0LlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoLCBnZXROZXdEYXRlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xyXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XHJcblxyXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xyXG5jb25zdCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBGdWxsIHBhdGggdG8gdGhlIGxvZyBmaWxlXHJcbiAgcGF0aFRvTG9nOiAnJyxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhIG1lc3NhZ2Ugd2l0aCBhIHNwZWNpZmllZCBsb2cgbGV2ZWwuIEFjY2VwdHMgYSB2YXJpYWJsZSBudW1iZXJcclxuICogb2YgYXJndW1lbnRzLiBUaGUgYXJndW1lbnRzIGFmdGVyIHRoZSBgbGV2ZWxgIGFyZSBwYXNzZWQgdG8gYGNvbnNvbGUubG9nYFxyXG4gKiBhbmQvb3IgdXNlZCB0byBjb25zdHJ1Y3QgYW5kIGFwcGVuZCBtZXNzYWdlcyB0byBhIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Li4udW5rbm93bn0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZ1xyXG4gKiBsZXZlbCBhbmQgdGhlIHJlbWFpbmluZyBhcmUgc3RyaW5ncyB1c2VkIHRvIGJ1aWxkIHRoZSBsb2cgbWVzc2FnZS5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZyguLi5hcmdzKSB7XHJcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xyXG5cclxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBpdCBhIGJlbmNobWFyayBsb2dcclxuICBpZiAoXHJcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxyXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcclxuICApIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtnZXROZXdEYXRlKCl9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSBhbG9uZyB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b21cclxuICogbWVzc2FnZSBjYW4gYmUgcHJvdmlkZWQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBsb2dXaXRoU3RhY2tcclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHN0YWNrIHRyYWNlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGluY2x1ZGVkXHJcbiAqIGluIHRoZSBsb2cgYWxvbmdzaWRlIHRoZSBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IEV4aXRzIHRoZSBmdW5jdGlvbiBleGVjdXRpb24gaWYgYXR0ZW1wdGluZyB0byBsb2cgYXQgYSBsZXZlbFxyXG4gKiBoaWdoZXIgdGhhbiBhbGxvd2VkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGxvZ1dpdGhTdGFjayhuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxyXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCAoZXJyb3IgJiYgZXJyb3IubWVzc2FnZSkgfHwgJyc7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXHJcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke2dldE5ld0RhdGUoKX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XHJcblxyXG4gIC8vIEFkZCB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9IGVycm9yICYmIGVycm9yLnN0YWNrO1xyXG5cclxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlLCBpZiBleGlzdHNcclxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZV07XHJcbiAgaWYgKHN0YWNrTWVzc2FnZSkge1xyXG4gICAgdGV4dHMucHVzaCgnXFxuJywgc3RhY2tNZXNzYWdlKTtcclxuICB9XHJcblxyXG4gIC8vIExvZyB0byBmaWxlXHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBfbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgdGV4dHMuc2hpZnQoKVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXHJcbiAgICAgICAgLi4udGV4dHNcclxuICAgICAgXSlcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHJlbGF0ZWQgdG8gWm9kIHZhbGlkYXRpb24gaXNzdWVzLiBPcHRpb25hbGx5LCBhIGN1c3RvbVxyXG4gKiBtZXNzYWdlIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQGZ1bmN0aW9uIGxvZ1pvZElzc3Vlc1xyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxyXG4gKiBAcGFyYW0ge0Vycm9yW119IGlzc3VlcyAtIEFuIGFycmF5IG9mIFpvZCB2YWxpZGF0aW9uIGlzc3Vlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBpbmNsdWRlZFxyXG4gKiBpbiB0aGUgbG9nIGFsb25nc2lkZSB0aGUgZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9nWm9kSXNzdWVzKG5ld0xldmVsLCBpc3N1ZXMsIGN1c3RvbU1lc3NhZ2UpIHtcclxuICBsb2dXaXRoU3RhY2soXHJcbiAgICBuZXdMZXZlbCxcclxuICAgIG51bGwsXHJcbiAgICBbXHJcbiAgICAgIGAke2N1c3RvbU1lc3NhZ2UgfHwgJ1t2YWxpZGF0aW9uXSBWYWxpZGF0aW9uIGVycm9yJ30gLSB0aGUgZm9sbG93aW5nIFpvZCBpc3N1ZXMgb2NjdXJlZDpgLFxyXG4gICAgICAuLi4oaXNzdWVzIHx8IFtdKS5tYXAoKGlzc3VlKSA9PiBgLSAke2lzc3VlLm1lc3NhZ2V9YClcclxuICAgIF0uam9pbignXFxuJylcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaW5pdExvZ2dpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGxvZ2dpbmdgIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaW5pdExvZ2dpbmcobG9nZ2luZ09wdGlvbnMpIHtcclxuICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBgbG9nZ2luZ09wdGlvbnNgIG9iamVjdFxyXG4gIGNvbnN0IHsgbGV2ZWwsIGRlc3QsIGZpbGUsIHRvQ29uc29sZSwgdG9GaWxlIH0gPSBsb2dnaW5nT3B0aW9ucztcclxuXHJcbiAgLy8gUmVzZXQgZmxhZ3MgdG8gdGhlIGRlZmF1bHQgdmFsdWVzXHJcbiAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IGZhbHNlO1xyXG4gIGxvZ2dpbmcucGF0aFRvTG9nID0gJyc7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nZ2luZyBsZXZlbFxyXG4gIHNldExvZ0xldmVsKGxldmVsKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxvZ2dpbmdcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyh0b0NvbnNvbGUpO1xyXG5cclxuICAvLyBTZXQgdGhlIGZpbGUgbG9nZ2luZ1xyXG4gIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKGAwYCA9IG5vIGxvZ2dpbmcsXHJcbiAqIGAxYCA9IGVycm9yLCBgMmAgPSB3YXJuaW5nLCBgM2AgPSBub3RpY2UsIGA0YCA9IHZlcmJvc2UsIG9yIGA1YCA9IGJlbmNobWFyaykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRMb2dMZXZlbFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsIHRvIGJlIHNldC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRMb2dMZXZlbChsZXZlbCkge1xyXG4gIGlmIChcclxuICAgIE51bWJlci5pc0ludGVnZXIobGV2ZWwpICYmXHJcbiAgICBsZXZlbCA+PSAwICYmXHJcbiAgICBsZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoXHJcbiAgKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIG1vZHVsZSBsb2dnaW5nJ3MgYGxldmVsYCBvcHRpb25cclxuICAgIGxvZ2dpbmcubGV2ZWwgPSBsZXZlbDtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGNvbnNvbGUgbG9nZ2luZy5cclxuICpcclxuICogQGZ1bmN0aW9uIGVuYWJsZUNvbnNvbGVMb2dnaW5nXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9Db25zb2xlIC0gVGhlIGZsYWcgZm9yIHNldHRpbmcgdGhlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZW5hYmxlQ29uc29sZUxvZ2dpbmcodG9Db25zb2xlKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBtb2R1bGUgbG9nZ2luZydzIGB0b0NvbnNvbGVgIG9wdGlvblxyXG4gIGxvZ2dpbmcudG9Db25zb2xlID0gISF0b0NvbnNvbGU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlIG5hbWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVGaWxlTG9nZ2luZ1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIHdoZXJlIHRoZSBsb2cgZmlsZSBzaG91bGRcclxuICogYmUgc2F2ZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBmaWxlIC0gVGhlIG5hbWUgb2YgdGhlIGxvZyBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvRmlsZSAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9nZ2luZyBzaG91bGRcclxuICogYmUgZGlyZWN0ZWQgdG8gYSBmaWxlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZUZpbGVMb2dnaW5nKGRlc3QsIGZpbGUsIHRvRmlsZSkge1xyXG4gIC8vIFVwZGF0ZSB0aGUgbW9kdWxlIGxvZ2dpbmcncyBgdG9GaWxlYCBvcHRpb25cclxuICBsb2dnaW5nLnRvRmlsZSA9ICEhdG9GaWxlO1xyXG5cclxuICAvLyBTZXQgdGhlIGBkZXN0YCBhbmQgYGZpbGVgIG9wdGlvbnMgb25seSBpZiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWRcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ2dpbmcuZGVzdCA9IGRlc3QgfHwgJ2xvZyc7XHJcbiAgICBsb2dnaW5nLmZpbGUgPSBmaWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJztcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzXHJcbiAqIHRoZSBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2xvZ1RvRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KSB7XHJcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcclxuICAgICFleGlzdHNTeW5jKGdldEFic29sdXRlUGF0aChsb2dnaW5nLmRlc3QpKSAmJlxyXG4gICAgICBta2RpclN5bmMoZ2V0QWJzb2x1dGVQYXRoKGxvZ2dpbmcuZGVzdCkpO1xyXG5cclxuICAgIC8vIENyZWF0ZSB0aGUgZnVsbCBwYXRoXHJcbiAgICBsb2dnaW5nLnBhdGhUb0xvZyA9IGdldEFic29sdXRlUGF0aChqb2luKGxvZ2dpbmcuZGVzdCwgbG9nZ2luZy5maWxlKSk7XHJcblxyXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcclxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXHJcbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICB9XHJcblxyXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcclxuICBhcHBlbmRGaWxlKFxyXG4gICAgbG9nZ2luZy5wYXRoVG9Mb2csXHJcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxyXG4gICAgKGVycm9yKSA9PiB7XHJcbiAgICAgIGlmIChlcnJvciAmJiBsb2dnaW5nLnRvRmlsZSAmJiBsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XHJcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgKTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgbG9nWm9kSXNzdWVzLFxyXG4gIGluaXRMb2dnaW5nLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBDb25maWd1cmF0aW9uIG1hbmFnZW1lbnQgbW9kdWxlIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLlxyXG4gKiBJdCBwcm92aWRlcyBhIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCBwcmVkZWZpbmVkIGRlZmF1bHQgdmFsdWVzLFxyXG4gKiBkZXNjcmlwdGlvbnMsIGFuZCBjaGFyYWN0ZXJpc3RpY3MgZm9yIGVhY2ggb3B0aW9uIHVzZWQgaW4gdGhlIEV4cG9ydCBTZXJ2ZXIuXHJcbiAqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmcgYWxsIGF2YWlsYWJsZSBvcHRpb25zLCBvcmdhbml6ZWRcclxuICogYnkgc2VjdGlvbnMuXHJcbiAqXHJcbiAqIFRoaXMgb2JqZWN0IGluY2x1ZGVzOlxyXG4gKiAtIERlZmF1bHQgdmFsdWVzIGZvciBlYWNoIG9wdGlvbi5cclxuICogLSBEYXRhIHR5cGVzIGZvciB2YWxpZGF0aW9uLlxyXG4gKiAtIE5hbWVzIG9mIGNvcnJlc3BvbmRpbmcgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKiAtIERlc2NyaXB0aW9ucyBvZiBlYWNoIHByb3BlcnR5LlxyXG4gKiAtIEluZm9ybWF0aW9uIHVzZWQgZm9yIHByb21wdHMgaW4gaW50ZXJhY3RpdmUgY29uZmlndXJhdGlvbi5cclxuICogLSBbT3B0aW9uYWxdIENvcnJlc3BvbmRpbmcgQ0xJIGFyZ3VtZW50IG5hbWVzIGZvciBDTEkgdXNhZ2UuXHJcbiAqIC0gW09wdGlvbmFsXSBMZWdhY3kgbmFtZXMgZnJvbSB0aGUgcHJldmlvdXMgUGhhbnRvbUpTLWJhc2VkIHNlcnZlci5cclxuICovXHJcbmNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZ1tdJ10sXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfQVJHUycsXHJcbiAgICAgIGNsaU5hbWU6ICdwdXBwZXRlZXJBcmdzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBcnJheSBvZiBQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgICBzZXBhcmF0b3I6ICc7J1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNkblVybDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdDRE4gVVJMIGZvciBIaWdoY2hhcnRzIHNjcmlwdHMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmb3JjZUZldGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19GT1JDRV9GRVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmxhZyB0byByZWZldGNoIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdEaXJlY3RvcnkgcGF0aCBmb3IgY2FjaGVkIEhpZ2hjaGFydHMgc2NyaXB0cycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nW10nXSxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbW9kdWxlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdzdG9jaycsXHJcbiAgICAgICAgJ21hcCcsXHJcbiAgICAgICAgJ2dhbnR0JyxcclxuICAgICAgICAnZXhwb3J0aW5nJyxcclxuICAgICAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgICAgICdhY2Nlc3NpYmlsaXR5JyxcclxuICAgICAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgICAgICdib29zdCcsXHJcbiAgICAgICAgJ2RhdGEnLFxyXG4gICAgICAgICdkYXRhLXRvb2xzJyxcclxuICAgICAgICAnZHJhZ2dhYmxlLXBvaW50cycsXHJcbiAgICAgICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAgICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICAgICAnaGVhdG1hcCcsXHJcbiAgICAgICAgJ3RpbGVtYXAnLFxyXG4gICAgICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAgICAgJ3RpbWVsaW5lJyxcclxuICAgICAgICAndHJlZW1hcCcsXHJcbiAgICAgICAgJ3RyZWVncmFwaCcsXHJcbiAgICAgICAgJ2l0ZW0tc2VyaWVzJyxcclxuICAgICAgICAnZHJpbGxkb3duJyxcclxuICAgICAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAgICAgJ2J1bGxldCcsXHJcbiAgICAgICAgJ2Z1bm5lbCcsXHJcbiAgICAgICAgJ2Z1bm5lbDNkJyxcclxuICAgICAgICAnZ2VvaGVhdG1hcCcsXHJcbiAgICAgICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAgICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAgICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxyXG4gICAgICAgICdwYXJldG8nLFxyXG4gICAgICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgICAgICdwaWN0b3JpYWwnLFxyXG4gICAgICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgICAgICdzYW5rZXknLFxyXG4gICAgICAgICdhcmMtZGlhZ3JhbScsXHJcbiAgICAgICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgICAgICdzZXJpZXMtb24tcG9pbnQnLFxyXG4gICAgICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAgICAgJ3NvbmlmaWNhdGlvbicsXHJcbiAgICAgICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgICAgICdzdW5idXJzdCcsXHJcbiAgICAgICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAgICAgJ3Zhcml3aWRlJyxcclxuICAgICAgICAndmVjdG9yJyxcclxuICAgICAgICAndmVubicsXHJcbiAgICAgICAgJ3dpbmRiYXJiJyxcclxuICAgICAgICAnd29yZGNsb3VkJyxcclxuICAgICAgICAneHJhbmdlJyxcclxuICAgICAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICAgICAnZHJhZy1wYW5lcycsXHJcbiAgICAgICAgJ2RlYnVnZ2VyJyxcclxuICAgICAgICAnZHVtYmJlbGwnLFxyXG4gICAgICAgICdsb2xsaXBvcCcsXHJcbiAgICAgICAgJ2N5bGluZGVyJyxcclxuICAgICAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICAgICAnZG90cGxvdCcsXHJcbiAgICAgICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAgICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICAgICAnaGVpa2luYXNoaScsXHJcbiAgICAgICAgJ2Zsb3dtYXAnLFxyXG4gICAgICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAgICAgJ25hdmlnYXRvcicsXHJcbiAgICAgICAgJ3RleHRwYXRoJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogWydpbmRpY2F0b3JzLWFsbCddLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnSGlnaGNoYXJ0cyBpbmRpY2F0b3Igc2NyaXB0cyB0byBmZXRjaCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlczogWydzdHJpbmdbXSddLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DVVNUT01fU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2gnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICAgIHNlcGFyYXRvcjogJzsnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGV4cG9ydDoge1xyXG4gICAgaW5maWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0lORklMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCBmaWxlbmFtZSB3aXRoIHR5cGUsIGZvcm1hdHRlZCBjb3JyZWN0bHkgYXMgSlNPTiBvciBTVkcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpbnN0cjoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSU5TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3ZlcnJpZGVzIHRoZSBgaW5maWxlYCB3aXRoIEpTT04sIHN0cmluZ2lmaWVkIEpTT04sIG9yIFNWRyBpbnB1dCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ09iamVjdCcsICdzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09QVElPTlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FsaWFzIGZvciB0aGUgYGluc3RyYCBvcHRpb24nLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzdmc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU1ZHJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTVkcgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydCB0byByZW5kZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBiYXRjaDoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CQVRDSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdCYXRjaCBqb2Igc3RyaW5nIHdpdGggaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX09VVEZJTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnT3V0cHV0IGZpbGVuYW1lIHdpdGggdHlwZS4gQ2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcgYW5kIGlnbm9yZXMgYHR5cGVgIG9wdGlvbicsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdGaWxlIGV4cG9ydCBmb3JtYXQuIENhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICAgIGhpbnQ6ICdEZWZhdWx0OiBwbmcnLFxyXG4gICAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDaGFydCBjb25zdHJ1Y3Rvci4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgICBoaW50OiAnRGVmYXVsdDogY2hhcnQnLFxyXG4gICAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGI2NDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9CNjQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gdGhlIGNoYXJ0IHNob3VsZCBiZSByZWNlaXZlZCBpbiBCYXNlNjQgZm9ybWF0IGluc3RlYWQgb2YgYmluYXJ5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBub0Rvd25sb2FkOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX05PX0RPV05MT0FEJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1doZXRoZXIgb3Igbm90IHRvIGluY2x1ZGUgb3IgZXhjbHVkZSBhdHRhY2htZW50IGhlYWRlcnMgaW4gdGhlIHJlc3BvbnNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRlcyBjaGFydCBzZXR0aW5ncycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc2NhbGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlcicsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfU0NBTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnU2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkZXMgY2hhcnQgc2V0dGluZ3MuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcclxuICAgICAgdmFsdWU6IDQwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlZmF1bHQgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCBpZiBub3Qgc2V0JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQgaWYgbm90IHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0RlZmF1bHQgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0IGlmIG5vdCBzZXQuIFJhbmdlcyBmcm9tIDAuMSB0byA1LjAnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgbWluOiAwLjEsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBnbG9iYWxPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9HTE9CQUxfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggZ2xvYmFsIG9wdGlvbnMgZm9yIEhpZ2hjaGFydHMuc2V0T3B0aW9ucycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRoZW1lT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnT2JqZWN0JywgJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfVEhFTUVfT1BUSU9OUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKU09OLCBzdHJpbmdpZmllZCBKU09OIG9yIGZpbGVuYW1lIHdpdGggdGhlbWUgb3B0aW9ucyBmb3IgSGlnaGNoYXJ0cy5zZXRPcHRpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDE1MDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIHdlYnBhZ2UgcmVuZGVyaW5nJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWxsb3dzIG9yIGRpc2FsbG93cyBleGVjdXRpb24gb2YgYXJiaXRyYXJ5IGNvZGUgZHVyaW5nIGV4cG9ydGluZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FsbG93cyBvciBkaXNhbGxvd3MgaW5qZWN0aW9uIG9mIGZpbGVzeXN0ZW0gcmVzb3VyY2VzIChkaXNhYmxlZCBpbiBzZXJ2ZXIgbW9kZSknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGN1c3RvbUNvZGU6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1VTVE9NX0NPREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIENhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgaW4gYSBmdW5jdGlvbiwgb3IgYSAuanMgZmlsZW5hbWUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19DQUxMQkFDSycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIENhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgLmpzIGZpbGVuYW1lJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICB0eXBlczogWydPYmplY3QnLCAnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19SRVNPVVJDRVMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZXMgYXMgSlNPTiwgc3RyaW5naWZpZWQgSlNPTiwgb3IgZmlsZW5hbWUsIGNvbnRhaW5pbmcgZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19MT0FEX0NPTkZJRycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICdmcm9tRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRmlsZSB3aXRoIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdQcm9tcHQtYmFzZWQgb3B0aW9uIHNldHRpbmcsIHNhdmVkIHRvIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHNlcnZlcjoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1N0YXJ0cyB0aGUgc2VydmVyIHdoZW4gdHJ1ZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlczogWydzdHJpbmcnXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdIb3N0bmFtZSBvZiB0aGUgc2VydmVyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUG9ydCBudW1iZXIgZm9yIHRoZSBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHVwbG9hZExpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiAzLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9VUExPQURfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ01heGltdW0gcmVxdWVzdCBib2R5IHNpemUgaW4gTUInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0Rpc3BsYXlzIG9yIG5vdCBhY3Rpb24gZHVyYXRpb25zIGluIG1pbGxpc2Vjb25kcyBkdXJpbmcgc2VydmVyIHJlcXVlc3RzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnSG9zdCBvZiB0aGUgcHJveHkgc2VydmVyLCBpZiBhcHBsaWNhYmxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHBvcnQ6IHtcclxuICAgICAgICB2YWx1ZTogbnVsbCxcclxuICAgICAgICB0eXBlczogWydudW1iZXInLCAnbnVsbCddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGFwcGxpY2FibGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgYXBwbGljYWJsZScsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByYXRlTGltaXRpbmc6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc2VydmVyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdNYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RpbWUgd2luZG93IGluIG1pbnV0ZXMgZm9yIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBkZWxheToge1xyXG4gICAgICAgIHZhbHVlOiAwLFxyXG4gICAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnRGVsYXkgZHVyYXRpb24gYmV0d2VlbiBzdWNjZXNzaXZlIHJlcXVlc3RzIGJlZm9yZSByZWFjaGluZyB0aGUgbGltaXQnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICB0cnVzdFByb3h5OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0tleSB0byBieXBhc3MgdGhlIHJhdGUgbGltaXRlciwgdXNlZCB3aXRoIGBza2lwVG9rZW5gJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBudWxsLFxyXG4gICAgICAgIHR5cGVzOiBbJ3N0cmluZycsICdudWxsJ10sXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVG9rZW4gdG8gYnlwYXNzIHRoZSByYXRlIGxpbWl0ZXIsIHVzZWQgd2l0aCBgc2tpcEtleWAnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0ZXh0J1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHNzbDoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIFNTTCBwcm90b2NvbCcsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdGb3JjZXMgdGhlIHNlcnZlciB0byB1c2UgSFRUUFMgb25seSB3aGVuIHRydWUnLFxyXG4gICAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdQb3J0IGZvciB0aGUgU1NMIHNlcnZlcicsXHJcbiAgICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGNlcnRQYXRoOiB7XHJcbiAgICAgICAgdmFsdWU6IG51bGwsXHJcbiAgICAgICAgdHlwZXM6IFsnc3RyaW5nJywgJ251bGwnXSxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdzc2xDZXJ0UGF0aCcsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlJyxcclxuICAgICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIHBvb2w6IHtcclxuICAgIG1pbldvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWluaW11bSBhbmQgaW5pdGlhbCBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTWF4aW11bSBudW1iZXIgb2YgcG9vbCB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnTnVtYmVyIG9mIHRhc2tzIGEgd29ya2VyIGNhbiBoYW5kbGUgYmVmb3JlIHJlc3RhcnRpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGltZW91dCBpbiBtaWxsaXNlY29uZHMgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaW1lb3V0IGluIG1pbGxpc2Vjb25kcyBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RpbWVvdXQgaW4gbWlsbGlzZWNvbmRzIGZvciBkZXN0cm95aW5nIGlkbGUgcmVzb3VyY2VzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGJlZm9yZSByZXRyeWluZyByZXNvdXJjZSBjcmVhdGlvbiBvbiBmYWlsdXJlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICByZWFwZXJJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMTAwMCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2hlY2sgYW5kIGRlc3Ryb3kgaWRsZSByZXNvdXJjZXMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ251bWJlcidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1Nob3dzIHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBsb2dnaW5nOiB7XHJcbiAgICBsZXZlbDoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZXM6IFsnbnVtYmVyJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdMb2dnaW5nIHZlcmJvc2l0eSBsZXZlbCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICByb3VuZDogMCxcclxuICAgICAgICBtaW46IDAsXHJcbiAgICAgICAgbWF4OiA1XHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnTG9nIGZpbGUgbmFtZS4gUmVxdWlyZXMgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCB0byBiZSBzZXQnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nJyxcclxuICAgICAgdHlwZXM6IFsnc3RyaW5nJ10sXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnUGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFJlcXVpcmVzIGBsb2dUb0ZpbGVgIHRvIGJlIHNldCcsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndGV4dCdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBjb25zb2xlIGxvZ2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICB1aToge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGVuZHBvaW50IHJvdXRlIGZvciB0aGUgVUknLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGVzOiBbJ3N0cmluZyddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBOb2RlLmpzIGVudmlyb25tZW50IHR5cGUnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RleHQnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIG5vTG9nbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0Rpc3BsYXkgb3Igc2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBoYXJkUmVzZXRQYWdlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdXaGV0aGVyIG9yIG5vdCB0byByZXNldCB0aGUgcGFnZSBjb250ZW50IGVudGlyZWx5JyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1doZXRoZXIgb3Igbm90IHRvIHNldCB0aGUgYnJvd3NlciB0byBydW4gaW4gc2hlbGwgbW9kZScsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgdmFsaWRhdGlvbjoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfVkFMSURBVElPTicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnV2hldGhlciBvciBub3QgdG8gZW5hYmxlIHZhbGlkYXRpb24gb2Ygb3B0aW9ucyB0eXBlcycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAndG9nZ2xlJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBkZWJ1Zzoge1xyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGhlYWRsZXNzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hldGhlciBvciBub3QgdG8gc2V0IHRoZSBicm93c2VyIHRvIHJ1biBpbiBoZWFkbGVzcyBtb2RlIGR1cmluZyBkZWJ1Z2dpbmcnLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZXM6IFsnYm9vbGVhbiddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgRGV2VG9vbHMgaW4gaGVhZGZ1bCBtb2RlJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlczogWydib29sZWFuJ10sXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGxpc3RlbmluZyB0byBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBwcm9tcHRPcHRpb25zOiB7XHJcbiAgICAgICAgdHlwZTogJ3RvZ2dsZSdcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIGR1bXBpbzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGVzOiBbJ2Jvb2xlYW4nXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdSZWRpcmVjdHMgb3Igbm90IGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICd0b2dnbGUnXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGVzOiBbJ251bWJlciddLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVsYXlzIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbWlsbGlzZWNvbmRzJyxcclxuICAgICAgcHJvbXB0T3B0aW9uczoge1xyXG4gICAgICAgIHR5cGU6ICdudW1iZXInXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlczogWydudW1iZXInXSxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdQb3J0IHVzZWQgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIHByb21wdE9wdGlvbnM6IHtcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQgZGVmYXVsdENvbmZpZztcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgZmlsZSBoYW5kbGVzIHBhcnNpbmcgYW5kIHZhbGlkYXRpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlXHJcbiAqIHNvdXJjZXMgKHRoZSBjb25maWcgZmlsZSwgY3VzdG9tIEpTT04sIGVudmlyb25tZW50IHZhcmlhYmxlcywgQ0xJIGFyZ3VtZW50cyxcclxuICogYW5kIHJlcXVlc3QgcGF5bG9hZCkgdXNpbmcgdGhlICd6b2QnIGxpYnJhcnkuXHJcbiAqXHJcbiAqIEVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIGF0IGFwcGxpY2F0aW9uXHJcbiAqIHN0YXJ0dXAsIGFuZCB0aGUgdmFsaWRhdGVkIHJlc3VsdHMgYXJlIGV4cG9ydGVkIGFzIGBlbnZzYCBmb3IgdXNlIHRocm91Z2hvdXRcclxuICogdGhlIGFwcGxpY2F0aW9uLlxyXG4gKlxyXG4gKiBPcHRpb25zIGZyb20gb3RoZXIgc291cmNlcywgaG93ZXZlciwgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9uIGRlbWFuZCxcclxuICogZWFjaCB0aW1lIGFuIGV4cG9ydCBpcyBhdHRlbXB0ZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xyXG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcclxuXHJcbmltcG9ydCBkZWZhdWx0Q29uZmlnIGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xyXG5cclxuLy8gTG9hZCB0aGUgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBHZXQgc2NyaXB0cyBuYW1lcyBvZiBlYWNoIGNhdGVnb3J5IGZyb20gdGhlIGRlZmF1bHQgY29uZmlnXHJcbmNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9XHJcbiAgZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzO1xyXG5cclxuLy8gU2V0cyB0aGUgY3VzdG9tIGVycm9yIG1hcCBnbG9iYWxseVxyXG56LnNldEVycm9yTWFwKF9jdXN0b21FcnJvck1hcCk7XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGdlbmVyYWwgdmFsaWRhdG9ycyBhbmQgcGFyc2VycyB0byBhdm9pZCByZXBldGl0aW9uXHJcbiAqIGluIHNjaGVtYSBvYmplY3RzLiBBbGwgdmFsaWRhdG9ycyBhcHBseSB0byB2YWx1ZXMgZnJvbSB2YXJpb3VzIHNvdXJjZXMsXHJcbiAqIGluY2x1ZGluZyB0aGUgZGVmYXVsdCBjb25maWcgZmlsZSwgYSBjdXN0b20gSlNPTiBmaWxlIGxvYWRlZCB3aXRoIHRoZSBvcHRpb25cclxuICogY2FsbGVkIGBsb2FkQ29uZmlnYCwgdGhlIC5lbnYgZmlsZSwgQ0xJIGFyZ3VtZW50cywgYW5kIHRoZSByZXF1ZXN0IHBheWxvYWQuXHJcbiAqIFRoZSBgc3RyaWN0Q2hlY2tgIGZsYWcgZW5hYmxlcyBzdHJpY3RlciB2YWxpZGF0aW9uIGFuZCBwYXJzaW5nIHJ1bGVzLiBUaGlzXHJcbiAqIGZsYWcgaXMgc2V0IHRvIGZhbHNlIGZvciB2YWx1ZXMgdGhhdCBjb21lIGZyb20gdGhlIC5lbnYgZmlsZSBvciBDTEkgYXJndW1lbnRzXHJcbiAqIGJlY2F1c2UgdGhleSBhcmUgcHJvdmlkZWQgYXMgc3RyaW5ncyBhbmQgbmVlZCB0byBiZSBwYXJzZWQgYWNjb3JkaW5nbHkgZmlyc3QuXHJcbiAqL1xyXG5jb25zdCB2ID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZVxyXG4gICAqIGFuZCBmYWxzZSBhbmQgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgYm9vbGVhblxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHZhbHVlcyBhcmUgdHJ1ZSxcclxuICAgKiBmYWxzZSwgbnVsbCwgJ3RydWUnLCAnMScsICdmYWxzZScsICcwJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqIFRoZSBzdHJpbmdzICd1bmRlZmluZWQnLCAnbnVsbCcsIGFuZCAnJyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwsXHJcbiAgICogdGhlIHN0cmluZyAndHJ1ZScgd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byB0aGUgYm9vbGVhbiB2YWx1ZSB0cnVlLFxyXG4gICAqIGFuZCAnZmFsc2UnIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gdGhlIGJvb2xlYW4gdmFsdWUgZmFsc2UuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYm9vbGVhblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGJvb2xlYW4gdmFsdWVzLlxyXG4gICAqL1xyXG4gIGJvb2xlYW4oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouYm9vbGVhbigpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5lbnVtKFsndHJ1ZScsICcxJywgJ2ZhbHNlJywgJzAnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyB2YWx1ZSA9PT0gJ3RydWUnIHx8IHZhbHVlID09PSAnMSdcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5ib29sZWFuKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5ncyBleGNlcHRcclxuICAgKiB0aGUgZm9yYmlkZGVuIHZhbHVlczogJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmdzXHJcbiAgICogYW5kIG51bGwuIFRoZSBmb3JiaWRkZW4gdmFsdWVzOiAnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2lsbFxyXG4gICAqIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3RyaW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgc3RyaW5nIHZhbHVlcy5cclxuICAgKi9cclxuICBzdHJpbmcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PiAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSBzdHJpbmcgY29udGFpbnMgYSBmb3JiaWRkZW4gdmFsdWUnXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVudW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgc2NoZW1hIHdpbGwgdmFsaWRhdGUgYWdhaW5zdCB0aGUgcHJvdmlkZWQgYHZhbHVlc2AgYXJyYXkuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIHZhbGlkYXRlIGFnYWluc3QgdGhlIGB2YWx1ZXNgXHJcbiAgICogYXJyYXkgd2l0aCB0aGUgZGVmYXVsdCBlbnVtIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGFsc28gbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycsIHdoaWNoIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbnVtXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge0FycmF5LjxzdHJpbmc+fSB2YWx1ZXMgLSBBbiBhcnJheSBvZiB2YWxpZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogZm9yIHRoZSBlbnVtLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBlbnVtIHZhbHVlcy5cclxuICAgKi9cclxuICBlbnVtKHZhbHVlcywgc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHouZW51bShbLi4udmFsdWVzXSlcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAuZW51bShbLi4udmFsdWVzLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10pXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYW4gYXJyYXkgb2YgdHJpbW1lZFxyXG4gICAqIHN0cmluZyB2YWx1ZXMgZmlsdGVyZWQgYnkgdGhlIGxvZ2ljIHByb3ZpZGVkIHRocm91Z2ggdGhlIGBmaWx0ZXJDYWxsYmFja2AuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBudWxsIGFuZCB0cmltbWVkXHJcbiAgICogc3RyaW5nIHZhbHVlcyB3aGljaCB3aWxsIGJlIHNwbGl0dGVkIGludG8gYW4gYXJyYXkgb2Ygc3RyaW5ncyBhbmQgZmlsdGVyZWRcclxuICAgKiBmcm9tIHRoZSAnWycgYW5kICddJyBjaGFyYWN0ZXJzIGFuZCBieSB0aGUgbG9naWMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gICAqIHRoZSBgZmlsdGVyQ2FsbGJhY2tgLiBJZiB0aGUgYXJyYXkgaXMgZW1wdHksIGl0IHdpbGwgYmUgdHJhbnNmb3JtZWRcclxuICAgKiB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0cmluZ0FycmF5XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Z1bmN0aW9ufSBmaWx0ZXJDYWxsYmFjayAtIFRoZSBmaWx0ZXIgY2FsbGJhY2suXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IHNlcGFyYXRvciAtIFRoZSBzZXBhcmF0b3IgZm9yIHNwbGl0aW5nIGEgc3RyaW5nLlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBhcnJheSBvZiBzdHJpbmdcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgc3RyaW5nQXJyYXkoZmlsdGVyQ2FsbGJhY2ssIHNlcGFyYXRvciwgc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IGFycmF5U2NoZW1hID0gei5zdHJpbmcoKS50cmltKCkuYXJyYXkoKTtcclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYSA9IHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+IHtcclxuICAgICAgICBpZiAodmFsdWUuc3RhcnRzV2l0aCgnWycpKSB7XHJcbiAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnNsaWNlKDEpO1xyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodmFsdWUuZW5kc1dpdGgoJ10nKSkge1xyXG4gICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZSgwLCAtMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHJldHVybiB2YWx1ZS5zcGxpdChzZXBhcmF0b3IpO1xyXG4gICAgICB9KTtcclxuXHJcbiAgICBjb25zdCB0cmFuc2Zvcm1DYWxsYmFjayA9ICh2YWx1ZSkgPT5cclxuICAgICAgdmFsdWUubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKS5maWx0ZXIoZmlsdGVyQ2FsbGJhY2spO1xyXG5cclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IGFycmF5U2NoZW1hLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgOiB6XHJcbiAgICAgICAgICAudW5pb24oW3N0cmluZ1NjaGVtYSwgYXJyYXlTY2hlbWFdKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSh0cmFuc2Zvcm1DYWxsYmFjaylcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiBudWxsKSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBwb3NpdGl2ZSBudW1iZXIgdmFsdWVzXHJcbiAgICogYW5kIHZhbGlkYXRlIGFnYWluc3QgdGhlIGRlZmF1bHQgcG9zaXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHBvc2l0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcywgbnVsbCwgYW5kIHRyaW1tZWQgc3RyaW5nIHZhbHVlcyB0aGF0IGNhbiBlaXRoZXIgYmUgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCAnJywgb3IgcmVwcmVzZW50IGEgcG9zaXRpdmUgbnVtYmVyLiBJdCB3aWxsIHRyYW5zZm9ybSB0aGUgc3RyaW5nXHJcbiAgICogdG8gYSBwb3NpdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9zaXRpdmVOdW1cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyBwb3NpdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMuXHJcbiAgICovXHJcbiAgcG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkucG9zaXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID4gMCkgfHxcclxuICAgICAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLnBvc2l0aXZlKClcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vbk5lZ2F0aXZlTnVtYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgbm9uLW5lZ2F0aXZlIG51bWJlclxyXG4gICAqIHZhbHVlcyBhbmQgdmFsaWRhdGUgYWdhaW5zdCB0aGUgZGVmYXVsdCBub24tbmVnYXRpdmUgbnVtYmVyIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG5vbi1uZWdhdGl2ZSBudW1iZXJcclxuICAgKiB2YWx1ZXMsIG51bGwsIGFuZCB0cmltbWVkIHN0cmluZyB2YWx1ZXMgdGhhdCBjYW4gZWl0aGVyIGJlICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgJycsIG9yIHJlcHJlc2VudCBhIG5vbi1uZWdhdGl2ZSBudW1iZXIuIEl0IHdpbGwgdHJhbnNmb3JtXHJcbiAgICogdGhlIHN0cmluZyB0byBhIG5vbi1uZWdhdGl2ZSBudW1iZXIsIG9yIHRvIG51bGwgaWYgaXQgaXMgJ3VuZGVmaW5lZCcsXHJcbiAgICogJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub25OZWdhdGl2ZU51bVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIG5vbi1uZWdhdGl2ZVxyXG4gICAqIG51bWJlciB2YWx1ZXMuXHJcbiAgICovXHJcbiAgbm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJiBOdW1iZXIodmFsdWUpID49IDApIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUnXHJcbiAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICApXHJcbiAgICAgICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgPyBOdW1iZXIodmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgIDogbnVsbFxyXG4gICAgICAgICAgICAgICksXHJcbiAgICAgICAgICAgIHoubnVtYmVyKCkubm9ubmVnYXRpdmUoKVxyXG4gICAgICAgICAgXSlcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSBzY2hlbWEgd2lsbCB2YWxpZGF0ZSBhZ2FpbnN0IHRoZSBwcm92aWRlZCBgcHJlZml4ZXNgIGFycmF5IHRvIGNoZWNrXHJcbiAgICogd2hldGhlciBhIHN0cmluZyB2YWx1ZSBzdGFydHMgd2l0aCBhbnkgb2YgdGhlIHZhbHVlcyBwcm92aWRlZFxyXG4gICAqIGluIHRoZSBgcHJlZml4ZXNgIGFycmF5LlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBzdGFydCB3aXRoIHZhbHVlcyBmcm9tIHRoZSBwcmVmaXhlcyBhcnJheS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgc3RhcnQgd2l0aCB2YWx1ZXMgZnJvbSB0aGUgcHJlZml4ZXMgYXJyYXksIG51bGwsICd1bmRlZmluZWQnLCAnbnVsbCcsXHJcbiAgICogYW5kICcnIHdoZXJlIHRoZSBzY2hlbWEgd2lsbCB0cmFuc2Zvcm0gdGhlbSB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHN0YXJ0c1dpdGhcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7QXJyYXkuPHN0cmluZz59IHByZWZpeGVzIC0gQW4gYXJyYXkgb2YgcHJlZml4ZXMgdG8gdmFsaWRhdGVcclxuICAgKiB0aGUgc3RyaW5nIGFnYWluc3QuXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHN0cmluZ3MgdGhhdFxyXG4gICAqIHN0YXJ0cyB3aXRoIHZhbHVlcy5cclxuICAgKi9cclxuICBzdGFydHNXaXRoKHByZWZpeGVzLCBzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+IHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAke3ByZWZpeGVzLmpvaW4oJywgJyl9YFxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgLnRyaW0oKVxyXG4gICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgIHByZWZpeGVzLnNvbWUoKHByZWZpeCkgPT4gdmFsdWUuc3RhcnRzV2l0aChwcmVmaXgpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IHN0YXJ0cyB3aXRoICR7cHJlZml4ZXMuam9pbignLCAnKX1gXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNoYXJ0Q29uZmlnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cywgc3RhcnRcclxuICAgKiB3aXRoIHRoZSAneycgYW5kIGVuZCB3aXRoIHRoZSAnfScsIGFuZCBudWxsLiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJyxcclxuICAgKiBhbmQgJycgdmFsdWVzIHdpbGwgYmUgdHJhbnNmb3JtZWQgdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjaGFydENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGNoYXJ0XHJcbiAgICogY29uZmlndXJhdGlvbiB2YWx1ZS5cclxuICAgKi9cclxuICBjaGFydENvbmZpZygpIHtcclxuICAgIHJldHVybiB6XHJcbiAgICAgIC51bmlvbihbXHJcbiAgICAgICAgelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkZGl0aW9uYWxPcHRpb25zYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgZW5kIHdpdGggJy5qc29uJyBhbmQgYXJlIGF0IGxlYXN0IG9uZVxyXG4gICAqIGNoYXJhY3RlciBsb25nIGV4Y2x1ZGluZyB0aGUgZXh0ZW5zaW9uLCBzdGFydCB3aXRoIHRoZSAneycgYW5kIGVuZFxyXG4gICAqIHdpdGggdGhlICd9JywgYW5kIG51bGwuIFRoZSAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgdmFsdWVzIHdpbGxcclxuICAgKiBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9ICBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIGFkZGl0aW9uYWwgY2hhcnRcclxuICAgKiBvcHRpb25zIHZhbHVlLlxyXG4gICAqL1xyXG4gIGFkZGl0aW9uYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnVuaW9uKFtcclxuICAgICAgICB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggJy5qc29uJyBvciBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfSdcIlxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKSxcclxuICAgICAgICB6Lm9iamVjdCh7fSkucGFzc3Rocm91Z2goKVxyXG4gICAgICBdKVxyXG4gICAgICAubnVsbGFibGUoKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogT2JqZWN0IGNvbnRhaW5pbmcgY3VzdG9tIGNvbmZpZyB2YWxpZGF0b3JzIGFuZCBwYXJzZXJzIHRvIGF2b2lkIHJlcGV0aXRpb25cclxuICogaW4gc2NoZW1hIG9iamVjdHMuIEFsbCB2YWxpZGF0b3JzIGFwcGx5IHRvIHZhbHVlcyBmcm9tIHZhcmlvdXMgc291cmNlcyxcclxuICogaW5jbHVkaW5nIHRoZSBkZWZhdWx0IGNvbmZpZyBmaWxlLCBhIGN1c3RvbSBKU09OIGZpbGUgbG9hZGVkIHdpdGggdGhlIG9wdGlvblxyXG4gKiBjYWxsZWQgYGxvYWRDb25maWdgLCB0aGUgLmVudiBmaWxlLCBDTEkgYXJndW1lbnRzLCBhbmQgdGhlIHJlcXVlc3QgcGF5bG9hZC5cclxuICogVGhlIGBzdHJpY3RDaGVja2AgZmxhZyBlbmFibGVzIHN0cmljdGVyIHZhbGlkYXRpb24gYW5kIHBhcnNpbmcgcnVsZXMuIFRoaXNcclxuICogZmxhZyBpcyBzZXQgdG8gZmFsc2UgZm9yIHZhbHVlcyB0aGF0IGNvbWUgZnJvbSB0aGUgLmVudiBmaWxlIG9yIENMSSBhcmd1bWVudHNcclxuICogYmVjYXVzZSB0aGV5IGFyZSBwcm92aWRlZCBhcyBzdHJpbmdzIGFuZCBuZWVkIHRvIGJlIHBhcnNlZCBhY2NvcmRpbmdseSBmaXJzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCB2YWxpZGF0b3JzID0ge1xyXG4gIC8qKlxyXG4gICAqIFRoZSBgYXJnc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFyZ3NcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGFyZ3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGFyZ3Moc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+ICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgJzsnLFxyXG4gICAgICBzdHJpY3RDaGVja1xyXG4gICAgKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHZlcnNpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCB0cmltbWVkIHN0cmluZyB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBhIFJlZ0V4cC1iYXNlZCB0aGF0IGFsbG93cyB0byBiZSAnbGF0ZXN0Jywgb3IgaW4gdGhlIGZvcm1hdCBYWCxcclxuICAgKiBYWC5ZWSwgb3IgWFguWVkuWlosIHdoZXJlIFhYLCBZWSwgYW5kIFpaIGFyZSBudW1lcmljIGZvciB0aGUgSGlnaGNoYXJ0c1xyXG4gICAqIHZlcnNpb24gb3B0aW9uLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgYWxzbyBudWxsLFxyXG4gICAqICd1bmRlZmluZWQnLCAnbnVsbCcsIG9yICcnIGFuZCBpbiBhbGwgY2FzZXMgdGhlIHNjaGVtYSB3aWxsIHRyYW5zZm9ybSB0aGVtXHJcbiAgICogdG8gbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2ZXJzaW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2ZXJzaW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2ZXJzaW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkezEsMn0oXFwuXFxkezEsMn0pezAsMn0pJC8udGVzdCh2YWx1ZSksIHtcclxuICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0pXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgL14obGF0ZXN0fFxcZHsxLDJ9KFxcLlxcZHsxLDJ9KXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8XHJcbiAgICAgICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgIGVycm9yTWVzc2FnZTpcclxuICAgICAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWlwiXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNkblVybGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdGFydHNXaXRoYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2RuVXJsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjZG5VcmxgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNkblVybChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RhcnRzV2l0aChbJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZm9yY2VGZXRjaGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZm9yY2VGZXRjaFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZm9yY2VGZXRjaGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgZm9yY2VGZXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjYWNoZVBhdGhgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY2FjaGVQYXRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWNoZVBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNhY2hlUGF0aChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGFkbWluVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWRtaW5Ub2tlblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYWRtaW5Ub2tlbmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgYWRtaW5Ub2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvcmVTY3JpcHRzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ0FycmF5YCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29yZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGNvcmVTY3JpcHRzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBjb3JlU2NyaXB0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nQXJyYXkoXHJcbiAgICAgICh2YWx1ZSkgPT4gY29yZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbW9kdWxlU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1vZHVsZVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgbW9kdWxlU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1vZHVsZVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IG1vZHVsZVNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5kaWNhdG9yU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluZGljYXRvclNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaW5kaWNhdG9yU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZGljYXRvclNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IGluZGljYXRvclNjcmlwdHMudmFsdWUuaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3VzdG9tU2NyaXB0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdBcnJheWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGN1c3RvbVNjcmlwdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgY3VzdG9tU2NyaXB0c2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGN1c3RvbVNjcmlwdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZ0FycmF5KFxyXG4gICAgICAodmFsdWUpID0+IHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpLFxyXG4gICAgICAnLCcsXHJcbiAgICAgIHN0cmljdENoZWNrXHJcbiAgICApO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgaW5maWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uLCBvciBudWxsLlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgZmFsc2UsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpzb24nIG9yICcuc3ZnJywgYXJlIGF0IGxlYXN0IG9uZSBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmdcclxuICAgKiB0aGUgZXh0ZW5zaW9uIGFuZCB3aWxsIGJlIG51bGwgaWYgdGhlIHByb3ZpZGVkIHZhbHVlIGlzIG51bGwsICd1bmRlZmluZWQnLFxyXG4gICAqICdudWxsJywgb3IgJycuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaW5maWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbmZpbGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGluZmlsZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHN0cmljdENoZWNrXHJcbiAgICAgID8gelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSxcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgICAgICAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmpzb24gb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLnN2ZycpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbiBvciAuc3ZnJ1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSA/IHZhbHVlIDogbnVsbFxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBpbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGluc3RyXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBpbnN0cmBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaW5zdHIoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgb3B0aW9uc2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG9wdGlvbnNcclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG9wdGlvbnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5jaGFydENvbmZpZygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc3ZnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYS5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBvYmplY3QgdmFsdWVzXHJcbiAgICogb3IgdHJpbW1lZCBzdHJpbmcgdmFsdWVzIHRoYXQgY29udGFpbiAnPHN2Zycgb3IgJzw/eG1sJyBlbGVtZW50cyBhbmQgbnVsbC5cclxuICAgKiBUaGUgJ3VuZGVmaW5lZCcsICdudWxsJywgYW5kICcnIHZhbHVlcyB3aWxsIGJlIHRyYW5zZm9ybWVkIHRvIG51bGwuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3ZnXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzdmdgIG9wdGlvbi5cclxuICAgKi9cclxuICBzdmcoKSB7XHJcbiAgICByZXR1cm4gelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlLmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XHJcbiAgICAgICAgICB2YWx1ZS5pbmRleE9mKCc8P3htbCcpID49IDAgfHxcclxuICAgICAgICAgIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgXCJUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGNvbnRhaW5zICc8c3ZnJyBvciAnPD94bWwnXCJcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpID8gdmFsdWUgOiBudWxsXHJcbiAgICAgIClcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBvdXRmaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhhdDpcclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIHRydWUsIHRoZSBzY2hlbWEgd2lsbCBhY2NlcHQgdHJpbW1lZCBzdHJpbmcgdmFsdWVzXHJcbiAgICogdGhhdCBlbmQgd2l0aCAnLmpwZWcnLCAnLmpwZycsICcucG5nJywgJy5wZGYnLCBvciAnLnN2ZycsIGFyZSBhdCBsZWFzdCBvbmVcclxuICAgKiBjaGFyYWN0ZXIgbG9uZyBleGNsdWRpbmcgdGhlIGV4dGVuc2lvbiwgb3IgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IHRyaW1tZWQgc3RyaW5nIHZhbHVlc1xyXG4gICAqIHRoYXQgZW5kIHdpdGggJy5qcGVnJywgJy5qcGcnLCAnLnBuZycsICcucGRmJywgb3IgJy5zdmcnLCBhcmUgYXQgbGVhc3Qgb25lXHJcbiAgICogY2hhcmFjdGVyIGxvbmcgZXhjbHVkaW5nIHRoZSBleHRlbnNpb24gYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWRcclxuICAgKiB2YWx1ZSBpcyBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBvciAnJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBvdXRmaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBvdXRmaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBvdXRmaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6XHJcbiAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qcGVnJykpIHx8XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA1ICYmXHJcbiAgICAgICAgICAgICAgICAodmFsdWUuZW5kc1dpdGgoJy5qcGcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBuZycpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcucGRmJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5zdmcnKSkpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnN0cmluZygpXHJcbiAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanBlZycpKSB8fFxyXG4gICAgICAgICAgICAgICh2YWx1ZS5sZW5ndGggPj0gNSAmJlxyXG4gICAgICAgICAgICAgICAgKHZhbHVlLmVuZHNXaXRoKCcuanBnJykgfHxcclxuICAgICAgICAgICAgICAgICAgdmFsdWUuZW5kc1dpdGgoJy5wbmcnKSB8fFxyXG4gICAgICAgICAgICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnLnBkZicpIHx8XHJcbiAgICAgICAgICAgICAgICAgIHZhbHVlLmVuZHNXaXRoKCcuc3ZnJykpKSB8fFxyXG4gICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6XHJcbiAgICAgICAgICAgICAgICAgICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanBlZywgLmpwZywgLnBuZywgLnBkZiwgb3IgLnN2ZydcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIClcclxuICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgICAgIClcclxuICAgICAgICAgIC5udWxsYWJsZSgpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHlwZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHlwZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHlwZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHlwZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShbJ2pwZWcnLCAnanBnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNvbnN0cmAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBlbnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY29uc3RyXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjb25zdHJgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGNvbnN0cihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuZW51bShcclxuICAgICAgWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSxcclxuICAgICAgc3RyaWN0Q2hlY2tcclxuICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBiNjRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGI2NFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgYjY0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgYjY0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vRG93bmxvYWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vRG93bmxvYWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vRG93bmxvYWRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vRG93bmxvYWQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVmYXVsdEhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRIZWlnaHRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZGVmYXVsdEhlaWdodGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRlZmF1bHRIZWlnaHQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRXaWR0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRXaWR0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0V2lkdGhgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRlZmF1bHRTY2FsZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoYXQ6XHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyB0cnVlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXMgdGhhdFxyXG4gICAqIGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKS5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgbnVtYmVyIHZhbHVlcyB0aGF0IGFyZSBiZXR3ZWVuIDAuMSBhbmQgNSAoaW5jbHVzaXZlKSwgbnVsbCxcclxuICAgKiAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlZmF1bHRTY2FsZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBkZWZhdWx0U2NhbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWZhdWx0U2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuZ3RlKDAuMSkubHRlKDUpXHJcbiAgICAgIDogelxyXG4gICAgICAgICAgLnVuaW9uKFtcclxuICAgICAgICAgICAgelxyXG4gICAgICAgICAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAgICAgICAgIC50cmltKClcclxuICAgICAgICAgICAgICAucmVmaW5lKFxyXG4gICAgICAgICAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgICAoIWlzTmFOKE51bWJlcih2YWx1ZSkpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgIT09IHRydWUgJiZcclxuICAgICAgICAgICAgICAgICAgICAhdmFsdWUuc3RhcnRzV2l0aCgnWycpICYmXHJcbiAgICAgICAgICAgICAgICAgICAgTnVtYmVyKHZhbHVlKSA+PSAwLjEgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwLjEgYW5kIDUuMCByYW5nZSdcclxuICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgIClcclxuICAgICAgICAgICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA/IE51bWJlcih2YWx1ZSlcclxuICAgICAgICAgICAgICAgICAgOiBudWxsXHJcbiAgICAgICAgICAgICAgKSxcclxuICAgICAgICAgICAgei5udW1iZXIoKS5ndGUoMC4xKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlaWdodGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgYSBudWxsYWJsZSBgZGVmYXVsdEhlaWdodGBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaGVpZ2h0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBoZWlnaHRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlaWdodChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHRoaXMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHdpZHRoYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0V2lkdGhgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHdpZHRoXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB3aWR0aGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2lkdGgoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRXaWR0aChzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHNjYWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBkZWZhdWx0U2NhbGVgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNjYWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzY2FsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2NhbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmRlZmF1bHRTY2FsZShzdHJpY3RDaGVjaykubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGdsb2JhbE9wdGlvbnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGFkZGl0aW9uYWxPcHRpb25zYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBnbG9iYWxPcHRpb25zXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICBnbG9iYWxPcHRpb25zKCkge1xyXG4gICAgcmV0dXJuIHYuYWRkaXRpb25hbE9wdGlvbnMoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHRoZW1lT3B0aW9uc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYWRkaXRpb25hbE9wdGlvbnNgXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHRoZW1lT3B0aW9uc1xyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGB0aGVtZU9wdGlvbnNgIG9wdGlvbi5cclxuICAgKi9cclxuICB0aGVtZU9wdGlvbnMoKSB7XHJcbiAgICByZXR1cm4gdi5hZGRpdGlvbmFsT3B0aW9ucygpO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYmF0Y2hgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYmF0Y2hcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGJhdGNoYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBiYXRjaChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHJhc3Rlcml6YXRpb25UaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGByYXN0ZXJpemF0aW9uVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICAgKi9cclxuICBhbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBhbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWxsb3dGaWxlUmVzb3VyY2VzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGN1c3RvbUNvZGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3VzdG9tQ29kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgY3VzdG9tQ29kZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY3VzdG9tQ29kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGNhbGxiYWNrYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNhbGxiYWNrXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBjYWxsYmFja2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgY2FsbGJhY2soc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBhIHBhcnRpYWwgb2JqZWN0XHJcbiAgICogd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlIGVhY2ggb2YgdGhlIGFsbG93ZWRcclxuICAgKiBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmdpZmllZCB2ZXJzaW9uIG9mIHRoZSBvYmplY3QsIHN0cmluZyB0aGF0IGVuZHNcclxuICAgKiB3aXRoIHRoZSAnLmpzb24nLCBhbmQgbnVsbC5cclxuICAgKlxyXG4gICAqIC0gV2hlbiBgc3RyaWN0Q2hlY2tgIGlzIGZhbHNlLCB0aGUgc2NoZW1hIHdpbGwgYWNjZXB0IGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gICAqIG9mIGEgcGFydGlhbCBvYmplY3Qgd2l0aCBhbGxvd2VkIHByb3BlcnRpZXMgYGpzYCwgYGNzc2AsIGFuZCBgZmlsZXNgIHdoZXJlXHJcbiAgICogZWFjaCBvZiB0aGUgYWxsb3dlZCBwcm9wZXJ0aWVzIGNhbiBiZSBudWxsLCBzdHJpbmcgdGhhdCBlbmRzIHdpdGggdGhlXHJcbiAgICogJy5qc29uJywgYW5kIHdpbGwgYmUgbnVsbCBpZiB0aGUgcHJvdmlkZWQgdmFsdWUgaXMgJ3VuZGVmaW5lZCcsICdudWxsJ1xyXG4gICAqIG9yICcnLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHJlc291cmNlc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgcmVzb3VyY2VzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXMoc3RyaWN0Q2hlY2spIHtcclxuICAgIGNvbnN0IG9iamVjdFNjaGVtYSA9IHpcclxuICAgICAgLm9iamVjdCh7XHJcbiAgICAgICAganM6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBjc3M6IHYuc3RyaW5nKGZhbHNlKSxcclxuICAgICAgICBmaWxlczogdlxyXG4gICAgICAgICAgLnN0cmluZ0FycmF5KFxyXG4gICAgICAgICAgICAodmFsdWUpID0+ICFbJ3VuZGVmaW5lZCcsICdudWxsJywgJyddLmluY2x1ZGVzKHZhbHVlKSxcclxuICAgICAgICAgICAgJywnLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApXHJcbiAgICAgICAgICAubnVsbGFibGUoKVxyXG4gICAgICB9KVxyXG4gICAgICAucGFydGlhbCgpO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTEgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOlxyXG4gICAgICAgICAgICAgIFwiVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBzdGFydHMgd2l0aCAneycgYW5kIGVuZHMgd2l0aCAnfVwiXHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICApO1xyXG5cclxuICAgIGNvbnN0IHN0cmluZ1NjaGVtYTIgPSB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ3snKSAmJiB2YWx1ZS5lbmRzV2l0aCgnfScpKSB8fFxyXG4gICAgICAgICAgKHZhbHVlLmxlbmd0aCA+PSA2ICYmIHZhbHVlLmVuZHNXaXRoKCcuanNvbicpKSB8fFxyXG4gICAgICAgICAgWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSksXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgcGFyYW1zOiB7XHJcbiAgICAgICAgICAgIGVycm9yTWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoIC5qc29uJ1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICAhWyd1bmRlZmluZWQnLCAnbnVsbCcsICcnXS5pbmNsdWRlcyh2YWx1ZSkgPyB2YWx1ZSA6IG51bGxcclxuICAgICAgKTtcclxuXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyB6LnVuaW9uKFtvYmplY3RTY2hlbWEsIHN0cmluZ1NjaGVtYTFdKS5udWxsYWJsZSgpXHJcbiAgICAgIDogei51bmlvbihbb2JqZWN0U2NoZW1hLCBzdHJpbmdTY2hlbWEyXSkubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvYWRDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcuanNvbicuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbG9hZENvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgbG9hZENvbmZpZ2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9hZENvbmZpZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHZcclxuICAgICAgLnN0cmluZyhzdHJpY3RDaGVjaylcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gbnVsbCB8fCAodmFsdWUubGVuZ3RoID49IDYgJiYgdmFsdWUuZW5kc1dpdGgoJy5qc29uJykpLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHBhcmFtczoge1xyXG4gICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSBhIHN0cmluZyB0aGF0IGVuZHMgd2l0aCAuanNvbidcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVDb25maWdgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbG9hZENvbmZpZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGNyZWF0ZUNvbmZpZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVDb25maWdgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVDb25maWcoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB0aGlzLmxvYWRDb25maWcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZW5hYmxlU2VydmVyYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVTZXJ2ZXJcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgZW5hYmxlU2VydmVyYCBvcHRpb24uXHJcbiAgICovXHJcbiAgZW5hYmxlU2VydmVyKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhvc3RgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gaG9zdFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgaG9zdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHBvcnRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHBvcnRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHBvcnQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVwbG9hZExpbWl0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHBvc2l0aXZlTnVtYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdXBsb2FkTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVwbG9hZExpbWl0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB1cGxvYWRMaW1pdChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYucG9zaXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2VydmVyQmVuY2htYXJraW5nYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzZXJ2ZXJCZW5jaG1hcmtpbmdcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgc2VydmVyQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgc2VydmVyQmVuY2htYXJraW5nKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHByb3h5SG9zdGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBwcm94eUhvc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHByb3h5SG9zdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcHJveHlIb3N0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcHJveHlQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyBhIG51bGxhYmxlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcHJveHlQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBwcm94eVBvcnRgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHByb3h5UG9ydChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spLm51bGxhYmxlKCk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBwcm94eVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHByb3h5VGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwcm94eVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBwcm94eVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVJhdGVMaW1pdGluZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlUmF0ZUxpbWl0aW5nXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGVuYWJsZVJhdGVMaW1pdGluZ2Agb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVJhdGVMaW1pdGluZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBtYXhSZXF1ZXN0c2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbWF4UmVxdWVzdHNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1heFJlcXVlc3RzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhSZXF1ZXN0cyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgd2luZG93YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3aW5kb3dcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdpbmRvd2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd2luZG93KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWxheWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbCBzdHJpY3RlclxyXG4gICAqIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZGVsYXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGRlbGF5YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWxheShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgdHJ1c3RQcm94eWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gdHJ1c3RQcm94eVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgdHJ1c3RQcm94eWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgdHJ1c3RQcm94eShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwS2V5YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHNraXBLZXlcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNraXBLZXlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBLZXkoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBza2lwVG9rZW5gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc2tpcFRva2VuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBza2lwVG9rZW5gXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNraXBUb2tlbihzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuc3RyaW5nKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVNzbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gZW5hYmxlU3NsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBlbmFibGVTc2xgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVNzbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xGb3JjZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gc3NsRm9yY2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNzbEZvcmNlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xGb3JjZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBzc2xQb3J0YFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBzc2xQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBzc2xDZXJ0UGF0aGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBzdHJpbmdgIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzc2xDZXJ0UGF0aFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgc3NsQ2VydFBhdGhgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHNzbENlcnRQYXRoKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5zdHJpbmcoc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbWluV29ya2Vyc2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBwb3NpdGl2ZU51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG1pbldvcmtlcnNcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG1pbldvcmtlcnNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG1pbldvcmtlcnMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnBvc2l0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG1heFdvcmtlcnNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBtYXhXb3JrZXJzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBtYXhXb3JrZXJzYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBtYXhXb3JrZXJzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB3b3JrTGltaXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgcG9zaXRpdmVOdW1gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB3b3JrTGltaXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHdvcmtMaW1pdGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgd29ya0xpbWl0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5wb3NpdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBhY3F1aXJlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYWNxdWlyZVRpbWVvdXRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgYWNxdWlyZVRpbWVvdXRgIG9wdGlvbi5cclxuICAgKi9cclxuICBhY3F1aXJlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgY3JlYXRlVGltZW91dGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gY3JlYXRlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBjcmVhdGVUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgY3JlYXRlVGltZW91dChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgZGVzdHJveVRpbWVvdXRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgbm9uTmVnYXRpdmVOdW1gXHJcbiAgICogdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGRlc3Ryb3lUaW1lb3V0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlc3Ryb3lUaW1lb3V0YCBvcHRpb24uXHJcbiAgICovXHJcbiAgZGVzdHJveVRpbWVvdXQoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2Lm5vbk5lZ2F0aXZlTnVtKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGlkbGVUaW1lb3V0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBpZGxlVGltZW91dFxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBpZGxlVGltZW91dGAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBjcmVhdGVSZXRyeUludGVydmFsYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoXHJcbiAgICogYW4gb3B0aW9uYWwgc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBjcmVhdGVSZXRyeUludGVydmFsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGNyZWF0ZVJldHJ5SW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICBjcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZWFwZXJJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVhcGVySW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVhcGVySW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZWFwZXJJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgcG9vbEJlbmNobWFya2luZ2AgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcG9vbEJlbmNobWFya2luZ1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBwb29sQmVuY2htYXJraW5nYCBvcHRpb24uXHJcbiAgICovXHJcbiAgcG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXNvdXJjZXNJbnRlcnZhbGAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aFxyXG4gICAqIGFuIG9wdGlvbmFsIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBub25OZWdhdGl2ZU51bWBcclxuICAgKiB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gcmVzb3VyY2VzSW50ZXJ2YWxcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgcmVzb3VyY2VzSW50ZXJ2YWxgIG9wdGlvbi5cclxuICAgKi9cclxuICByZXNvdXJjZXNJbnRlcnZhbChzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYubm9uTmVnYXRpdmVOdW0oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nTGV2ZWxgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGF0OlxyXG4gICAqXHJcbiAgICogLSBXaGVuIGBzdHJpY3RDaGVja2AgaXMgdHJ1ZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiB0aGF0IGFyZSBiZXR3ZWVuIDAgYW5kIDUgKGluY2x1c2l2ZSkuXHJcbiAgICpcclxuICAgKiAtIFdoZW4gYHN0cmljdENoZWNrYCBpcyBmYWxzZSwgdGhlIHNjaGVtYSB3aWxsIGFjY2VwdCBpbnRlZ2VyIG51bWJlciB2YWx1ZXNcclxuICAgKiBhbmQgc3RyaW5naWZpZWQgaW50ZWdlciBudW1iZXIgdmFsdWVzIHRoYXQgYXJlIGJldHdlZW4gMSBhbmQgNSAoaW5jbHVzaXZlKSxcclxuICAgKiBudWxsLCAndW5kZWZpbmVkJywgJ251bGwnLCBhbmQgJycgd2hpY2ggd2lsbCBiZSB0cmFuc2Zvcm1lZCB0byBudWxsLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0xldmVsXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dMZXZlbGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nTGV2ZWwoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiBzdHJpY3RDaGVja1xyXG4gICAgICA/IHoubnVtYmVyKCkuaW50KCkuZ3RlKDApLmx0ZSg1KVxyXG4gICAgICA6IHpcclxuICAgICAgICAgIC51bmlvbihbXHJcbiAgICAgICAgICAgIHpcclxuICAgICAgICAgICAgICAuc3RyaW5nKClcclxuICAgICAgICAgICAgICAudHJpbSgpXHJcbiAgICAgICAgICAgICAgLnJlZmluZShcclxuICAgICAgICAgICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICAgICAgICAgKCFpc05hTihOdW1iZXIodmFsdWUpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlICE9PSB0cnVlICYmXHJcbiAgICAgICAgICAgICAgICAgICAgIXZhbHVlLnN0YXJ0c1dpdGgoJ1snKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgIE51bWJlci5pc0ludGVnZXIoTnVtYmVyKHZhbHVlKSkgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgICAgICAgICAgICBOdW1iZXIodmFsdWUpIDw9IDUpIHx8XHJcbiAgICAgICAgICAgICAgICAgIFsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpLFxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgICAgICAgICBlcnJvck1lc3NhZ2U6ICdUaGUgdmFsdWUgbXVzdCBiZSB3aXRoaW4gYSAwIGFuZCA1IHJhbmdlJ1xyXG4gICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgKVxyXG4gICAgICAgICAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxyXG4gICAgICAgICAgICAgICAgIVsndW5kZWZpbmVkJywgJ251bGwnLCAnJ10uaW5jbHVkZXModmFsdWUpXHJcbiAgICAgICAgICAgICAgICAgID8gTnVtYmVyKHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICA6IG51bGxcclxuICAgICAgICAgICAgICApLFxyXG4gICAgICAgICAgICB6Lm51bWJlcigpLmludCgpLmd0ZSgwKS5sdGUoNSlcclxuICAgICAgICAgIF0pXHJcbiAgICAgICAgICAubnVsbGFibGUoKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxvZ0ZpbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5nIHRoYXQgZW5kcyB3aXRoICcubG9nJy5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dGaWxlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGBsb2dGaWxlYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dGaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdlxyXG4gICAgICAuc3RyaW5nKHN0cmljdENoZWNrKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSBudWxsIHx8ICh2YWx1ZS5sZW5ndGggPj0gNSAmJiB2YWx1ZS5lbmRzV2l0aCgnLmxvZycpKSxcclxuICAgICAgICB7XHJcbiAgICAgICAgICBwYXJhbXM6IHtcclxuICAgICAgICAgICAgZXJyb3JNZXNzYWdlOiAnVGhlIHZhbHVlIG11c3QgYmUgYSBzdHJpbmcgdGhhdCBlbmRzIHdpdGggLmxvZydcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dEZXN0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYHN0cmluZ2AgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ0Rlc3RcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ0Rlc3RgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxvZ0Rlc3Qoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0cmluZyhzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBsb2dUb0NvbnNvbGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxvZ1RvQ29uc29sZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBsb2dUb0NvbnNvbGVgIG9wdGlvbi5cclxuICAgKi9cclxuICBsb2dUb0NvbnNvbGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbG9nVG9GaWxlYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBsb2dUb0ZpbGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYGxvZ1RvRmlsZWBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbG9nVG9GaWxlKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZVVpYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVVaVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlVWlgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZVVpKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYHVpUm91dGVgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RhcnRzV2l0aGAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIHVpUm91dGVcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHVpUm91dGVgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIHVpUm91dGUoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LnN0YXJ0c1dpdGgoWycvJ10sIHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYG5vZGVFbnZgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgZW51bWAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIG5vZGVFbnZcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vZGVFbnZgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIG5vZGVFbnYoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSwgc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbGlzdGVuVG9Qcm9jZXNzRXhpdHNgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGhcclxuICAgKiBhbiBvcHRpb25hbCBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGxpc3RlblRvUHJvY2Vzc0V4aXRzXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvUHJvY2Vzc0V4aXRzYCBvcHRpb24uXHJcbiAgICovXHJcbiAgbGlzdGVuVG9Qcm9jZXNzRXhpdHMoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgbm9Mb2dvYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBub0xvZ29cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYG5vTG9nb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgbm9Mb2dvKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhhcmRSZXNldFBhZ2VgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGhhcmRSZXNldFBhZ2VcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZ1xyXG4gICAqIHRoZSBgaGFyZFJlc2V0UGFnZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhhcmRSZXNldFBhZ2Uoc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgYnJvd3NlclNoZWxsTW9kZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gYnJvd3NlclNoZWxsTW9kZVxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nXHJcbiAgICogdGhlIGBicm93c2VyU2hlbGxNb2RlYCBvcHRpb24uXHJcbiAgICovXHJcbiAgYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGB2YWxpZGF0aW9uYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiB2YWxpZGF0aW9uXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmcgdGhlIGB2YWxpZGF0aW9uYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICB2YWxpZGF0aW9uKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGVuYWJsZURlYnVnYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBlbmFibGVEZWJ1Z1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZW5hYmxlRGVidWdgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGVuYWJsZURlYnVnKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGhlYWRsZXNzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBoZWFkbGVzc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgaGVhZGxlc3NgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGhlYWRsZXNzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGRldnRvb2xzYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYGJvb2xlYW5gIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZXZ0b29sc1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZGV2dG9vbHNgXHJcbiAgICogb3B0aW9uLlxyXG4gICAqL1xyXG4gIGRldnRvb2xzKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ib29sZWFuKHN0cmljdENoZWNrKTtcclxuICB9LFxyXG5cclxuICAvKipcclxuICAgKiBUaGUgYGxpc3RlblRvQ29uc29sZWAgdmFsaWRhdG9yIHRoYXQgcmV0dXJucyBhIFpvZCBzY2hlbWEgd2l0aCBhbiBvcHRpb25hbFxyXG4gICAqIHN0cmljdGVyIGNoZWNrIGJhc2VkIG9uIHRoZSBgc3RyaWN0Q2hlY2tgIHBhcmFtZXRlci5cclxuICAgKlxyXG4gICAqIFRoZSB2YWxpZGF0aW9uIHNjaGVtYSBlbnN1cmVzIHRoZSBzYW1lIHdvcmsgYXMgdGhlIGBib29sZWFuYCB2YWxpZGF0b3IuXHJcbiAgICpcclxuICAgKiBAZnVuY3Rpb24gbGlzdGVuVG9Db25zb2xlXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGxpc3RlblRvQ29uc29sZWAgb3B0aW9uLlxyXG4gICAqL1xyXG4gIGxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjaykge1xyXG4gICAgcmV0dXJuIHYuYm9vbGVhbihzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkdW1waW9gIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWwgc3RyaWN0ZXJcclxuICAgKiBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgYm9vbGVhbmAgdmFsaWRhdG9yLlxyXG4gICAqXHJcbiAgICogQGZ1bmN0aW9uIGR1bXBpb1xyXG4gICAqXHJcbiAgICogQHBhcmFtIHtib29sZWFufSBzdHJpY3RDaGVjayAtIERldGVybWluZXMgaWYgc3RyaWN0ZXIgdmFsaWRhdGlvbiBzaG91bGRcclxuICAgKiBiZSBhcHBsaWVkLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge3ouWm9kU2NoZW1hfSBBIFpvZCBzY2hlbWEgb2JqZWN0IGZvciB2YWxpZGF0aW5nIHRoZSBgZHVtcGlvYFxyXG4gICAqIG9wdGlvbi5cclxuICAgKi9cclxuICBkdW1waW8oc3RyaWN0Q2hlY2spIHtcclxuICAgIHJldHVybiB2LmJvb2xlYW4oc3RyaWN0Q2hlY2spO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFRoZSBgc2xvd01vYCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsIHN0cmljdGVyXHJcbiAgICogY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBzbG93TW9cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHNsb3dNb2BcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgc2xvd01vKHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGBkZWJ1Z2dpbmdQb3J0YCB2YWxpZGF0b3IgdGhhdCByZXR1cm5zIGEgWm9kIHNjaGVtYSB3aXRoIGFuIG9wdGlvbmFsXHJcbiAgICogc3RyaWN0ZXIgY2hlY2sgYmFzZWQgb24gdGhlIGBzdHJpY3RDaGVja2AgcGFyYW1ldGVyLlxyXG4gICAqXHJcbiAgICogVGhlIHZhbGlkYXRpb24gc2NoZW1hIGVuc3VyZXMgdGhlIHNhbWUgd29yayBhcyB0aGUgYG5vbk5lZ2F0aXZlTnVtYFxyXG4gICAqIHZhbGlkYXRvci5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiBkZWJ1Z2dpbmdQb3J0XHJcbiAgICpcclxuICAgKiBAcGFyYW0ge2Jvb2xlYW59IHN0cmljdENoZWNrIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uIHNob3VsZFxyXG4gICAqIGJlIGFwcGxpZWQuXHJcbiAgICpcclxuICAgKiBAcmV0dXJucyB7ei5ab2RTY2hlbWF9IEEgWm9kIHNjaGVtYSBvYmplY3QgZm9yIHZhbGlkYXRpbmdcclxuICAgKiB0aGUgYGRlYnVnZ2luZ1BvcnRgIG9wdGlvbi5cclxuICAgKi9cclxuICBkZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKSB7XHJcbiAgICByZXR1cm4gdi5ub25OZWdhdGl2ZU51bShzdHJpY3RDaGVjayk7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVGhlIGByZXF1ZXN0SWRgIHZhbGlkYXRvciB0aGF0IHJldHVybnMgYSBab2Qgc2NoZW1hIHdpdGggYW4gb3B0aW9uYWxcclxuICAgKiBzdHJpY3RlciBjaGVjayBiYXNlZCBvbiB0aGUgYHN0cmljdENoZWNrYCBwYXJhbWV0ZXIuXHJcbiAgICpcclxuICAgKiBUaGUgdmFsaWRhdGlvbiBzY2hlbWEgZW5zdXJlcyB0aGUgc2FtZSB3b3JrIGFzIHRoZSBgc3RyaW5nYCB2YWxpZGF0b3IuXHJcbiAgICogQWRkaXRpb25hbGx5LCBpdCBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCBvciBjYW4gYmUgbnVsbC5cclxuICAgKlxyXG4gICAqIEBmdW5jdGlvbiByZXF1ZXN0SWRcclxuICAgKlxyXG4gICAqIEBwYXJhbSB7Ym9vbGVhbn0gc3RyaWN0Q2hlY2sgLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb24gc2hvdWxkXHJcbiAgICogYmUgYXBwbGllZC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHt6LlpvZFNjaGVtYX0gQSBab2Qgc2NoZW1hIG9iamVjdCBmb3IgdmFsaWRhdGluZyB0aGUgYHJlcXVlc3RJZGBcclxuICAgKiBvcHRpb24uXHJcbiAgICovXHJcbiAgcmVxdWVzdElkKCkge1xyXG4gICAgcmV0dXJuIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC51dWlkKHsgbWVzc2FnZTogJ1RoZSB2YWx1ZSBtdXN0IGJlIGEgc3RyaW5naWZpZWQgVVVJRCcgfSlcclxuICAgICAgLm51bGxhYmxlKCk7XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgcHVwcGV0ZWVyIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQdXBwZXRlZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFyZ3M6IHZhbGlkYXRvcnMuYXJncyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgaGlnaGNoYXJ0cyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgSGlnaGNoYXJ0c1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgdmVyc2lvbjogdmFsaWRhdG9ycy52ZXJzaW9uKHN0cmljdENoZWNrKSxcclxuICAgICAgY2RuVXJsOiB2YWxpZGF0b3JzLmNkblVybChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlRmV0Y2g6IHZhbGlkYXRvcnMuZm9yY2VGZXRjaChzdHJpY3RDaGVjayksXHJcbiAgICAgIGNhY2hlUGF0aDogdmFsaWRhdG9ycy5jYWNoZVBhdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb3JlU2NyaXB0czogdmFsaWRhdG9ycy5jb3JlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIG1vZHVsZVNjcmlwdHM6IHZhbGlkYXRvcnMubW9kdWxlU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGluZGljYXRvclNjcmlwdHM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGN1c3RvbVNjcmlwdHM6IHZhbGlkYXRvcnMuY3VzdG9tU2NyaXB0cyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZXhwb3J0IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBFeHBvcnRTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGluZmlsZTogdmFsaWRhdG9ycy5pbmZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBpbnN0cjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gICAgICBvcHRpb25zOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICAgICAgc3ZnOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gICAgICBvdXRmaWxlOiB2YWxpZGF0b3JzLm91dGZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0eXBlOiB2YWxpZGF0b3JzLnR5cGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjb25zdHI6IHZhbGlkYXRvcnMuY29uc3RyKHN0cmljdENoZWNrKSxcclxuICAgICAgYjY0OiB2YWxpZGF0b3JzLmI2NChzdHJpY3RDaGVjayksXHJcbiAgICAgIG5vRG93bmxvYWQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRIZWlnaHQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIGRlZmF1bHRXaWR0aDogdmFsaWRhdG9ycy5kZWZhdWx0V2lkdGgoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWZhdWx0U2NhbGU6IHZhbGlkYXRvcnMuZGVmYXVsdFNjYWxlKHN0cmljdENoZWNrKSxcclxuICAgICAgaGVpZ2h0OiB2YWxpZGF0b3JzLmhlaWdodChzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpZHRoOiB2YWxpZGF0b3JzLndpZHRoKHN0cmljdENoZWNrKSxcclxuICAgICAgc2NhbGU6IHZhbGlkYXRvcnMuc2NhbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBnbG9iYWxPcHRpb25zOiB2YWxpZGF0b3JzLmdsb2JhbE9wdGlvbnMoKSxcclxuICAgICAgdGhlbWVPcHRpb25zOiB2YWxpZGF0b3JzLnRoZW1lT3B0aW9ucygpLFxyXG4gICAgICBiYXRjaDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB2YWxpZGF0b3JzLnJhc3Rlcml6YXRpb25UaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBjdXN0b21Mb2dpYyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgQ3VzdG9tTG9naWNTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IHZhbGlkYXRvcnMuYWxsb3dGaWxlUmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgY3VzdG9tQ29kZTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICAgICAgY2FsbGJhY2s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gICAgICByZXNvdXJjZXM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKHN0cmljdENoZWNrKSxcclxuICAgICAgbG9hZENvbmZpZzogdmFsaWRhdG9ycy5sb2FkQ29uZmlnKGZhbHNlKSxcclxuICAgICAgY3JlYXRlQ29uZmlnOiB2YWxpZGF0b3JzLmNyZWF0ZUNvbmZpZyhmYWxzZSlcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgc2VydmVyLnByb3h5IHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQcm94eVNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgaG9zdDogdmFsaWRhdG9ycy5wcm94eUhvc3QoZmFsc2UpLFxyXG4gICAgICBwb3J0OiB2YWxpZGF0b3JzLnByb3h5UG9ydChzdHJpY3RDaGVjayksXHJcbiAgICAgIHRpbWVvdXQ6IHZhbGlkYXRvcnMucHJveHlUaW1lb3V0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBzZXJ2ZXIucmF0ZUxpbWl0aW5nIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBSYXRlTGltaXRpbmdTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVSYXRlTGltaXRpbmcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhSZXF1ZXN0czogdmFsaWRhdG9ycy5tYXhSZXF1ZXN0cyhzdHJpY3RDaGVjayksXHJcbiAgICAgIHdpbmRvdzogdmFsaWRhdG9ycy53aW5kb3coc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZWxheTogdmFsaWRhdG9ycy5kZWxheShzdHJpY3RDaGVjayksXHJcbiAgICAgIHRydXN0UHJveHk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShzdHJpY3RDaGVjayksXHJcbiAgICAgIHNraXBLZXk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgICAgIHNraXBUb2tlbjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlci5zc2wgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFNzbFNjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgZW5hYmxlOiB2YWxpZGF0b3JzLmVuYWJsZVNzbChzdHJpY3RDaGVjayksXHJcbiAgICAgIGZvcmNlOiB2YWxpZGF0b3JzLnNzbEZvcmNlKHN0cmljdENoZWNrKSxcclxuICAgICAgcG9ydDogdmFsaWRhdG9ycy5zc2xQb3J0KHN0cmljdENoZWNrKSxcclxuICAgICAgY2VydFBhdGg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpXHJcbiAgICB9KVxyXG4gICAgLnBhcnRpYWwoKTtcclxuXHJcbi8vIFNjaGVtYSBmb3IgdGhlIHNlcnZlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgU2VydmVyU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHoub2JqZWN0KHtcclxuICAgIGVuYWJsZTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBob3N0OiB2YWxpZGF0b3JzLmhvc3Qoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwb3J0OiB2YWxpZGF0b3JzLnBvcnQoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICB1cGxvYWRMaW1pdDogdmFsaWRhdG9ycy51cGxvYWRMaW1pdChzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIGJlbmNobWFya2luZzogdmFsaWRhdG9ycy5zZXJ2ZXJCZW5jaG1hcmtpbmcoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICBwcm94eTogUHJveHlTY2hlbWEoc3RyaWN0Q2hlY2spLm9wdGlvbmFsKCksXHJcbiAgICByYXRlTGltaXRpbmc6IFJhdGVMaW1pdGluZ1NjaGVtYShzdHJpY3RDaGVjaykub3B0aW9uYWwoKSxcclxuICAgIHNzbDogU3NsU2NoZW1hKHN0cmljdENoZWNrKS5vcHRpb25hbCgpXHJcbiAgfSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBwb29sIHNlY3Rpb24gb2Ygb3B0aW9uc1xyXG5jb25zdCBQb29sU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBtaW5Xb3JrZXJzOiB2YWxpZGF0b3JzLm1pbldvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBtYXhXb3JrZXJzOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB3b3JrTGltaXQ6IHZhbGlkYXRvcnMud29ya0xpbWl0KHN0cmljdENoZWNrKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXQ6IHZhbGlkYXRvcnMuYWNxdWlyZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBjcmVhdGVUaW1lb3V0OiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0cm95VGltZW91dDogdmFsaWRhdG9ycy5kZXN0cm95VGltZW91dChzdHJpY3RDaGVjayksXHJcbiAgICAgIGlkbGVUaW1lb3V0OiB2YWxpZGF0b3JzLmlkbGVUaW1lb3V0KHN0cmljdENoZWNrKSxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbDogdmFsaWRhdG9ycy5jcmVhdGVSZXRyeUludGVydmFsKHN0cmljdENoZWNrKSxcclxuICAgICAgcmVhcGVySW50ZXJ2YWw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBiZW5jaG1hcmtpbmc6IHZhbGlkYXRvcnMucG9vbEJlbmNobWFya2luZyhzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgbG9nZ2luZyBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgTG9nZ2luZ1NjaGVtYSA9IChzdHJpY3RDaGVjaykgPT5cclxuICB6XHJcbiAgICAub2JqZWN0KHtcclxuICAgICAgbGV2ZWw6IHZhbGlkYXRvcnMubG9nTGV2ZWwoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBmaWxlOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBkZXN0OiB2YWxpZGF0b3JzLmxvZ0Rlc3Qoc3RyaWN0Q2hlY2spLFxyXG4gICAgICB0b0NvbnNvbGU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKHN0cmljdENoZWNrKSxcclxuICAgICAgdG9GaWxlOiB2YWxpZGF0b3JzLmxvZ1RvRmlsZShzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgdWkgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IFVpU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoc3RyaWN0Q2hlY2spLFxyXG4gICAgICByb3V0ZTogdmFsaWRhdG9ycy51aVJvdXRlKHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBvdGhlciBzZWN0aW9uIG9mIG9wdGlvbnNcclxuY29uc3QgT3RoZXJTY2hlbWEgPSAoc3RyaWN0Q2hlY2spID0+XHJcbiAgelxyXG4gICAgLm9iamVjdCh7XHJcbiAgICAgIG5vZGVFbnY6IHZhbGlkYXRvcnMubm9kZUVudihzdHJpY3RDaGVjayksXHJcbiAgICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKHN0cmljdENoZWNrKSxcclxuICAgICAgbm9Mb2dvOiB2YWxpZGF0b3JzLm5vTG9nbyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGhhcmRSZXNldFBhZ2U6IHZhbGlkYXRvcnMuaGFyZFJlc2V0UGFnZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGJyb3dzZXJTaGVsbE1vZGU6IHZhbGlkYXRvcnMuYnJvd3NlclNoZWxsTW9kZShzdHJpY3RDaGVjayksXHJcbiAgICAgIHZhbGlkYXRpb246IHZhbGlkYXRvcnMudmFsaWRhdGlvbihzdHJpY3RDaGVjaylcclxuICAgIH0pXHJcbiAgICAucGFydGlhbCgpO1xyXG5cclxuLy8gU2NoZW1hIGZvciB0aGUgZGVidWcgc2VjdGlvbiBvZiBvcHRpb25zXHJcbmNvbnN0IERlYnVnU2NoZW1hID0gKHN0cmljdENoZWNrKSA9PlxyXG4gIHpcclxuICAgIC5vYmplY3Qoe1xyXG4gICAgICBlbmFibGU6IHZhbGlkYXRvcnMuZW5hYmxlRGVidWcoc3RyaWN0Q2hlY2spLFxyXG4gICAgICBoZWFkbGVzczogdmFsaWRhdG9ycy5oZWFkbGVzcyhzdHJpY3RDaGVjayksXHJcbiAgICAgIGRldnRvb2xzOiB2YWxpZGF0b3JzLmRldnRvb2xzKHN0cmljdENoZWNrKSxcclxuICAgICAgbGlzdGVuVG9Db25zb2xlOiB2YWxpZGF0b3JzLmxpc3RlblRvQ29uc29sZShzdHJpY3RDaGVjayksXHJcbiAgICAgIGR1bXBpbzogdmFsaWRhdG9ycy5kdW1waW8oc3RyaWN0Q2hlY2spLFxyXG4gICAgICBzbG93TW86IHZhbGlkYXRvcnMuc2xvd01vKHN0cmljdENoZWNrKSxcclxuICAgICAgZGVidWdnaW5nUG9ydDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KHN0cmljdENoZWNrKVxyXG4gICAgfSlcclxuICAgIC5wYXJ0aWFsKCk7XHJcblxyXG4vLyBTdHJpY3Qgc2NoZW1hIGZvciB0aGUgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBTdHJpY3RDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKHRydWUpLFxyXG4gIGhpZ2hjaGFydHM6IEhpZ2hjaGFydHNTY2hlbWEodHJ1ZSksXHJcbiAgZXhwb3J0OiBFeHBvcnRTY2hlbWEodHJ1ZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKHRydWUpLFxyXG4gIHNlcnZlcjogU2VydmVyU2NoZW1hKHRydWUpLFxyXG4gIHBvb2w6IFBvb2xTY2hlbWEodHJ1ZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYSh0cnVlKSxcclxuICB1aTogVWlTY2hlbWEodHJ1ZSksXHJcbiAgb3RoZXI6IE90aGVyU2NoZW1hKHRydWUpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYSh0cnVlKVxyXG59KTtcclxuXHJcbi8vIExvb3NlIHNjaGVtYSBmb3IgdGhlIGNvbmZpZ1xyXG5leHBvcnQgY29uc3QgTG9vc2VDb25maWdTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgcmVxdWVzdElkOiB2YWxpZGF0b3JzLnJlcXVlc3RJZCgpLFxyXG4gIHB1cHBldGVlcjogUHVwcGV0ZWVyU2NoZW1hKGZhbHNlKSxcclxuICBoaWdoY2hhcnRzOiBIaWdoY2hhcnRzU2NoZW1hKGZhbHNlKSxcclxuICBleHBvcnQ6IEV4cG9ydFNjaGVtYShmYWxzZSksXHJcbiAgY3VzdG9tTG9naWM6IEN1c3RvbUxvZ2ljU2NoZW1hKGZhbHNlKSxcclxuICBzZXJ2ZXI6IFNlcnZlclNjaGVtYShmYWxzZSksXHJcbiAgcG9vbDogUG9vbFNjaGVtYShmYWxzZSksXHJcbiAgbG9nZ2luZzogTG9nZ2luZ1NjaGVtYShmYWxzZSksXHJcbiAgdWk6IFVpU2NoZW1hKGZhbHNlKSxcclxuICBvdGhlcjogT3RoZXJTY2hlbWEoZmFsc2UpLFxyXG4gIGRlYnVnOiBEZWJ1Z1NjaGVtYShmYWxzZSlcclxufSk7XHJcblxyXG4vLyBTY2hlbWEgZm9yIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgY29uZmlnXHJcbmV4cG9ydCBjb25zdCBFbnZTY2hlbWEgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX0FSR1M6IHZhbGlkYXRvcnMuYXJncyhmYWxzZSksXHJcblxyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHZhbGlkYXRvcnMudmVyc2lvbihmYWxzZSksXHJcbiAgSElHSENIQVJUU19DRE5fVVJMOiB2YWxpZGF0b3JzLmNkblVybChmYWxzZSksXHJcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdmFsaWRhdG9ycy5mb3JjZUZldGNoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHZhbGlkYXRvcnMuY2FjaGVQYXRoKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2YWxpZGF0b3JzLmFkbWluVG9rZW4oZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLmNvcmVTY3JpcHRzKGZhbHNlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2YWxpZGF0b3JzLm1vZHVsZVNjcmlwdHMoZmFsc2UpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHZhbGlkYXRvcnMuaW5kaWNhdG9yU2NyaXB0cyhmYWxzZSksXHJcbiAgSElHSENIQVJUU19DVVNUT01fU0NSSVBUUzogdmFsaWRhdG9ycy5jdXN0b21TY3JpcHRzKGZhbHNlKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX0lORklMRTogdmFsaWRhdG9ycy5pbmZpbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9JTlNUUjogdmFsaWRhdG9ycy5pbnN0cigpLFxyXG4gIEVYUE9SVF9PUFRJT05TOiB2YWxpZGF0b3JzLm9wdGlvbnMoKSxcclxuICBFWFBPUlRfU1ZHOiB2YWxpZGF0b3JzLnN2ZygpLFxyXG4gIEVYUE9SVF9CQVRDSDogdmFsaWRhdG9ycy5iYXRjaChmYWxzZSksXHJcbiAgRVhQT1JUX09VVEZJTEU6IHZhbGlkYXRvcnMub3V0ZmlsZShmYWxzZSksXHJcbiAgRVhQT1JUX1RZUEU6IHZhbGlkYXRvcnMudHlwZShmYWxzZSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdmFsaWRhdG9ycy5jb25zdHIoZmFsc2UpLFxyXG4gIEVYUE9SVF9CNjQ6IHZhbGlkYXRvcnMuYjY0KGZhbHNlKSxcclxuICBFWFBPUlRfTk9fRE9XTkxPQUQ6IHZhbGlkYXRvcnMubm9Eb3dubG9hZChmYWxzZSksXHJcbiAgRVhQT1JUX0hFSUdIVDogdmFsaWRhdG9ycy5oZWlnaHQoZmFsc2UpLFxyXG4gIEVYUE9SVF9XSURUSDogdmFsaWRhdG9ycy53aWR0aChmYWxzZSksXHJcbiAgRVhQT1JUX1NDQUxFOiB2YWxpZGF0b3JzLnNjYWxlKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHZhbGlkYXRvcnMuZGVmYXVsdEhlaWdodChmYWxzZSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHZhbGlkYXRvcnMuZGVmYXVsdFdpZHRoKGZhbHNlKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdmFsaWRhdG9ycy5kZWZhdWx0U2NhbGUoZmFsc2UpLFxyXG4gIEVYUE9SVF9HTE9CQUxfT1BUSU9OUzogdmFsaWRhdG9ycy5nbG9iYWxPcHRpb25zKCksXHJcbiAgRVhQT1JUX1RIRU1FX09QVElPTlM6IHZhbGlkYXRvcnMudGhlbWVPcHRpb25zKCksXHJcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdmFsaWRhdG9ycy5yYXN0ZXJpemF0aW9uVGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdmFsaWRhdG9ycy5hbGxvd0NvZGVFeGVjdXRpb24oZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdmFsaWRhdG9ycy5hbGxvd0ZpbGVSZXNvdXJjZXMoZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19DVVNUT01fQ09ERTogdmFsaWRhdG9ycy5jdXN0b21Db2RlKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfQ0FMTEJBQ0s6IHZhbGlkYXRvcnMuY2FsbGJhY2soZmFsc2UpLFxyXG4gIENVU1RPTV9MT0dJQ19SRVNPVVJDRVM6IHZhbGlkYXRvcnMucmVzb3VyY2VzKGZhbHNlKSxcclxuICBDVVNUT01fTE9HSUNfTE9BRF9DT05GSUc6IHZhbGlkYXRvcnMubG9hZENvbmZpZyhmYWxzZSksXHJcbiAgQ1VTVE9NX0xPR0lDX0NSRUFURV9DT05GSUc6IHZhbGlkYXRvcnMuY3JlYXRlQ29uZmlnKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVTZXJ2ZXIoZmFsc2UpLFxyXG4gIFNFUlZFUl9IT1NUOiB2YWxpZGF0b3JzLmhvc3QoZmFsc2UpLFxyXG4gIFNFUlZFUl9QT1JUOiB2YWxpZGF0b3JzLnBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9VUExPQURfTElNSVQ6IHZhbGlkYXRvcnMudXBsb2FkTGltaXQoZmFsc2UpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHZhbGlkYXRvcnMuc2VydmVyQmVuY2htYXJraW5nKGZhbHNlKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHZhbGlkYXRvcnMucHJveHlIb3N0KGZhbHNlKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdmFsaWRhdG9ycy5wcm94eVBvcnQoZmFsc2UpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2YWxpZGF0b3JzLnByb3h5VGltZW91dChmYWxzZSksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2YWxpZGF0b3JzLmVuYWJsZVJhdGVMaW1pdGluZyhmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2YWxpZGF0b3JzLm1heFJlcXVlc3RzKGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHZhbGlkYXRvcnMud2luZG93KGZhbHNlKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdmFsaWRhdG9ycy5kZWxheShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHZhbGlkYXRvcnMudHJ1c3RQcm94eShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHZhbGlkYXRvcnMuc2tpcEtleShmYWxzZSksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdmFsaWRhdG9ycy5za2lwVG9rZW4oZmFsc2UpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlU3NsKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2YWxpZGF0b3JzLnNzbEZvcmNlKGZhbHNlKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHZhbGlkYXRvcnMuc3NsUG9ydChmYWxzZSksXHJcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHZhbGlkYXRvcnMuc3NsQ2VydFBhdGgoZmFsc2UpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdmFsaWRhdG9ycy5taW5Xb3JrZXJzKGZhbHNlKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2YWxpZGF0b3JzLm1heFdvcmtlcnMoZmFsc2UpLFxyXG4gIFBPT0xfV09SS19MSU1JVDogdmFsaWRhdG9ycy53b3JrTGltaXQoZmFsc2UpLFxyXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2YWxpZGF0b3JzLmFjcXVpcmVUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2YWxpZGF0b3JzLmNyZWF0ZVRpbWVvdXQoZmFsc2UpLFxyXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2YWxpZGF0b3JzLmRlc3Ryb3lUaW1lb3V0KGZhbHNlKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdmFsaWRhdG9ycy5pZGxlVGltZW91dChmYWxzZSksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHZhbGlkYXRvcnMuY3JlYXRlUmV0cnlJbnRlcnZhbChmYWxzZSksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHZhbGlkYXRvcnMucmVhcGVySW50ZXJ2YWwoZmFsc2UpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2YWxpZGF0b3JzLnBvb2xCZW5jaG1hcmtpbmcoZmFsc2UpLFxyXG5cclxuICAvLyBsb2dnaW5nXHJcbiAgTE9HR0lOR19MRVZFTDogdmFsaWRhdG9ycy5sb2dMZXZlbChmYWxzZSksXHJcbiAgTE9HR0lOR19GSUxFOiB2YWxpZGF0b3JzLmxvZ0ZpbGUoZmFsc2UpLFxyXG4gIExPR0dJTkdfREVTVDogdmFsaWRhdG9ycy5sb2dEZXN0KGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHZhbGlkYXRvcnMubG9nVG9Db25zb2xlKGZhbHNlKSxcclxuICBMT0dHSU5HX1RPX0ZJTEU6IHZhbGlkYXRvcnMubG9nVG9GaWxlKGZhbHNlKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHZhbGlkYXRvcnMuZW5hYmxlVWkoZmFsc2UpLFxyXG4gIFVJX1JPVVRFOiB2YWxpZGF0b3JzLnVpUm91dGUoZmFsc2UpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2YWxpZGF0b3JzLm5vZGVFbnYoZmFsc2UpLFxyXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2YWxpZGF0b3JzLmxpc3RlblRvUHJvY2Vzc0V4aXRzKGZhbHNlKSxcclxuICBPVEhFUl9OT19MT0dPOiB2YWxpZGF0b3JzLm5vTG9nbyhmYWxzZSksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2YWxpZGF0b3JzLmhhcmRSZXNldFBhZ2UoZmFsc2UpLFxyXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdmFsaWRhdG9ycy5icm93c2VyU2hlbGxNb2RlKGZhbHNlKSxcclxuICBPVEhFUl9WQUxJREFUSU9OOiB2YWxpZGF0b3JzLnZhbGlkYXRpb24oZmFsc2UpLFxyXG5cclxuICAvLyBkZWJ1Z2dlclxyXG4gIERFQlVHX0VOQUJMRTogdmFsaWRhdG9ycy5lbmFibGVEZWJ1ZyhmYWxzZSksXHJcbiAgREVCVUdfSEVBRExFU1M6IHZhbGlkYXRvcnMuaGVhZGxlc3MoZmFsc2UpLFxyXG4gIERFQlVHX0RFVlRPT0xTOiB2YWxpZGF0b3JzLmRldnRvb2xzKGZhbHNlKSxcclxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdmFsaWRhdG9ycy5saXN0ZW5Ub0NvbnNvbGUoZmFsc2UpLFxyXG4gIERFQlVHX0RVTVBJTzogdmFsaWRhdG9ycy5kdW1waW8oZmFsc2UpLFxyXG4gIERFQlVHX1NMT1dfTU86IHZhbGlkYXRvcnMuc2xvd01vKGZhbHNlKSxcclxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdmFsaWRhdG9ycy5kZWJ1Z2dpbmdQb3J0KGZhbHNlKVxyXG59KTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBvcHRpb25zIHVzaW5nIHRoZSBFbnZTY2hlbWEuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwcm9jZXNzLmVudiAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgZnJvbSBlbnZpcm9ubWVudFxyXG4gKiB2YXJpYWJsZXMgZmlsZSB0byB2YWxpZGF0ZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbnZzID0gRW52U2NoZW1hLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzIHRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdXNpbmcgdGhlIGBTdHJpY3RDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc3RyaWN0VmFsaWRhdGVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIHZhbGlkYXRlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHN0cmljdFZhbGlkYXRlKGNvbmZpZ09wdGlvbnMpIHtcclxuICByZXR1cm4gU3RyaWN0Q29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHVzaW5nIHRoZSBgTG9vc2VDb25maWdTY2hlbWFgLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gdmFsaWRhdGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gbG9vc2VWYWxpZGF0ZShjb25maWdPcHRpb25zKSB7XHJcbiAgcmV0dXJuIExvb3NlQ29uZmlnU2NoZW1hLnBhcnRpYWwoKS5wYXJzZShjb25maWdPcHRpb25zKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEN1c3RvbSBlcnJvciBtYXBwaW5nIGZ1bmN0aW9uIGZvciBab2Qgc2NoZW1hIHZhbGlkYXRpb24uXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gY3VzdG9taXplcyB0aGUgZXJyb3IgbWVzc2FnZXMgcHJvZHVjZWQgYnkgWm9kIHNjaGVtYVxyXG4gKiB2YWxpZGF0aW9uLCBwcm92aWRpbmcgbW9yZSBzcGVjaWZpYyBhbmQgdXNlci1mcmllbmRseSBmZWVkYmFjayBiYXNlZCBvbiB0aGVcclxuICogaXNzdWUgdHlwZSBhbmQgY29udGV4dC5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIG1vZGlmaWVzIHRoZSBlcnJvciBtZXNzYWdlcyBhcyBmb2xsb3dzOlxyXG4gKlxyXG4gKiAtIEZvciBtaXNzaW5nIHJlcXVpcmVkIHZhbHVlcyAodW5kZWZpbmVkKSwgaXQgcmV0dXJucyBhIG1lc3NhZ2UgaW5kaWNhdGluZ1xyXG4gKiB0aGF0IG5vIHZhbHVlIHdhcyBwcm92aWRlZCBmb3IgdGhlIHNwZWNpZmljIHByb3BlcnR5LlxyXG4gKlxyXG4gKiAtIEZvciBjdXN0b20gdmFsaWRhdGlvbiBlcnJvcnMsIGlmIGEgY3VzdG9tIGVycm9yIG1lc3NhZ2UgaXMgcHJvdmlkZWQgaW4gdGhlXHJcbiAqIGlzc3VlIHBhcmFtZXRlcnMsIGl0IGluY2x1ZGVzIHRoaXMgbWVzc2FnZSBhbG9uZyB3aXRoIHRoZSBpbnZhbGlkIGRhdGFcclxuICogcmVjZWl2ZWQuXHJcbiAqXHJcbiAqIC0gRm9yIGFsbCBvdGhlciBlcnJvcnMsIGl0IGFwcGVuZHMgcHJvcGVydHktc3BlY2lmaWMgaW5mb3JtYXRpb24gdG8gdGhlXHJcbiAqIGRlZmF1bHQgZXJyb3IgbWVzc2FnZSBwcm92aWRlZCBieSBab2QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3VzdG9tRXJyb3JNYXBcclxuICpcclxuICogQHBhcmFtIHt6LlpvZElzc3VlfSBpc3N1ZSAtIFRoZSBpc3N1ZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSB2YWxpZGF0aW9uXHJcbiAqIGVycm9yLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29udGV4dCAtIFRoZSBjb250ZXh0IG9iamVjdCBwcm92aWRpbmcgYWRkaXRpb25hbCBpbmZvcm1hdGlvblxyXG4gKiBhYm91dCB0aGUgdmFsaWRhdGlvbiBlcnJvci5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIGN1c3RvbWl6ZWQgZXJyb3IgbWVzc2FnZS5cclxuICovXHJcbmZ1bmN0aW9uIF9jdXN0b21FcnJvck1hcChpc3N1ZSwgY29udGV4dCkge1xyXG4gIC8vIEdldCB0aGUgY2hhaW4gb2YgcHJvcGVydGllcyB3aGljaCBlcnJvciBkaXJlY3RseSByZWZlcnMgdG9cclxuICBjb25zdCBwcm9wZXJ0eU5hbWUgPSBpc3N1ZS5wYXRoLmpvaW4oJy4nKTtcclxuXHJcbiAgLy8gQ3JlYXRlIHRoZSBmaXJzdCBwYXJ0IG9mIHRoZSBtZXNzYWdlIGFib3V0IHRoZSBwcm9wZXJ0eSBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IHByb3BlcnR5SW5mbyA9IGBJbnZhbGlkIHZhbHVlIGZvciB0aGUgJHtwcm9wZXJ0eU5hbWV9YDtcclxuXHJcbiAgLy8gTW9kaWZpZWQgbWVzc2FnZSBmb3IgdGhlIGludmFsaWQgdHlwZVxyXG4gIGlmIChpc3N1ZS5jb2RlID09PSB6LlpvZElzc3VlQ29kZS5pbnZhbGlkX3R5cGUpIHtcclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSByZXF1aXJlZCB2YWx1ZXNcclxuICAgIGlmIChpc3N1ZS5yZWNlaXZlZCA9PT0gei5ab2RQYXJzZWRUeXBlLnVuZGVmaW5lZCkge1xyXG4gICAgICByZXR1cm4ge1xyXG4gICAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBObyB2YWx1ZSB3YXMgcHJvdmlkZWQuYFxyXG4gICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBzcGVjaWZpYyBpbnZhbGlkIHR5cGUgd2hlbiB2YWx1ZXMgZXhpc3RcclxuICAgIHJldHVybiB7XHJcbiAgICAgIG1lc3NhZ2U6IGAke3Byb3BlcnR5SW5mb30gLSBJbnZhbGlkIHR5cGUuICR7Y29udGV4dC5kZWZhdWx0RXJyb3J9LmBcclxuICAgIH07XHJcbiAgfVxyXG5cclxuICAvLyBNb2RpZmllZCBtZXNzYWdlIGZvciB0aGUgY3VzdG9tIHZhbGlkYXRpb25cclxuICBpZiAoaXNzdWUuY29kZSA9PT0gei5ab2RJc3N1ZUNvZGUuY3VzdG9tKSB7XHJcbiAgICAvLyBJZiB0aGUgY3VzdG9tIG1lc3NhZ2UgZm9yIGVycm9yIGV4aXN0LCBpbmNsdWRlIGl0XHJcbiAgICBpZiAoaXNzdWUucGFyYW1zPy5lcnJvck1lc3NhZ2UpIHtcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtpc3N1ZS5wYXJhbXM/LmVycm9yTWVzc2FnZX0sIHJlY2VpdmVkICcke2NvbnRleHQuZGF0YX0nLmBcclxuICAgICAgfTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE1vZGlmaWVkIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgaWYgKGlzc3VlLmNvZGUgPT09IHouWm9kSXNzdWVDb2RlLmludmFsaWRfdW5pb24pIHtcclxuICAgIC8vIENyZWF0ZSB0aGUgZmlyc3QgcGFydCBvZiB0aGUgbWVzc2FnZSBhYm91dCB0aGUgbXVsdGlwbGUgZXJyb3JzXHJcbiAgICBsZXQgbWVzc2FnZSA9IGBNdWx0aXBsZSBlcnJvcnMgb2NjdXJyZWQgZm9yIHRoZSAke3Byb3BlcnR5TmFtZX06XFxuYDtcclxuXHJcbiAgICAvLyBDeWNsZSB0aHJvdWdoIGFsbCBlcnJvcnMgYW5kIGNyZWF0ZSBhIGNvcnJlY3QgbWVzc2FnZVxyXG4gICAgaXNzdWUudW5pb25FcnJvcnMuZm9yRWFjaCgodmFsdWUpID0+IHtcclxuICAgICAgY29uc3QgaW5kZXggPSB2YWx1ZS5pc3N1ZXNbMF0ubWVzc2FnZS5pbmRleE9mKCctJyk7XHJcbiAgICAgIG1lc3NhZ2UgKz1cclxuICAgICAgICBpbmRleCAhPT0gLTFcclxuICAgICAgICAgID8gYCR7dmFsdWUuaXNzdWVzWzBdLm1lc3NhZ2V9XFxuYC5zdWJzdHJpbmcoaW5kZXgpXHJcbiAgICAgICAgICA6IGAke3ZhbHVlLmlzc3Vlc1swXS5tZXNzYWdlfVxcbmA7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBSZXR1cm4gdGhlIGZpbmFsIG1lc3NhZ2UgZm9yIHRoZSBpbnZhbGlkIHVuaW9uIGVycm9yXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICBtZXNzYWdlXHJcbiAgICB9O1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBkZWZhdWx0IGVycm9yIG1lc3NhZ2UsIGV4dGVuZGVkIGJ5IHRoZSBpbmZvIGFib3V0IHRoZSBwcm9wZXJ0eVxyXG4gIHJldHVybiB7XHJcbiAgICBtZXNzYWdlOiBgJHtwcm9wZXJ0eUluZm99IC0gJHtjb250ZXh0LmRlZmF1bHRFcnJvcn0uYFxyXG4gIH07XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICB2YWxpZGF0b3JzLFxyXG4gIFN0cmljdENvbmZpZ1NjaGVtYSxcclxuICBMb29zZUNvbmZpZ1NjaGVtYSxcclxuICBFbnZTY2hlbWEsXHJcbiAgZW52cyxcclxuICBzdHJpY3RWYWxpZGF0ZSxcclxuICBsb29zZVZhbGlkYXRlXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEEgY3VzdG9tIGVycm9yIGNsYXNzIGZvciBoYW5kbGluZyBleHBvcnQtcmVsYXRlZCBlcnJvcnMuIEV4dGVuZHMgdGhlIG5hdGl2ZVxyXG4gKiBgRXJyb3JgIGNsYXNzIHRvIGluY2x1ZGUgYWRkaXRpb25hbCBwcm9wZXJ0aWVzIGxpa2Ugc3RhdHVzIGNvZGUgYW5kIHN0YWNrXHJcbiAqIHRyYWNlIGRldGFpbHMuXHJcbiAqL1xyXG5jbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcclxuICAvKipcclxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIHRoZSBgRXhwb3J0RXJyb3JgLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtzdHJpbmd9IG1lc3NhZ2UgLSBUaGUgZXJyb3IgbWVzc2FnZSB0byBiZSBkaXNwbGF5ZWQuXHJcbiAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXR1c0NvZGUgLSBPcHRpb25hbCBIVFRQIHN0YXR1cyBjb2RlIGFzc29jaWF0ZWRcclxuICAgKiB3aXRoIHRoZSBlcnJvciAoZS5nLiwgNDAwLCA1MDApLlxyXG4gICAqL1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1c0NvZGUpIHtcclxuICAgIHN1cGVyKCk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBgbWVzc2FnZWAgYW5kIGBzdGFja01lc3NhZ2VgIHdpdGggcHJvdmlkZWQgbWVzc2FnZVxyXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcclxuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGBzdGF0dXNDb2RlYCBpZiBwcm92aWRlZFxyXG4gICAgaWYgKHN0YXR1c0NvZGUpIHtcclxuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzQ29kZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8qKlxyXG4gICAqIFNldHMgYWRkaXRpb25hbCBlcnJvciBkZXRhaWxzIGJhc2VkIG9uIGFuIGV4aXN0aW5nIGVycm9yIG9iamVjdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gQW4gZXJyb3Igb2JqZWN0IGNvbnRhaW5pbmcgZGV0YWlscyB0byBwb3B1bGF0ZVxyXG4gICAqIHRoZSBgRXhwb3J0RXJyb3JgIGluc3RhbmNlLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge0V4cG9ydEVycm9yfSBUaGUgdXBkYXRlZCBpbnN0YW5jZSBvZiB0aGUgYEV4cG9ydEVycm9yYCBjbGFzcy5cclxuICAgKi9cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgLy8gU2F2ZSB0aGUgcHJvdmlkZWQgZXJyb3JcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGVycm9yJ3MgbmFtZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3IubmFtZSkge1xyXG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBpZiBwcmVzZW50XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNldCB0aGUgZXJyb3IncyBzdGFjayBhbmQgc3RhY2sncyBtZXNzYWdlIGlmIHByZXNlbnRcclxuICAgIGlmIChlcnJvci5zdGFjaykge1xyXG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XHJcbiAgICAgIHRoaXMuc3RhY2sgPSBlcnJvci5zdGFjaztcclxuICAgIH1cclxuXHJcbiAgICAvLyBSZXR1cm4gdXBkYXRlZCBgRXhwb3J0RXJyb3JgIGluc3RhbmNlXHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgbWFuYWdlcyBjb25maWd1cmF0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcbiAqIGJ5IGxvYWRpbmcgYW5kIG1lcmdpbmcgb3B0aW9ucyBmcm9tIG11bHRpcGxlIHNvdXJjZXMsIHN1Y2ggYXMgdGhlIGRlZmF1bHRcclxuICogc2V0dGluZ3MsIGVudmlyb25tZW50IHZhcmlhYmxlcywgdXNlci1wcm92aWRlZCBvcHRpb25zLCBhbmQgY29tbWFuZC1saW5lXHJcbiAqIGFyZ3VtZW50cy4gRW5zdXJlcyB0aGUgZ2xvYmFsIG9wdGlvbnMgYXJlIHVwLXRvLWRhdGUgd2l0aCB0aGUgaGlnaGVzdFxyXG4gKiBwcmlvcml0eSB2YWx1ZXMuIFByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgYWNjZXNzaW5nIGFuZCB1cGRhdGluZyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrLCBsb2dab2RJc3N1ZXMgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGRlZXBDb3B5LCBnZXRBYnNvbHV0ZVBhdGgsIGlzT2JqZWN0IH0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZW52cyxcclxuICBsb29zZVZhbGlkYXRlLFxyXG4gIHN0cmljdFZhbGlkYXRlLFxyXG4gIHZhbGlkYXRvcnNcclxufSBmcm9tICcuL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IGRlZmF1bHRDb25maWcgZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gU2V0cyB0aGUgZ2xvYmFsIG9wdGlvbnMgd2l0aCBpbml0aWFsIHZhbHVlcyBmcm9tIHRoZSBkZWZhdWx0IGNvbmZpZ1xyXG5jb25zdCBnbG9iYWxPcHRpb25zID0gX2luaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuZXN0aW5nIGxldmVsIG9mIGFsbCBvcHRpb25zXHJcbmNvbnN0IG5lc3RlZFByb3BzID0gX2NyZWF0ZU5lc3RlZFByb3BzKGRlZmF1bHRDb25maWcpO1xyXG5cclxuLy8gUHJvcGVydGllcyBuYW1lcyB0aGF0IHNob3VsZCBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkXHJcbmNvbnN0IGFic29sdXRlUHJvcHMgPSBfY3JlYXRlQWJzb2x1dGVQcm9wcyhkZWZhdWx0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYSBjb3B5IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgb3IgYW4gb3JpZ2luYWwgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiB0aGUgYGdldENvcHlgIGZsYWcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9dHJ1ZV0gLSBTcGVjaWZpZXMgd2hldGhlciB0byByZXR1cm4gYSBjb3BpZWRcclxuICogb2JqZWN0IG9mIHRoZSBnbG9iYWwgb3B0aW9ucyAoYHRydWVgKSBvciBhIHJlZmVyZW5jZSB0byB0aGUgZ2xvYmFsIG9wdGlvbnNcclxuICogb2JqZWN0IChgZmFsc2VgKS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYHRydWVgLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgb3IgYSByZWZlcmVuY2VcclxuICogdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRPcHRpb25zKGdldENvcHkgPSB0cnVlKSB7XHJcbiAgLy8gUmV0dXJuIGEgY29weSBvciBhbiBvcmlnaW5hbCBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gZ2V0Q29weSA/IGRlZXBDb3B5KGdsb2JhbE9wdGlvbnMpIDogZ2xvYmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBvciBhIGNvcHkgb2YgdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAqIG9iamVjdCwgYmFzZWQgb24gdGhlIGBnZXRDb3B5YCBmbGFnLiBUaGUgYG5ld09wdGlvbnNgIG9iamVjdCBjYW4gYmVcclxuICogc3RyaWN0bHkgdmFsaWRhdGVkIGRlcGVuZGluZyBvbiB0aGUgYHN0cmljdENoZWNrYCBmbGFnLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gdXBkYXRlT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBuZXcgb3B0aW9ucyB0byBiZVxyXG4gKiBtZXJnZWQgaW50byB0aGUgZ2xvYmFsIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2dldENvcHk9ZmFsc2VdIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRvIG1lcmdlIHRoZSBuZXdcclxuICogb3B0aW9ucyBpbnRvIGEgY29weSBvZiB0aGUgZ2xvYmFsIG9wdGlvbnMgb2JqZWN0IChgdHJ1ZWApIG9yIGRpcmVjdGx5IGludG9cclxuICogdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCAoYGZhbHNlYCkuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3N0cmljdENoZWNrPXRydWVdIC0gRGV0ZXJtaW5lcyBpZiBzdHJpY3RlciB2YWxpZGF0aW9uXHJcbiAqIHNob3VsZCBiZSBhcHBsaWVkLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgdHJ1ZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIG9wdGlvbnMgb2JqZWN0LCBlaXRoZXIgdGhlIG1vZGlmaWVkIGdsb2JhbFxyXG4gKiBvcHRpb25zIG9yIGEgbW9kaWZpZWQgY29weSwgYmFzZWQgb24gdGhlIHZhbHVlIG9mIGBnZXRDb3B5YC5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiB1cGRhdGVPcHRpb25zKG5ld09wdGlvbnMsIGdldENvcHkgPSBmYWxzZSwgc3RyaWN0Q2hlY2sgPSB0cnVlKSB7XHJcbiAgLy8gTWVyZ2UgbmV3IG9wdGlvbnMgdG8gdGhlIGdsb2JhbCBvcHRpb25zIG9yIGl0cyBjb3B5IGFuZCByZXR1cm4gdGhlIHJlc3VsdFxyXG4gIHJldHVybiBfbWVyZ2VPcHRpb25zKFxyXG4gICAgLy8gRmlyc3QsIGdldCB0aGUgb3B0aW9uc1xyXG4gICAgZ2V0T3B0aW9ucyhnZXRDb3B5KSxcclxuICAgIC8vIE5leHQsIHZhbGlkYXRlIHRoZSBuZXcgb3B0aW9uc1xyXG4gICAgdmFsaWRhdGVPcHRpb25zKG5ld09wdGlvbnMsIHN0cmljdENoZWNrKVxyXG4gICk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBVcGRhdGVzIGFuZCByZXR1cm5zIHRoZSBnbG9iYWwgb3B0aW9ucyBvYmplY3Qgd2l0aCB2YWx1ZXMgcHJvdmlkZWQgdGhyb3VnaFxyXG4gKiB0aGUgQ0xJLCBrZWVwaW5nIHRoZSBwcmluY2lwbGUgb2Ygb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBUaGUgZnVuY3Rpb24gYWNjZXB0c1xyXG4gKiBhIGBjbGlBcmdzYCBhcnJheSBjb250YWluaW5nIGFyZ3VtZW50cyBmcm9tIHRoZSBDTEksIHdoaWNoIHdpbGwgYmUgdmFsaWRhdGVkXHJcbiAqIGFuZCBhcHBsaWVkIGlmIHByb3ZpZGVkLlxyXG4gKlxyXG4gKiBUaGUgZnVuY3Rpb24gcHJpb3JpdGl6ZXMgdmFsdWVzIGluIHRoZSBmb2xsb3dpbmcgb3JkZXI6XHJcbiAqXHJcbiAqIDEuIFZhbHVlcyBmcm9tIHRoZSBjb21tYW5kIGxpbmUgaW50ZXJmYWNlIChDTEkpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSBhIGN1c3RvbSBKU09OIGZpbGUgKGxvYWRlZCBieSB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHNldENsaU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBjbGlBcmdzIC0gQW4gYXJyYXkgb2YgY29tbWFuZCBsaW5lIGFyZ3VtZW50cyB1c2VkXHJcbiAqIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcmVmbGVjdGluZyB0aGUgbWVyZ2VkXHJcbiAqIGNvbmZpZ3VyYXRpb24gZnJvbSBzb3VyY2VzIHByb3ZpZGVkIHRocm91Z2ggdGhlIENMSS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzZXRDbGlPcHRpb25zKGNsaUFyZ3MpIHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGNsaUFyZ3MgJiYgQXJyYXkuaXNBcnJheShjbGlBcmdzKSAmJiBjbGlBcmdzLmxlbmd0aCkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gR2V0IG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gbG9hZGVkIHZpYSB0aGUgYC0tbG9hZENvbmZpZ2BcclxuICAgICAgY29uc3QgY29uZmlnT3B0aW9ucyA9IF9sb2FkQ29uZmlnRmlsZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNvbmZpZ09wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY29uZmlnT3B0aW9ucyk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2coMiwgJ1t2YWxpZGF0aW9uXSBObyBvcHRpb25zIGFkZGVkIGZyb20gdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbi4nKTtcclxuICAgIH1cclxuXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBHZXQgb3B0aW9ucyBmcm9tIHRoZSBDTElcclxuICAgICAgY29uc3QgY2xpT3B0aW9ucyA9IF9wYWlyQXJndW1lbnRWYWx1ZShjbGlBcmdzKTtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSBnbG9iYWwgb3B0aW9ucyB3aXRoIHZhbGlkYXRlZCB2YWx1ZXMgZnJvbSB0aGUgYGNsaU9wdGlvbnNgXHJcbiAgICAgIHVwZGF0ZU9wdGlvbnMoY2xpT3B0aW9ucywgZmFsc2UsIGZhbHNlKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZygyLCAnW3ZhbGlkYXRpb25dIE5vIG9wdGlvbnMgYWRkZWQgZnJvbSB0aGUgQ0xJIGFyZ3VtZW50cy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZWZlcmVuY2UgdG8gdGhlIGdsb2JhbCBvcHRpb25zXHJcbiAgcmV0dXJuIGdldE9wdGlvbnMoZmFsc2UpO1xyXG59XHJcblxyXG4vKipcclxuICogTWFwcyBvbGQtc3RydWN0dXJlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMgKFBoYW50b21KUy1iYXNlZCkgdG8gYSBuZXcgZm9ybWF0XHJcbiAqIChQdXBwZXRlZXItYmFzZWQpLiBUaGlzIGZ1bmN0aW9uIGNvbnZlcnRzIGZsYXQsIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgaW50b1xyXG4gKiBhIG5ldywgbmVzdGVkIGNvbmZpZ3VyYXRpb24gZm9ybWF0IGJhc2VkIG9uIGEgcHJlZGVmaW5lZCBtYXBwaW5nIHByb3ZpZGVkXHJcbiAqIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC4gVGhlIG5ldyBmb3JtYXQgaXMgdXNlZCBmb3IgUHVwcGV0ZWVyLCB3aGlsZVxyXG4gKiB0aGUgb2xkIGZvcm1hdCB3YXMgdXNlZCBmb3IgUGhhbnRvbUpTLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbWFwVG9OZXdPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gVGhlIG9sZCwgZmxhdCBjb25maWd1cmF0aW9uIG9wdGlvbnNcclxuICogdG8gYmUgY29udmVydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBIG5ldyBvYmplY3QgY29udGFpbmluZyBvcHRpb25zIHN0cnVjdHVyZWQgYWNjb3JkaW5nXHJcbiAqIHRvIHRoZSBtYXBwaW5nIGRlZmluZWQgaW4gdGhlIGBuZXN0ZWRQcm9wc2Agb2JqZWN0IG9yIGFuIGVtcHR5IG9iamVjdFxyXG4gKiBpZiB0aGUgcHJvdmlkZWQgYG9sZE9wdGlvbnNgIGlzIG5vdCBhIGNvcnJlY3Qgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIG1hcFRvTmV3T3B0aW9ucyhvbGRPcHRpb25zKSB7XHJcbiAgLy8gQW4gb2JqZWN0IGZvciB0aGUgbmV3IHN0cnVjdHVyZWQgb3B0aW9uc1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgdmFsdWUgaXMgYSBjb3JyZWN0IG9iamVjdFxyXG4gIGlmIChpc09iamVjdChvbGRPcHRpb25zKSkge1xyXG4gICAgLy8gSXRlcmF0ZSBvdmVyIGVhY2gga2V5LXZhbHVlIHBhaXIgaW4gdGhlIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIHRoZXJlIGlzIGEgbmVzdGVkIG1hcHBpbmcsIHNwbGl0IGl0IGludG8gYSBwcm9wZXJ0aWVzIGNoYWluXHJcbiAgICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZFByb3BzW2tleV1cclxuICAgICAgICA/IG5lc3RlZFByb3BzW2tleV0uc3BsaXQoJy4nKVxyXG4gICAgICAgIDogW107XHJcblxyXG4gICAgICAvLyBJZiBpdCBpcyB0aGUgbGFzdCBwcm9wZXJ0eSBpbiB0aGUgY2hhaW4sIGFzc2lnbiB0aGUgdmFsdWUsIG90aGVyd2lzZSxcclxuICAgICAgLy8gY3JlYXRlIG9yIHJldXNlIHRoZSBuZXN0ZWQgb2JqZWN0XHJcbiAgICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgICAob2JqW3Byb3BdID1cclxuICAgICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICAgIG5ld09wdGlvbnNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICAnW2NvbmZpZ10gTm8gY29ycmVjdCBvYmplY3Qgd2l0aCBvcHRpb25zIHdhcyBwcm92aWRlZC4gUmV0dXJuaW5nIGFuIGVtcHR5IG9iamVjdC4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBuZXcsIHN0cnVjdHVyZWQgb3B0aW9ucyBvYmplY3RcclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhIHNwZWNpZmllZCBvcHRpb24gdXNpbmcgdGhlIGNvcnJlc3BvbmRpbmcgdmFsaWRhdG9yIGZyb20gdGhlXHJcbiAqIGNvbmZpZ3VyYXRpb24gb2JqZWN0LiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb25cclxuICogaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBvcHRpb24gdG8gdmFsaWRhdGUuXHJcbiAqIEBwYXJhbSB7YW55fSBjb25maWdPcHRpb24gLSBUaGUgdmFsdWUgb2YgdGhlIG9wdGlvbiB0byB2YWxpZGF0ZS5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge2FueX0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIHZhbHVlIG9mIHRoZSBvcHRpb24uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb24obmFtZSwgY29uZmlnT3B0aW9uLCBzdHJpY3RDaGVjayA9IHRydWUpIHtcclxuICAvLyBSZXR1cm4gdGhlIG9yaWdpbmFsIG9wdGlvbiBpZiB0aGUgdmFsaWRhdGlvbiBpcyBkaXNhYmxlZFxyXG4gIGlmICghZ2V0T3B0aW9ucygpLm90aGVyLnZhbGlkYXRpb24pIHtcclxuICAgIHJldHVybiBjb25maWdPcHRpb247XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25cclxuICAgIHJldHVybiB2YWxpZGF0b3JzW25hbWVdKHN0cmljdENoZWNrKS5wYXJzZShjb25maWdPcHRpb24pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBMb2cgWm9kIGlzc3Vlc1xyXG4gICAgbG9nWm9kSXNzdWVzKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvci5pc3N1ZXMsXHJcbiAgICAgIGBbdmFsaWRhdGlvbl0gVGhlICR7bmFtZX0gb3B0aW9uIHZhbGlkYXRpb24gZXJyb3JgXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgYFt2YWxpZGF0aW9uXSBUaGUgJHtuYW1lfSBvcHRpb24gdmFsaWRhdGlvbiBlcnJvcmAsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKiBSZXR1cm5zIHRoZSBvcmlnaW5hbCBvcHRpb24gaWYgdGhlIHZhbGlkYXRpb24gaXMgZGlzYWJsZWQgZ2xvYmFsbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2YWxpZGF0ZU9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIHZhbGlkYXRlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc3RyaWN0Q2hlY2s9dHJ1ZV0gLSBEZXRlcm1pbmVzIGlmIHN0cmljdGVyIHZhbGlkYXRpb25cclxuICogc2hvdWxkIGJlIGFwcGxpZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGB0cnVlYC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdmFsaWRhdGVPcHRpb25zKGNvbmZpZ09wdGlvbnMsIHN0cmljdENoZWNrID0gdHJ1ZSkge1xyXG4gIC8vIFJldHVybiB0aGUgb3JpZ2luYWwgY29uZmlnIGlmIHRoZSB2YWxpZGF0aW9uIGlzIGRpc2FibGVkXHJcbiAgaWYgKCFnZXRPcHRpb25zKCkub3RoZXIudmFsaWRhdGlvbikge1xyXG4gICAgcmV0dXJuIGNvbmZpZ09wdGlvbnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gUmV0dXJuIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICByZXR1cm4gc3RyaWN0Q2hlY2tcclxuICAgICAgPyBzdHJpY3RWYWxpZGF0ZShjb25maWdPcHRpb25zKVxyXG4gICAgICA6IGxvb3NlVmFsaWRhdGUoY29uZmlnT3B0aW9ucyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIExvZyBab2QgaXNzdWVzXHJcbiAgICBsb2dab2RJc3N1ZXMoMSwgZXJyb3IuaXNzdWVzLCAnW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicpO1xyXG5cclxuICAgIC8vIFRocm93IHZhbGlkYXRpb24gZXJyb3JcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW3ZhbGlkYXRpb25dIE9wdGlvbnMgdmFsaWRhdGlvbiBlcnJvcicsIDQwMCk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVmFsaWRhdGVzLCBwYXJzZXMsIGFuZCBjaGVja3MgaWYgdGhlIHByb3ZpZGVkIGNvbmZpZyBpcyBhbGxvd2VkIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnXHJcbiAqXHJcbiAqIEBwYXJhbSB7dW5rbm93bn0gY29uZmlnIC0gVGhlIGNvbmZpZyB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZCBhcyBhIHNldFxyXG4gKiBvZiBvcHRpb25zLiBNdXN0IGJlIGVpdGhlciBhbiBvYmplY3Qgb3IgYSBzdHJpbmcuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW3RvU3RyaW5nPWZhbHNlXSAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgdmVyc2lvblxyXG4gKiBvZiB0aGUgcGFyc2VkIGNvbmZpZy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICogQHBhcmFtIHtib29sZWFufSBbYWxsb3dGdW5jdGlvbnM9ZmFsc2VdIC0gV2hldGhlciB0byBhbGxvdyBmdW5jdGlvbnNcclxuICogaW4gdGhlIHBhcnNlZCBjb25maWcuIElmIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWQuIE90aGVyd2lzZSwgd2hlblxyXG4gKiBhIGZ1bmN0aW9uIGlzIGZvdW5kLCBgbnVsbGAgaXMgcmV0dXJuZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGBmYWxzZWAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHsoT2JqZWN0fHN0cmluZ3xudWxsKX0gUmV0dXJucyBhIHBhcnNlZCBzZXQgb2Ygb3B0aW9ucyBvYmplY3QsXHJcbiAqIGEgc3RyaW5naWZpZWQgc2V0IG9mIG9wdGlvbnMgb2JqZWN0IGlmIHRoZSBgdG9TdHJpbmdgIGlzIGB0cnVlYCwgYW5kIGBudWxsYFxyXG4gKiBpZiB0aGUgY29uZmlnIGlzIG5vdCBhIHZhbGlkIHNldCBvZiBvcHRpb25zIG9yIHBhcnNpbmcgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNBbGxvd2VkQ29uZmlnKFxyXG4gIGNvbmZpZyxcclxuICB0b1N0cmluZyA9IGZhbHNlLFxyXG4gIGFsbG93RnVuY3Rpb25zID0gZmFsc2VcclxuKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEFjY2VwdCBvbmx5IG9iamVjdHMgYW5kIHN0cmluZ3NcclxuICAgIGlmICghaXNPYmplY3QoY29uZmlnKSAmJiB0eXBlb2YgY29uZmlnICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBSZXR1cm4gYG51bGxgIGlmIGFueSBvdGhlciB0eXBlXHJcbiAgICAgIHJldHVybiBudWxsO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgb2JqZWN0IHJlcHJlc2VudGF0aW9uIG9mIHRoZSBvcmlnaW5hbCBjb25maWdcclxuICAgIGNvbnN0IG9iamVjdENvbmZpZyA9XHJcbiAgICAgIHR5cGVvZiBjb25maWcgPT09ICdzdHJpbmcnXHJcbiAgICAgICAgPyBhbGxvd0Z1bmN0aW9uc1xyXG4gICAgICAgICAgPyBldmFsKGAoJHtjb25maWd9KWApXHJcbiAgICAgICAgICA6IEpTT04ucGFyc2UoY29uZmlnKVxyXG4gICAgICAgIDogY29uZmlnO1xyXG5cclxuICAgIC8vIFByZXNlcnZlIG9yIHJlbW92ZSBwb3RlbnRpYWwgZnVuY3Rpb25zIGJhc2VkIG9uIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGZsYWdcclxuICAgIGNvbnN0IHN0cmluZ2lmaWVkT3B0aW9ucyA9IF9vcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICBvYmplY3RDb25maWcsXHJcbiAgICAgIGFsbG93RnVuY3Rpb25zLFxyXG4gICAgICBmYWxzZVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBQYXJzZSB0aGUgY29uZmlnIHRvIGNoZWNrIGlmIGl0IGlzIHZhbGlkIHNldCBvZiBvcHRpb25zXHJcbiAgICBjb25zdCBwYXJzZWRPcHRpb25zID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgPyBKU09OLnBhcnNlKFxyXG4gICAgICAgICAgX29wdGlvbnNTdHJpbmdpZnkob2JqZWN0Q29uZmlnLCBhbGxvd0Z1bmN0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgICAoXywgdmFsdWUpID0+XHJcbiAgICAgICAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24nKVxyXG4gICAgICAgICAgICAgID8gZXZhbChgKCR7dmFsdWV9KWApXHJcbiAgICAgICAgICAgICAgOiB2YWx1ZVxyXG4gICAgICAgIClcclxuICAgICAgOiBKU09OLnBhcnNlKHN0cmluZ2lmaWVkT3B0aW9ucyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHN0cmluZ2lmaWVkIG9yIG9iamVjdCBvcHRpb25zIGJhc2VkIG9uIHRoZSBgdG9TdHJpbmdgIGZsYWdcclxuICAgIHJldHVybiB0b1N0cmluZyA/IHN0cmluZ2lmaWVkT3B0aW9ucyA6IHBhcnNlZE9wdGlvbnM7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIFJldHVybiBgbnVsbGAgaWYgcGFyc2luZyBmYWlsc1xyXG4gICAgcmV0dXJuIG51bGw7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgYW5kIHJldHVybnMgdGhlIGdsb2JhbCBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiB0aGUgcHJvdmlkZWRcclxuICogY29uZmlndXJhdGlvbiwgc2V0dGluZyB2YWx1ZXMgZnJvbSBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBWYWx1ZXMgZnJvbSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgKHNwZWNpZmllZCBpbiB0aGUgYC5lbnZgIGZpbGUpLlxyXG4gKiAyLiBWYWx1ZXMgZnJvbSB0aGUgYC4vbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIChkZWZhdWx0cykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaW5pdE9wdGlvbnNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogdGhlIGdsb2JhbCBvcHRpb25zLiBJdCBzaG91bGQgaW5jbHVkZSBuZXN0ZWQgcHJvcGVydGllcyB3aXRoIGEgYHZhbHVlYFxyXG4gKiBhbmQgYW4gYGVudkxpbmtgIGZvciBsaW5raW5nIHRvIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGluaXRpYWxpemVkIGdsb2JhbCBvcHRpb25zIG9iamVjdCwgcG9wdWxhdGVkIHdpdGhcclxuICogdmFsdWVzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHlcclxuICogb3JkZXIuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaW5pdE9wdGlvbnMoY29uZmlnKSB7XHJcbiAgLy8gSW5pdCB0aGUgb2JqZWN0IGZvciBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHt9O1xyXG5cclxuICAvLyBTdGFydCBpbml0aWFsaXppbmcgdGhlIGBvcHRpb25zYCBvYmplY3QgcmVjdXJzaXZlbHlcclxuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhjb25maWcpKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpKSB7XHJcbiAgICAgIC8vIFNldCB0aGUgY29ycmVjdCB2YWx1ZSBiYXNlZCBvbiB0aGUgZXN0YWJsaXNoZWQgcHJpb3JpdHkgb3JkZXJcclxuICAgICAgaWYgKGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkICYmIGVudnNbaXRlbS5lbnZMaW5rXSAhPT0gbnVsbCkge1xyXG4gICAgICAgIC8vIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgdmFsdWVcclxuICAgICAgICBvcHRpb25zW25hbWVdID0gZW52c1tpdGVtLmVudkxpbmtdO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIFRoZSB2YWx1ZSBmcm9tIHRoZSBjb25maWcgZmlsZVxyXG4gICAgICAgIG9wdGlvbnNbbmFtZV0gPSBpdGVtLnZhbHVlO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBDcmVhdGUgYSBjYXRlZ29yeSBvZiBvcHRpb25zIGluIHRoZSBgb3B0aW9uc2Agb2JqZWN0XHJcbiAgICAgIG9wdGlvbnNbbmFtZV0gPSBfaW5pdE9wdGlvbnMoaXRlbSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gdGhlIGNyZWF0ZWQgYG9wdGlvbnNgIG9iamVjdFxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgbWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgdGFraW5nIGludG8gYWNjb3VudFxyXG4gKiBwcm9wZXJ0aWVzIHNwZWNpZmllZCBpbiB0aGUgYGFic29sdXRlUHJvcHNgIGFycmF5IHRoYXQgcmVxdWlyZSBhYnNvbHV0ZVxyXG4gKiBtZXJnaW5nLiBUaGUgYG9yaWdpbmFsT3B0aW9uc2Agb2JqZWN0IHdpbGwgYmUgZXh0ZW5kZWQgd2l0aCBvcHRpb25zIGZyb21cclxuICogdGhlIGBuZXdPcHRpb25zYCBvYmplY3QuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfbWVyZ2VPcHRpb25zXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcmlnaW5hbE9wdGlvbnMgLSBUaGUgb3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdFxyXG4gKiB0byBiZSBleHRlbmRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBUaGUgbmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gbWVyZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBleHRlbmRlZCBgb3JpZ2luYWxPcHRpb25zYCBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBfbWVyZ2VPcHRpb25zKG9yaWdpbmFsT3B0aW9ucywgbmV3T3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSBgb3JpZ2luYWxPcHRpb25zYCBhbmQgYG5ld09wdGlvbnNgIGFyZSBjb3JyZWN0IG9iamVjdHNcclxuICBpZiAoaXNPYmplY3Qob3JpZ2luYWxPcHRpb25zKSAmJiBpc09iamVjdChuZXdPcHRpb25zKSkge1xyXG4gICAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgICAgb3JpZ2luYWxPcHRpb25zW2tleV0gPVxyXG4gICAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcclxuICAgICAgICBvcmlnaW5hbE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IF9tZXJnZU9wdGlvbnMob3JpZ2luYWxPcHRpb25zW2tleV0sIHZhbHVlKVxyXG4gICAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgICAgOiBvcmlnaW5hbE9wdGlvbnNba2V5XSB8fCBudWxsO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHRoZSBvcmlnaW5hbCAobW9kaWZpZWQgb3Igbm90KSBvcHRpb25zXHJcbiAgcmV0dXJuIG9yaWdpbmFsT3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04gc3RyaW5nIHdpdGggdGhlIG9wdGlvblxyXG4gKiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuIEluIG9yZGVyIGZvciBhIGZ1bmN0aW9uIHRvIGJlIHByZXNlcnZlZCwgaXQgbmVlZHNcclxuICogdG8gZm9sbG93IHRoZSBmb3JtYXQgYGZ1bmN0aW9uICguLi4pIHsuLi59YC4gU3VjaCBhIGZ1bmN0aW9uIGNhbiBhbHNvXHJcbiAqIGJlIHN0cmluZ2lmaWVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnlcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIGB0cnVlYCwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcclxuICogaW4gdGhlIG91dHB1dC4gT3RoZXJ3aXNlIGFuIGVycm9yIGlzIHRocm93bi5cclxuICogQHBhcmFtIHtib29sZWFufSBzdHJpbmdpZnlGdW5jdGlvbnMgLSBJZiBzZXQgdG8gYHRydWVgLCBmdW5jdGlvbnMgYXJlIHNhdmVkXHJcbiAqIGFzIHN0cmluZ3MuIFRoZSBgYWxsb3dGdW5jdGlvbnNgIG11c3QgYmUgc2V0IHRvIGB0cnVlYCBhcyB3ZWxsIGZvciB0aGlzXHJcbiAqIHRvIHRha2UgYW4gZWZmZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IFRocm93cyBhbiBgRXJyb3JgIHdoZW4gZnVuY3Rpb25zIGFyZSBub3QgYWxsb3dlZCBidXQgYXJlXHJcbiAqIGZvdW5kIGluIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gX29wdGlvbnNTdHJpbmdpZnkob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMsIHN0cmluZ2lmeUZ1bmN0aW9ucykge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAoXywgdmFsdWUpID0+IHtcclxuICAgIC8vIFRyaW0gc3RyaW5nIHZhbHVlc1xyXG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gSWYgYHZhbHVlYCBpcyBhIGZ1bmN0aW9uIG9yIHN0cmluZ2lmaWVkIGZ1bmN0aW9uXHJcbiAgICBpZiAoXHJcbiAgICAgIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJyB8fFxyXG4gICAgICAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uJykgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIElmIHRoZSBgYWxsb3dGdW5jdGlvbnNgIGlzIHNldCB0byBgdHJ1ZWAsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoYWxsb3dGdW5jdGlvbnMpIHtcclxuICAgICAgICAvLyBCYXNlZCBvbiB0aGUgYHN0cmluZ2lmeUZ1bmN0aW9uc2Agb3B0aW9ucywgc2V0IGZ1bmN0aW9uIHZhbHVlc1xyXG4gICAgICAgIHJldHVybiBzdHJpbmdpZnlGdW5jdGlvbnNcclxuICAgICAgICAgID8gLy8gQXMgc3RyaW5naWZpZWQgZnVuY3Rpb25zXHJcbiAgICAgICAgICAgIGBcIkVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTlwiYFxyXG4gICAgICAgICAgOiAvLyBBcyBmdW5jdGlvbnNcclxuICAgICAgICAgICAgYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXHMrL2csICcgJyl9RVhQX0ZVTmA7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3Igb3RoZXJ3aXNlXHJcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBJbiBhbGwgb3RoZXIgY2FzZXMsIHNpbXBseSByZXR1cm4gdGhlIHZhbHVlXHJcbiAgICByZXR1cm4gdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICBzdHJpbmdpZnlGdW5jdGlvbnMgPyAvXFxcXFwiRVhQX0ZVTnxFWFBfRlVOXFxcXFwiL2cgOiAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSBwcm92aWRlZCB2aWFcclxuICogdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBpbiB0aGUgY29tbWFuZC1saW5lIGFyZ3VtZW50cy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9sb2FkQ29uZmlnRmlsZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIHNlYXJjaFxyXG4gKiBmb3IgdGhlIGAtLWxvYWRDb25maWdgIG9wdGlvbiBhbmQgdGhlIGNvcnJlc3BvbmRpbmcgZmlsZSBwYXRoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWRcclxuICogZmlsZSwgb3IgYW4gZW1wdHkgb2JqZWN0IGlmIHRoZSBmaWxlIGlzIG5vdCBmb3VuZCwgaW52YWxpZCwgb3IgYW4gZXJyb3JcclxuICogb2NjdXJzLlxyXG4gKi9cclxuZnVuY3Rpb24gX2xvYWRDb25maWdGaWxlKGNsaUFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGFsbG93IGZsYWdzIGZvciB0aGUgY3VzdG9tIGxvZ2ljIGNoZWNrXHJcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24sIGFsbG93RmlsZVJlc291cmNlcyB9ID0gZ2V0T3B0aW9ucygpLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2Agb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBjbGlBcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBgLS1sb2FkQ29uZmlnYCBvcHRpb24gdmFsdWVcclxuICBjb25zdCBjb25maWdGaWxlTmFtZSA9IGNvbmZpZ0luZGV4ID4gLTEgJiYgY2xpQXJnc1tjb25maWdJbmRleCArIDFdO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgYC0tbG9hZENvbmZpZ2AgaXMgcHJlc2VudCBhbmQgaGFzIGEgY29ycmVjdCB2YWx1ZVxyXG4gIGlmIChjb25maWdGaWxlTmFtZSAmJiBhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgcmV0dXJuIGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGNvbmZpZ0ZpbGVOYW1lKSwgJ3V0ZjgnKSxcclxuICAgICAgICBmYWxzZSxcclxuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGVycm9yLFxyXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cclxuICByZXR1cm4ge307XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYXJzZXMgY29tbWFuZC1saW5lIGFyZ3VtZW50cyBhbmQgcGFpcnMgZWFjaCBhcmd1bWVudCB3aXRoIGl0cyBjb3JyZXNwb25kaW5nXHJcbiAqIG9wdGlvbiBpbiB0aGUgY29uZmlndXJhdGlvbi4gVGhlIHZhbHVlcyBhcmUgc3RydWN0dXJlZCBpbnRvIGEgbmVzdGVkIG9wdGlvbnNcclxuICogb2JqZWN0LCBiYXNlZCBvbiBwcmVkZWZpbmVkIG1hcHBpbmdzIGluIHRoZSBgbmVzdGVkUHJvcHNgIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIF9wYWlyQXJndW1lbnRWYWx1ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IGNsaUFyZ3MgLSBBbiBhcnJheSBvZiBjb21tYW5kLWxpbmUgYXJndW1lbnRzXHJcbiAqIGNvbnRhaW5pbmcgb3B0aW9ucyBhbmQgdGhlaXIgYXNzb2NpYXRlZCB2YWx1ZXMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIHVwZGF0ZWQgb3B0aW9ucyBvYmplY3Qgd2hlcmUgZWFjaCBvcHRpb24gZnJvbVxyXG4gKiB0aGUgY29tbWFuZC1saW5lIGlzIHBhaXJlZCB3aXRoIGl0cyB2YWx1ZSwgc3RydWN0dXJlZCBpbnRvIG5lc3RlZCBvYmplY3RzXHJcbiAqIGFzIGRlZmluZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfcGFpckFyZ3VtZW50VmFsdWUoY2xpQXJncykge1xyXG4gIC8vIEFuIGVtcHR5IG9iamVjdCB0byBjb2xsZWN0IGFuZCBzdHJ1Y3R1cml6ZSBkYXRhIGZyb20gdGhlIGFyZ3NcclxuICBjb25zdCBjbGlPcHRpb25zID0ge307XHJcblxyXG4gIC8vIEN5Y2xlIHRocm91Z2ggYWxsIENMSSBhcmdzIGFuZCBmaWx0ZXIgdGhlbVxyXG4gIGZvciAobGV0IGkgPSAwOyBpIDwgY2xpQXJncy5sZW5ndGg7IGkrKykge1xyXG4gICAgY29uc3Qgb3B0aW9uID0gY2xpQXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkUHJvcHNbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZFByb3BzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIENyZWF0ZSBvcHRpb25zIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIENMSSBmb3IgbGF0ZXIgcGFyc2luZyBhbmQgbWVyZ2luZ1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgY29uc3QgdmFsdWUgPSBjbGlBcmdzWysraV07XHJcbiAgICAgICAgaWYgKCF2YWx1ZSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlIENMSSAnLS0ke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgICBvYmpbcHJvcF0gPSB2YWx1ZSB8fCBudWxsO1xyXG4gICAgICB9IGVsc2UgaWYgKG9ialtwcm9wXSA9PT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgb2JqW3Byb3BdID0ge307XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIGNsaU9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHBhcnNlZCBDTEkgb3B0aW9uc1xyXG4gIHJldHVybiBjbGlPcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgZ2VuZXJhdGVzIGEgbWFwcGluZyBvZiBuZXN0ZWQgYXJndW1lbnQgY2hhaW5zIGZyb20gYSBuZXN0ZWRcclxuICogY29uZmlnIG9iamVjdC4gVGhpcyBmdW5jdGlvbiB0cmF2ZXJzZXMgYSBuZXN0ZWQgb2JqZWN0IGFuZCBjcmVhdGVzIGEgbWFwcGluZ1xyXG4gKiB3aGVyZSBlYWNoIGtleSBpcyBhbiBhcmd1bWVudCBuYW1lIChlaXRoZXIgZnJvbSBgY2xpTmFtZWAsIGBsZWdhY3lOYW1lYCxcclxuICogb3IgdGhlIG9yaWdpbmFsIGtleSkgYW5kIGVhY2ggdmFsdWUgaXMgYSBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBjaGFpblxyXG4gKiBvZiBuZXN0ZWQgcHJvcGVydGllcyBsZWFkaW5nIHRvIHRoYXQgYXJndW1lbnQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlTmVzdGVkUHJvcHNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IFtuZXN0ZWRQcm9wcz17fV0gLSBUaGUgYWNjdW11bGF0b3Igb2JqZWN0IGZvciBzdG9yaW5nXHJcbiAqIHRoZSByZXN1bHRpbmcgYXJndW1lbnRzIGNoYWlucy4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3Byb3BDaGFpbj0nJ10gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllcyxcclxuICogdXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24uIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQW4gb2JqZWN0IG1hcHBpbmcgYXJndW1lbnQgbmFtZXMgdG8gdGhlaXIgY29ycmVzcG9uZGluZ1xyXG4gKiBuZXN0ZWQgcHJvcGVydHkgY2hhaW5zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2NyZWF0ZU5lc3RlZFByb3BzKGNvbmZpZywgbmVzdGVkUHJvcHMgPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWcpLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgLy8gR2V0IHRoZSBzcGVjaWZpYyBzZWN0aW9uXHJcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ1trZXldO1xyXG5cclxuICAgIC8vIENoZWNrIGlmIHRoZXJlIGlzIHN0aWxsIG1vcmUgZGVwdGggdG8gdHJhdmVyc2VcclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIFJlY3Vyc2UgaW50byBkZWVwZXIgbGV2ZWxzIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgX2NyZWF0ZU5lc3RlZFByb3BzKGVudHJ5LCBuZXN0ZWRQcm9wcywgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICBuZXN0ZWRQcm9wc1tlbnRyeS5jbGlOYW1lIHx8IGtleV0gPSBgJHtwcm9wQ2hhaW59LiR7a2V5fWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIG5lc3RlZFByb3BzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2tleX1gLnN1YnN0cmluZygxKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIG9iamVjdCB3aXRoIG5lc3RlZCBhcmd1bWVudCBjaGFpbnNcclxuICByZXR1cm4gbmVzdGVkUHJvcHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSBnYXRoZXJzIHRoZSBuYW1lcyBvZiBwcm9wZXJ0aWVzIGZyb20gYSBjb25maWd1cmF0aW9uIG9iamVjdCB0aGF0XHJcbiAqIHNob3VsZCBiZSB0cmVhdGVkIGFzIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZXNlIHByb3BlcnRpZXMgaGF2ZSB2YWx1ZXMgdGhhdFxyXG4gKiBhcmUgb2JqZWN0cyBhbmQgZG8gbm90IGNvbnRhaW4gZnVydGhlciBuZXN0ZWQgZGVwdGggd2hlbiBtZXJnaW5nIGFuIG9iamVjdFxyXG4gKiBjb250YWluaW5nIHRoZXNlIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfY3JlYXRlQWJzb2x1dGVQcm9wc1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0FycmF5PHN0cmluZz59IFthYnNvbHV0ZVByb3BzPVtdXSAtIEFuIGFycmF5IHRvIGNvbGxlY3QgdGhlIG5hbWVzXHJcbiAqIG9mIGFic29sdXRlIHByb3BlcnRpZXMuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7QXJyYXk8c3RyaW5nPn0gQW4gYXJyYXkgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWJzb2x1dGVcclxuICogcHJvcGVydGllcy5cclxuICovXHJcbmZ1bmN0aW9uIF9jcmVhdGVBYnNvbHV0ZVByb3BzKGNvbmZpZywgYWJzb2x1dGVQcm9wcyA9IFtdKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIC8vIEdldCB0aGUgc3BlY2lmaWMgc2VjdGlvblxyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdba2V5XTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGVyZSBpcyBzdGlsbCBtb3JlIGRlcHRoIHRvIHRyYXZlcnNlXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnR5cGVzID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAvLyBSZWN1cnNlIGludG8gZGVlcGVyIGxldmVsc1xyXG4gICAgICBfY3JlYXRlQWJzb2x1dGVQcm9wcyhlbnRyeSwgYWJzb2x1dGVQcm9wcyk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBJZiB0aGUgb3B0aW9uIGNhbiBiZSBhbiBvYmplY3QsIHNhdmUgaXRzIHR5cGUgaW4gdGhlIGFycmF5XHJcbiAgICAgIGlmIChlbnRyeS50eXBlcy5pbmNsdWRlcygnT2JqZWN0JykpIHtcclxuICAgICAgICBhYnNvbHV0ZVByb3BzLnB1c2goa2V5KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdGhlIGFycmF5IHdpdGggdGhlIG5hbWVzIG9mIGFic29sdXRlIHByb3BlcnRpZXNcclxuICByZXR1cm4gYWJzb2x1dGVQcm9wcztcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldE9wdGlvbnMsXHJcbiAgdXBkYXRlT3B0aW9ucyxcclxuICBzZXRDbGlPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuICB2YWxpZGF0ZU9wdGlvbixcclxuICB2YWxpZGF0ZU9wdGlvbnMsXHJcbiAgaXNBbGxvd2VkQ29uZmlnXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIVFRQIHV0aWxpdHkgbW9kdWxlIGZvciBmZXRjaGluZyBhbmQgcG9zdGluZyBkYXRhLiBTdXBwb3J0cyBib3RoXHJcbiAqIEhUVFAgYW5kIEhUVFBTIHByb3RvY29scywgcHJvdmlkaW5nIG1ldGhvZHMgdG8gbWFrZSBHRVQgYW5kIFBPU1QgcmVxdWVzdHNcclxuICogd2l0aCBjdXN0b21pemFibGUgb3B0aW9ucy4gSW5jbHVkZXMgcHJvdG9jb2wgZGV0ZXJtaW5hdGlvbiBiYXNlZCBvbiBVUkxcclxuICogYW5kIGF1Z21lbnRzIHJlc3BvbnNlIG9iamVjdHMgd2l0aCBhICd0ZXh0JyBwcm9wZXJ0eSBmb3IgZWFzaWVyIGRhdGEgYWNjZXNzLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFNlbmRzIGEgR0VUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gZ2V0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGdldCBkYXRhIGZyb20uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbcmVxdWVzdE9wdGlvbnM9e31dIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAvSFRUUFMgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgSFRUUC9IVFRQUyByZXNwb25zZVxyXG4gKiBvYmplY3Qgd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIHByb3RvY29sXHJcbiAgICBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAuZ2V0KHVybCwgcmVxdWVzdE9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIGlmICghcmVzcG9uc2VEYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgLy8gR2V0IHRoZSBmdWxsIHJlc3VsdCBhbmQgcmVzb2x2ZSB0aGUgcmVxdWVzdFxyXG4gICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgIHJlc29sdmUocmVzcG9uc2UpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcG9zdFxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbYm9keT17fV0gLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdC5cclxuICogVGhlIGRlZmF1bHQgdmFsdWUgaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW3JlcXVlc3RPcHRpb25zPXt9XSAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQL0hUVFBTIHJlcXVlc3QuXHJcbiAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIEhUVFAvSFRUUFMgcmVzcG9uc2VcclxuICogb2JqZWN0IHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xyXG5cclxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggYHJlcXVlc3RPcHRpb25zYFxyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIC8vIERlY2lkZSBvbiB0aGUgcHJvdG9jb2xcclxuICAgIGNvbnN0IHJlcXVlc3QgPSBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKVxyXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkXHJcbiAgICAgICAgcmVzcG9uc2Uub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIC8vIEdldCB0aGUgZnVsbCByZXN1bHQgYW5kIHJlc29sdmUgdGhlIHJlcXVlc3RcclxuICAgICAgICAgICAgcmVzcG9uc2UudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXNwb25zZSk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0XHJcbiAgICByZXF1ZXN0LndyaXRlKGRhdGEpO1xyXG4gICAgcmVxdWVzdC5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChgaHR0cGAgb3IgYGh0dHBzYCkuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZ2V0UHJvdG9jb2xNb2R1bGUodXJsKSB7XHJcbiAgcmV0dXJuIHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIHBvc3RcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoZSBjYWNoZSBtYW5hZ2VyIGlzIHJlc3BvbnNpYmxlIGZvciBoYW5kbGluZyBhbmQgbWFuYWdpbmdcclxuICogdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbG9uZyB3aXRoIGl0cyBkZXBlbmRlbmNpZXMuIEl0IGVuc3VyZXMgdGhhdCB0aGVzZVxyXG4gKiByZXNvdXJjZXMgYXJlIHN0b3JlZCBhbmQgcmV0cmlldmVkIGVmZmljaWVudGx5IHRvIG9wdGltaXplIHBlcmZvcm1hbmNlXHJcbiAqIGFuZCByZWR1Y2UgcmVkdW5kYW50IG5ldHdvcmsgcmVxdWVzdHMuIFRoZSBjYWNoZSBpcyBzdG9yZWQgaW4gdGhlIGAuY2FjaGVgXHJcbiAqIGRpcmVjdG9yeSBieSBkZWZhdWx0LCB3aGljaCBzZXJ2ZXMgYXMgYSBkZWRpY2F0ZWQgZm9sZGVyIGZvciBrZWVwaW5nIGNhY2hlZFxyXG4gKiBmaWxlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgdXBkYXRlT3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZ2V0IH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0QWJzb2x1dGVQYXRoIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGluaXRpYWwgY2FjaGUgdGVtcGxhdGVcclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVXJsOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyB0aGUgY2FjaGUgZm9yIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLCB1cGRhdGVzIHRoZSBjYWNoZSBpZiBuZWVkZWQsXHJcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjaGVja0NhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNoZWNrQ2FjaGUoaGlnaGNoYXJ0c09wdGlvbnMsIHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjYWNoZSBwYXRoXHJcbiAgICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcclxuXHJcbiAgICAvLyBQcmVwYXJlIHBhdGhzIHRvIG1hbmlmZXN0IGFuZCBzb3VyY2VzIGZyb20gdGhlIGNhY2hlIGZvbGRlclxyXG4gICAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcclxuICAgICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCwgeyByZWN1cnNpdmU6IHRydWUgfSk7XHJcblxyXG4gICAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiB0aGUgYG1hbmlmZXN0Lmpzb25gIGRvZXMgbm90IGV4aXN0XHJcbiAgICAvLyBvciBpZiB0aGUgYGZvcmNlRmV0Y2hgIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgICBpZiAoIWV4aXN0c1N5bmMobWFuaWZlc3RQYXRoKSB8fCBoaWdoY2hhcnRzT3B0aW9ucy5mb3JjZUZldGNoKSB7XHJcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcclxuXHJcbiAgICAgIC8vIFRoZSBpbml0aWFsIGNhY2hlIHVwZGF0ZVxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IF91cGRhdGVDYWNoZShcclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgc291cmNlUGF0aFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcclxuXHJcbiAgICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cclxuICAgICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpLCAndXRmOCcpO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcclxuICAgICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlc1xyXG4gICAgICBpZiAobWFuaWZlc3QubW9kdWxlcyAmJiBBcnJheS5pc0FycmF5KG1hbmlmZXN0Lm1vZHVsZXMpKSB7XHJcbiAgICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xyXG4gICAgICAgIG1hbmlmZXN0Lm1vZHVsZXMgPSBtb2R1bGVNYXA7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgYWN0dWFsIG51bWJlciBvZiBzY3JpcHRzIHRvIGJlIGZldGNoZWRcclxuICAgICAgY29uc3QgeyBjb3JlU2NyaXB0cywgbW9kdWxlU2NyaXB0cywgaW5kaWNhdG9yU2NyaXB0cyB9ID1cclxuICAgICAgICBoaWdoY2hhcnRzT3B0aW9ucztcclxuICAgICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xyXG5cclxuICAgICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxyXG4gICAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxyXG4gICAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbikge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAyLFxyXG4gICAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgICApO1xyXG4gICAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgICB9IGVsc2UgaWYgKFxyXG4gICAgICAgIE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzXHJcbiAgICAgICkge1xyXG4gICAgICAgIC8vIENoZWNrIHRoZSBudW1iZXIgb2YgbW9kdWxlc1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xyXG4gICAgICAgICk7XHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XHJcbiAgICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVXBkYXRlIGNhY2hlIGlmIG5lZWRlZFxyXG4gICAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgX3VwZGF0ZUNhY2hlKFxyXG4gICAgICAgICAgaGlnaGNoYXJ0c09wdGlvbnMsXHJcbiAgICAgICAgICBzZXJ2ZXJQcm94eU9wdGlvbnMsXHJcbiAgICAgICAgICBzb3VyY2VQYXRoXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgICAvLyBMb2FkIHRoZSBzb3VyY2VzXHJcbiAgICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xyXG5cclxuICAgICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcclxuXHJcbiAgICAgICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgICAgICBjYWNoZS5oY1ZlcnNpb24gPSBfZXh0cmFjdEhjVmVyc2lvbihjYWNoZS5zb3VyY2VzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xyXG4gICAgLy8gaW4gYSBzbGlnaHRseSBkaWZmZXJlbnQgZm9ybWF0XHJcbiAgICBhd2FpdCBfc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbiwgZmV0Y2hlZE1vZHVsZXMpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjb25maWd1cmUgY2FjaGUgYW5kIGNyZWF0ZSBvciB1cGRhdGUgdGhlIGNvbmZpZyBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIHZlcnNpb24gb2YgSGlnaGNoYXJ0cyBmcm9tIHRoZSBjYWNoZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY2FjaGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRIY1ZlcnNpb24oKSB7XHJcbiAgcmV0dXJuIGNhY2hlLmhjVmVyc2lvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgc2NyaXB0cyBvZiBhIG5ldyB2ZXJzaW9uLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHVwZGF0ZUhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbmV3VmVyc2lvbiAtIFRoZSBuZXcgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdXBkYXRlSGNWZXJzaW9uKG5ld1ZlcnNpb24pIHtcclxuICAvLyBVcGRhdGUgdG8gdGhlIG5ldyB2ZXJzaW9uXHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoe1xyXG4gICAgaGlnaGNoYXJ0czoge1xyXG4gICAgICB2ZXJzaW9uOiBuZXdWZXJzaW9uXHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0NhY2hlKG9wdGlvbnMuaGlnaGNoYXJ0cywgb3B0aW9ucy5zZXJ2ZXIucHJveHkpO1xyXG59XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IGNhY2hlIG9iamVjdC5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldENhY2hlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBjYWNoZSBvYmplY3QgY29udGFpbmluZyB2YXJpb3VzIGNhY2hlZCBkYXRhLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldENhY2hlKCkge1xyXG4gIHJldHVybiBjYWNoZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEdldHMgdGhlIGNhY2hlIHBhdGggZm9yIEhpZ2hjaGFydHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRDYWNoZVBhdGhcclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGFic29sdXRlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeSBmb3IgSGlnaGNoYXJ0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRDYWNoZVBhdGgoKSB7XHJcbiAgcmV0dXJuIGdldEFic29sdXRlUGF0aChnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgsICd1dGY4Jyk7IC8vICM1NjJcclxufVxyXG5cclxuLyoqXHJcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XHJcbiAqIGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NhdmVDb25maWdUb01hbmlmZXN0XHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2ZXJzaW9uIC0gVGhlIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICogQHBhcmFtIHtPYmplY3R9IFtmZXRjaGVkTW9kdWxlcz17fV0gLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIG1vZHVsZXNcclxuICogaGF2ZSBiZWVuIGZldGNoZWQuIFRoZSBkZWZhdWx0IHZhbHVlIGlzIGFuIGVtcHR5IG9iamVjdC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZVxyXG4gKiB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9zYXZlQ29uZmlnVG9NYW5pZmVzdCh2ZXJzaW9uLCBmZXRjaGVkTW9kdWxlcyA9IHt9KSB7XHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IHtcclxuICAgIHZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlc1xyXG4gIH07XHJcblxyXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xyXG4gIHRyeSB7XHJcbiAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShjYWNoZS5hY3RpdmVNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxyXG4gICAgICA1MDBcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGNvbnRlbnQgYW5kIGluZm9ybWF0aW9uLFxyXG4gKiBhbmQgdXNlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3VwZGF0ZUNhY2hlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBoaWdoY2hhcnRzT3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nXHJcbiAqIGBoaWdoY2hhcnRzYCBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyUHJveHlPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBhbiBvYmplY3QgcmVwcmVzZW50aW5nXHJcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF91cGRhdGVDYWNoZShoaWdoY2hhcnRzT3B0aW9ucywgc2VydmVyUHJveHlPcHRpb25zLCBzb3VyY2VQYXRoKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCBIaWdoY2hhcnRzIHZlcnNpb24gZm9yIHNjcmlwdHNcclxuICAgIGNvbnN0IGhjVmVyc2lvbiA9XHJcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb24gPT09ICdsYXRlc3QnXHJcbiAgICAgICAgPyBudWxsXHJcbiAgICAgICAgOiBgJHtoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9ufWA7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgQ0ROIHVybCBmb3Igc2NyaXB0c1xyXG4gICAgY29uc3QgY2RuVXJsID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVXJsIHx8IGNhY2hlLmNkblVybDtcclxuXHJcbiAgICAvLyBQcmVwYXJlIG9wdGlvbnMgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSBfY29uZmlndXJlUmVxdWVzdChzZXJ2ZXJQcm94eU9wdGlvbnMpO1xyXG5cclxuICAgIC8vIEFuIG9iamVjdCB0byByZWNvcmQgd2hpY2ggc2NyaXB0cyBhcmUgZmV0Y2hlZFxyXG4gICAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcclxuXHJcbiAgICAvLyBKb2luIGFsbCBmZXRjaGVkIHNjcmlwdHMgYW5kIHNhdmUgaW4gdGhlIG1hbmlmZXN0J3Mgc291cmNlc1xyXG4gICAgY2FjaGUuc291cmNlcyA9IChcclxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIGZldGNoXHJcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuY29yZVNjcmlwdHMubWFwKChjcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgaGNWZXJzaW9uID8gYCR7Y2RuVXJsfS8ke2hjVmVyc2lvbn0vJHtjc31gIDogYCR7Y2RuVXJsfS8ke2NzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlcyxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gSGlnaGNoYXJ0cyBtb2R1bGUgc2NyaXB0cyBmZXRjaFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtcykgPT5cclxuICAgICAgICAgIF9mZXRjaFNjcmlwdChcclxuICAgICAgICAgICAgbXMgPT09ICdtYXAnXHJcbiAgICAgICAgICAgICAgPyBoY1ZlcnNpb25cclxuICAgICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9tYXBzLyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21hcHMvbW9kdWxlcy8ke21zfWBcclxuICAgICAgICAgICAgICA6IGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgICAgPyBgJHtjZG5Vcmx9LyR7aGNWZXJzaW9ufS9tb2R1bGVzLyR7bXN9YFxyXG4gICAgICAgICAgICAgICAgOiBgJHtjZG5Vcmx9L21vZHVsZXMvJHttc31gLFxyXG4gICAgICAgICAgICByZXF1ZXN0T3B0aW9ucyxcclxuICAgICAgICAgICAgZmV0Y2hlZE1vZHVsZXNcclxuICAgICAgICAgIClcclxuICAgICAgICApLFxyXG4gICAgICAgIC8vIEhpZ2hjaGFydHMgaW5kaWNhdG9yIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcCgoaXMpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoXHJcbiAgICAgICAgICAgIGhjVmVyc2lvblxyXG4gICAgICAgICAgICAgID8gYCR7Y2RuVXJsfS9zdG9jay8ke2hjVmVyc2lvbn0vaW5kaWNhdG9ycy8ke2lzfWBcclxuICAgICAgICAgICAgICA6IGAke2NkblVybH0vc3RvY2svaW5kaWNhdG9ycy8ke2lzfWAsXHJcbiAgICAgICAgICAgIHJlcXVlc3RPcHRpb25zLFxyXG4gICAgICAgICAgICBmZXRjaGVkTW9kdWxlc1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgICksXHJcbiAgICAgICAgLy8gQ3VzdG9tIHNjcmlwdHMgZmV0Y2hcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLm1hcCgoY3MpID0+XHJcbiAgICAgICAgICBfZmV0Y2hTY3JpcHQoYCR7Y3N9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICAgICAgKVxyXG4gICAgICBdKVxyXG4gICAgKS5qb2luKCc7XFxuJyk7XHJcblxyXG4gICAgLy8gRXh0cmFjdCBhbmQgc2F2ZSB2ZXJzaW9uIG9mIGN1cnJlbnRseSB1c2VkIEhpZ2hjaGFydHNcclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlLnNvdXJjZXMpO1xyXG5cclxuICAgIC8vIFNhdmUgdGhlIGZldGNoZWQgbW9kdWxlcyBpbnRvIGNhY2hlcycgc291cmNlIEpTT05cclxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBmZXRjaGVkIG1vZHVsZXNcclxuICAgIHJldHVybiBmZXRjaGVkTW9kdWxlcztcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW2NhY2hlXSBVbmFibGUgdG8gdXBkYXRlIHRoZSBsb2NhbCBIaWdoY2hhcnRzIGNhY2hlLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGBmZXRjaGVkTW9kdWxlc2AgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2ZldGNoU2NyaXB0XHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCByZXF1ZXN0cyBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBbc2hvdWxkVGhyb3dFcnJvcj1mYWxzZV0gLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yXHJcbiAqIHNob3VsZCBiZSB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy4gVGhlIGRlZmF1bHRcclxuICogdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYSBwcm9ibGVtXHJcbiAqIHdpdGggZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9mZXRjaFNjcmlwdChcclxuICBzY3JpcHQsXHJcbiAgcmVxdWVzdE9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXMsXHJcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXHJcbikge1xyXG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xyXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XHJcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcclxuICB9XHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBnZXQoYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcclxuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xyXG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gX2V4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xyXG4gIH1cclxuXHJcbiAgLy8gQmFzZWQgb24gdGhlIGBzaG91bGRUaHJvd0Vycm9yYCBmbGFnLCBkZWNpZGUgaG93IHRvIHNlcnZlIGVycm9yIG1lc3NhZ2VcclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYCxcclxuICAgICAgNDA0XHJcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcclxuICB9IGVsc2Uge1xyXG4gICAgbG9nKFxyXG4gICAgICAyLFxyXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcclxuICAgICk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ29uZmlndXJlcyBhIHByb3h5IGFnZW50IGZvciBvdXRnb2luZyBIVFRQIHJlcXVlc3RzIGJhc2VkIG9uIHRoZSBwcm92aWRlZFxyXG4gKiBgc2VydmVyLnByb3h5YCBvcHRpb25zLiBJZiBhIHZhbGlkIGBob3N0YCBhbmQgYHBvcnRgIGFyZSBzcGVjaWZpZWQsIGl0IHRyaWVzXHJcbiAqIHRvIGNyZWF0ZSBhbiBgSHR0cHNQcm94eUFnZW50YC4gSWYgdGhlIGNyZWF0aW9uIGZhaWxzLCBhbiBgRXhwb3J0RXJyb3JgXHJcbiAqIGlzIHRocm93bi4gSWYgbm8gcHJveHkgaXMgY29uZmlndXJlZCwgYW4gZW1wdHkgb2JqZWN0IGlzIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NvbmZpZ3VyZVJlcXVlc3RcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlclByb3h5T3B0aW9ucy0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHNlcnZlci5wcm94eWAgb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIHJlcXVlc3Qgb3B0aW9ucywgaW5jbHVkaW5nIHRoZSBwcm94eSBhZ2VudCBpZiBjcmVhdGVkLFxyXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm8gcHJveHkgY29uZmlndXJhdGlvbiBpcyBwcm92aWRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBwcm94eSBhZ2VudCBjcmVhdGlvblxyXG4gKiBmYWlscy5cclxuICovXHJcbmZ1bmN0aW9uIF9jb25maWd1cmVSZXF1ZXN0KHNlcnZlclByb3h5T3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGhvc3RgIGFuZCBgcG9ydGAgb2YgdGhlIHByb3h5XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gc2VydmVyUHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gc2VydmVyUHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBwcm94eSBhZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDcmVhdGUgdGhlIGFnZW50XHJcbiAgICAgIGNvbnN0IHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0OiBwcm94eUhvc3QsXHJcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gQWRkIHRoZSBhZ2VudCB0byB0aGUgcmVxdWVzdCdzIG9wdGlvbnNcclxuICAgICAgcmV0dXJuIHtcclxuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcclxuICAgICAgICB0aW1lb3V0OiBzZXJ2ZXJQcm94eU9wdGlvbnMudGltZW91dFxyXG4gICAgICB9O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhbiBlbXB0eSBvYmplY3Qgd2hlbiBubyBwcm94eSBhZ2VudCBpcyBjcmVhdGVkXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIGNhY2hlJ3Mgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZXh0cmFjdEhjVmVyc2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2FjaGVTb3VyY2VzIC0gVGhlIGNhY2hlIHNvdXJjZXMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgZXh0cmFjdGVkIEhpZ2hjaGFydHMgdmVyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0SGNWZXJzaW9uKGNhY2hlU291cmNlcykge1xyXG4gIHJldHVybiBjYWNoZVNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGVTb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyB0aGUgSGlnaGNoYXJ0cyBtb2R1bGUgbmFtZSBiYXNlZCBvbiB0aGUgYHNjcmlwdFBhdGhgIHByb3BlcnR5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2V4dHJhY3RNb2R1bGVOYW1lXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHRQYXRoIC0gVGhlIHBhdGggb2YgdGhlIHNjcmlwdCBmcm9tIHdoaWNoIHRoZSBtb2R1bGVcclxuICogbmFtZSB3aWxsIGJlIGV4dHJhY3RlZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBtb2R1bGUgbmFtZS5cclxuICovXHJcbmZ1bmN0aW9uIF9leHRyYWN0TW9kdWxlTmFtZShzY3JpcHRQYXRoKSB7XHJcbiAgcmV0dXJuIHNjcmlwdFBhdGgucmVwbGFjZShcclxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxyXG4gICAgJydcclxuICApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tDYWNoZSxcclxuICBnZXRIY1ZlcnNpb24sXHJcbiAgdXBkYXRlSGNWZXJzaW9uLFxyXG4gIGdldENhY2hlLFxyXG4gIGdldENhY2hlUGF0aFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgUHJvdmlkZXMgbWV0aG9kcyBmb3IgaW5pdGlhbGl6aW5nIEhpZ2hjaGFydHMgd2l0aCBjdXN0b21pemVkXHJcbiAqIGFuaW1hdGlvbiBzZXR0aW5ncyBhbmQgdHJpZ2dlcmluZyB0aGUgY3JlYXRpb24gb2YgSGlnaGNoYXJ0cyBjaGFydHMgd2l0aFxyXG4gKiBleHBvcnQtc3BlY2lmaWMgY29uZmlndXJhdGlvbnMgaW4gdGhlIHBhZ2UgY29udGV4dC4gU3VwcG9ydHMgZHluYW1pYyBvcHRpb25cclxuICogbWVyZ2luZywgY3VzdG9tIGxvZ2ljIGluamVjdGlvbiwgYW5kIGNvbnRyb2wgb3ZlciByZW5kZXJpbmcgYmVoYXZpb3JzLiBVc2VkXHJcbiAqIGJ5IHRoZSBQdXBwZXRlZXIgcGFnZS5cclxuICovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGBIaWdoY2hhcnRzLmFuaW1PYmplY3RgIGZ1bmN0aW9uLiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBIaWdoY2hhcnRzIGNoYXJ0IG9uIGEgcGFnZS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVDaGFydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlQ2hhcnQoZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgc2V0T3B0aW9ucywgbWVyZ2UsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgYHNldE9wdGlvbnNgIHVzYWdlcyBpbiBvcmRlclxyXG4gIC8vIHRvIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHRoZSBgdXNlck9wdGlvbnNgIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB0aGUgYHVzZXJPcHRpb25zYCB3aGVuIGBmb3JFeHBvcnRgIGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBTb21lIG1hbmRhdG9yeSBhZGRpdGlvbmFsIGBjaGFydGAgYW5kIGBleHBvcnRpbmdgIG9wdGlvbnNcclxuICBjb25zdCBhZGRpdGlvbmFsT3B0aW9ucyA9IHtcclxuICAgIGNoYXJ0OiB7XHJcbiAgICAgIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgICAgIGFuaW1hdGlvbjogZmFsc2UsXHJcbiAgICAgIC8vIEdldCB0aGUgcmlnaHQgc2l6ZSB2YWx1ZXNcclxuICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcclxuICAgIH0sXHJcbiAgICBleHBvcnRpbmc6IHtcclxuICAgICAgLy8gTm8gbmVlZCBmb3IgdGhlIGV4cG9ydGluZyBidXR0b25cclxuICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBHZXQgdGhlIGlucHV0IHRvIGV4cG9ydCBmcm9tIHRoZSBgaW5zdHJgIG9wdGlvblxyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLmluc3RyfWApKCk7XHJcblxyXG4gIC8vIEdldCB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uXHJcbiAgY29uc3QgdGhlbWVPcHRpb25zID0gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtleHBvcnRPcHRpb25zLnRoZW1lT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZm9sbG93aW5nIG9wdGlvbnMgb2JqZWN0cyB0byBjcmVhdGUgZmluYWwgb3B0aW9uc1xyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICB0aGVtZU9wdGlvbnMsXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIGFkZGl0aW9uYWxPcHRpb25zXHJcbiAgKTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgYGNhbGxiYWNrYCBvcHRpb25cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7Y3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrfWApKClcclxuICAgIDogbnVsbDtcclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSkge1xyXG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvblxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBuZXcgRnVuY3Rpb24oYHJldHVybiAke2V4cG9ydE9wdGlvbnMuZ2xvYmFsT3B0aW9uc31gKSgpO1xyXG5cclxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XHJcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcclxuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBDYWxsIHRoZSBjaGFydCBjcmVhdGlvblxyXG4gIEhpZ2hjaGFydHNbZXhwb3J0T3B0aW9ucy5jb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xyXG5cclxuICAvLyBHZXQgYWxsIGltYWdlcyBmcm9tIHdpdGhpbiB0aGUgY2hhcnRcclxuICBjb25zdCBpbWFnZXMgPSBBcnJheS5mcm9tKFxyXG4gICAgZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbCgnLmhpZ2hjaGFydHMtY29udGFpbmVyIGltYWdlJylcclxuICApO1xyXG5cclxuICAvLyBXYWl0IGZvciBhbGwgaW1hZ2VzIGZvciAyIHNlY29uZHNcclxuICBhd2FpdCBQcm9taXNlLnJhY2UoW1xyXG4gICAgUHJvbWlzZS5hbGwoXHJcbiAgICAgIGltYWdlcy5tYXAoKGltYWdlKSA9PlxyXG4gICAgICAgIGltYWdlLmNvbXBsZXRlICYmIGltYWdlLm5hdHVyYWxIZWlnaHQgIT09IDBcclxuICAgICAgICAgID8gUHJvbWlzZS5yZXNvbHZlKClcclxuICAgICAgICAgIDogbmV3IFByb21pc2UoKHJlc29sdmUpID0+XHJcbiAgICAgICAgICAgICAgaW1hZ2UuYWRkRXZlbnRMaXN0ZW5lcignbG9hZCcsIHJlc29sdmUsIHsgb25jZTogdHJ1ZSB9KVxyXG4gICAgICAgICAgICApXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAvLyBQcm9jZWVkIGZ1cnRoZXIgZXZlbiBpZiBpbWFnZXMgZGlkIG5vdCBsb2FkXHJcbiAgICBuZXcgUHJvbWlzZSgocmVzb2x2ZSkgPT4gc2V0VGltZW91dChyZXNvbHZlLCAyMDAwKSlcclxuICBdKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgYHNldE9wdGlvbnNgIHdhcyB1c2VkIGluIHRoZSBgY3VzdG9tQ29kZWApXHJcbiAgZm9yIChjb25zdCBwcm9wIGluIGRlZmF1bHRPcHRpb25zKSB7XHJcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XHJcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgZGVmYXVsdCBvcHRpb25zIGJhY2tcclxuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XHJcblxyXG4gIC8vIEVtcHR5IHRoZSBjdXN0b20gZ2xvYmFsIG9wdGlvbnMgb2JqZWN0XHJcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzZXR1cEhpZ2hjaGFydHMsXHJcbiAgY3JlYXRlQ2hhcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGZ1bmN0aW9ucyBmb3IgbWFuYWdpbmcgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UsIGNyZWF0aW5nIGFuZCBjbGVhcmluZyBwYWdlcywgaW5qZWN0aW5nIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyxcclxuICogYW5kIHNldHRpbmcgdXAgSGlnaGNoYXJ0cyBmb3Igc2VydmVyLXNpZGUgcmVuZGVyaW5nLiBUaGUgbW9kdWxlIGVuc3VyZXNcclxuICogdGhhdCB0aGUgYnJvd3NlciBhbmQgcGFnZXMgYXJlIGNvcnJlY3RseSBtYW5hZ2VkIGFuZCBjYW4gaGFuZGxlIGZhaWx1cmVzXHJcbiAqIGR1cmluZyBvcGVyYXRpb25zIGxpa2UgbGF1bmNoaW5nIHRoZSBicm93c2VyIG9yIGNyZWF0aW5nIG5ldyBwYWdlcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lLCBnZXRBYnNvbHV0ZVBhdGggfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciBwYWdlc1xyXG5jb25zdCBwYWdlVGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoXHJcbiAgam9pbihfX2Rpcm5hbWUsICd0ZW1wbGF0ZXMnLCAndGVtcGxhdGUuaHRtbCcpLFxyXG4gICd1dGY4J1xyXG4pO1xyXG5cclxuLy8gVG8gc2F2ZSB0aGUgYnJvd3NlclxyXG5sZXQgYnJvd3NlciA9IG51bGw7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEJyb3dzZXJcclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgbm8gdmFsaWQgYnJvd3NlclxyXG4gKiBoYXMgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEJyb3dzZXIoKSB7XHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJywgNTAwKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjcmVhdGVCcm93c2VyXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXk8c3RyaW5nPn0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXJcclxuICogYnJvd3NlcidzIGxhdW5jaC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyXHJcbiAqIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBtYXggcmV0cmllcyB0byBvcGVuXHJcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlclxyXG4gKiByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZUJyb3dzZXIocHVwcGV0ZWVyQXJncykge1xyXG4gIC8vIEdldCBgZGVidWdgIGFuZCBgb3RoZXJgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGBkZWJ1Z2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XHJcblxyXG4gIC8vIExhdW5jaCBvcHRpb25zIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZVxyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxyXG4gICAgdXNlckRhdGFEaXI6ICd0bXAnLFxyXG4gICAgYXJnczogcHVwcGV0ZWVyQXJncyB8fCBbXSxcclxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXHJcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxyXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxyXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgLy8gQSBjb3VudGVyIGZvciB0aGUgYnJvd3NlcidzIGxhdW5jaCByZXRyaWVzXHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG4gICAgY29uc3Qgb3BlbkJyb3dzZXIgPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBsYXVuY2ggYW5kIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gTGF1bmNoIHRoZSBicm93c2VyXHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG5cclxuICAgICAgICAgIC8vIFdhaXQgZm9yIGEgNCBzZWNvbmRzIGJlZm9yZSB0cnlpbmcgYWdhaW5cclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbkJyb3dzZXIoKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIC8vIFRyeSB0byBvcGVuIGEgYnJvd3NlclxyXG4gICAgICBhd2FpdCBvcGVuQnJvd3NlcigpO1xyXG5cclxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcclxuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLicsXHJcbiAgICAgICAgNTAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE5vIGNvcnJlY3QgYnJvd3NlclxyXG4gICAgaWYgKCFicm93c2VyKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIGluc3RhbmNlXHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbG9zZUJyb3dzZXJcclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZUJyb3dzZXIoKSB7XHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25uZWN0ZWRcclxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xyXG4gIH1cclxuICBicm93c2VyID0gbnVsbDtcclxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBwYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxyXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcclxuICogdGhlIGBfc2V0UGFnZUNvbnRlbnQoKWAsIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIG5ld1BhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgYGlkYCxcclxuICogYHdvcmtDb3VudGAsIGFuZCBgcGFnZWAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBubyB2YWxpZCBicm93c2VyXHJcbiAqIGhhcyBiZWVuIGNvbm5lY3RlZCBvciBpZiBhIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZShwb29sUmVzb3VyY2UpIHtcclxuICAvLyBFcnJvciBpbiBjYXNlIG9mIG5vIGNvbm5lY3RlZCBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbYnJvd3Nlcl0gQnJvd3NlciBpcyBub3QgeWV0IGNvbm5lY3RlZC5gLCA1MDApO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIHBvb2xSZXNvdXJjZS5wYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xyXG5cclxuICAvLyBTZXQgdGhlIGNvbnRlbnRcclxuICBhd2FpdCBfc2V0UGFnZUNvbnRlbnQocG9vbFJlc291cmNlLnBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBfc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UucGFnZSk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXHJcbiAgaWYgKCFwb29sUmVzb3VyY2UucGFnZSB8fCBwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nLCA0MDApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBwYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS4gTG9nc1xyXG4gKiB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgb2YgYSBwYWdlJ3MgY29udGVudCBmYWlscy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBjbGVhclBhZ2VcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGFpbnMgcGFnZSBhbmQgaWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gW2hhcmRSZXNldD1mYWxzZV0gLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIGB0cnVlYCwgbmF2aWdhdGVzIHRvIGBhYm91dDpibGFua2AgYW5kIHJlc2V0cyBjb250ZW50XHJcbiAqIGFuZCBzY3JpcHRzLiBJZiBgZmFsc2VgLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYGZhbHNlYC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGB0cnVlYCB3aGVuIHBhZ2VcclxuICogaXMgY29ycmVjdGx5IGNsZWFyZWQgYW5kIGBmYWxzZWAgd2hlbiBpdCBpcyBub3QuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBvb2xSZXNvdXJjZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlICYmICFwb29sUmVzb3VyY2UucGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcclxuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBgYWJvdXQ6YmxhbmtgXHJcbiAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7XHJcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXHJcbiAgICAgICAgYXdhaXQgX3NldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XHJcbiAgICAgICAgICAgICc8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+PGRpdiBpZD1cImNvbnRhaW5lclwiPjwvZGl2PjwvZGl2Pic7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICB9XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgMixcclxuICAgICAgZXJyb3IsXHJcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxyXG4gICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA9IGdldE9wdGlvbnMoKS5wb29sLndvcmtMaW1pdCArIDE7XHJcbiAgfVxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIHBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXNcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGFkZGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxPYmplY3Q+Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gYXJyYXlcclxuICogb2YgaW5qZWN0ZWQgcmVzb3VyY2VzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XHJcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgLy8gVXNlIHRoZSBjb250ZW50IG9mIHRoZSBgcmVzb3VyY2VzYFxyXG4gIGNvbnN0IHJlc291cmNlcyA9IGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9IGZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gZmFsc2UgOiB0cnVlO1xyXG5cclxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xyXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcclxuICAgICAgICAgIGlzTG9jYWxcclxuICAgICAgICAgICAgPyB7XHJcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGZpbGUpLCAndXRmOCcpXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICA6IHtcclxuICAgICAgICAgICAgICAgIHVybDogZmlsZVxyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhlIGFjdHVhbCBpbmplY3Rpb24gb2YgY29sbGVjdGVkIHNjcmlwdHNcclxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBjb25zdCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcclxuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cclxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcclxuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XHJcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXHJcbiAgICAgICAgICAgICAgLnRyaW0oKTtcclxuXHJcbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcclxuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgICAgICAgICBwYXRoOiBnZXRBYnNvbHV0ZVBhdGgoY3NzSW1wb3J0UGF0aClcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcclxuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XHJcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcclxuICAgICAgfSk7XHJcblxyXG4gICAgICAvLyBUaGUgYWN0dWFsIGluamVjdGlvbiBvZiBjb2xsZWN0ZWQgQ1NTXHJcbiAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgMixcclxuICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgIGBbYnJvd3Nlcl0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XHJcbiAgICB9XHJcbiAgfVxyXG4gIHJldHVybiBpbmplY3RlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGBhZGRTY3JpcHRUYWdgIGFuZCBgYWRkU3R5bGVUYWdgLlxyXG4gKiBSZW1vdmVzIGluamVjdGVkIHJlc291cmNlcyBhbmQgcmVzZXRzIENTUyBhbmQgc2NyaXB0IHRhZ3Mgb24gdGhlIHBhZ2UuXHJcbiAqIEFkZGl0aW9uYWxseSwgaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCBmcm9tIHdoaWNoIHJlc291cmNlcyB3aWxsXHJcbiAqIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcclxuICogdG8gYmUgY2xlYXJlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICB0cnkge1xyXG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xyXG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xyXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCB3aGVuIGRvaW5nIFNWRyBleHBvcnRzXHJcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXHJcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XHJcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XHJcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcclxuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XHJcblxyXG4gICAgICAvLyBSZW1vdmUgdGFnc1xyXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcclxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcclxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICAgIF0pIHtcclxuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXHJcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX3NldFBhZ2VDb250ZW50XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBwYWdlIG9iamVjdCB0byB3aGljaCB0aGUgY29udGVudFxyXG4gKiBpcyBiZWluZyBzZXQuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBfc2V0UGFnZUNvbnRlbnQocGFnZSkge1xyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBwYWdlIGNvbnRlbnRcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQocGFnZVRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xyXG5cclxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xyXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogam9pbihnZXRDYWNoZVBhdGgoKSwgJ3NvdXJjZXMuanMnKSB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSBpbml0aWFsIGBhbmltT2JqZWN0YCBmb3IgSGlnaGNoYXJ0c1xyXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldCBldmVudHMgKGxpa2UgYHBhZ2VlcnJvcmAgYW5kIGBjb25zb2xlYCkgZm9yIGEgUHVwcGV0ZWVyIHBhZ2UgaW4gb3JkZXJcclxuICogdG8gY2F0Y2ggYW5kIGRpc3BsYXkgZXJyb3JzIGFuZCBjb25zb2xlIGxvZ3MgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfc2V0UGFnZUV2ZW50c1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgcGFnZSBvYmplY3QgdG8gd2hpY2ggdGhlIGxpc3RlbmVyc1xyXG4gKiBhcmUgYmVpbmcgc2V0LlxyXG4gKi9cclxuZnVuY3Rpb24gX3NldFBhZ2VFdmVudHMocGFnZSkge1xyXG4gIC8vIEdldCBgZGVidWdgIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIFNldCB0aGUgYHBhZ2VlcnJvcmAgbGlzdGVuZXJcclxuICBwYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoKSA9PiB7XHJcbiAgICAvLyBJdCB3b3VsZCBzZWVtIGxpa2UgdGhpcyBtYXkgZmlyZSBhdCB0aGUgc2FtZSB0aW1lIG9yIHNob3J0bHkgYmVmb3JlXHJcbiAgICAvLyBhIHBhZ2UgaXMgY2xvc2VkLlxyXG4gICAgaWYgKHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgYGNvbnNvbGVgIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRCcm93c2VyLFxyXG4gIGNyZWF0ZUJyb3dzZXIsXHJcbiAgY2xvc2VCcm93c2VyLFxyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlLFxyXG4gIGFkZFBhZ2VSZXNvdXJjZXMsXHJcbiAgY2xlYXJQYWdlUmVzb3VyY2VzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIFRoZSBDU1MgdG8gYmUgdXNlZCBvbiB0aGUgZXhwb3J0ZWQgcGFnZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIENTUyBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKCkgPT4gYFxyXG5cclxuaHRtbCwgYm9keSB7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIHBhZGRpbmc6IDA7XHJcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcclxufVxyXG5cclxuI3RhYmxlLWRpdiwgI3NsaWRlcnMsICNkYXRhdGFibGUsICNjb250cm9scywgLmxkLXJvdyB7XHJcbiAgZGlzcGxheTogbm9uZTtcclxuICBoZWlnaHQ6IDA7XHJcbn1cclxuXHJcbiNjaGFydC1jb250YWluZXIge1xyXG4gIGJveC1zaXppbmc6IGJvcmRlci1ib3g7XHJcbiAgbWFyZ2luOiAwO1xyXG4gIG92ZXJmbG93OiBhdXRvO1xyXG4gIGZvbnQtc2l6ZTogMDtcclxufVxyXG5cclxuI2NoYXJ0LWNvbnRhaW5lciA+IGZpZ3VyZSwgZGl2IHtcclxuICBtYXJnaW4tdG9wOiAwICFpbXBvcnRhbnQ7XHJcbiAgbWFyZ2luLWJvdHRvbTogMCAhaW1wb3J0YW50O1xyXG59XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG4vKipcclxuICogVGhlIFNWRyB0ZW1wbGF0ZSB0byB1c2Ugd2hlbiBsb2FkaW5nIFNWRyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyBpbnB1dCBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgU1ZHIHRlbXBsYXRlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKHN2ZykgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke3N2Z31cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIGhhbmRsZXMgY2hhcnQgZXhwb3J0IGZ1bmN0aW9uYWxpdHkgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKiBJdCBzdXBwb3J0cyBleHBvcnRpbmcgY2hhcnRzIGFzIFNWRywgUE5HLCBKUEVHLCBhbmQgUERGIGZvcm1hdHMuIFRoZSBtb2R1bGVcclxuICogbWFuYWdlcyBwYWdlIHJlc291cmNlcywgc2V0cyB1cCB0aGUgZXhwb3J0IGVudmlyb25tZW50LCBhbmQgcHJvY2Vzc2VzIGNoYXJ0XHJcbiAqIGNvbmZpZ3VyYXRpb25zIG9yIFNWRyBpbnB1dHMgZm9yIHJlbmRlcmluZy4gRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlXHJcbiAqIHVzaW5nIFB1cHBldGVlci5cclxuICovXHJcblxyXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBjcmVhdGVDaGFydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLi90ZW1wbGF0ZXMvc3ZnRXhwb3J0L3N2Z0V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPChzdHJpbmd8QnVmZmVyfEV4cG9ydEVycm9yKT59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzXHJcbiAqIHRvIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIGBFeHBvcnRFcnJvcmAuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBleHBvcnQgdG8gYW4gdW5zdXBwb3J0ZWRcclxuICogb3V0cHV0IGZvcm1hdCBvY2N1cnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcHVwcGV0ZWVyRXhwb3J0KHBhZ2UsIGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XHJcblxyXG4gIHRyeSB7XHJcbiAgICBsZXQgaXNTVkcgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBEZWNpZGUgb24gdGhlIGV4cG9ydCBtZXRob2RcclxuICAgIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBgdHlwZWAgaXMgYWxzbyBTVkcsIHJldHVybiB0aGUgaW5wdXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gZXhwb3J0T3B0aW9ucy5zdmc7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIE1hcmsgYXMgU1ZHIGV4cG9ydCBmb3IgdGhlIGxhdGVyIHNpemUgY29ycmVjdGlvbnNcclxuICAgICAgaXNTVkcgPSB0cnVlO1xyXG5cclxuICAgICAgLy8gU1ZHIGV4cG9ydFxyXG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoZXhwb3J0T3B0aW9ucy5zdmcpLCB7XHJcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcclxuICAgICAgfSk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIEpTT04gY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRcclxuICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZShjcmVhdGVDaGFydCwgZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWNPcHRpb25zKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goXHJcbiAgICAgIC4uLihhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIGN1c3RvbUxvZ2ljT3B0aW9ucykpXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBhd2FpdCBfZ2V0Q2hhcnRTaXplKHBhZ2UsIGlzU1ZHLCBleHBvcnRPcHRpb25zLnNjYWxlKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBfZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICAvLyBTZXQgZmluYWwgYGhlaWdodGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGB3aWR0aGAgZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aClcclxuICAgICk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxyXG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XHJcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxyXG4gICAgfSk7XHJcblxyXG4gICAgbGV0IHJlc3VsdDtcclxuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xyXG4gICAgc3dpdGNoIChleHBvcnRPcHRpb25zLnR5cGUpIHtcclxuICAgICAgY2FzZSAnc3ZnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlU1ZHKHBhZ2UpO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwbmcnOlxyXG4gICAgICBjYXNlICdqcGVnJzpcclxuICAgICAgICByZXN1bHQgPSBhd2FpdCBfY3JlYXRlSW1hZ2UoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICAge1xyXG4gICAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgICAgeCxcclxuICAgICAgICAgICAgeVxyXG4gICAgICAgICAgfSxcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyZWFrO1xyXG4gICAgICBjYXNlICdwZGYnOlxyXG4gICAgICAgIHJlc3VsdCA9IGF3YWl0IF9jcmVhdGVQREYoXHJcbiAgICAgICAgICBwYWdlLFxyXG4gICAgICAgICAgdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJlYWs7XHJcbiAgICAgIGRlZmF1bHQ6XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQ6ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIHJlc3VsdDtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudFxyXG4gKiB3aXRoIHRoZSAnY2hhcnQtY29udGFpbmVyJyBpZC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2xpcFJlZ2lvblxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYHhgLCBgeWAsIGB3aWR0aGAsIGFuZCBgaGVpZ2h0YCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2dldENsaXBSZWdpb24ocGFnZSkge1xyXG4gIHJldHVybiBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIHJlYWwgY2hhcnQgZGltZW5zaW9ucyBmcm9tIGEgUHVwcGV0ZWVyIHBhZ2UuIFRoZSBmdW5jdGlvblxyXG4gKiBiZWhhdmVzIGRpZmZlcmVudGx5IGJhc2VkIG9uIHdoZXRoZXIgdGhlIGV4cG9ydCB0eXBlIGlzIFNWRyBvciBhbm90aGVyXHJcbiAqIGZvcm1hdC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfZ2V0Q2hhcnRTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGlzU1ZHIC0gRGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBjaGFydCBiZWluZyBwcm9jZXNzZWRcclxuICogaXMgYW4gU1ZHIG9yIGFub3RoZXIgZm9ybWF0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gc2NhbGUgLSBUaGUgc2NhbGUgZmFjdG9yIHRvIGJlIGFwcGxpZWQgdG8gdGhlIGNoYXJ0XHJcbiAqIGRpbWVuc2lvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdCBjb250YWluaW5nXHJcbiAqIHRoZSBhY3R1YWwgaGVpZ2h0IGFuZCB3aWR0aCBvZiB0aGUgY2hhcnQgYWZ0ZXIgc2NhbGluZy5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIF9nZXRDaGFydFNpemUocGFnZSwgaXNTVkcsIHNjYWxlKSB7XHJcbiAgLy8gVHJpZ2dlciBhcHByb3ByaWF0ZSBmdW5jdGlvbiBiYXNlZCBvbiB0aGUgYGlzU3ZnYCBmbGFnIHRvIGdldCBjaGFydCBzaXplXHJcbiAgcmV0dXJuIGlzU1ZHXHJcbiAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XHJcbiAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keSBhcyBzY2FsZVxyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgfTtcclxuICAgICAgfSwgcGFyc2VGbG9hdChzY2FsZSkpXHJcbiAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlc1xyXG4gICAgICAgIC8vIG9mIGV4cG9ydHMuIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICBjaGFydEhlaWdodCxcclxuICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICB9O1xyXG4gICAgICB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIGJ5IGV2YWx1YXRpbmcgdGhlIGBvdXRlckhUTUxgIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9jcmVhdGVTVkdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBTVkcgc3RyaW5nLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVNWRyhwYWdlKSB7XHJcbiAgcmV0dXJuIHBhZ2UuJGV2YWwoXHJcbiAgICAnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsXHJcbiAgICAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUxcclxuICApO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIGBzY3JlZW5zaG90YCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZUltYWdlXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIGltYWdlIGJ1ZmZlclxyXG4gKiBvciByZWplY3Rpbmcgd2l0aCBhbiBgRXhwb3J0RXJyb3JgIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZUltYWdlKHBhZ2UsIHR5cGUsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSB7XHJcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXHJcbiAgICAgIC8vIEFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZycgLy8gIzQ0NywgIzQ2M1xyXG4gICAgfSksXHJcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cclxuICAgICAgc2V0VGltZW91dChcclxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBgcGRmYCBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gX2NyZWF0ZVBERlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSBQREYgYnVmZmVyLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2NyZWF0ZVBERihwYWdlLCBoZWlnaHQsIHdpZHRoLCByYXN0ZXJpemF0aW9uVGltZW91dCkge1xyXG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZzogJ2Jhc2U2NCcsXHJcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBwdXBwZXRlZXJFeHBvcnRcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFRoaXMgbW9kdWxlIHByb3ZpZGVzIGEgd29ya2VyIHBvb2wgaW1wbGVtZW50YXRpb24gZm9yIG1hbmFnaW5nXHJcbiAqIHRoZSBicm93c2VyIGluc3RhbmNlIGFuZCBwYWdlcywgc3BlY2lmaWNhbGx5IGRlc2lnbmVkIGZvciB1c2Ugd2l0aFxyXG4gKiB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyLiBJdCBvcHRpbWl6ZXMgcmVzb3VyY2VzIHVzYWdlIGFuZCBwZXJmb3JtYW5jZVxyXG4gKiBieSBtYWludGFpbmluZyBhIHBvb2wgb2Ygd29ya2VycyB0aGF0IGNhbiBoYW5kbGUgY29uY3VycmVudCBleHBvcnQgdGFza3NcclxuICogdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgY2xlYXJQYWdlLCBjcmVhdGVCcm93c2VyLCBjbG9zZUJyb3dzZXIsIG5ld1BhZ2UgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBwdXBwZXRlZXJFeHBvcnQgfSBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXROZXdEYXRlVGltZSwgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxyXG5sZXQgcG9vbCA9IG51bGw7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuY29uc3QgcG9vbFN0YXRzID0ge1xyXG4gIGV4cG9ydHNBdHRlbXB0ZWQ6IDAsXHJcbiAgZXhwb3J0c1BlcmZvcm1lZDogMCxcclxuICBleHBvcnRzRHJvcHBlZDogMCxcclxuICBleHBvcnRzRnJvbVN2ZzogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnM6IDAsXHJcbiAgZXhwb3J0c0Zyb21TdmdBdHRlbXB0czogMCxcclxuICBleHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0czogMCxcclxuICB0aW1lU3BlbnQ6IDAsXHJcbiAgdGltZVNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBpbml0UG9vbFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICogQHBhcmFtIHtBcnJheTxzdHJpbmc+fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlclxyXG4gKiBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byBlbmRpbmcgdGhlIGZ1bmN0aW9uXHJcbiAqIGV4ZWN1dGlvbiB3aGVuIGFuIGFscmVhZHkgaW5pdGlhbGl6ZWQgcG9vbCBvZiByZXNvdXJjZXMgaXMgZm91bmQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sXHJcbiAqIG9mIHdvcmtlcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gaW5pdFBvb2wocG9vbE9wdGlvbnMsIHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKHB1cHBldGVlckFyZ3MpO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbE9wdGlvbnMubWluV29ya2Vyc30sIG1heCAke3Bvb2xPcHRpb25zLm1heFdvcmtlcnN9LmBcclxuICAgICk7XHJcblxyXG4gICAgaWYgKHBvb2wpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXAgYW4gZXllIG9uIGEgY29ycmVjdCBtaW4gYW5kIG1heCB3b3JrZXJzIG51bWJlclxyXG4gICAgaWYgKHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPiBwb29sT3B0aW9ucy5tYXhXb3JrZXJzKSB7XHJcbiAgICAgIHBvb2xPcHRpb25zLm1pbldvcmtlcnMgPSBwb29sT3B0aW9ucy5tYXhXb3JrZXJzO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xyXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcclxuICAgICAgLy8gR2V0IHRoZSBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYW5kIGBkZXN0cm95YCBmdW5jdGlvbnNcclxuICAgICAgLi4uX2ZhY3RvcnkocG9vbE9wdGlvbnMpLFxyXG4gICAgICBtaW46IHBvb2xPcHRpb25zLm1pbldvcmtlcnMsXHJcbiAgICAgIG1heDogcG9vbE9wdGlvbnMubWF4V29ya2VycyxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xPcHRpb25zLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5jcmVhdGVUaW1lb3V0LFxyXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbE9wdGlvbnMuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sT3B0aW9ucy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbE9wdGlvbnMuY3JlYXRlUmV0cnlJbnRlcnZhbCxcclxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sT3B0aW9ucy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgY29uc3QgY2xlYXJTdGF0dXMgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuIENsZWFyIHBhZ2Ugc3RhdHVzOiAke2NsZWFyU3RhdHVzfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChfZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDQsXHJcbiAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBEZXN0cm95ZWQgYSB3b3JrZXIgc3VjY2Vzc2Z1bGx5LmBcclxuICAgICAgKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xPcHRpb25zLm1pbldvcmtlcnM7IGkrKykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogVGVybWluYXRlcyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24ga2lsbFBvb2xcclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgYWxsIHdvcmtlcnMgYXJlXHJcbiAqIHRlcm1pbmF0ZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIHN1Y2Nlc3NmdWxseSBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICAgIHBvb2wgPSBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBwb3N0V29ya1xyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgZXhwb3J0IHJlc3VsdFxyXG4gKiBhbmQgb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvc3RXb3JrKG9wdGlvbnMpIHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICAvLyBBbiBleHBvcnQgYXR0ZW1wdCBjb3VudGVkXHJcbiAgICArK3Bvb2xTdGF0cy5leHBvcnRzQXR0ZW1wdGVkO1xyXG5cclxuICAgIC8vIERpc3BsYXkgdGhlIHBvb2wgaW5mb3JtYXRpb24gaWYgbmVlZGVkXHJcbiAgICBpZiAob3B0aW9ucy5wb29sLmJlbmNobWFya2luZykge1xyXG4gICAgICBfZ2V0UG9vbEluZm8oKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBUaHJvdyBhbiBlcnJvciBpbiBjYXNlIG9mIGxhY2tpbmcgdGhlIHBvb2wgaW5zdGFuY2VcclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRoZSBhY3F1aXJlIGNvdW50ZXJcclxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBUcnkgdG8gYWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkLCB3b3JrcyBjb3VudCBhbmQgcGFnZVxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICAgIC8vIEFjcXVpcmUgYSBwb29sIHJlc291cmNlXHJcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcblxyXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcclxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gJHtvcHRpb25zLnJlcXVlc3RJZCA/IGBSZXF1ZXN0IFske29wdGlvbnMucmVxdWVzdElkfV0gLSBgIDogJyd9YCxcclxuICAgICAgICAgIGBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlIHRvb2sgJHthY3F1aXJlQ291bnRlcigpfW1zLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtwb29sXSAke1xyXG4gICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgfUVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcclxuICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1twb29sXSBSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3dvcmtlckhhbmRsZS5pZH1dIC0gU3RhcnRpbmcgd29yayBvbiB0aGlzIHBvb2wgZW50cnkuYFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBTdGFydCBtZWFzdXJpbmcgZXhwb3J0IHRpbWVcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXHJcbiAgICBjb25zdCBleHBvcnRSZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQoXHJcbiAgICAgIHdvcmtlckhhbmRsZS5wYWdlLFxyXG4gICAgICBvcHRpb25zLmV4cG9ydCxcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAoZXhwb3J0UmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gTk9URTpcclxuICAgICAgLy8gSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxyXG4gICAgICAvLyBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxyXG4gICAgICAvLyB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXHJcbiAgICAgIC8vIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcclxuICAgICAgLy8gYW5kIHBhZ2UgY29uc2lzdGVuY3kuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIE9ubHkgYHBhZ2Uuc2NyZWVuc2hvdGAgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXHJcbiAgICAgIC8vIGhhbmRsZWQgYnkgdGhlIGBwYWdlLnBkZmAgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXHJcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IG9wdGlvbnMucG9vbC53b3JrTGltaXQgKyAxO1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcclxuICAgICAgfVxyXG5cclxuICAgICAgaWYgKFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxyXG4gICAgICAgIGV4cG9ydFJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xyXG4gICAgICApIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICBgW3Bvb2xdICR7XHJcbiAgICAgICAgICAgIG9wdGlvbnMucmVxdWVzdElkID8gYFJlcXVlc3QgWyR7b3B0aW9ucy5yZXF1ZXN0SWR9XSAtIGAgOiAnJ1xyXG4gICAgICAgICAgfVJhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS5gXHJcbiAgICAgICAgKS5zZXRFcnJvcihleHBvcnRSZXN1bHQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbcG9vbF0gJHtcclxuICAgICAgICAgICAgb3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnXHJcbiAgICAgICAgICB9RXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IoZXhwb3J0UmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgYFtiZW5jaG1hcmtdICR7b3B0aW9ucy5yZXF1ZXN0SWQgPyBgUmVxdWVzdCBbJHtvcHRpb25zLnJlcXVlc3RJZH1dIC0gYCA6ICcnfWAsXHJcbiAgICAgICAgYEV4cG9ydGluZyBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5IHRvb2sgJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVwZGF0ZSBzdGF0aXN0aWNzXHJcbiAgICBwb29sU3RhdHMudGltZVNwZW50ICs9IGV4cG9ydENvdW50ZXIoKTtcclxuICAgIHBvb2xTdGF0cy50aW1lU3BlbnRBdmVyYWdlID1cclxuICAgICAgcG9vbFN0YXRzLnRpbWVTcGVudCAvICsrcG9vbFN0YXRzLmV4cG9ydHNQZXJmb3JtZWQ7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRDb3VudGVyKCl9bXMuYCk7XHJcblxyXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiBhbiBvYmplY3Qgd2l0aCB0aGUgcmVzdWx0IGFuZCBvcHRpb25zXHJcbiAgICByZXR1cm4ge1xyXG4gICAgICByZXN1bHQ6IGV4cG9ydFJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytwb29sU3RhdHMuZXhwb3J0c0Ryb3BwZWQ7XHJcblxyXG4gICAgLy8gVHJ5IHRvIHJlbGVhc2UgdGhlIHdvcmtlciwgaWYgaXQgZXhpc3RzXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IGVycm9yO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KE9iamVjdHxudWxsKX0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgYG51bGxgXHJcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2woKSB7XHJcbiAgcmV0dXJuIHBvb2w7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXRzIHRoZSBzdGF0aXN0aWMgb2YgYSBwb29sIGluc3RhY2UgYWJvdXQgZXhwb3J0cy5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFBvb2xTdGF0c1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgY3VycmVudCBwb29sIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbFN0YXRzKCkge1xyXG4gIHJldHVybiBwb29sU3RhdHM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm9KU09OKCkge1xyXG4gIHJldHVybiB7XHJcbiAgICBtaW46IHBvb2wubWluLFxyXG4gICAgbWF4OiBwb29sLm1heCxcclxuICAgIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gICAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICAgIGFsbENyZWF0ZWQ6IHBvb2wubnVtVXNlZCgpICsgcG9vbC5udW1GcmVlKCksXHJcbiAgICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXHJcbiAgICBwZW5kaW5nQ3JlYXRlczogcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zOiBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXHJcbiAgICBhYnNvbHV0ZUFsbDpcclxuICAgICAgcG9vbC5udW1Vc2VkKCkgK1xyXG4gICAgICBwb29sLm51bUZyZWUoKSArXHJcbiAgICAgIHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCkgK1xyXG4gICAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcclxuICAgICAgcG9vbC5wZW5kaW5nRGVzdHJveXMubGVuZ3RoXHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZ2V0UG9vbEluZm9cclxuICovXHJcbmZ1bmN0aW9uIF9nZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7XHJcbiAgICBtaW4sXHJcbiAgICBtYXgsXHJcbiAgICB1c2VkLFxyXG4gICAgYXZhaWxhYmxlLFxyXG4gICAgYWxsQ3JlYXRlZCxcclxuICAgIHBlbmRpbmdBY3F1aXJlcyxcclxuICAgIHBlbmRpbmdDcmVhdGVzLFxyXG4gICAgcGVuZGluZ1ZhbGlkYXRpb25zLFxyXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxyXG4gICAgYWJzb2x1dGVBbGxcclxuICB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgZnJlZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkICh1c2VkIGFuZCBmcmVlKSByZXNvdXJjZXM6ICR7YWxsQ3JlYXRlZH0uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nQWNxdWlyZXN9LmBcclxuICApO1xyXG4gIGxvZyhcclxuICAgIDUsXHJcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxyXG4gICk7XHJcbiAgbG9nKFxyXG4gICAgNSxcclxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSB2YWxpZGF0ZWQ6ICR7cGVuZGluZ1ZhbGlkYXRpb25zfS5gXHJcbiAgKTtcclxuICBsb2coXHJcbiAgICA1LFxyXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGRlc3Ryb3llZDogJHtwZW5kaW5nRGVzdHJveXN9LmBcclxuICApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIHJlc291cmNlczogJHthYnNvbHV0ZUFsbH0uYCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBGYWN0b3J5IGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBgY3JlYXRlYCwgYHZhbGlkYXRlYCwgYGRlc3Ryb3lgXHJcbiAqIGZ1bmN0aW9ucyBmb3IgdGhlIHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZmFjdG9yeVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgcG9vbGBcclxuICogb3B0aW9ucy5cclxuICovXHJcbmZ1bmN0aW9uIF9mYWN0b3J5KHBvb2xPcHRpb25zKSB7XHJcbiAgcmV0dXJuIHtcclxuICAgIC8qKlxyXG4gICAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIGNyZWF0ZVxyXG4gICAgICpcclxuICAgICAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGFuIG9iamVjdFxyXG4gICAgICogY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbFxyXG4gICAgICogd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgYW4gZXJyb3IgZHVyaW5nXHJcbiAgICAgKiB0aGUgY3JlYXRpb24gb2YgdGhlIG5ldyBwYWdlLlxyXG4gICAgICovXHJcbiAgICBjcmVhdGU6IGFzeW5jICgpID0+IHtcclxuICAgICAgLy8gSW5pdCB0aGUgcmVzb3VyY2Ugd2l0aCB1bmlxdWUgaWQgYW5kIHdvcmsgY291bnRcclxuICAgICAgY29uc3QgcG9vbFJlc291cmNlID0ge1xyXG4gICAgICAgIGlkOiB1dWlkKCksXHJcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxyXG4gICAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xPcHRpb25zLndvcmtMaW1pdCAvIDIpKVxyXG4gICAgICB9O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBTdGFydCBtZWFzdXJpbmcgYSBwYWdlIGNyZWF0aW9uIHRpbWVcclxuICAgICAgICBjb25zdCBzdGFydERhdGUgPSBnZXROZXdEYXRlVGltZSgpO1xyXG5cclxuICAgICAgICAvLyBDcmVhdGUgYSBuZXcgcGFnZVxyXG4gICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcclxuXHJcbiAgICAgICAgLy8gTWVhc3VyZSB0aGUgdGltZSBvZiBmdWxsIGNyZWF0aW9uIGFuZCBjb25maWd1cmF0aW9uIG9mIGEgcGFnZVxyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciwgdG9vayAke1xyXG4gICAgICAgICAgICBnZXROZXdEYXRlVGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgICB9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHVybiByZWFkeSBwb29sIHJlc291cmNlXHJcbiAgICAgICAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG5cclxuICAgIC8qKlxyXG4gICAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgICAqIHRoZSB3b3JrIGxpbWl0LlxyXG4gICAgICpcclxuICAgICAqIEBhc3luY1xyXG4gICAgICogQGZ1bmN0aW9uIHZhbGlkYXRlXHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqXHJcbiAgICAgKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBpZiB0aGUgd29ya2VyXHJcbiAgICAgKiBpcyB2YWxpZCBhbmQgd2l0aGluIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHRvIGZhbHNlLlxyXG4gICAgICovXHJcbiAgICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBOT1RFOlxyXG4gICAgICAvLyBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBgVGFyZ2V0Q2xvc2VFcnJvcmAsIHdoaWNoIG1heVxyXG4gICAgICAvLyBiZSBjYXVzZWQgYnkgdHdvIHRoaW5nczpcclxuICAgICAgLy8gLSBUaGUgcGFnZSBpcyBjbG9zZWQgYW5kIGF0dGVtcHRlZCB0byBiZSByZXVzZWQuXHJcbiAgICAgIC8vIC0gTG9zdCBjb250YWN0IHdpdGggdGhlIGJyb3dzZXIuXHJcbiAgICAgIC8vXHJcbiAgICAgIC8vIFdoYXQgd2UncmUgc2VlaW5nIGluIGxvZ3MgaXMgdGhhdCBzdWNjZXNzaXZlIGV4cG9ydHMgdHlwaWNhbGx5XHJcbiAgICAgIC8vIHN1Y2NlZWRzLCBhbmQgdGhlIHNlcnZlciByZWNvdmVycywgaW5kaWNhdGluZyB0aGF0IGl0J3MgbGlrZWx5XHJcbiAgICAgIC8vIHRoZSBmaXJzdCBjYXNlLiBUaGlzIGlzIGFuIGF0dGVtcHQgYXQgYWxsaWV2YXRpbmcgdGhlIGlzc3VlIGJ5XHJcbiAgICAgIC8vIHNpbXBseSBub3QgdmFsaWRhdGluZyB0aGUgd29ya2VyIGlmIHRoZSBwYWdlIGlzIG51bGwgb3IgY2xvc2VkLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBUaGUgYWN0dWFsIHJlc3VsdCBmcm9tIHdoZW4gdGhpcyBoYXBwZW5lZCwgd2FzIHRoYXQgYSB3b3JrZXIgd291bGRcclxuICAgICAgLy8gYmUgY29tcGxldGVseSBsb2NrZWQsIHN0b3BwaW5nIGl0IGZyb20gYmVpbmcgYWNxdWlyZWQgdW50aWxcclxuICAgICAgLy8gaXRzIHdvcmsgY291bnQgcmVhY2hlZCB0aGUgbGltaXQuXHJcblxyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIHZhbGlkXHJcbiAgICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKG5vIHZhbGlkIHBhZ2UgaXMgZm91bmQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBwYWdlYCBpcyBjbG9zZWRcclxuICAgICAgaWYgKHBvb2xSZXNvdXJjZS5wYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Bvb2xSZXNvdXJjZS5pZH1dIC0gVmFsaWRhdGlvbiBmYWlsZWQgKHBhZ2UgaXMgY2xvc2VkIG9yIGludmFsaWQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgaWYgdGhlIGBtYWluRnJhbWVgIGlzIGRldGFjaGVkXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5tYWluRnJhbWUoKS5kZXRhY2hlZCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSdzIGZyYW1lIGlzIGRldGFjaGVkKS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgd29ya0xpbWl0YCBpcyBleGNlZWRlZFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcG9vbE9wdGlvbnMud29ya0xpbWl0ICYmXHJcbiAgICAgICAgKytwb29sUmVzb3VyY2Uud29ya0NvdW50ID4gcG9vbE9wdGlvbnMud29ya0xpbWl0XHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAoZXhjZWVkZWQgdGhlICR7cG9vbE9wdGlvbnMud29ya0xpbWl0fSB3b3JrcyBwZXIgcmVzb3VyY2UgbGltaXQpLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gVGhlIGBwb29sUmVzb3VyY2VgIGlzIHZhbGlkYXRlZFxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH0sXHJcblxyXG4gICAgLyoqXHJcbiAgICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cclxuICAgICAqXHJcbiAgICAgKiBAYXN5bmNcclxuICAgICAqIEBmdW5jdGlvbiBkZXN0cm95XHJcbiAgICAgKlxyXG4gICAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAgICogdGhlIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgICAqL1xyXG4gICAgZGVzdHJveTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBEZXN0cm95aW5nIGEgd29ya2VyLmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZSAmJiAhcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAvLyBSZW1vdmUgYWxsIGF0dGFjaGVkIGV2ZW50IGxpc3RlbmVycyBmcm9tIHRoZSByZXNvdXJjZVxyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdwYWdlZXJyb3InKTtcclxuICAgICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnY29uc29sZScpO1xyXG4gICAgICAgICAgcG9vbFJlc291cmNlLnBhZ2UucmVtb3ZlQWxsTGlzdGVuZXJzKCdmcmFtZWRldGFjaGVkJyk7XHJcblxyXG4gICAgICAgICAgLy8gV2UgbmVlZCB0byB3YWl0IGFyb3VuZCBmb3IgdGhpc1xyXG4gICAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuY2xvc2UoKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAzLFxyXG4gICAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBQYWdlIGNvdWxkIG5vdCBiZSBjbG9zZWQgdXBvbiBkZXN0cm95aW5nLmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sU3RhdHMsXHJcbiAgZ2V0UG9vbEluZm9KU09OXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICovXHJcblxyXG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XHJcbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuIFRoaXMgZnVuY3Rpb24gdXNlc1xyXG4gKiBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+PC9zY3JpcHQ+XHJcbiAqIHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gc2FuaXRpemVcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IC0gVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIC8vIEdldCB0aGUgdmlydHVhbCBET01cclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuXHJcbiAgLy8gQ3JlYXRlIGEgcHVyaWZ5aW5nIGluc3RhbmNlXHJcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XHJcblxyXG4gIC8vIFJldHVybiBzYW5pdGl6ZWQgaW5wdXQsIGFsbG93aW5nIGZvciB0aGUgYGZvcmVpZ25PYmplY3RgIGVsZW1lbnRzXHJcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzYW5pdGl6ZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgZnVuY3Rpb25zIHRoYXQgcHJlcGFyZSBmb3IgdGhlIGV4cG9ydGluZ1xyXG4gKiBjaGFydHMgaW50byB2YXJpb3VzIGltYWdlIG91dHB1dCBmb3JtYXRzIHN1Y2ggYXMgSlBFRywgUE5HLCBQREYsIGFuZCBTVkdzLlxyXG4gKiBJdCBzdXBwb3J0cyBzaW5nbGUgYW5kIGJhdGNoIGV4cG9ydCBvcGVyYXRpb25zIGFuZCBhbGxvd3MgY3VzdG9taXphdGlvblxyXG4gKiB0aHJvdWdoIG9wdGlvbnMgcGFzc2VkIGZyb20gY29uZmlndXJhdGlvbnMgb3IgQVBJcy5cclxuICovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBpc0FsbG93ZWRDb25maWcsIHVwZGF0ZU9wdGlvbnMsIHZhbGlkYXRlT3B0aW9uIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZ2V0UG9vbFN0YXRzLCBraWxsUG9vbCwgcG9zdFdvcmsgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xyXG5pbXBvcnQgeyBnZXRBYnNvbHV0ZVBhdGgsIGdldEJhc2U2NCwgaXNPYmplY3QsIHJvdW5kTnVtYmVyIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIGdsb2JhbCBmbGFnIGZvciB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucyBhbmQgc2F2ZXNcclxuICogdGhlIHJlc3VsdGluZyBpbWFnZSB0byB0aGUgcHJvdmlkZWQgb3V0cHV0IGZpbGUuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gc2luZ2xlRXhwb3J0XHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGBvcHRpb25zYCBvYmplY3QsIHdoaWNoIHNob3VsZCBpbmNsdWRlIHNldHRpbmdzXHJcbiAqIGZyb20gdGhlIGBleHBvcnRgIGFuZCBgY3VzdG9tTG9naWNgIHNlY3Rpb25zLiBJdCBjYW4gYmUgYSBwYXJ0aWFsIG9yIGNvbXBsZXRlXHJcbiAqIHNldCBvZiBvcHRpb25zIGZyb20gdGhlc2Ugc2VjdGlvbnMuIFRoZSBvYmplY3QgbXVzdCBjb250YWluIGF0IGxlYXN0IG9uZVxyXG4gKiBvZiB0aGUgZm9sbG93aW5nIGBleHBvcnRgIHByb3BlcnRpZXM6IGBpbmZpbGVgLCBgaW5zdHJgLCBgb3B0aW9uc2AsIG9yIGBzdmdgXHJcbiAqIHRvIGdlbmVyYXRlIGEgdmFsaWQgaW1hZ2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBzaW5nbGUgZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHNpbmdsZUV4cG9ydChvcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgaWYgdGhlIGV4cG9ydCBtYWtlcyBzZW5zZVxyXG4gIGlmIChvcHRpb25zICYmIG9wdGlvbnMuZXhwb3J0KSB7XHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQoXHJcbiAgICAgIHsgZXhwb3J0OiBvcHRpb25zLmV4cG9ydCwgY3VzdG9tTG9naWM6IG9wdGlvbnMuY3VzdG9tTG9naWMgfSxcclxuICAgICAgYXN5bmMgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3IgZXhpc3RzXHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYGI2NGAsIGBvdXRmaWxlYCwgYW5kIGB0eXBlYCBmb3IgYSBjaGFydFxyXG4gICAgICAgIGNvbnN0IHsgYjY0LCBvdXRmaWxlLCB0eXBlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBTYXZlIHRoZSByZXN1bHRcclxuICAgICAgICB0cnkge1xyXG4gICAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgICAvLyBBcyBhIEJhc2U2NCBzdHJpbmcgdG8gYSB0eHQgZmlsZVxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIGAke291dGZpbGUuc3BsaXQoJy4nKS5zaGlmdCgpIHx8ICdjaGFydCd9LnR4dGAsXHJcbiAgICAgICAgICAgICAgZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgLy8gQXMgYSBjb3JyZWN0IGltYWdlIGZvcm1hdFxyXG4gICAgICAgICAgICB3cml0ZUZpbGVTeW5jKFxyXG4gICAgICAgICAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSA6IGRhdGEucmVzdWx0XHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICAgJ1tjaGFydF0gRXJyb3Igd2hpbGUgc2F2aW5nIGEgY2hhcnQuJyxcclxuICAgICAgICAgICAgNTAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSBvbmUgb2YgdGhlIGZvbGxvd2luZyBvcHRpb25zOiBgaW5maWxlYCwgYGluc3RyYCwgYG9wdGlvbnNgLCBvciBgc3ZnYCB0byBnZW5lcmF0ZSBhIHZhbGlkIGltYWdlLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIGluZm9ybWF0aW9uXHJcbiAqIHByb3ZpZGVkIGluIHRoZSBgYmF0Y2hgIG9wdGlvbi4gVGhlIGBiYXRjaGAgaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZ1xyXG4gKiBmb3JtYXQ6IFwiaW5maWxlMS5qc29uPW91dGZpbGUxLnBuZztpbmZpbGUyLmpzb249b3V0ZmlsZTIucG5nOy4uLlwiLiBSZXN1bHRzXHJcbiAqIGFyZSBzYXZlZCB0byB0aGUgc3BlY2lmaWVkIG91dHB1dCBmaWxlcy5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBiYXRjaEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBgb3B0aW9uc2Agb2JqZWN0LCB3aGljaCBzaG91bGQgaW5jbHVkZSBzZXR0aW5nc1xyXG4gKiBmcm9tIHRoZSBgZXhwb3J0YCBhbmQgYGN1c3RvbUxvZ2ljYCBzZWN0aW9ucy4gSXQgY2FuIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZVxyXG4gKiBzZXQgb2Ygb3B0aW9ucyBmcm9tIHRoZXNlIHNlY3Rpb25zLiBJdCBtdXN0IGNvbnRhaW4gdGhlIGBiYXRjaGAgb3B0aW9uIGZyb21cclxuICogdGhlIGBleHBvcnRgIHNlY3Rpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3NlcyBhcmUgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xyXG4gKiBhbnkgb2YgdGhlIGJhdGNoIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGJhdGNoRXhwb3J0KG9wdGlvbnMpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgZXhwb3J0IG1ha2VzIHNlbnNlXHJcbiAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5leHBvcnQgJiYgb3B0aW9ucy5leHBvcnQuYmF0Y2gpIHtcclxuICAgIC8vIEFuIGFycmF5IGZvciBjb2xsZWN0aW5nIGJhdGNoIGV4cG9ydHNcclxuICAgIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIGBiYXRjaGAgYXJndW1lbnRzXHJcbiAgICBmb3IgKGxldCBwYWlyIG9mIG9wdGlvbnMuZXhwb3J0LmJhdGNoLnNwbGl0KCc7JykgfHwgW10pIHtcclxuICAgICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcclxuICAgICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgICAgYmF0Y2hGdW5jdGlvbnMucHVzaChcclxuICAgICAgICAgIHN0YXJ0RXhwb3J0KFxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgZXhwb3J0OiB7XHJcbiAgICAgICAgICAgICAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cclxuICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgIGN1c3RvbUxvZ2ljOiBvcHRpb25zLmN1c3RvbUxvZ2ljXHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIChlcnJvciwgZGF0YSkgPT4ge1xyXG4gICAgICAgICAgICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yIGV4aXN0c1xyXG4gICAgICAgICAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBHZXQgdGhlIGBiNjRgLCBgb3V0ZmlsZWAsIGFuZCBgdHlwZWAgZm9yIGEgY2hhcnRcclxuICAgICAgICAgICAgICBjb25zdCB7IGI2NCwgb3V0ZmlsZSwgdHlwZSB9ID0gZGF0YS5vcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgICAgICAgICAgICAgLy8gU2F2ZSB0aGUgcmVzdWx0XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIGlmIChiNjQpIHtcclxuICAgICAgICAgICAgICAgICAgLy8gQXMgYSBCYXNlNjQgc3RyaW5nIHRvIGEgdHh0IGZpbGVcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBgJHtvdXRmaWxlLnNwbGl0KCcuJykuc2hpZnQoKSB8fCAnY2hhcnQnfS50eHRgLFxyXG4gICAgICAgICAgICAgICAgICAgIGdldEJhc2U2NChkYXRhLnJlc3VsdCwgdHlwZSlcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgIC8vIEFzIGEgY29ycmVjdCBpbWFnZSBmb3JtYXRcclxuICAgICAgICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgICAgICAgICAgICAgICBvdXRmaWxlLFxyXG4gICAgICAgICAgICAgICAgICAgIHR5cGUgIT09ICdzdmcnXHJcbiAgICAgICAgICAgICAgICAgICAgICA/IEJ1ZmZlci5mcm9tKGRhdGEucmVzdWx0LCAnYmFzZTY0JylcclxuICAgICAgICAgICAgICAgICAgICAgIDogZGF0YS5yZXN1bHRcclxuICAgICAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICAgICAgICAnW2NoYXJ0XSBFcnJvciB3aGlsZSBzYXZpbmcgYSBjaGFydC4nLFxyXG4gICAgICAgICAgICAgICAgICA1MDBcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgKVxyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbG9nKDIsICdbY2hhcnRdIE5vIGNvcnJlY3QgcGFpciBmb3VuZCBmb3IgdGhlIGJhdGNoIGV4cG9ydC4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEF3YWl0IGFsbCBleHBvcnRzIGFyZSBkb25lXHJcbiAgICBjb25zdCBiYXRjaFJlc3VsdHMgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG5cclxuICAgIC8vIExvZyBlcnJvcnMgaWYgZm91bmRcclxuICAgIGJhdGNoUmVzdWx0cy5mb3JFYWNoKChyZXN1bHQsIGluZGV4KSA9PiB7XHJcbiAgICAgIC8vIExvZyB0aGUgZXJyb3Igd2l0aCBzdGFjayBhYm91dCB0aGUgc3BlY2lmaWMgYmF0Y2ggZXhwb3J0XHJcbiAgICAgIGlmIChyZXN1bHQucmVhc29uKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIHJlc3VsdC5yZWFzb24sXHJcbiAgICAgICAgICBgW2NoYXJ0XSBCYXRjaCBleHBvcnQgbnVtYmVyICR7aW5kZXggKyAxfSBjb3VsZCBub3QgYmUgY29ycmVjdGx5IGNvbXBsZXRlZC5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1tjaGFydF0gTm8gZXhwZWN0ZWQgYGV4cG9ydGAgb3B0aW9ucyB3ZXJlIGZvdW5kLiBQbGVhc2UgcHJvdmlkZSB0aGUgYGJhdGNoYCBvcHRpb24gdG8gZ2VuZXJhdGUgdmFsaWQgaW1hZ2VzLicsXHJcbiAgICAgIDQwMFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgaW1hZ2VPcHRpb25zYCBwYXJhbWV0ZXIgaXMgYW4gb2JqZWN0IHRoYXRcclxuICogc2hvdWxkIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgcGFydGlhbFxyXG4gKiBvcHRpb25zIGFyZSBwcm92aWRlZCwgbWlzc2luZyB2YWx1ZXMgd2lsbCBiZSBtZXJnZWQgd2l0aCB0aGUgY3VycmVudCBnbG9iYWxcclxuICogb3B0aW9ucy5cclxuICpcclxuICogVGhlIGBlbmRDYWxsYmFja2AgZnVuY3Rpb24gaXMgaW52b2tlZCB1cG9uIHRoZSBjb21wbGV0aW9uIG9mIHRoZSBleHBvcnQsXHJcbiAqIGVpdGhlciBzdWNjZXNzZnVsbHkgb3Igd2l0aCBhbiBlcnJvci4gVGhlIGBlcnJvcmAgb2JqZWN0IGlzIHByb3ZpZGVkXHJcbiAqIGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYW5kIHRoZSBgZGF0YWAgb2JqZWN0IGlzIHRoZSBzZWNvbmQsIGNvbnRhaW5pbmdcclxuICogdGhlIEJhc2U2NCByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQgaW4gdGhlIGByZXN1bHRgIHByb3BlcnR5XHJcbiAqIGFuZCB0aGUgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBzdGFydEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaW1hZ2VPcHRpb25zIC0gVGhlIGBpbWFnZU9wdGlvbnNgIG9iamVjdCwgd2hpY2ggc2hvdWxkXHJcbiAqIGluY2x1ZGUgc2V0dGluZ3MgZnJvbSB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMuIEl0IGNhblxyXG4gKiBiZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0IG9mIG9wdGlvbnMgZnJvbSB0aGVzZSBzZWN0aW9ucy4gSWYgdGhlIHByb3ZpZGVkXHJcbiAqIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmcgdmFsdWVzIHdpbGwgYmUgbWVyZ2VkIHdpdGggdGhlIGN1cnJlbnQgZ2xvYmFsXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHRoZSBleHBvcnQgcHJvY2VzcyBvciB1cG9uIGVuY291bnRlcmluZyBhbiBlcnJvci4gVGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGlzIHRoZSBgZXJyb3JgIG9iamVjdCwgYW5kIHRoZSBzZWNvbmQgYXJndW1lbnQgaXMgdGhlIGBkYXRhYCBvYmplY3QsXHJcbiAqIHdoaWNoIGluY2x1ZGVzIHRoZSBCYXNlNjQgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0IGluIHRoZSBgcmVzdWx0YFxyXG4gKiBwcm9wZXJ0eSBhbmQgdGhlIGZ1bGwgc2V0IG9mIG9wdGlvbnMgaW4gdGhlIGBvcHRpb25zYCBwcm9wZXJ0eS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHkuXHJcbiAqIEluc3RlYWQsIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgYGVuZENhbGxiYWNrYC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIHByb2Nlc3NpbmcgaW5wdXQgb2YgYW55IHR5cGUuIFRoZSBlcnJvciBpcyBwYXNzZWQgaW50byB0aGUgYGVuZENhbGxiYWNrYFxyXG4gKiBmdW5jdGlvbiBhbmQgcHJvY2Vzc2VkIHRoZXJlLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0RXhwb3J0KGltYWdlT3B0aW9ucywgZW5kQ2FsbGJhY2spIHtcclxuICB0cnkge1xyXG4gICAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgb3B0aW9ucyBhcmUgaW4gYW4gb2JqZWN0XHJcbiAgICBpZiAoIWlzT2JqZWN0KGltYWdlT3B0aW9ucykpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgcHJvdmlkZWQgYGltYWdlT3B0aW9uc2AuIE5lZWRzIHRvIGJlIGFuIG9iamVjdC4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIGFkZGl0aW9uYWwgb3B0aW9ucyB0byB0aGUgY29weSBvZiB0aGUgaW5zdGFuY2Ugb3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoXHJcbiAgICAgIHtcclxuICAgICAgICBleHBvcnQ6IGltYWdlT3B0aW9ucy5leHBvcnQsXHJcbiAgICAgICAgY3VzdG9tTG9naWM6IGltYWdlT3B0aW9ucy5jdXN0b21Mb2dpY1xyXG4gICAgICB9LFxyXG4gICAgICB0cnVlXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldCB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcclxuICAgIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZSBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgZmlsZSBpbnB1dC4nKTtcclxuXHJcbiAgICAgIGxldCBmaWxlQ29udGVudDtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgICAgIGZpbGVDb250ZW50ID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnMuaW5maWxlKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBjb250ZW50IGZyb20gYSBmaWxlIGlucHV0LicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIGZpbGUncyBleHRlbnNpb25cclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlLmVuZHNXaXRoKCcuc3ZnJykpIHtcclxuICAgICAgICAvLyBTZXQgdG8gdGhlIGBzdmdgIG9wdGlvblxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc3ZnID0gdmFsaWRhdGVPcHRpb24oJ3N2ZycsIGZpbGVDb250ZW50KTtcclxuICAgICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLmluZmlsZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIFNldCB0byB0aGUgYGluc3RyYCBvcHRpb25cclxuICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyID0gdmFsaWRhdGVPcHRpb24oJ2luc3RyJywgZmlsZUNvbnRlbnQpO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdbY2hhcnRdIEluY29ycmVjdCB2YWx1ZSBvZiB0aGUgYGluZmlsZWAgb3B0aW9uLicsXHJcbiAgICAgICAgICA0MDBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIFNWRyBhcyBhbiBpbnB1dFxyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnICE9PSBudWxsKSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIFNWRyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFNWRyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzO1xyXG5cclxuICAgICAgLy8gRXhwb3J0IGZyb20gYW4gU1ZHIHN0cmluZ1xyXG4gICAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBfZXhwb3J0RnJvbVN2ZyhcclxuICAgICAgICBzYW5pdGl6ZShleHBvcnRPcHRpb25zLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBTVkcgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21Tdmc7XHJcblxyXG4gICAgICAvLyBQYXNzIFNWRyBleHBvcnQgcmVzdWx0IHRvIHRoZSBlbmQgY2FsbGJhY2tcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKG51bGwsIHJlc3VsdCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgYXMgYW4gaW5wdXRcclxuICAgIGlmIChleHBvcnRPcHRpb25zLmluc3RyICE9PSBudWxsIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gbnVsbCkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBvcHRpb25zIGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gT3B0aW9ucyBleHBvcnRzIGF0dGVtcHRzIGNvdW50ZXJcclxuICAgICAgKytnZXRQb29sU3RhdHMoKS5leHBvcnRzRnJvbU9wdGlvbnNBdHRlbXB0cztcclxuXHJcbiAgICAgIC8vIEV4cG9ydCBmcm9tIG9wdGlvbnNcclxuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgX2V4cG9ydEZyb21PcHRpb25zKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgfHwgZXhwb3J0T3B0aW9ucy5vcHRpb25zLFxyXG4gICAgICAgIG9wdGlvbnNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIE9wdGlvbnMgZXhwb3J0cyBjb3VudGVyXHJcbiAgICAgICsrZ2V0UG9vbFN0YXRzKCkuZXhwb3J0c0Zyb21PcHRpb25zO1xyXG5cclxuICAgICAgLy8gUGFzcyBvcHRpb25zIGV4cG9ydCByZXN1bHQgdG8gdGhlIGVuZCBjYWxsYmFja1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2sobnVsbCwgcmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IFRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbi5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSB7XHJcbiAgcmV0dXJuIGFsbG93Q29kZUV4ZWN1dGlvbjtcclxufVxyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSB2YWx1ZSAtIFRoZSBib29sZWFuIHZhbHVlIHRvIGJlIGFzc2lnbmVkIHRvIHRoZSBnbG9iYWxcclxuICogYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEFsbG93Q29kZUV4ZWN1dGlvbih2YWx1ZSkge1xyXG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHZhbHVlO1xyXG59XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBmcm9tIGFuIFNWRyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tU3ZnXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dFRvRXhwb3J0IC0gVGhlIFNWRyBiYXNlZCBpbnB1dCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBjb21wbGV0ZSBzZXRcclxuICogb2Ygb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dW5rbm93bj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIGEgcmVzdWx0IG9mIHRoZSBleHBvcnRcclxuICogcHJvY2Vzcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZXJlIGlzIG5vdCBhIGNvcnJlY3QgU1ZHXHJcbiAqIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21TdmcoaW5wdXRUb0V4cG9ydCwgb3B0aW9ucykge1xyXG4gIC8vIENoZWNrIGlmIGl0IGlzIFNWR1xyXG4gIGlmIChcclxuICAgIHR5cGVvZiBpbnB1dFRvRXhwb3J0ID09PSAnc3RyaW5nJyAmJlxyXG4gICAgKGlucHV0VG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgaW5wdXRUb0V4cG9ydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcblxyXG4gICAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgU1ZHXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdmcgPSBpbnB1dFRvRXhwb3J0O1xyXG5cclxuICAgIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IG51bGw7XHJcbiAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb24gd2l0aCBhbiBTVkcgc3RyaW5nIGFzIGFuIGV4cG9ydCBpbnB1dFxyXG4gICAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gTm90IGEgY29ycmVjdCBTVkcgaW5wdXQuJywgNDAwKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIGZyb20gYW4gb3B0aW9ucyBiYXNlZCBpbnB1dCB3aXRoIHRoZSBwcm92aWRlZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIF9leHBvcnRGcm9tT3B0aW9uc1xyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRUb0V4cG9ydCAtIFRoZSBvcHRpb25zIGJhc2VkIGlucHV0IHRvIGJlIGV4cG9ydGVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlcmUgaXMgbm90IGEgY29ycmVjdFxyXG4gKiBjaGFydCBvcHRpb25zIGlucHV0LlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX2V4cG9ydEZyb21PcHRpb25zKGlucHV0VG9FeHBvcnQsIG9wdGlvbnMpIHtcclxuICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBmcm9tIG9wdGlvbnMuJyk7XHJcblxyXG4gIC8vIFRyeSB0byBjaGVjaywgdmFsaWRhdGUgYW5kIHBhcnNlIHRvIHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBjb25zdCBzdHJpbmdpZmllZE9wdGlvbnMgPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICBpbnB1dFRvRXhwb3J0LFxyXG4gICAgdHJ1ZSxcclxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgYSBjb3JyZWN0IHN0cmluZ2lmaWVkIG9wdGlvbnNcclxuICBpZiAoXHJcbiAgICBzdHJpbmdpZmllZE9wdGlvbnMgPT09IG51bGwgfHxcclxuICAgIHR5cGVvZiBzdHJpbmdpZmllZE9wdGlvbnMgIT09ICdzdHJpbmcnIHx8XHJcbiAgICAhc3RyaW5naWZpZWRPcHRpb25zLnN0YXJ0c1dpdGgoJ3snKSB8fFxyXG4gICAgIXN0cmluZ2lmaWVkT3B0aW9ucy5lbmRzV2l0aCgnfScpXHJcbiAgKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEludmFsaWQgY29uZmlndXJhdGlvbiBwcm92aWRlZCAtIE9ubHkgb3B0aW9ucyBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIG9wdGlvbnMgc2V0IHRvIHRydWUuJyxcclxuICAgICAgNDAzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBleHBvcnQgaW5wdXQgYXMgYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBzdHJpbmdpZmllZE9wdGlvbnM7XHJcblxyXG4gIC8vIFJlc2V0IHRoZSByZXN0IG9mIHRoZSBleHBvcnQgaW5wdXQgb3B0aW9uc1xyXG4gIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBudWxsO1xyXG4gIG9wdGlvbnMuZXhwb3J0LnN2ZyA9IG51bGw7XHJcblxyXG4gIC8vIENhbGwgdGhlIGZ1bmN0aW9uIHdpdGggYSBzdHJpbmdpZmllZCBjaGFydCBvcHRpb25zXHJcbiAgcmV0dXJuIF9wcmVwYXJlRXhwb3J0KG9wdGlvbnMpO1xyXG59XHJcblxyXG4vKipcclxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbnMgYmVmb3JlIGV4cG9ydC5cclxuICpcclxuICogQGFzeW5jXHJcbiAqIEBmdW5jdGlvbiBfcHJlcGFyZUV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGNvbXBsZXRlIHNldFxyXG4gKiBvZiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx1bmtub3duPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gYSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBwcm9jZXNzLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gX3ByZXBhcmVFeHBvcnQob3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agb3B0aW9uc1xyXG4gIGNvbnN0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY29uc3RyYCBvcHRpb25cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IF9maXhDb25zdHIoZXhwb3J0T3B0aW9ucy5jb25zdHIpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgdHlwZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gX2ZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgb3V0ZmlsZWAgb3B0aW9uXHJcbiAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlID0gX2ZpeE91dGZpbGUoXHJcbiAgICBleHBvcnRPcHRpb25zLnR5cGUsXHJcbiAgICBleHBvcnRPcHRpb25zLm91dGZpbGVcclxuICApO1xyXG5cclxuICAvLyBOb3RpZnkgYWJvdXQgdGhlIGN1c3RvbSBsb2dpYyB1c2FnZSBzdGF0dXNcclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjaGFydF0gVGhlIGN1c3RvbSBsb2dpYyBpcyAke2N1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPyAnYWxsb3dlZCcgOiAnZGlzYWxsb3dlZCd9LmBcclxuICApO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgY3VzdG9tQ29kZWAsIGBjYWxsYmFja2AsIGFuZCBgcmVzb3VyY2VzYCBvcHRpb25zXHJcbiAgX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucyk7XHJcblxyXG4gIC8vIFByZXBhcmUgdGhlIGBnbG9iYWxPcHRpb25zYCBhbmQgYHRoZW1lT3B0aW9uc2Agb3B0aW9uc1xyXG4gIF9oYW5kbGVHbG9iYWxBbmRUaGVtZShleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpY09wdGlvbnMpO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBgaGVpZ2h0YCwgYHdpZHRoYCwgYW5kIGBzY2FsZWAgb3B0aW9uc1xyXG4gIF9oYW5kbGVTaXplKGV4cG9ydE9wdGlvbnMpO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGUgaW1hZ2Ugb3B0aW9ucyBvYmplY3QgZG9lcyBub3QgZXhjZWVkIHRoZSBzaXplIGxpbWl0XHJcbiAgX2NoZWNrRGF0YVNpemUoeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSk7XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICByZXR1cm4gcG9zdFdvcmsob3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFkanVzdGluZyB0aGUgY29uc3RydWN0b3IgbmFtZSBieSB0cmFuc2Zvcm1pbmcgYW5kIG5vcm1hbGl6aW5nXHJcbiAqIGl0IGJhc2VkIG9uIGNvbW1vbiBjaGFydCB0eXBlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhDb25zdHJcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbnN0ciAtIFRoZSBvcmlnaW5hbCBjb25zdHJ1Y3RvciBuYW1lIHRvIGJlIGFkanVzdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgY29ycmVjdGVkIGNvbnN0cnVjdG9yIG5hbWUsIG9yICdjaGFydCcgaWYgdGhlIGlucHV0XHJcbiAqIGlzIG5vdCByZWNvZ25pemVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2ZpeENvbnN0cihjb25zdHIpIHtcclxuICB0cnkge1xyXG4gICAgLy8gRml4IHRoZSBjb25zdHJ1Y3RvciBieSBsb3dlcmluZyBjYXNpbmdcclxuICAgIGNvbnN0IGZpeGVkQ29uc3RyID0gYCR7Y29uc3RyLnRvTG93ZXJDYXNlKCkucmVwbGFjZSgnY2hhcnQnLCAnJyl9Q2hhcnRgO1xyXG5cclxuICAgIC8vIEhhbmRsZSB0aGUgY2FzZSB3aGVyZSB0aGUgcmVzdWx0IGlzIGp1c3QgJ0NoYXJ0J1xyXG4gICAgaWYgKGZpeGVkQ29uc3RyID09PSAnQ2hhcnQnKSB7XHJcbiAgICAgIGZpeGVkQ29uc3RyLnRvTG93ZXJDYXNlKCk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIHRoZSBjb3JyZWN0ZWQgY29uc3RydWN0b3IsIG90aGVyd2lzZSBkZWZhdWx0IHRvICdjaGFydCdcclxuICAgIHJldHVybiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddLmluY2x1ZGVzKFxyXG4gICAgICBmaXhlZENvbnN0clxyXG4gICAgKVxyXG4gICAgICA/IGZpeGVkQ29uc3RyXHJcbiAgICAgIDogJ2NoYXJ0JztcclxuICB9IGNhdGNoIHtcclxuICAgIC8vIERlZmF1bHQgdG8gJ2NoYXJ0JyBpbiBjYXNlIG9mIGFueSBlcnJvclxyXG4gICAgcmV0dXJuICdjaGFydCc7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyBmaXhpbmcgdGhlIG91dGZpbGUgYmFzZWQgb24gcHJvdmlkZWQgdHlwZS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9maXhPdXRmaWxlXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGNvcnJlY3RlZCBvdXRmaWxlLCBvciAnY2hhcnQucG5nJyBpZiB0aGUgaW5wdXRcclxuICogaXMgbm90IHJlY29nbml6ZWQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfZml4T3V0ZmlsZSh0eXBlLCBvdXRmaWxlKSB7XHJcbiAgLy8gR2V0IHRoZSBmaWxlIG5hbWUgZnJvbSB0aGUgYG91dGZpbGVgIG9wdGlvblxyXG4gIGNvbnN0IGZpbGVOYW1lID0gZ2V0QWJzb2x1dGVQYXRoKG91dGZpbGUgfHwgJ2NoYXJ0JylcclxuICAgIC5zcGxpdCgnLicpXHJcbiAgICAuc2hpZnQoKTtcclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCBvdXRmaWxlXHJcbiAgcmV0dXJuIGAke2ZpbGVOYW1lfS4ke3R5cGUgfHwgJ3BuZyd9YDtcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgZml4aW5nIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfZml4VHlwZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtvdXRmaWxlPW51bGxdIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLiBUaGUgZGVmYXVsdCB2YWx1ZVxyXG4gKiBpcyBgbnVsbGAuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUsIG9yICdwbmcnIGlmIHRoZSBpbnB1dFxyXG4gKiBpcyBub3QgcmVjb2duaXplZC5cclxuICovXHJcbmZ1bmN0aW9uIF9maXhUeXBlKHR5cGUsIG91dGZpbGUgPSBudWxsKSB7XHJcbiAgLy8gTUlNRSB0eXBlc1xyXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcclxuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcclxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxyXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxyXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xyXG4gIH07XHJcblxyXG4gIC8vIEdldCBmb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IE9iamVjdC52YWx1ZXMobWltZVR5cGVzKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgLy8gU3VwcG9ydCB0aGUgSlBHIHR5cGVcclxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xyXG4gICAgICB0eXBlID0gJ2pwZWcnO1xyXG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcclxuICAgICAgdHlwZSA9IG91dFR5cGU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcclxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGUgY2FsY3VsYXRpbmcgdGhlIGBoZWlnaHRgLCBgd2lkdGhgIGFuZCBgc2NhbGVgIGZvciBjaGFydCBleHBvcnRzIGJhc2VkXHJcbiAqIG9uIHRoZSBwcm92aWRlZCBleHBvcnQgb3B0aW9ucy5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIHByaW9yaXRpemVzIHZhbHVlcyBpbiB0aGUgZm9sbG93aW5nIG9yZGVyOlxyXG4gKlxyXG4gKiAxLiBUaGUgYGhlaWdodGAsIGB3aWR0aGAsIGBzY2FsZWAgZnJvbSB0aGUgYGV4cG9ydE9wdGlvbnNgLlxyXG4gKiAyLiBPcHRpb25zIGZyb20gdGhlIGNoYXJ0IGNvbmZpZ3VyYXRpb24gKGZyb20gYGV4cG9ydGluZ2AgYW5kIGBjaGFydGApLlxyXG4gKiAzLiBPcHRpb25zIGZyb20gdGhlIGdsb2JhbCBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgKS5cclxuICogNC4gT3B0aW9ucyBmcm9tIHRoZSB0aGVtZSBvcHRpb25zIChmcm9tIGBleHBvcnRpbmdgIGFuZCBgY2hhcnRgIHNlY3Rpb25zKS5cclxuICogNS4gRmFsbGJhY2sgZGVmYXVsdCB2YWx1ZXMgKGBoZWlnaHQgPSA0MDBgLCBgd2lkdGggPSA2MDBgLCBgc2NhbGUgPSAxYCkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlU2l6ZVxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIFRoZSBjb25maWd1cmF0aW9uIG9iamVjdCBjb250YWluaW5nIGBleHBvcnRgXHJcbiAqIG9wdGlvbnMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlU2l6ZShleHBvcnRPcHRpb25zKSB7XHJcbiAgLy8gQ2hlY2sgdGhlIGBvcHRpb25zYCBhbmQgYGluc3RyYCBmb3IgY2hhcnQgYW5kIGV4cG9ydGluZyBzZWN0aW9uc1xyXG4gIGNvbnN0IHsgY2hhcnQ6IG9wdGlvbnNDaGFydCwgZXhwb3J0aW5nOiBvcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMuaW5zdHIpIHx8IGZhbHNlO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogZ2xvYmFsT3B0aW9uc0NoYXJ0LCBleHBvcnRpbmc6IGdsb2JhbE9wdGlvbnNFeHBvcnRpbmcgfSA9XHJcbiAgICBpc0FsbG93ZWRDb25maWcoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIGB0aGVtZU9wdGlvbnNgIGZvciBjaGFydCBhbmQgZXhwb3J0aW5nIHNlY3Rpb25zXHJcbiAgY29uc3QgeyBjaGFydDogdGhlbWVPcHRpb25zQ2hhcnQsIGV4cG9ydGluZzogdGhlbWVPcHRpb25zRXhwb3J0aW5nIH0gPVxyXG4gICAgaXNBbGxvd2VkQ29uZmlnKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSB8fCBmYWxzZTtcclxuXHJcbiAgLy8gRmluZCB0aGUgYGhlaWdodGAgdmFsdWVcclxuICBjb25zdCBoZWlnaHQgPVxyXG4gICAgZXhwb3J0T3B0aW9ucy5oZWlnaHQgfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgb3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIGdsb2JhbE9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py5oZWlnaHQgfHxcclxuICAgIHRoZW1lT3B0aW9uc0V4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICB0aGVtZU9wdGlvbnNDaGFydD8uaGVpZ2h0IHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRIZWlnaHQgfHxcclxuICAgIDQwMDtcclxuXHJcbiAgLy8gRmluZCB0aGUgYHdpZHRoYCB2YWx1ZVxyXG4gIGNvbnN0IHdpZHRoID1cclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggfHxcclxuICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICBvcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgZ2xvYmFsT3B0aW9uc0NoYXJ0Py53aWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxyXG4gICAgdGhlbWVPcHRpb25zQ2hhcnQ/LndpZHRoIHx8XHJcbiAgICBleHBvcnRPcHRpb25zLmRlZmF1bHRXaWR0aCB8fFxyXG4gICAgNjAwO1xyXG5cclxuICAvLyBGaW5kIHRoZSBgc2NhbGVgIHZhbHVlOlxyXG4gIC8vIC0gQ2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xXHJcbiAgLy8gLSBDYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgLy8gLSBNdXN0IGJlIHJvdW5kZWQgdG8gMiBkZWNpbWFsIHBsYWNlcyAoZS5nLiAwLjIzMjM0IC0+IDAuMjMpXHJcbiAgY29uc3Qgc2NhbGUgPSByb3VuZE51bWJlcihcclxuICAgIE1hdGgubWF4KFxyXG4gICAgICAwLjEsXHJcbiAgICAgIE1hdGgubWluKFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMuc2NhbGUgfHxcclxuICAgICAgICAgIG9wdGlvbnNFeHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICAgICAgICBnbG9iYWxPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgdGhlbWVPcHRpb25zRXhwb3J0aW5nPy5zY2FsZSB8fFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9ucy5kZWZhdWx0U2NhbGUgfHxcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgNS4wXHJcbiAgICAgIClcclxuICAgICksXHJcbiAgICAyXHJcbiAgKTtcclxuXHJcbiAgLy8gVXBkYXRlIGBoZWlnaHRgLCBgd2lkdGhgLCBhbmQgYHNjYWxlYCBpbmZvcm1hdGlvbiBpbiB0aGUgYGV4cG9ydGAgb3B0aW9uc1xyXG4gIGV4cG9ydE9wdGlvbnMuaGVpZ2h0ID0gaGVpZ2h0O1xyXG4gIGV4cG9ydE9wdGlvbnMud2lkdGggPSB3aWR0aDtcclxuICBleHBvcnRPcHRpb25zLnNjYWxlID0gc2NhbGU7XHJcblxyXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIGBweGAgYW5kIGAlYFxyXG4gIGZvciAobGV0IHBhcmFtIG9mIFsnaGVpZ2h0JywgJ3dpZHRoJywgJ3NjYWxlJ10pIHtcclxuICAgIGlmICh0eXBlb2YgZXhwb3J0T3B0aW9uc1twYXJhbV0gPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbcGFyYW1dID0gK2V4cG9ydE9wdGlvbnNbcGFyYW1dLnJlcGxhY2UoL3B4fCUvZ2ksICcnKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleGVjdXRpb24gb2YgY3VzdG9tIGxvZ2ljIG9wdGlvbnMsIGluY2x1ZGluZyBsb2FkaW5nIGByZXNvdXJjZXNgLFxyXG4gKiBgY3VzdG9tQ29kZWAsIGFuZCBgY2FsbGJhY2tgLiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBhbGxvd2VkLCBpdCBwcm9jZXNzZXNcclxuICogdGhlIGN1c3RvbSBsb2dpYyBvcHRpb25zIGFjY29yZGluZ2x5LiBJZiBjb2RlIGV4ZWN1dGlvbiBpcyBub3QgYWxsb3dlZCxcclxuICogaXQgZGlzYWJsZXMgdGhlIHVzYWdlIG9mIHJlc291cmNlcywgY3VzdG9tIGNvZGUgYW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21Mb2dpY09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgY3VzdG9tTG9naWNgIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiBjb2RlIGV4ZWN1dGlvblxyXG4gKiBpcyBub3QgYWxsb3dlZCBidXQgY3VzdG9tIGxvZ2ljIG9wdGlvbnMgYXJlIHN0aWxsIHByb3ZpZGVkLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUN1c3RvbUxvZ2ljKGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEluIGNhc2Ugb2YgYWxsb3dpbmcgY29kZSBleGVjdXRpb25cclxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xyXG4gICAgLy8gUHJvY2VzcyB0aGUgYHJlc291cmNlc2Agb3B0aW9uXHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBUcnkgdG8gaGFuZGxlIHJlc291cmNlc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gX2hhbmRsZVJlc291cmNlcyhcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgb3B0aW9uXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAncmVzb3VyY2VzJyxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2coMiwgJ1tjaGFydF0gVGhlIGByZXNvdXJjZXNgIGNhbm5vdCBiZSBsb2FkZWQuJyk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUHJvY2VzcyB0aGUgYGN1c3RvbUNvZGVgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY3VzdG9tIGNvZGUgYW5kIHdyYXAgYXJvdW5kIGl0IGluIGEgc2VsZiBpbnZva2luZyBmdW5jdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IF9oYW5kbGVDdXN0b21Db2RlKFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXNcclxuICAgICAgKTtcclxuXHJcbiAgICAgIC8vIFZhbGlkYXRlIHRoZSBvcHRpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY3VzdG9tQ29kZScsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1tjaGFydF0gVGhlIGBjdXN0b21Db2RlYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gbnVsbDtcclxuICAgIH1cclxuXHJcbiAgICAvLyBQcm9jZXNzIHRoZSBgY2FsbGJhY2tgIG9wdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gVHJ5IHRvIGxvYWQgY2FsbGJhY2sgZnVuY3Rpb25cclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gX2hhbmRsZUN1c3RvbUNvZGUoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0ZpbGVSZXNvdXJjZXMsXHJcbiAgICAgICAgdHJ1ZVxyXG4gICAgICApO1xyXG5cclxuICAgICAgLy8gVmFsaWRhdGUgdGhlIG9wdGlvblxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAnY2FsbGJhY2snLFxyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFja1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW2NoYXJ0XSBUaGUgYGNhbGxiYWNrYCBjYW5ub3QgYmUgbG9hZGVkLicpO1xyXG5cclxuICAgICAgLy8gSW4gY2FzZSBvZiBhbiBlcnJvciwgc2V0IHRoZSBvcHRpb24gd2l0aCBudWxsXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IG51bGw7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjdXN0b21Db2RlYCBwcmVzZW50XHJcbiAgICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUpKSB7XHJcbiAgICAgIGxvZygzLCAnW2NoYXJ0XSBObyB2YWx1ZSBmb3IgdGhlIGBjdXN0b21Db2RlYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGBjYWxsYmFja2AgcHJlc2VudFxyXG4gICAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaykpIHtcclxuICAgICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGNhbGxiYWNrYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgdGhlcmUgaXMgdGhlIGByZXNvdXJjZXNgIHByZXNlbnRcclxuICAgIGlmIChbbnVsbCwgdW5kZWZpbmVkXS5pbmNsdWRlcyhjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzKSkge1xyXG4gICAgICBsb2coMywgJ1tjaGFydF0gTm8gdmFsdWUgZm9yIHRoZSBgcmVzb3VyY2VzYCBvcHRpb24gZm91bmQuJyk7XHJcbiAgICB9XHJcbiAgfSBlbHNlIHtcclxuICAgIC8vIElmIHRoZSBgYWxsb3dDb2RlRXhlY3V0aW9uYCBmbGFnIGlzIHNldCB0byBmYWxzZSwgd2Ugc2hvdWxkIHJlZnVzZVxyXG4gICAgLy8gdGhlIHVzYWdlIG9mIHRoZSBgY2FsbGJhY2tgLCBgcmVzb3VyY2VzYCwgYW5kIGBjdXN0b21Db2RlYCBvcHRpb25zLlxyXG4gICAgLy8gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGwgcmVmdXNlIHRvIHJ1biBhcmJpdHJhcnkgSmF2YVNjcmlwdC5cclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBSZXNldCBhbGwgY3VzdG9tIGNvZGUgb3B0aW9uc1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBudWxsO1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gbnVsbDtcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBudWxsO1xyXG5cclxuICAgICAgLy8gU2VuZCBhIG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnQgdGhlc2Ugc2V0dGluZ3NcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJywgYW5kICdjdXN0b21Db2RlJyBvcHRpb25zIGhhdmUgYmVlbiBkaXNhYmxlZCBmb3IgdGhpcyBzZXJ2ZXIuYCxcclxuICAgICAgICA0MDNcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZyb20gdGhlIGByZXNvdXJjZXNgIG9wdGlvbiBmb3IgZXhwb3J0LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2hhbmRsZVJlc291cmNlc1xyXG4gKlxyXG4gKiBAcGFyYW0geyhPYmplY3R8c3RyaW5nfG51bGwpfSBbcmVzb3VyY2VzPW51bGxdIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLlxyXG4gKiBDYW4gYmUgZWl0aGVyIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sIGEgcGF0aCB0byBhIEpTT04gZmlsZSxcclxuICogb3IgbnVsbC4gVGhlIGRlZmF1bHQgdmFsdWUgaXMgYG51bGxgLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgbG9hZGluZ1xyXG4gKiByZXNvdXJjZXMgZnJvbSBmaWxlcyBpcyBhbGxvd2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93Q29kZUV4ZWN1dGlvbiAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgY29kZVxyXG4gKiBleGVjdXRpb24gaXMgYWxsb3dlZC5cclxuICpcclxuICogQHJldHVybnMgeyhPYmplY3R8bnVsbCl9IFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciBudWxsIGlmIG5vIHZhbGlkIHJlc291cmNlc1xyXG4gKiBhcmUgZm91bmQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlUmVzb3VyY2VzKFxyXG4gIHJlc291cmNlcyA9IG51bGwsXHJcbiAgYWxsb3dGaWxlUmVzb3VyY2VzLFxyXG4gIGFsbG93Q29kZUV4ZWN1dGlvblxyXG4pIHtcclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuXHJcbiAgLy8gSWYgbm8gcmVzb3VyY2VzIGZvdW5kLCB0cnkgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXNcclxuICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIHJlc291cmNlcyA9ICdyZXNvdXJjZXMuanNvbic7XHJcbiAgfVxyXG5cclxuICAvLyBMaXN0IG9mIGFsbG93ZWQgc2VjdGlvbnMgaW4gdGhlIHJlc291cmNlcyBKU09OXHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgLy8gQSBmbGFnIHRoYXQgZGVjaWRlcyBiYXNlZCB0byByZXR1cm4gcmVzb3VyY2VzIG9yIGBudWxsYFxyXG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XHJcblxyXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxyXG4gIGlmIChcclxuICAgIGFsbG93RmlsZVJlc291cmNlcyAmJlxyXG4gICAgdHlwZW9mIHJlc291cmNlcyA9PT0gJ3N0cmluZycgJiZcclxuICAgIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKVxyXG4gICkge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgcmVhZEZpbGVTeW5jKGdldEFic29sdXRlUGF0aChyZXNvdXJjZXMpLCAndXRmOCcpLFxyXG4gICAgICBmYWxzZSxcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICApO1xyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0FsbG93ZWRDb25maWcocmVzb3VyY2VzLCBmYWxzZSwgYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXHJcbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xyXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xyXG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcclxuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcclxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcclxuICAgIHJldHVybiBudWxsO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufVxyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlQ3VzdG9tQ29kZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtpc0NhbGxiYWNrPWZhbHNlXSAtIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhlIHJldHVybmVkIGNvZGVcclxuICogbXVzdCBiZSBpbiBhIGNhbGxiYWNrIGZvcm1hdC5cclxuICpcclxuICogQHJldHVybnMgeyhzdHJpbmd8bnVsbCl9IFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIG51bGwgaWYgd3JhcHBpbmcgZmFpbHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfaGFuZGxlQ3VzdG9tQ29kZShjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMsIGlzQ2FsbGJhY2sgPSBmYWxzZSkge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICAvLyBMb2FkIGEgZmlsZSBpZiB0aGUgZmlsZSByZXNvdXJjZXMgYXJlIGFsbG93ZWRcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gX2hhbmRsZUN1c3RvbUNvZGUoXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhnZXRBYnNvbHV0ZVBhdGgoY3VzdG9tQ29kZSksICd1dGY4JyksXHJcbiAgICAgICAgICAgIGFsbG93RmlsZVJlc291cmNlcyxcclxuICAgICAgICAgICAgaXNDYWxsYmFja1xyXG4gICAgICAgICAgKVxyXG4gICAgICAgIDogbnVsbDtcclxuICAgIH0gZWxzZSBpZiAoXHJcbiAgICAgICFpc0NhbGxiYWNrICYmXHJcbiAgICAgIChjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxyXG4gICAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpKVxyXG4gICAgKSB7XHJcbiAgICAgIC8vIFRyZWF0IGEgZnVuY3Rpb24gYXMgYSBzZWxmLWludm9raW5nIGV4cHJlc3Npb25cclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gT3IgcmV0dXJuIGFzIGEgc3RyaW5naWZpZWQgY29kZVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogSGFuZGxlcyB0aGUgbG9hZGluZyBhbmQgdmFsaWRhdGlvbiBvZiB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYFxyXG4gKiBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIElmIHRoZSBvcHRpb24gaXMgYSBzdHJpbmcgYW5kIHJlZmVyZW5jZXMgYSBKU09OIGZpbGVcclxuICogKHdoZW4gdGhlIGBhbGxvd0ZpbGVSZXNvdXJjZXNgIGlzIGB0cnVlYCksIGl0IHJlYWRzIGFuZCBwYXJzZXMgdGhlIGZpbGUuXHJcbiAqIE90aGVyd2lzZSwgaXQgYXR0ZW1wdHMgdG8gcGFyc2UgdGhlIHN0cmluZyBvciBvYmplY3QgYXMgSlNPTi4gSWYgYW55IGVycm9yc1xyXG4gKiBvY2N1ciBkdXJpbmcgdGhpcyBwcm9jZXNzLCB0aGUgb3B0aW9uIGlzIHNldCB0byBgbnVsbGAuIElmIHRoZXJlIGlzIGFuIGVycm9yXHJcbiAqIGxvYWRpbmcgb3IgcGFyc2luZyB0aGUgYGdsb2JhbE9wdGlvbnNgIG9yIGB0aGVtZU9wdGlvbnNgLCB0aGUgZXJyb3IgaXMgbG9nZ2VkXHJcbiAqIGFuZCB0aGUgb3B0aW9uIGlzIHNldCB0byBgbnVsbGAuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBfaGFuZGxlR2xvYmFsQW5kVGhlbWVcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZyBgZXhwb3J0YFxyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tTG9naWNPcHRpb25zIC0gVGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogYGN1c3RvbUxvZ2ljYCBvcHRpb25zLlxyXG4gKi9cclxuZnVuY3Rpb24gX2hhbmRsZUdsb2JhbEFuZFRoZW1lKGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xyXG4gIC8vIEdldCB0aGUgYGFsbG93RmlsZVJlc291cmNlc2AgYW5kIGBhbGxvd0NvZGVFeGVjdXRpb25gIGZsYWdzXHJcbiAgY29uc3QgeyBhbGxvd0ZpbGVSZXNvdXJjZXMsIGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gY3VzdG9tTG9naWNPcHRpb25zO1xyXG5cclxuICAvLyBDaGVjayB0aGUgYGdsb2JhbE9wdGlvbnNgIGFuZCBgdGhlbWVPcHRpb25zYCBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiB0aGUgb3B0aW9uIGV4aXN0c1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0pIHtcclxuICAgICAgICAvLyBDaGVjayBpZiBpdCBpcyBhIHN0cmluZyBhbmQgYSBmaWxlIG5hbWUgd2l0aCB0aGUgYC5qc29uYCBleHRlbnNpb25cclxuICAgICAgICBpZiAoXHJcbiAgICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXMgJiZcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgZmlsZSBjb250ZW50IGNhbiBiZSBhIGNvbmZpZywgYW5kIHNhdmUgaXQgYXMgYSBzdHJpbmdcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgICByZWFkRmlsZVN5bmMoZ2V0QWJzb2x1dGVQYXRoKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZSxcclxuICAgICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgdmFsdWUgY2FuIGJlIGEgY29uZmlnLCBhbmQgc2F2ZSBpdCBhcyBhIHN0cmluZ1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0FsbG93ZWRDb25maWcoXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBWYWxpZGF0ZSB0aGUgb3B0aW9uXHJcbiAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB2YWxpZGF0ZU9wdGlvbihcclxuICAgICAgICAgIG9wdGlvbnNOYW1lLFxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV1cclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NoYXJ0XSBUaGUgXFxgJHtvcHRpb25zTmFtZX1cXGAgY2Fubm90IGJlIGxvYWRlZC5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICAvLyBJbiBjYXNlIG9mIGFuIGVycm9yLCBzZXQgdGhlIG9wdGlvbiB3aXRoIG51bGxcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBudWxsO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBDaGVjayBpZiB0aGVyZSBpcyB0aGUgYGdsb2JhbE9wdGlvbnNgIHByZXNlbnRcclxuICBpZiAoW251bGwsIHVuZGVmaW5lZF0uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy5nbG9iYWxPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYGdsb2JhbE9wdGlvbnNgIG9wdGlvbiBmb3VuZC4nKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZXJlIGlzIHRoZSBgdGhlbWVPcHRpb25zYCBwcmVzZW50XHJcbiAgaWYgKFtudWxsLCB1bmRlZmluZWRdLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudGhlbWVPcHRpb25zKSkge1xyXG4gICAgbG9nKDMsICdbY2hhcnRdIE5vIHZhbHVlIGZvciB0aGUgYHRoZW1lT3B0aW9uc2Agb3B0aW9uIGZvdW5kLicpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyB0aGUgc2l6ZSBvZiB0aGUgZGF0YSBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzIGFnYWluc3QgYSBmaXhlZCBsaW1pdFxyXG4gKiBvZiAxMDBNQi5cclxuICpcclxuICogQGZ1bmN0aW9uIF9jaGVja0RhdGFTaXplXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpbWFnZU9wdGlvbnMgLSBUaGUgZGF0YSBvYmplY3QsIHdoaWNoIGluY2x1ZGVzIG9wdGlvbnMgZnJvbVxyXG4gKiB0aGUgYGV4cG9ydGAgYW5kIGBjdXN0b21Mb2dpY2Agc2VjdGlvbnMgYW5kIHdpbGwgYmUgc2VudCB0byBhIFB1cHBldGVlciBwYWdlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIHNpemUgb2YgdGhlIGRhdGEgZm9yXHJcbiAqIHRoZSBleHBvcnQgcHJvY2VzcyBvYmplY3QgZXhjZWVkcyB0aGUgMTAwTUIgbGltaXQuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2hlY2tEYXRhU2l6ZShpbWFnZU9wdGlvbnMpIHtcclxuICAvLyBTZXQgdGhlIGZpeGVkIGRhdGEgbGltaXQgKDEwME1CKSBmb3IgdGhlIGRldi10b29scyBwcm90b2NvbFxyXG4gIGNvbnN0IGRhdGFMaW1pdCA9IDEwMCAqIDEwMjQgKiAxMDI0O1xyXG5cclxuICAvLyBHZXQgdGhlIHNpemUgb2YgdGhlIGRhdGFcclxuICBjb25zdCB0b3RhbFNpemUgPSBCdWZmZXIuYnl0ZUxlbmd0aChKU09OLnN0cmluZ2lmeShpbWFnZU9wdGlvbnMpLCAndXRmLTgnKTtcclxuXHJcbiAgLy8gTG9nIHRoZSBzaXplIGluIE1CXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbY2hhcnRdIFRoZSBjdXJyZW50IHRvdGFsIHNpemUgb2YgdGhlIGRhdGEgZm9yIHRoZSBleHBvcnQgcHJvY2VzcyBpcyBhcm91bmQgJHsoXHJcbiAgICAgIHRvdGFsU2l6ZSAvXHJcbiAgICAgICgxMDI0ICogMTAyNClcclxuICAgICkudG9GaXhlZCgyKX1NQi5gXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgdGhlIHNpemUgb2YgZGF0YSBiZWZvcmUgcGFzc2luZyB0byBhIHBhZ2VcclxuICBpZiAodG90YWxTaXplID49IGRhdGFMaW1pdCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBUaGUgZGF0YSBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzIGV4Y2VlZHMgMTAwTUIgbGltaXQuYFxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvblxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNSwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8qKlxyXG4gKiBAb3ZlcnZpZXcgVGhpcyBtb2R1bGUgcHJvdmlkZXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIG1hbmFnaW5nIGludGVydmFsc1xyXG4gKiBhbmQgdGltZW91dHMgaW4gYSBjZW50cmFsaXplZCBtYW5uZXIuIEl0IG1haW50YWlucyBhIHJlZ2lzdHJ5IG9mIGFsbCBhY3RpdmVcclxuICogdGltZXJzIGFuZCBhbGxvd3MgZm9yIHRoZWlyIGVmZmljaWVudCBjbGVhbnVwIHdoZW4gbmVlZGVkIHRvIGF2b2lkIHBvdGVudGlhbFxyXG4gKiBtZW1vcnkgbGVha3MsIHVuaW50ZW5kZWQgYmVoYXZpb3Igb3IgYSBwcm9jZXNzIGZyb20gYmVpbmcgc3RvcHBlZC5cclxuICovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzXHJcbmNvbnN0IHRpbWVySWRzID0gW107XHJcblxyXG4vKipcclxuICogQWRkcyBpZCBvZiB0aGUgYHNldEludGVydmFsYCBvciBgc2V0VGltZW91dGAgYW5kIHRvIHRoZSBgdGltZXJJZHNgIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gYWRkVGltZXJcclxuICpcclxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbCBvciBhIHRpbWVvdXQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gYWRkVGltZXIoaWQpIHtcclxuICB0aW1lcklkcy5wdXNoKGlkKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYW5kIHRpbWVvdXRzIGJ5IGlkcyBnYXRoZXJlZFxyXG4gKiBpbiB0aGUgYHRpbWVySWRzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsZWFyQWxsVGltZXJzXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gY2xlYXJBbGxUaW1lcnMoKSB7XHJcbiAgbG9nKDQsIGBbdGltZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscyBhbmQgdGltZW91dHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiB0aW1lcklkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgICBjbGVhclRpbWVvdXQoaWQpO1xyXG4gIH1cclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZFRpbWVyLFxyXG4gIGNsZWFyQWxsVGltZXJzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZXNcclxuICogYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlcyBpbiBhbiBFeHByZXNzIGFwcGxpY2F0aW9uLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24gd2l0aFxyXG4gKiB0aGUgcGFzc2VkIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9nRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxyXG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XHJcblxyXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxyXG4gIGlmIChnZXRPcHRpb25zKCkub3RoZXIubm9kZUVudiAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgYHJldHVybkVycm9yTWlkZGxld2FyZWAgbWlkZGxld2FyZVxyXG4gIHJldHVybiBuZXh0KGVycm9yKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuZnVuY3Rpb24gcmV0dXJuRXJyb3JNaWRkbGV3YXJlKGVycm9yLCByZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XHJcblxyXG4gIC8vIFVzZSB0aGUgZXJyb3IncyBzdGF0dXMgY29kZSBvciB0aGUgZGVmYXVsdCA0MDBcclxuICBjb25zdCBzdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZSB8fCA0MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzcG9uc2Uuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIGVycm9yIG1pZGRsZXdhcmVzIHRvIHRoZSBwYXNzZWQgZXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXJyb3JNaWRkbGV3YXJlKGFwcCkge1xyXG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcclxuXHJcbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgY29uZmlndXJpbmcgYW5kIGVuYWJsaW5nIHJhdGVcclxuICogbGltaXRpbmcgaW4gYW4gRXhwcmVzcyBhcHBsaWNhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgY291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc2V0XHJcbiAqIHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgcmF0ZUxpbWl0aW5nT3B0aW9ucykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBDaGVjayBpZiB0aGUgcmF0ZSBsaW1pdGluZyBpcyBlbmFibGVkIGFuZCB0aGUgYXBwIGV4aXN0c1xyXG4gICAgaWYgKGFwcCAmJiByYXRlTGltaXRpbmdPcHRpb25zLmVuYWJsZSkge1xyXG4gICAgICBjb25zdCBtZXNzYWdlID1cclxuICAgICAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gICAgICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXHJcbiAgICAgIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgICAgIHdpbmRvdzogcmF0ZUxpbWl0aW5nT3B0aW9ucy53aW5kb3cgfHwgMSxcclxuICAgICAgICBtYXhSZXF1ZXN0czogcmF0ZUxpbWl0aW5nT3B0aW9ucy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgICAgICBkZWxheTogcmF0ZUxpbWl0aW5nT3B0aW9ucy5kZWxheSB8fCAwLFxyXG4gICAgICAgIHRydXN0UHJveHk6IHJhdGVMaW1pdGluZ09wdGlvbnMudHJ1c3RQcm94eSB8fCBmYWxzZSxcclxuICAgICAgICBza2lwS2V5OiByYXRlTGltaXRpbmdPcHRpb25zLnNraXBLZXkgfHwgbnVsbCxcclxuICAgICAgICBza2lwVG9rZW46IHJhdGVMaW1pdGluZ09wdGlvbnMuc2tpcFRva2VuIHx8IG51bGxcclxuICAgICAgfTtcclxuXHJcbiAgICAgIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxyXG4gICAgICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICAgICAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICAgICAgLy8gVGltZSBmcmFtZSBmb3Igd2hpY2ggcmVxdWVzdHMgYXJlIGNoZWNrZWQgYW5kIHJlbWVtYmVyZWRcclxuICAgICAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciBgd2luZG93TXNgXHJcbiAgICAgICAgbGltaXQ6IHJhdGVPcHRpb25zLm1heFJlcXVlc3RzLFxyXG4gICAgICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICAgICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXHJcbiAgICAgICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgICAgICBqc29uOiAoKSA9PiB7XHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2UgfSk7XHJcbiAgICAgICAgICAgIH0sXHJcbiAgICAgICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICAgICAgaWYgKFxyXG4gICAgICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBudWxsICYmXHJcbiAgICAgICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gbnVsbCAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICAgICApIHtcclxuICAgICAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICAgICAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXhSZXF1ZXN0c30gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAnW3JhdGUgbGltaXRpbmddIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHNldCB0aGUgcmF0ZSBsaW1pdGluZyBvcHRpb25zLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBQcm92aWRlcyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBmb3IgdmFsaWRhdGluZyBpbmNvbWluZyBIVFRQIHJlcXVlc3RzXHJcbiAqIGluIGFuIEV4cHJlc3MgYXBwbGljYXRpb24uIFRoaXMgbW9kdWxlIGVuc3VyZXMgdGhhdCByZXF1ZXN0cyBjb250YWluXHJcbiAqIGFwcHJvcHJpYXRlIGNvbnRlbnQgdHlwZXMgYW5kIHZhbGlkIHJlcXVlc3QgYm9kaWVzLCBpbmNsdWRpbmcgcHJvcGVyIEpTT05cclxuICogc3RydWN0dXJlcyBhbmQgY2hhcnQgZGF0YSBmb3IgZXhwb3J0cy4gSXQgY2hlY2tzIGZvciBwb3RlbnRpYWwgaXNzdWVzIHN1Y2hcclxuICogYXMgbWlzc2luZyBvciBtYWxmb3JtZWQgZGF0YSwgcHJpdmF0ZSByYW5nZSBVUkxzIGluIFNWRyBwYXlsb2FkcywgYW5kIGFsbG93c1xyXG4gKiBmb3IgZmxleGlibGUgb3B0aW9ucyB2YWxpZGF0aW9uLiBUaGUgbWlkZGxld2FyZSBsb2dzIGRldGFpbGVkIGluZm9ybWF0aW9uXHJcbiAqIGFuZCBoYW5kbGVzIGVycm9ycyByZWxhdGVkIHRvIGluY29ycmVjdCBwYXlsb2FkcywgY2hhcnQgZGF0YSwgYW5kIHByaXZhdGUgVVJMXHJcbiAqIHVzYWdlLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgaXNBbGxvd2VkQ29uZmlnIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaXNPYmplY3RFbXB0eSwgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHZhbGlkYXRpbmcgdGhlIGNvbnRlbnQtdHlwZSBoZWFkZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBjb250ZW50VHlwZU1pZGRsZXdhcmVcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHt1bmRlZmluZWR9IFRoZSBjYWxsIHRvIHRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgY29udGVudC10eXBlXHJcbiAqIGlzIG5vdCBjb3JyZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gY29udGVudFR5cGVNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgY29udGVudCB0eXBlIGhlYWRlclxyXG4gICAgY29uc3QgY29udGVudFR5cGUgPSByZXF1ZXN0LmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddIHx8ICcnO1xyXG5cclxuICAgIC8vIEFsbG93IG9ubHkgSlNPTiwgVVJMLWVuY29kZWQgYW5kIGZvcm0gZGF0YSB3aXRob3V0IGZpbGVzIHR5cGVzIG9mIGRhdGFcclxuICAgIGlmIChcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi9qc29uJykgJiZcclxuICAgICAgIWNvbnRlbnRUeXBlLmluY2x1ZGVzKCdhcHBsaWNhdGlvbi94LXd3dy1mb3JtLXVybGVuY29kZWQnKSAmJlxyXG4gICAgICAhY29udGVudFR5cGUuaW5jbHVkZXMoJ211bHRpcGFydC9mb3JtLWRhdGEnKVxyXG4gICAgKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3ZhbGlkYXRpb25dIENvbnRlbnQtVHlwZSBtdXN0IGJlIGFwcGxpY2F0aW9uL2pzb24sIGFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZCwgb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YS4nLFxyXG4gICAgICAgIDQxNVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENhbGwgdGhlIGByZXF1ZXN0Qm9keU1pZGRsZXdhcmVgIG1pZGRsZXdhcmVcclxuICAgIHJldHVybiBuZXh0KCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciB2YWxpZGF0aW5nIHRoZSByZXF1ZXN0J3MgYm9keS5cclxuICpcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RCb2R5TWlkZGxld2FyZVxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge3VuZGVmaW5lZH0gVGhlIGNhbGwgdG8gdGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGlmIHRoZSBib2R5IGlzIG5vdCBjb3JyZWN0LlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIGBFeHBvcnRFcnJvcmAgaWYgdGhlIGNoYXJ0IGRhdGEgZnJvbSB0aGUgYm9keVxyXG4gKiBpcyBub3QgY29ycmVjdC5cclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBgRXhwb3J0RXJyb3JgIGluIGNhc2Ugb2YgdGhlIHByaXZhdGUgcmFuZ2VcclxuICogdXJsIGVycm9yLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVxdWVzdEJvZHlNaWRkbGV3YXJlKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBib2R5XHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0SWQgPSB1dWlkKCk7XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGhlcmUgaXMgbm8gY29ycmVjdCBib2R5XHJcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIGVtcHR5LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QuIEFjY2VwdGVkIHR5cGVzIGFyZSAnYXBwbGljYXRpb24vanNvbicgYW5kICdtdWx0aXBhcnQvZm9ybS1kYXRhJy5gLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEdldCB0aGUgYGFsbG93Q29kZUV4ZWN1dGlvbmAgb3B0aW9uIGZvciB0aGUgc2VydmVyXHJcbiAgICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb24gPSBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKTtcclxuXHJcbiAgICAvLyBGaW5kIGEgY29ycmVjdCBjaGFydCBvcHRpb25zXHJcbiAgICBjb25zdCBpbnN0ciA9IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgLy8gVXNlIG9uZSBvZiB0aGUgYmVsb3dcclxuICAgICAgYm9keS5pbnN0ciB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5pbmZpbGUgfHwgYm9keS5kYXRhLFxyXG4gICAgICAvLyBTdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICB0cnVlLFxyXG4gICAgICAvLyBBbGxvdyBvciBkaXNhbGxvdyBmdW5jdGlvbnNcclxuICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRocm93IGFuIGVycm9yIGlmIHRoZXJlIGlzIG5vIGNvcnJlY3QgY2hhcnQgZGF0YVxyXG4gICAgaWYgKGluc3RyID09PSBudWxsICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgcmVxdWVzdCBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBSZWNlaXZlZCBwYXlsb2FkIGlzIG1pc3NpbmcgY29ycmVjdCBjaGFydCBkYXRhIGZvciBleHBvcnQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keSl9LmBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLmAsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVGhyb3cgYW4gZXJyb3IgaWYgdGVzdCBvZiB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWRyBmYWlsc1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQoYm9keS5zdmcpKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW3ZhbGlkYXRpb25dIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiAneGxpbms6aHJlZicgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuYCxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBHZXQgYW5kIHByZS12YWxpZGF0ZSB0aGUgb3B0aW9ucyBhbmQgc3RvcmUgdGhlbSBpbiB0aGUgcmVxdWVzdFxyXG4gICAgcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zID0ge1xyXG4gICAgICAvLyBTZXQgdGhlIGNyZWF0ZWQgSUQgYXMgYSBgcmVxdWVzdElkYCBwcm9wZXJ0eSBpbiB0aGUgb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0SWQsXHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHN2ZzogYm9keS5zdmcsXHJcbiAgICAgICAgb3V0ZmlsZTpcclxuICAgICAgICAgIGJvZHkub3V0ZmlsZSB8fFxyXG4gICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtib2R5LnR5cGUgfHwgJ3BuZyd9YCxcclxuICAgICAgICB0eXBlOiBib2R5LnR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0cixcclxuICAgICAgICBiNjQ6IGJvZHkuYjY0LFxyXG4gICAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQWxsb3dlZENvbmZpZyhcclxuICAgICAgICAgIGJvZHkuZ2xvYmFsT3B0aW9ucyxcclxuICAgICAgICAgIHRydWUsXHJcbiAgICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgICApLFxyXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNBbGxvd2VkQ29uZmlnKFxyXG4gICAgICAgICAgYm9keS50aGVtZU9wdGlvbnMsXHJcbiAgICAgICAgICB0cnVlLFxyXG4gICAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICAgKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbixcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZSxcclxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQWxsb3dlZENvbmZpZyhib2R5LnJlc291cmNlcywgdHJ1ZSwgYWxsb3dDb2RlRXhlY3V0aW9uKVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8vIENhbGwgdGhlIG5leHQgbWlkZGxld2FyZVxyXG4gICAgcmV0dXJuIG5leHQoKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIHZhbGlkYXRpb24gbWlkZGxld2FyZXMgdG8gdGhlIHBhc3NlZCBleHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiB2YWxpZGF0aW9uTWlkZGxld2FyZShhcHApIHtcclxuICAvLyBBZGQgY29udGVudCB0eXBlIHZhbGlkYXRpb24gbWlkZGxld2FyZVxyXG4gIGFwcC5wb3N0KFsnLycsICcvOmZpbGVuYW1lJ10sIGNvbnRlbnRUeXBlTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCByZXF1ZXN0IGJvZHkgcmVxdWVzdCB2YWxpZGF0aW9uIG1pZGRsZXdhcmVcclxuICBhcHAucG9zdChbJy8nLCAnLzpmaWxlbmFtZSddLCByZXF1ZXN0Qm9keU1pZGRsZXdhcmUpO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIHRoZSBleHBvcnQgcm91dGVzIGFuZCBsb2dpYyBmb3IgaGFuZGxpbmcgY2hhcnQgZXhwb3J0XHJcbiAqIHJlcXVlc3RzIGluIGFuIEV4cHJlc3Mgc2VydmVyLiBUaGlzIG1vZHVsZSBwcm9jZXNzZXMgaW5jb21pbmcgcmVxdWVzdHNcclxuICogdG8gZXhwb3J0IGNoYXJ0cyBpbiB2YXJpb3VzIGZvcm1hdHMgKGUuZy4gSlBFRywgUE5HLCBQREYsIFNWRykuIEl0IGludGVncmF0ZXNcclxuICogd2l0aCBIaWdoY2hhcnRzJyBjb3JlIGZ1bmN0aW9uYWxpdGllcyBhbmQgc3VwcG9ydHMgYm90aCBpbW1lZGlhdGUgZG93bmxvYWRcclxuICogcmVzcG9uc2VzIGFuZCBCYXNlNjQtZW5jb2RlZCBjb250ZW50IHJldHVybnMuIFRoZSBjb2RlIGFsc28gZmVhdHVyZXNcclxuICogYmVuY2htYXJraW5nIGZvciBwZXJmb3JtYW5jZSBtb25pdG9yaW5nLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRCYXNlNjQsIG1lYXN1cmVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnRcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHJlcXVlc3RFeHBvcnQocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpIHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZSBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCByZXF1ZXN0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcblxyXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xyXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XHJcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcclxuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEdldCB0aGUgb3B0aW9ucyBwcmV2aW91c2x5IHZhbGlkYXRlZCBpbiB0aGUgdmFsaWRhdGlvbiBtaWRkbGV3YXJlXHJcbiAgICBjb25zdCBvcHRpb25zID0gcmVxdWVzdC52YWxpZGF0ZWRPcHRpb25zO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVxdWVzdCBpZFxyXG4gICAgY29uc3QgcmVxdWVzdElkID0gb3B0aW9ucy5yZXF1ZXN0SWQ7XHJcblxyXG4gICAgLy8gSW5mbyBhYm91dCBhbiBpbmNvbWluZyByZXF1ZXN0IHdpdGggY29ycmVjdCBkYXRhXHJcbiAgICBsb2coNCwgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0LmApO1xyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBkYXRhKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBSZXF1ZXN0IFske3JlcXVlc3RJZH1dIC0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIHJldHVybjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKCFkYXRhIHx8ICFkYXRhLnJlc3VsdCkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gUmVxdWVzdCBbJHtyZXF1ZXN0SWR9XSAtIFJlcXVlc3QgZnJvbSAke1xyXG4gICAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8XHJcbiAgICAgICAgICAgIHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgICB9IHdhcyBpbmNvcnJlY3QuIFJlY2VpdmVkIHJlc3VsdCBpcyAke2RhdGEucmVzdWx0fS5gXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBVbmV4cGVjdGVkIHJldHVybiBvZiB0aGUgZXhwb3J0IHJlc3VsdCBmcm9tIHRoZSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFJldHVybiB0aGUgcmVzdWx0IGluIGFuIGFwcHJvcHJpYXRlIGZvcm1hdFxyXG4gICAgICBpZiAoZGF0YS5yZXN1bHQpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtleHBvcnRdIFJlcXVlc3QgWyR7cmVxdWVzdElkfV0gLSBUaGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3MgdG9vayAke3JlcXVlc3RDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgYHR5cGVgLCBgYjY0YCwgYG5vRG93bmxvYWRgLCBhbmQgYG91dGZpbGVgIGZyb20gb3B0aW9uc1xyXG4gICAgICAgIGNvbnN0IHsgdHlwZSwgYjY0LCBub0Rvd25sb2FkLCBvdXRmaWxlIH0gPSBkYXRhLm9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgICAgICAvLyBJZiBvbmx5IEJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XHJcbiAgICAgICAgaWYgKGI2NCkge1xyXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoZ2V0QmFzZTY0KGRhdGEucmVzdWx0LCB0eXBlKSk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFub0Rvd25sb2FkKSB7XHJcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KG91dGZpbGUpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudCwgb3RoZXJ3aXNlIGEgYjY0IHN0cmluZyBmcm9tIGEgYnVmZmVyXHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoZGF0YS5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oZGF0YS5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gbmV4dChlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYGV4cG9ydGAgcm91dGVzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gZXhwb3J0Um91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gZXhwb3J0Um91dGVzKGFwcCkge1xyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy8nIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdFxyXG4gICAqIGVuZHBvaW50LlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvJywgcmVxdWVzdEV4cG9ydCk7XHJcblxyXG4gIC8qKlxyXG4gICAqIEFkZHMgdGhlIFBPU1QgJy86ZmlsZW5hbWUnIC0gQSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgcmVxdWVzdEV4cG9ydCk7XHJcbn1cclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjUsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IERlZmluZXMgYW4gRXhwcmVzcyByb3V0ZSBmb3Igc2VydmVyIGhlYWx0aCBtb25pdG9yaW5nLCBpbmNsdWRpbmdcclxuICogdXB0aW1lLCBzdWNjZXNzIHJhdGVzLCBhbmQgb3RoZXIgc2VydmVyIHN0YXRpc3RpY3MuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBnZXRIY1ZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IGdldFBvb2xJbmZvSlNPTiwgZ2V0UG9vbFN0YXRzIH0gZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGFkZFRpbWVyIH0gZnJvbSAnLi4vLi4vdGltZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldE5ld0RhdGVUaW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuLy8gU2V0IHRoZSBzdGFydCBkYXRlIG9mIHRoZSBzZXJ2ZXJcclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbi8vIEdldCB0aGUgYHBhY2thZ2UuanNvbmAgY29udGVudFxyXG5jb25zdCBwYWNrYWdlRmlsZSA9IEpTT04ucGFyc2UoXHJcbiAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJyksICd1dGY4JylcclxuKTtcclxuXHJcbi8vIEFuIGFycmF5IGZvciBzdWNjZXNzIHJhdGUgcmF0aW9zXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5cclxuLy8gUmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDtcclxuXHJcbi8vIDMwIG1pbnV0ZXNcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwO1xyXG5cclxuLyoqXHJcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIGBzdWNjZXNzUmF0ZXNgXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2VcclxuICpcclxuICogQHJldHVybnMge251bWJlcn0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICByZXR1cm4gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBjb2xsZWN0cyByZWNvcmRzIHRvIHRoZSBgc3VjY2Vzc1JhdGVzYCBhcnJheS5cclxuICpcclxuICogQGZ1bmN0aW9uIF9zdGFydFN1Y2Nlc3NSYXRlXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5mdW5jdGlvbiBfc3RhcnRTdWNjZXNzUmF0ZSgpIHtcclxuICByZXR1cm4gc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBnZXRQb29sU3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQgPT09IDBcclxuICAgICAgICA/IDFcclxuICAgICAgICA6IChzdGF0cy5leHBvcnRzUGVyZm9ybWVkIC8gc3RhdHMuZXhwb3J0c0F0dGVtcHRlZCkgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgaGVhbHRoYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBoZWFsdGhSb3V0ZXNcclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBoZWFsdGhSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBgYWRkVGltZXJgIGZ1bnRpb25cclxuICBhZGRUaW1lcihfc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgR0VUICcvaGVhbHRoJyAtIEEgcm91dGUgZm9yIGdldHRpbmcgdGhlIGJhc2ljIHN0YXRzIG9mIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbaGVhbHRoXSBSZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcclxuXHJcbiAgICAgIGNvbnN0IHN0YXRzID0gZ2V0UG9vbFN0YXRzKCk7XHJcbiAgICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbiAgICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBfY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xyXG5cclxuICAgICAgLy8gU2VuZCB0aGUgc2VydmVyJ3Mgc3RhdGlzdGljc1xyXG4gICAgICByZXNwb25zZS5zZW5kKHtcclxuICAgICAgICAvLyBTdGF0dXMgYW5kIHRpbWVzXHJcbiAgICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgICAgdXB0aW1lOiBgJHtNYXRoLmZsb29yKChnZXROZXdEYXRlVGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjApfSBtaW51dGVzYCxcclxuXHJcbiAgICAgICAgLy8gVmVyc2lvbnNcclxuICAgICAgICBzZXJ2ZXJWZXJzaW9uOiBwYWNrYWdlRmlsZS52ZXJzaW9uLFxyXG4gICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIY1ZlcnNpb24oKSxcclxuXHJcbiAgICAgICAgLy8gRXhwb3J0c1xyXG4gICAgICAgIGF2ZXJhZ2VFeHBvcnRUaW1lOiBzdGF0cy50aW1lU3BlbnRBdmVyYWdlLFxyXG4gICAgICAgIGF0dGVtcHRlZEV4cG9ydHM6IHN0YXRzLmV4cG9ydHNBdHRlbXB0ZWQsXHJcbiAgICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMuZXhwb3J0c1BlcmZvcm1lZCxcclxuICAgICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5leHBvcnRzRHJvcHBlZCxcclxuICAgICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLmV4cG9ydHNQZXJmb3JtZWQgLyBzdGF0cy5leHBvcnRzQXR0ZW1wdGVkKSAqIDEwMCxcclxuXHJcbiAgICAgICAgLy8gUG9vbFxyXG4gICAgICAgIHBvb2w6IGdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICAgIHBlcmlvZCxcclxuICAgICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxyXG4gICAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcclxuICAgICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgICAvLyBTVkcgYW5kIEpTT04gZXhwb3J0c1xyXG4gICAgICAgIHN2Z0V4cG9ydHM6IHN0YXRzLmV4cG9ydHNGcm9tU3ZnLFxyXG4gICAgICAgIGpzb25FeHBvcnRzOiBzdGF0cy5leHBvcnRzRnJvbU9wdGlvbnMsXHJcbiAgICAgICAgc3ZnRXhwb3J0c0F0dGVtcHRzOiBzdGF0cy5leHBvcnRzRnJvbVN2Z0F0dGVtcHRzLFxyXG4gICAgICAgIGpzb25FeHBvcnRzQXR0ZW1wdHM6IHN0YXRzLmV4cG9ydHNGcm9tT3B0aW9uc0F0dGVtcHRzXHJcbiAgICAgIH0pO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHNlcnZpbmcgdGhlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlclxyXG4gKiB3aGVuIGVuYWJsZWQuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBgdWlgIHJvdXRlcy5cclxuICpcclxuICogQGZ1bmN0aW9uIHVpUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdWlSb3V0ZXMoYXBwKSB7XHJcbiAgLy8gQWRkIHRoZSBVSSBlbmRwb2ludCBvbmx5IGlmIHJlcXVpcmVkXHJcbiAgaWYgKGdldE9wdGlvbnMoKS51aS5lbmFibGUpIHtcclxuICAgIC8qKlxyXG4gICAgICogQWRkcyB0aGUgR0VUICcvJyAtIEEgcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxyXG4gICAgICovXHJcbiAgICBhcHAuZ2V0KGdldE9wdGlvbnMoKS51aS5yb3V0ZSB8fCAnLycsIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyg0LCAnW3VpXSBSZXR1cm5pbmcgVUkgZm9yIHRoZSBleHBvcnQuJyk7XHJcblxyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xyXG4gICAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIHJldHVybiBuZXh0KGVycm9yKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfVxyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBEZWZpbmVzIGFuIEV4cHJlc3Mgcm91dGUgZm9yIHVwZGF0aW5nIHRoZSBIaWdoY2hhcnRzIHZlcnNpb25cclxuICogb24gdGhlIHNlcnZlciwgd2l0aCBhdXRoZW50aWNhdGlvbiBhbmQgdmFsaWRhdGlvbi5cclxuICovXHJcblxyXG5pbXBvcnQgeyBnZXRIY1ZlcnNpb24sIHVwZGF0ZUhjVmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL3ZhbGlkYXRpb24uanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgYHZlcnNpb25fY2hhbmdlYCByb3V0ZXMuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiB2ZXJzaW9uQ2hhbmdlUm91dGVzXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gdmVyc2lvbkNoYW5nZVJvdXRlcyhhcHApIHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUICcvdmVyc2lvbl9jaGFuZ2UvOm5ld1ZlcnNpb24nIC0gQSByb3V0ZSBmb3IgY2hhbmdpbmdcclxuICAgKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy92ZXJzaW9uX2NoYW5nZS86bmV3VmVyc2lvbicsIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbdmVyc2lvbl0gQ2hhbmdpbmcgSGlnaGNoYXJ0cyB2ZXJzaW9uLicpO1xyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0b2tlbiBkaXJlY3RseSBmcm9tIGVudnNcclxuICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW3ZlcnNpb25dIFRoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IGBISUdIQ0hBUlRTX0FETUlOX1RPS0VOYCBpcyBub3Qgc2V0LicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIHRva2VuIGZyb20gdGhlIGhjLWF1dGggaGVhZGVyXHJcbiAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuXHJcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1t2ZXJzaW9uXSBJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXHJcbiAgICAgICAgICA0MDFcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBHZXQgdGhlIG5ldyB2ZXJzaW9uIGZyb20gdGhlIHBhcmFtc1xyXG4gICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuXHJcbiAgICAgIC8vIFVwZGF0ZSB2ZXJzaW9uXHJcbiAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgdHJ5IHtcclxuICAgICAgICAgIGF3YWl0IHVwZGF0ZUhjVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgICBgW3ZlcnNpb25dIFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgNDAwXHJcbiAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFN1Y2Nlc3NcclxuICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcclxuICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcclxuICAgICAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiBnZXRIY1ZlcnNpb24oKSxcclxuICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbdmVyc2lvbl0gTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIG5leHQoZXJyb3IpO1xyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBBIG1vZHVsZSB0aGF0IHNldHMgdXAgYW5kIG1hbmFnZXMgSFRUUCBhbmQgSFRUUFMgc2VydmVyc1xyXG4gKiBmb3IgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlci4gSXQgaGFuZGxlcyBzZXJ2ZXIgaW5pdGlhbGl6YXRpb24sXHJcbiAqIGNvbmZpZ3VyYXRpb24sIGVycm9yIGhhbmRsaW5nLCBtaWRkbGV3YXJlcyBzZXR1cCwgcm91dGUgZGVmaW5pdGlvbiwgYW5kIHJhdGVcclxuICogbGltaXRpbmcuIFRoZSBtb2R1bGUgZXhwb3J0cyBmdW5jdGlvbnMgdG8gc3RhcnQsIHN0b3AsIGFuZCBtYW5hZ2Ugc2VydmVyXHJcbiAqIGluc3RhbmNlcywgYXMgd2VsbCBhcyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgZGVmaW5pbmcgcm91dGVzIGFuZCBhdHRhY2hpbmdcclxuICogbWlkZGxld2FyZXMuXHJcbiAqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgeyB1cGRhdGVPcHRpb25zIH0gZnJvbSAnLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUsIGdldEFic29sdXRlUGF0aCB9IGZyb20gJy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBlcnJvck1pZGRsZXdhcmUgZnJvbSAnLi9taWRkbGV3YXJlcy9lcnJvci5qcyc7XHJcbmltcG9ydCByYXRlTGltaXRpbmdNaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvcmF0ZUxpbWl0aW5nLmpzJztcclxuaW1wb3J0IHZhbGlkYXRpb25NaWRkbGV3YXJlIGZyb20gJy4vbWlkZGxld2FyZXMvdmFsaWRhdGlvbi5qcyc7XHJcblxyXG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XHJcbmltcG9ydCBoZWFsdGhSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcclxuaW1wb3J0IHVpUm91dGVzIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuaW1wb3J0IHZlcnNpb25DaGFuZ2VSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvdmVyc2lvbkNoYW5nZS5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXHJcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XHJcblxyXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcclxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhbiBIVFRQIGFuZC9vciBIVFRQUyBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uXHJcbiAqIFRoZSBgc2VydmVyT3B0aW9uc2Agb2JqZWN0IGNvbnRhaW5zIHNlcnZlci1yZWxhdGVkIHByb3BlcnRpZXMgKHJlZmVyXHJcbiAqIHRvIHRoZSBgc2VydmVyYCBzZWN0aW9uIGluIHRoZSBgLi9saWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGRldGFpbHMpLlxyXG4gKlxyXG4gKiBAYXN5bmNcclxuICogQGZ1bmN0aW9uIHN0YXJ0U2VydmVyXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBbc2VydmVyT3B0aW9ucz17fV0gLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgc2VydmVyYCBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0XHJcbiAqIG9mIHRoZSBgc2VydmVyYCBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXMgd2lsbFxyXG4gKiBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBhbiBlbXB0eVxyXG4gKiBvYmplY3QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aGVuIHRoZSBzZXJ2ZXIgaXMgZWl0aGVyXHJcbiAqIG5vdCBlbmFibGVkIG9yIG5vIHZhbGlkIEV4cHJlc3MgYXBwIGlzIGZvdW5kLCBzaWduYWxpbmcgdGhlIGVuZCBvZiB0aGVcclxuICogZnVuY3Rpb24ncyBleGVjdXRpb24uXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gYEV4cG9ydEVycm9yYCBpZiB0aGUgc2VydmVyIGNhbm5vdFxyXG4gKiBiZSBjb25maWd1cmVkIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0U2VydmVyKHNlcnZlck9wdGlvbnMgPSB7fSkge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIHNlcnZlcjogc2VydmVyT3B0aW9uc1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gVXNlIHZhbGlkYXRlZCBvcHRpb25zXHJcbiAgICBzZXJ2ZXJPcHRpb25zID0gb3B0aW9ucy5zZXJ2ZXI7XHJcblxyXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxyXG4gICAgaWYgKCFzZXJ2ZXJPcHRpb25zLmVuYWJsZSB8fCAhYXBwKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnW3NlcnZlcl0gU2VydmVyIGNhbm5vdCBiZSBzdGFydGVkIChub3QgZW5hYmxlZCBvciBubyBjb3JyZWN0IEV4cHJlc3MgYXBwIGZvdW5kKS4nLFxyXG4gICAgICAgIDUwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW5cclxuICAgIC8vIHRoZSByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3dcclxuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSBzZXJ2ZXJPcHRpb25zLnVwbG9hZExpbWl0ICogMTAyNCAqIDEwMjQ7XHJcblxyXG4gICAgLy8gTWVtb3J5IHN0b3JhZ2UgZm9yIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIG11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xyXG4gICAgICBzdG9yYWdlLFxyXG4gICAgICBsaW1pdHM6IHtcclxuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxyXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xyXG5cclxuICAgIC8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuICAgIGFwcC51c2UoXHJcbiAgICAgIGNvcnMoe1xyXG4gICAgICAgIG1ldGhvZHM6IFsnUE9TVCcsICdHRVQnLCAnT1BUSU9OUyddXHJcbiAgICAgIH0pXHJcbiAgICApO1xyXG5cclxuICAgIC8vIEdldHRpbmcgYSBsb3Qgb2YgYFJhbmdlTm90U2F0aXNmaWFibGVFcnJvcmAgZXhjZXB0aW9ucyAoZXZlbiB0aG91Z2ggdGhpc1xyXG4gICAgLy8gaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UpXHJcbiAgICBhcHAudXNlKChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICByZXNwb25zZS5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xyXG4gICAgICBuZXh0KCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIEpTT04gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy5qc29uKHtcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXIgZm9yIFVSTC1lbmNvZGVkIGZvcm0gZGF0YVxyXG4gICAgYXBwLnVzZShcclxuICAgICAgZXhwcmVzcy51cmxlbmNvZGVkKHtcclxuICAgICAgICBleHRlbmRlZDogdHJ1ZSxcclxuICAgICAgICBsaW1pdDogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcclxuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXHJcbiAgICBpZiAoIXNlcnZlck9wdGlvbnMuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgX2F0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XHJcblxyXG4gICAgICAvLyBMaXN0ZW5cclxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyT3B0aW9ucy5wb3J0LCBzZXJ2ZXJPcHRpb25zLmhvc3QsICgpID0+IHtcclxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJPcHRpb25zLnBvcnQsIGh0dHBTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJPcHRpb25zLmhvc3R9OiR7c2VydmVyT3B0aW9ucy5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxyXG4gICAgaWYgKHNlcnZlck9wdGlvbnMuc3NsLmVuYWJsZSkge1xyXG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXHJcbiAgICAgIGxldCBrZXksIGNlcnQ7XHJcblxyXG4gICAgICB0cnkge1xyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxyXG4gICAgICAgIGtleSA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5rZXknKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXHJcbiAgICAgICAgY2VydCA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGpvaW4oZ2V0QWJzb2x1dGVQYXRoKHNlcnZlck9wdGlvbnMuc3NsLmNlcnRQYXRoKSwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyT3B0aW9ucy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcclxuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXHJcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcclxuXHJcbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxyXG4gICAgICAgIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcclxuXHJcbiAgICAgICAgLy8gTGlzdGVuXHJcbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlck9wdGlvbnMuc3NsLnBvcnQsIHNlcnZlck9wdGlvbnMuaG9zdCwgKCkgPT4ge1xyXG4gICAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyT3B0aW9ucy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgMyxcclxuICAgICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyT3B0aW9ucy5ob3N0fToke3NlcnZlck9wdGlvbnMuc3NsLnBvcnR9LmBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHJhdGUgbGltaXRlclxyXG4gICAgcmF0ZUxpbWl0aW5nTWlkZGxld2FyZShhcHAsIHNlcnZlck9wdGlvbnMucmF0ZUxpbWl0aW5nKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIHZhbGlkYXRpb24gaGFuZGxlclxyXG4gICAgdmFsaWRhdGlvbk1pZGRsZXdhcmUoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgcm91dGVzXHJcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcclxuICAgIGhlYWx0aFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZXMoYXBwKTtcclxuICAgIHZlcnNpb25DaGFuZ2VSb3V0ZXMoYXBwKTtcclxuXHJcbiAgICAvLyBTZXQgdXAgdGhlIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9yTWlkZGxld2FyZShhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLicsXHJcbiAgICAgIDUwMFxyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGNsb3NlU2VydmVyc1xyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGNsb3NlU2VydmVycygpIHtcclxuICAvLyBDaGVjayBpZiB0aGVyZSBhcmUgc2VydmVycyB3b3JraW5nXHJcbiAgaWYgKGFjdGl2ZVNlcnZlcnMuc2l6ZSA+IDApIHtcclxuICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcclxuXHJcbiAgICAvLyBDbG9zZSBlYWNoIG9uZSBvZiBzZXJ2ZXJzXHJcbiAgICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcclxuICAgICAgc2VydmVyLmNsb3NlKCgpID0+IHtcclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldFNlcnZlcnNcclxuICpcclxuICogQHJldHVybnMge0FycmF5PE9iamVjdD59IFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldFNlcnZlcnMoKSB7XHJcbiAgcmV0dXJuIGFjdGl2ZVNlcnZlcnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRFeHByZXNzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtFeHByZXNzfSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRFeHByZXNzKCkge1xyXG4gIHJldHVybiBleHByZXNzO1xyXG59XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQGZ1bmN0aW9uIGdldEFwcFxyXG4gKlxyXG4gKiBAcmV0dXJucyB7RXhwcmVzc30gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldEFwcCgpIHtcclxuICByZXR1cm4gYXBwO1xyXG59XHJcblxyXG4vKipcclxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBlbmFibGVSYXRlTGltaXRpbmdcclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHJhdGVMaW1pdGluZ09wdGlvbnMgLSBUaGUgY29uZmlndXJhdGlvbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBUaGlzIG9iamVjdCBtYXkgaW5jbHVkZSBhIHBhcnRpYWwgb3IgY29tcGxldGUgc2V0XHJcbiAqIG9mIHRoZSBgcmF0ZUxpbWl0aW5nYCBvcHRpb25zLiBJZiB0aGUgb3B0aW9ucyBhcmUgcGFydGlhbCwgbWlzc2luZyB2YWx1ZXNcclxuICogd2lsbCBkZWZhdWx0IHRvIHRoZSBjdXJyZW50IGdsb2JhbCBjb25maWd1cmF0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGVuYWJsZVJhdGVMaW1pdGluZyhyYXRlTGltaXRpbmdPcHRpb25zKSB7XHJcbiAgLy8gVXBkYXRlIHRoZSBpbnN0YW5jZSBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgIHNlcnZlcjoge1xyXG4gICAgICByYXRlTGltaXRpbmc6IHJhdGVMaW1pdGluZ09wdGlvbnNcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gU2V0IHRoZSByYXRlIGxpbWl0aW5nIG9wdGlvbnNcclxuICByYXRlTGltaXRpbmdNaWRkbGV3YXJlKGFwcCwgb3B0aW9ucy5zZXJ2ZXIucmF0ZUxpbWl0aW5nT3B0aW9ucyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cclxuICpcclxuICogQGZ1bmN0aW9uIHVzZVxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9uKHMpIHRvIGJlIGFwcGxpZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gdXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSB7XHJcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXHJcbiAqXHJcbiAqIEBmdW5jdGlvbiBnZXRcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldChwYXRoLCAuLi5taWRkbGV3YXJlcykge1xyXG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQGZ1bmN0aW9uIHBvc3RcclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbihzKSB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpIHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cclxuICpcclxuICogQGZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzXHJcbiAqXHJcbiAqIEBwYXJhbSB7KGh0dHAuU2VydmVyfGh0dHBzLlNlcnZlcil9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmZ1bmN0aW9uIF9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKHNlcnZlcikge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBzdGFydFNlcnZlcixcclxuICBjbG9zZVNlcnZlcnMsXHJcbiAgZ2V0U2VydmVycyxcclxuICBnZXRFeHByZXNzLFxyXG4gIGdldEFwcCxcclxuICBlbmFibGVSYXRlTGltaXRpbmcsXHJcbiAgdXNlLFxyXG4gIGdldCxcclxuICBwb3N0XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBIYW5kbGVzIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIsIGVuc3VyaW5nXHJcbiAqIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlcyBzdWNoIGFzIGJyb3dzZXIsIHBhZ2VzLCBzZXJ2ZXJzLCBhbmQgdGltZXJzLlxyXG4gKi9cclxuXHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xlYXJBbGxUaW1lcnMgfSBmcm9tICcuL3RpbWVyLmpzJztcclxuXHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogUGVyZm9ybXMgY2xlYW51cCBvcGVyYXRpb25zIHRvIGVuc3VyZSBhIGdyYWNlZnVsIHNodXRkb3duIG9mIHRoZSBwcm9jZXNzLlxyXG4gKiBUaGlzIGluY2x1ZGVzIGNsZWFyaW5nIGFsbCByZWdpc3RlcmVkIHRpbWVvdXRzL2ludGVydmFscywgY2xvc2luZyBhY3RpdmVcclxuICogc2VydmVycywgdGVybWluYXRpbmcgcmVzb3VyY2VzIChwYWdlcykgb2YgdGhlIHBvb2wsIHBvb2wgaXRzZWxmLCBhbmQgY2xvc2luZ1xyXG4gKiB0aGUgYnJvd3Nlci5cclxuICpcclxuICogQGZ1bmN0aW9uIHNodXRkb3duQ2xlYW5VcFxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2V4aXRDb2RlPTBdIC0gVGhlIGV4aXQgY29kZSB0byB1c2Ugd2l0aCBgcHJvY2Vzcy5leGl0KClgLlxyXG4gKiBUaGUgZGVmYXVsdCB2YWx1ZSBpcyBgMGAuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc2h1dGRvd25DbGVhblVwKGV4aXRDb2RlID0gMCkge1xyXG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xyXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXHJcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuICAgIGNsZWFyQWxsVGltZXJzKCksXHJcblxyXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxyXG4gICAgY2xvc2VTZXJ2ZXJzKCksXHJcblxyXG4gICAgLy8gQ2xvc2UgYW4gYWN0aXZlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI1LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBUaGlzIGNvcmUgbW9kdWxlIGluaXRpYWxpemVzIGFuZCBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydFxyXG4gKiBTZXJ2ZXIuIFRoZSBtYWluIGBpbml0RXhwb3J0YCBmdW5jdGlvbiBoYW5kbGVzIGxvZ2dpbmcsIHNjcmlwdCBjYWNoaW5nLFxyXG4gKiByZXNvdXJjZSBwb29saW5nLCBicm93c2VyIHN0YXJ0dXAsIGFuZCBlbnN1cmVzIGdyYWNlZnVsIHByb2Nlc3MgY2xlYW51cFxyXG4gKiBvbiBleGl0LiBBZGRpdGlvbmFsbHksIGl0IHByb3ZpZGVzIEFQSSBmdW5jdGlvbnMgZm9yIHVzaW5nIGl0IGFzIGEgTm9kZS5qc1xyXG4gKiBtb2R1bGUsIG9mZmVyaW5nIGZ1bmN0aW9uYWxpdGllcyBmb3IgcHJvY2Vzc2luZyBvcHRpb25zLCBjb25maWd1cmluZ1xyXG4gKiBhbmQgcGVyZm9ybWluZyBleHBvcnRzLCBhbmQgc2V0dGluZyB1cCBzZXJ2ZXIuXHJcbiAqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb25cclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHVwZGF0ZU9wdGlvbnMsXHJcbiAgbWFwVG9OZXdPcHRpb25zLFxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9uc1xyXG59IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBpbml0TG9nZ2luZyxcclxuICBlbmFibGVDb25zb2xlTG9nZ2luZyxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBzZXRMb2dMZXZlbFxyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZVJlbGVhc2UuanMnO1xyXG5cclxuaW1wb3J0IHNlcnZlciBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiB0aGUgY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHJlc291cmNlIHBvb2wgb2NjdXIgZHVyaW5nIHRoaXNcclxuICogc3RhZ2UuXHJcbiAqXHJcbiAqIFRoaXMgZnVuY3Rpb24gbXVzdCBiZSBjYWxsZWQgYmVmb3JlIGF0dGVtcHRpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXRcclxuICogdXAgYSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBhc3luY1xyXG4gKiBAZnVuY3Rpb24gaW5pdEV4cG9ydFxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gW2luaXRPcHRpb25zPXt9XSAtIFRoZSBgaW5pdE9wdGlvbnNgIG9iamVjdCwgd2hpY2ggbWF5XHJcbiAqIGJlIGEgcGFydGlhbCBvciBjb21wbGV0ZSBzZXQgb2Ygb3B0aW9ucy4gSWYgdGhlIG9wdGlvbnMgYXJlIHBhcnRpYWwsIG1pc3NpbmdcclxuICogdmFsdWVzIHdpbGwgZGVmYXVsdCB0byB0aGUgY3VycmVudCBnbG9iYWwgY29uZmlndXJhdGlvbi4gVGhlIGRlZmF1bHQgdmFsdWVcclxuICogaXMgYW4gZW1wdHkgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXRFeHBvcnQoaW5pdE9wdGlvbnMgPSB7fSkge1xyXG4gIC8vIEluaXQsIHZhbGlkYXRlIGFuZCB1cGRhdGUgdGhlIG9wdGlvbnMgb2JqZWN0XHJcbiAgY29uc3Qgb3B0aW9ucyA9IHVwZGF0ZU9wdGlvbnMoaW5pdE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdGhlIGBhbGxvd0NvZGVFeGVjdXRpb25gIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjYWNoZVxyXG4gIGF3YWl0IGNoZWNrQ2FjaGUob3B0aW9ucy5oaWdoY2hhcnRzLCBvcHRpb25zLnNlcnZlci5wcm94eSk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbChvcHRpb25zLnBvb2wsIG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MpO1xyXG59XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJyxcclxuICogYW5kICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKlxyXG4gKiBAZnVuY3Rpb24gX2F0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzXHJcbiAqL1xyXG5mdW5jdGlvbiBfYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKSB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBbcHJvY2Vzc10gVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xyXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFtwcm9jZXNzXSBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcclxuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3Byb2Nlc3NdIFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgLi4uc2VydmVyLFxyXG5cclxuICAvLyBPcHRpb25zXHJcbiAgZ2V0T3B0aW9ucyxcclxuICB1cGRhdGVPcHRpb25zLFxyXG4gIG1hcFRvTmV3T3B0aW9ucyxcclxuXHJcbiAgLy8gVmFsaWRhdGlvblxyXG4gIHZhbGlkYXRlT3B0aW9uLFxyXG4gIHZhbGlkYXRlT3B0aW9ucyxcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFJlbGVhc2VcclxuICBraWxsUG9vbCxcclxuICBzaHV0ZG93bkNsZWFuVXAsXHJcblxyXG4gIC8vIExvZ3NcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIGxvZ1pvZElzc3VlcyxcclxuICBzZXRMb2dMZXZlbDogZnVuY3Rpb24gKGxldmVsKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICBsZXZlbFxyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgc2V0TG9nTGV2ZWwob3B0aW9ucy5sb2dnaW5nLmxldmVsKTtcclxuICB9LFxyXG4gIGVuYWJsZUNvbnNvbGVMb2dnaW5nOiBmdW5jdGlvbiAodG9Db25zb2xlKSB7XHJcbiAgICAvLyBVcGRhdGUgdGhlIGluc3RhbmNlIG9wdGlvbnMgb2JqZWN0XHJcbiAgICBjb25zdCBvcHRpb25zID0gdXBkYXRlT3B0aW9ucyh7XHJcbiAgICAgIGxvZ2dpbmc6IHtcclxuICAgICAgICB0b0NvbnNvbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUNvbnNvbGVMb2dnaW5nKG9wdGlvbnMubG9nZ2luZy50b0NvbnNvbGUpO1xyXG4gIH0sXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmc6IGZ1bmN0aW9uIChkZXN0LCBmaWxlLCB0b0ZpbGUpIHtcclxuICAgIC8vIFVwZGF0ZSB0aGUgaW5zdGFuY2Ugb3B0aW9ucyBvYmplY3RcclxuICAgIGNvbnN0IG9wdGlvbnMgPSB1cGRhdGVPcHRpb25zKHtcclxuICAgICAgbG9nZ2luZzoge1xyXG4gICAgICAgIGRlc3QsXHJcbiAgICAgICAgZmlsZSxcclxuICAgICAgICB0b0ZpbGVcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgZnVuY3Rpb25cclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBvcHRpb25zLmxvZ2dpbmcuZGVzdCxcclxuICAgICAgb3B0aW9ucy5sb2dnaW5nLmZpbGUsXHJcbiAgICAgIG9wdGlvbnMubG9nZ2luZy50b0ZpbGVcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG4iXSwibmFtZXMiOlsiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZGVlcENvcHkiLCJvYmpBcnIiLCJvYmpBcnJDb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwiT2JqZWN0IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwiZ2V0QWJzb2x1dGVQYXRoIiwicGF0aCIsImlzQWJzb2x1dGUiLCJub3JtYWxpemUiLCJyZXNvbHZlIiwiZ2V0QmFzZTY0IiwiaW5wdXQiLCJ0eXBlIiwiQnVmZmVyIiwiZnJvbSIsInRvU3RyaW5nIiwiZ2V0TmV3RGF0ZSIsIkRhdGUiLCJzcGxpdCIsInRyaW0iLCJnZXROZXdEYXRlVGltZSIsImdldFRpbWUiLCJpc09iamVjdCIsIml0ZW0iLCJpc09iamVjdEVtcHR5Iiwia2V5cyIsImxlbmd0aCIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJzb21lIiwicGF0dGVybiIsInRlc3QiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwicHJvY2VzcyIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsInJvdW5kTnVtYmVyIiwidmFsdWUiLCJwcmVjaXNpb24iLCJtdWx0aXBsaWVyIiwiTWF0aCIsInBvdyIsInJvdW5kIiwiY29sb3JzIiwibG9nZ2luZyIsInRvQ29uc29sZSIsInRvRmlsZSIsInBhdGhDcmVhdGVkIiwicGF0aFRvTG9nIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsb2ciLCJhcmdzIiwibmV3TGV2ZWwiLCJ0ZXh0cyIsImxldmVsIiwicHJlZml4IiwiX2xvZ1RvRmlsZSIsImNvbnNvbGUiLCJhcHBseSIsInVuZGVmaW5lZCIsImNvbmNhdCIsImxvZ1dpdGhTdGFjayIsImVycm9yIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwibWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwicHVzaCIsInNoaWZ0IiwibG9nWm9kSXNzdWVzIiwiaXNzdWVzIiwibWFwIiwiaXNzdWUiLCJqb2luIiwiaW5pdExvZ2dpbmciLCJsb2dnaW5nT3B0aW9ucyIsImRlc3QiLCJmaWxlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVDb25zb2xlTG9nZ2luZyIsImVuYWJsZUZpbGVMb2dnaW5nIiwiaXNJbnRlZ2VyIiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwidHlwZXMiLCJlbnZMaW5rIiwiY2xpTmFtZSIsImRlc2NyaXB0aW9uIiwicHJvbXB0T3B0aW9ucyIsInNlcGFyYXRvciIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiY2RuVXJsIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImNvcmVTY3JpcHRzIiwiaW5zdHJ1Y3Rpb25zIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwic3ZnIiwiYmF0Y2giLCJvdXRmaWxlIiwiaGludCIsImNob2ljZXMiLCJjb25zdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJtaW4iLCJtYXgiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJ1cGxvYWRMaW1pdCIsImJlbmNobWFya2luZyIsInByb3h5IiwidGltZW91dCIsInJhdGVMaW1pdGluZyIsIm1heFJlcXVlc3RzIiwid2luZG93IiwiZGVsYXkiLCJ0cnVzdFByb3h5Iiwic2tpcEtleSIsInNraXBUb2tlbiIsInNzbCIsImZvcmNlIiwiY2VydFBhdGgiLCJwb29sIiwibWluV29ya2VycyIsIm1heFdvcmtlcnMiLCJ3b3JrTGltaXQiLCJhY3F1aXJlVGltZW91dCIsImNyZWF0ZVRpbWVvdXQiLCJkZXN0cm95VGltZW91dCIsImlkbGVUaW1lb3V0IiwiY3JlYXRlUmV0cnlJbnRlcnZhbCIsInJlYXBlckludGVydmFsIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJ2YWxpZGF0aW9uIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsImRvdGVudiIsImNvbmZpZyIsInoiLCJzZXRFcnJvck1hcCIsIl9jdXN0b21FcnJvck1hcCIsInYiLCJib29sZWFuIiwic3RyaWN0Q2hlY2siLCJ1bmlvbiIsImVudW0iLCJ0cmFuc2Zvcm0iLCJpbmNsdWRlcyIsIm51bGxhYmxlIiwic3RyaW5nIiwicmVmaW5lIiwicGFyYW1zIiwiZXJyb3JNZXNzYWdlIiwidmFsdWVzIiwic3RyaW5nQXJyYXkiLCJmaWx0ZXJDYWxsYmFjayIsImFycmF5U2NoZW1hIiwiYXJyYXkiLCJzdHJpbmdTY2hlbWEiLCJzdGFydHNXaXRoIiwic2xpY2UiLCJlbmRzV2l0aCIsInRyYW5zZm9ybUNhbGxiYWNrIiwiZmlsdGVyIiwicG9zaXRpdmVOdW0iLCJudW1iZXIiLCJwb3NpdGl2ZSIsImlzTmFOIiwibm9uTmVnYXRpdmVOdW0iLCJub25uZWdhdGl2ZSIsInByZWZpeGVzIiwiY2hhcnRDb25maWciLCJvYmplY3QiLCJwYXNzdGhyb3VnaCIsImFkZGl0aW9uYWxPcHRpb25zIiwidmFsaWRhdG9ycyIsImFkbWluVG9rZW4iLCJpbmRleE9mIiwiZ3RlIiwibHRlIiwidGhpcyIsIm9iamVjdFNjaGVtYSIsImpzIiwiY3NzIiwiZmlsZXMiLCJwYXJ0aWFsIiwic3RyaW5nU2NoZW1hMSIsInN0cmluZ1NjaGVtYTIiLCJlbmFibGVTZXJ2ZXIiLCJzZXJ2ZXJCZW5jaG1hcmtpbmciLCJwcm94eUhvc3QiLCJwcm94eVBvcnQiLCJwcm94eVRpbWVvdXQiLCJlbmFibGVSYXRlTGltaXRpbmciLCJlbmFibGVTc2wiLCJzc2xGb3JjZSIsInNzbFBvcnQiLCJzc2xDZXJ0UGF0aCIsInBvb2xCZW5jaG1hcmtpbmciLCJyZXNvdXJjZXNJbnRlcnZhbCIsImxvZ0xldmVsIiwiaW50IiwibG9nRmlsZSIsImxvZ0Rlc3QiLCJsb2dUb0NvbnNvbGUiLCJsb2dUb0ZpbGUiLCJlbmFibGVVaSIsInVpUm91dGUiLCJlbmFibGVEZWJ1ZyIsInJlcXVlc3RJZCIsInV1aWQiLCJQdXBwZXRlZXJTY2hlbWEiLCJIaWdoY2hhcnRzU2NoZW1hIiwiRXhwb3J0U2NoZW1hIiwiQ3VzdG9tTG9naWNTY2hlbWEiLCJQcm94eVNjaGVtYSIsIlJhdGVMaW1pdGluZ1NjaGVtYSIsIlNzbFNjaGVtYSIsIlNlcnZlclNjaGVtYSIsIm9wdGlvbmFsIiwiUG9vbFNjaGVtYSIsIkxvZ2dpbmdTY2hlbWEiLCJVaVNjaGVtYSIsIk90aGVyU2NoZW1hIiwiRGVidWdTY2hlbWEiLCJTdHJpY3RDb25maWdTY2hlbWEiLCJMb29zZUNvbmZpZ1NjaGVtYSIsIkVudlNjaGVtYSIsIlBVUFBFVEVFUl9BUkdTIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwiSElHSENIQVJUU19GT1JDRV9GRVRDSCIsIkhJR0hDSEFSVFNfQ0FDSEVfUEFUSCIsIkhJR0hDSEFSVFNfQURNSU5fVE9LRU4iLCJISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMiLCJISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTIiwiSElHSENIQVJUU19DVVNUT01fU0NSSVBUUyIsIkVYUE9SVF9JTkZJTEUiLCJFWFBPUlRfSU5TVFIiLCJFWFBPUlRfT1BUSU9OUyIsIkVYUE9SVF9TVkciLCJFWFBPUlRfQkFUQ0giLCJFWFBPUlRfT1VURklMRSIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9CNjQiLCJFWFBPUlRfTk9fRE9XTkxPQUQiLCJFWFBPUlRfSEVJR0hUIiwiRVhQT1JUX1dJRFRIIiwiRVhQT1JUX1NDQUxFIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9HTE9CQUxfT1BUSU9OUyIsIkVYUE9SVF9USEVNRV9PUFRJT05TIiwiRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCIsIkNVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTiIsIkNVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUyIsIkNVU1RPTV9MT0dJQ19DVVNUT01fQ09ERSIsIkNVU1RPTV9MT0dJQ19DQUxMQkFDSyIsIkNVU1RPTV9MT0dJQ19SRVNPVVJDRVMiLCJDVVNUT01fTE9HSUNfTE9BRF9DT05GSUciLCJDVVNUT01fTE9HSUNfQ1JFQVRFX0NPTkZJRyIsIlNFUlZFUl9FTkFCTEUiLCJTRVJWRVJfSE9TVCIsIlNFUlZFUl9QT1JUIiwiU0VSVkVSX1VQTE9BRF9MSU1JVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX1ZBTElEQVRJT04iLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJlbnZzIiwicGFyc2UiLCJlbnYiLCJzdHJpY3RWYWxpZGF0ZSIsImNvbmZpZ09wdGlvbnMiLCJsb29zZVZhbGlkYXRlIiwiY29udGV4dCIsInByb3BlcnR5TmFtZSIsInByb3BlcnR5SW5mbyIsImNvZGUiLCJab2RJc3N1ZUNvZGUiLCJpbnZhbGlkX3R5cGUiLCJyZWNlaXZlZCIsIlpvZFBhcnNlZFR5cGUiLCJkZWZhdWx0RXJyb3IiLCJjdXN0b20iLCJkYXRhIiwiaW52YWxpZF91bmlvbiIsInVuaW9uRXJyb3JzIiwiZm9yRWFjaCIsImluZGV4Iiwic3Vic3RyaW5nIiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3RhdHVzQ29kZSIsInN1cGVyIiwic2V0RXJyb3IiLCJuYW1lIiwiX2luaXRPcHRpb25zIiwibmVzdGVkUHJvcHMiLCJfY3JlYXRlTmVzdGVkUHJvcHMiLCJhYnNvbHV0ZVByb3BzIiwiX2NyZWF0ZUFic29sdXRlUHJvcHMiLCJnZXRPcHRpb25zIiwiZ2V0Q29weSIsInVwZGF0ZU9wdGlvbnMiLCJuZXdPcHRpb25zIiwiX21lcmdlT3B0aW9ucyIsInZhbGlkYXRlT3B0aW9ucyIsIm1hcFRvTmV3T3B0aW9ucyIsIm9sZE9wdGlvbnMiLCJlbnRyaWVzIiwicHJvcGVydGllc0NoYWluIiwicmVkdWNlIiwib2JqIiwicHJvcCIsInZhbGlkYXRlT3B0aW9uIiwiY29uZmlnT3B0aW9uIiwiaXNBbGxvd2VkQ29uZmlnIiwiYWxsb3dGdW5jdGlvbnMiLCJvYmplY3RDb25maWciLCJldmFsIiwiSlNPTiIsInN0cmluZ2lmaWVkT3B0aW9ucyIsIl9vcHRpb25zU3RyaW5naWZ5IiwicGFyc2VkT3B0aW9ucyIsIl8iLCJvcmlnaW5hbE9wdGlvbnMiLCJzdHJpbmdpZnlGdW5jdGlvbnMiLCJzdHJpbmdpZnkiLCJyZXBsYWNlQWxsIiwicHJvcENoYWluIiwiZW50cnkiLCJhc3luYyIsImdldCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlamVjdCIsIl9nZXRQcm90b2NvbE1vZHVsZSIsInJlc3BvbnNlIiwicmVzcG9uc2VEYXRhIiwib24iLCJjaHVuayIsInRleHQiLCJodHRwcyIsImh0dHAiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImNoZWNrQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInNlcnZlclByb3h5T3B0aW9ucyIsImZldGNoZWRNb2R1bGVzIiwiZ2V0Q2FjaGVQYXRoIiwibWFuaWZlc3RQYXRoIiwic291cmNlUGF0aCIsInJlY3Vyc2l2ZSIsIl91cGRhdGVDYWNoZSIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsInJlYWRGaWxlU3luYyIsIm1vZHVsZXMiLCJtb2R1bGVNYXAiLCJtIiwibnVtYmVyT2ZNb2R1bGVzIiwibW9kdWxlTmFtZSIsIl9leHRyYWN0SGNWZXJzaW9uIiwiX3NhdmVDb25maWdUb01hbmlmZXN0IiwiZ2V0SGNWZXJzaW9uIiwidXBkYXRlSGNWZXJzaW9uIiwibmV3VmVyc2lvbiIsIndyaXRlRmlsZVN5bmMiLCJfY29uZmlndXJlUmVxdWVzdCIsImFsbCIsImNzIiwiX2ZldGNoU2NyaXB0IiwibXMiLCJpcyIsInNjcmlwdCIsInNob3VsZFRocm93RXJyb3IiLCJfZXh0cmFjdE1vZHVsZU5hbWUiLCJhZ2VudCIsIkh0dHBzUHJveHlBZ2VudCIsImNhY2hlU291cmNlcyIsInJlcGxhY2UiLCJzY3JpcHRQYXRoIiwic2V0dXBIaWdoY2hhcnRzIiwiSGlnaGNoYXJ0cyIsImFuaW1PYmplY3QiLCJkdXJhdGlvbiIsImNyZWF0ZUNoYXJ0IiwiZXhwb3J0T3B0aW9ucyIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsInNldE9wdGlvbnMiLCJtZXJnZSIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJhbmltYXRpb24iLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImNoYXJ0IiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiaW1hZ2VzIiwicXVlcnlTZWxlY3RvckFsbCIsInJhY2UiLCJpbWFnZSIsImNvbXBsZXRlIiwibmF0dXJhbEhlaWdodCIsImFkZEV2ZW50TGlzdGVuZXIiLCJvbmNlIiwic2V0VGltZW91dCIsImRlZmF1bHRPcHRpb25zIiwicGFnZVRlbXBsYXRlIiwiYnJvd3NlciIsImNyZWF0ZUJyb3dzZXIiLCJwdXBwZXRlZXJBcmdzIiwiZW5hYmxlZERlYnVnIiwiZGVidWdPcHRpb25zIiwibGF1bmNoT3B0aW9ucyIsInVzZXJEYXRhRGlyIiwiaGFuZGxlU0lHSU5UIiwiaGFuZGxlU0lHVEVSTSIsImhhbmRsZVNJR0hVUCIsIndhaXRGb3JJbml0aWFsUGFnZSIsImRlZmF1bHRWaWV3cG9ydCIsInRyeUNvdW50Iiwib3BlbkJyb3dzZXIiLCJsYXVuY2giLCJjbG9zZUJyb3dzZXIiLCJjb25uZWN0ZWQiLCJjbG9zZSIsIm5ld1BhZ2UiLCJwb29sUmVzb3VyY2UiLCJwYWdlIiwic2V0Q2FjaGVFbmFibGVkIiwiX3NldFBhZ2VDb250ZW50IiwiX3NldFBhZ2VFdmVudHMiLCJpc0Nsb3NlZCIsImNsZWFyUGFnZSIsImhhcmRSZXNldCIsImdvdG8iLCJ3YWl0VW50aWwiLCJldmFsdWF0ZSIsImJvZHkiLCJpbm5lckhUTUwiLCJpZCIsIndvcmtDb3VudCIsImFkZFBhZ2VSZXNvdXJjZXMiLCJpbmplY3RlZFJlc291cmNlcyIsImluamVjdGVkSnMiLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJhZGRTY3JpcHRUYWciLCJpbmplY3RlZENzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJlbGVtZW50IiwicmVtb3ZlIiwic2V0Q29udGVudCIsImNzc1RlbXBsYXRlIiwic3ZnVGVtcGxhdGUiLCJwdXBwZXRlZXJFeHBvcnQiLCJpc1NWRyIsInNpemUiLCJfZ2V0Q2hhcnRTaXplIiwieCIsInkiLCJfZ2V0Q2xpcFJlZ2lvbiIsInZpZXdwb3J0SGVpZ2h0IiwiYWJzIiwiY2VpbCIsImNoYXJ0SGVpZ2h0Iiwidmlld3BvcnRXaWR0aCIsImNoYXJ0V2lkdGgiLCJyZXN1bHQiLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwicGFyc2VGbG9hdCIsIl9jcmVhdGVTVkciLCJfY3JlYXRlSW1hZ2UiLCJfY3JlYXRlUERGIiwiJGV2YWwiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiYmFzZVZhbCIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsIm91dGVySFRNTCIsImNsaXAiLCJzY3JlZW5zaG90IiwiZW5jb2RpbmciLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJwb29sU3RhdHMiLCJleHBvcnRzQXR0ZW1wdGVkIiwiZXhwb3J0c1BlcmZvcm1lZCIsImV4cG9ydHNEcm9wcGVkIiwiZXhwb3J0c0Zyb21TdmciLCJleHBvcnRzRnJvbU9wdGlvbnMiLCJleHBvcnRzRnJvbVN2Z0F0dGVtcHRzIiwiZXhwb3J0c0Zyb21PcHRpb25zQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJ0aW1lU3BlbnRBdmVyYWdlIiwiaW5pdFBvb2wiLCJwb29sT3B0aW9ucyIsIlBvb2wiLCJfZmFjdG9yeSIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJjbGVhclN0YXR1cyIsIl9ldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImkiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsIl9nZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwiZXhwb3J0Q291bnRlciIsImV4cG9ydFJlc3VsdCIsImdldFBvb2xTdGF0cyIsImdldFBvb2xJbmZvSlNPTiIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJudW1GcmVlIiwiYWxsQ3JlYXRlZCIsInBlbmRpbmdBY3F1aXJlcyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBlbmRpbmdDcmVhdGVzIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsImNyZWF0ZSIsInJhbmRvbSIsInN0YXJ0RGF0ZSIsInZhbGlkYXRlIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJzYW5pdGl6ZSIsIkpTRE9NIiwiRE9NUHVyaWZ5IiwiQUREX1RBR1MiLCJzaW5nbGVFeHBvcnQiLCJzdGFydEV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiYmF0Y2hSZXN1bHRzIiwiYWxsU2V0dGxlZCIsInJlYXNvbiIsImltYWdlT3B0aW9ucyIsImVuZENhbGxiYWNrIiwiZmlsZUNvbnRlbnQiLCJfZXhwb3J0RnJvbVN2ZyIsIl9leHBvcnRGcm9tT3B0aW9ucyIsImdldEFsbG93Q29kZUV4ZWN1dGlvbiIsInNldEFsbG93Q29kZUV4ZWN1dGlvbiIsImlucHV0VG9FeHBvcnQiLCJfcHJlcGFyZUV4cG9ydCIsIl9maXhDb25zdHIiLCJfZml4VHlwZSIsIl9maXhPdXRmaWxlIiwiX2hhbmRsZUN1c3RvbUxvZ2ljIiwiX2hhbmRsZUdsb2JhbEFuZFRoZW1lIiwiX2hhbmRsZVNpemUiLCJfY2hlY2tEYXRhU2l6ZSIsImZpeGVkQ29uc3RyIiwidG9Mb3dlckNhc2UiLCJtaW1lVHlwZXMiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0Iiwib3B0aW9uc0NoYXJ0Iiwib3B0aW9uc0V4cG9ydGluZyIsImdsb2JhbE9wdGlvbnNDaGFydCIsImdsb2JhbE9wdGlvbnNFeHBvcnRpbmciLCJ0aGVtZU9wdGlvbnNDaGFydCIsInRoZW1lT3B0aW9uc0V4cG9ydGluZyIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJfaGFuZGxlUmVzb3VyY2VzIiwiX2hhbmRsZUN1c3RvbUNvZGUiLCJoYW5kbGVkUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiY29ycmVjdFJlc291cmNlcyIsInByb3BOYW1lIiwiaXNDYWxsYmFjayIsIm9wdGlvbnNOYW1lIiwidG90YWxTaXplIiwiYnl0ZUxlbmd0aCIsInRvRml4ZWQiLCJ0aW1lcklkcyIsImFkZFRpbWVyIiwiY2xlYXJBbGxUaW1lcnMiLCJjbGVhckludGVydmFsIiwiY2xlYXJUaW1lb3V0IiwibG9nRXJyb3JNaWRkbGV3YXJlIiwicmVxdWVzdCIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdGF0dXMiLCJqc29uIiwiZXJyb3JNaWRkbGV3YXJlIiwiYXBwIiwidXNlIiwicmF0ZUxpbWl0aW5nTWlkZGxld2FyZSIsInJhdGVMaW1pdGluZ09wdGlvbnMiLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJyYXRlTGltaXQiLCJ3aW5kb3dNcyIsImxpbWl0IiwiZGVsYXlNcyIsImhhbmRsZXIiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsImNvbnRlbnRUeXBlTWlkZGxld2FyZSIsImNvbnRlbnRUeXBlIiwiaGVhZGVycyIsInJlcXVlc3RCb2R5TWlkZGxld2FyZSIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwidmFsaWRhdGVkT3B0aW9ucyIsImZpbGVuYW1lIiwidmFsaWRhdGlvbk1pZGRsZXdhcmUiLCJwb3N0IiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RFeHBvcnQiLCJyZXF1ZXN0Q291bnRlciIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImV4cG9ydFJvdXRlcyIsInNlcnZlclN0YXJ0VGltZSIsInBhY2thZ2VGaWxlIiwic3VjY2Vzc1JhdGVzIiwicmVjb3JkSW50ZXJ2YWwiLCJ3aW5kb3dTaXplIiwiX2NhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UiLCJhIiwiYiIsIl9zdGFydFN1Y2Nlc3NSYXRlIiwic2V0SW50ZXJ2YWwiLCJzdGF0cyIsInN1Y2Nlc3NSYXRpbyIsImhlYWx0aFJvdXRlcyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwic2VydmVyVmVyc2lvbiIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZUV4cG9ydFRpbWUiLCJhdHRlbXB0ZWRFeHBvcnRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInN2Z0V4cG9ydHMiLCJqc29uRXhwb3J0cyIsInN2Z0V4cG9ydHNBdHRlbXB0cyIsImpzb25FeHBvcnRzQXR0ZW1wdHMiLCJ1aVJvdXRlcyIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidmVyc2lvbkNoYW5nZVJvdXRlcyIsInRva2VuIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJzdGFydFNlcnZlciIsInNlcnZlck9wdGlvbnMiLCJ1cGxvYWRMaW1pdEJ5dGVzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJkaXNhYmxlIiwiY29ycyIsIm1ldGhvZHMiLCJzZXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwic3RhdGljIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsIl9hdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwibGlzdGVuIiwiY2VydCIsImh0dHBzU2VydmVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiZXhpdCIsImluaXRFeHBvcnQiLCJpbml0T3B0aW9ucyIsIl9hdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyJdLCJtYXBwaW5ncyI6IndsQkEwQk8sTUFBTUEsWUFBWUMsSUFBYUEsY0FBQyxJQUFJQyxJQUFJLE9BQVEsb0JBQUFDLFNBQUFDLFFBQUEsT0FBQUMsY0FBQUMsWUFBQUMsS0FBQUMsd0JBQUEsV0FBQUEsdUJBQUFDLFFBQUFDLGVBQUFGLHVCQUFBRyxLQUFBLElBQUFULElBQUEsWUFBQUMsU0FBQVMsU0FBQUwsT0ErQmhELFNBQVNNLFNBQVNDLEdBRXZCLEdBQWUsT0FBWEEsR0FBcUMsaUJBQVhBLEVBQzVCLE9BQU9BLEVBSVQsTUFBTUMsRUFBYUMsTUFBTUMsUUFBUUgsR0FBVSxHQUFLLEdBR2hELElBQUssTUFBTUksS0FBT0osRUFDWkssT0FBT0MsVUFBVUMsZUFBZUMsS0FBS1IsRUFBUUksS0FDL0NILEVBQVdHLEdBQU9MLFNB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 diff --git a/dist/index.esm.js b/dist/index.esm.js deleted file mode 100644 index 77682997..00000000 --- a/dist/index.esm.js +++ /dev/null @@ -1,2 +0,0 @@ -import"colors";import{existsSync,mkdirSync,appendFile,readFileSync,writeFileSync}from"fs";import{normalize,resolve,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 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 getAbsolutePath(e){return isAbsolute(e)?normalize(e):resolve(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}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:i}=logging;if(5!==t&&(0===t||t>i||i>r.length))return;const n=`${getNewDate()} [${r[t-1].title}] -`;logging.toFile&&_logToFile(o,n),logging.toConsole&&console.log.apply(void 0,[n.toString()[logging.levelsDesc[t-1].color]].concat(o))}function logWithStack(e,t,o){const r=o||t&&t.message||"",{level:i,levelsDesc:n}=logging;if(0===e||e>i||i>n.length)return;const s=`${getNewDate()} [${n[e-1].title}] -`,a=t&&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||"[validation] Validation error"} - the following Zod issues occured:`,...(t||[]).map((e=>`- ${e.message}`))].join("\n"))}function initLogging(e){const{level:t,dest:o,file:r,toConsole:i,toFile:n}=e;logging.pathCreated=!1,logging.pathToLog="",setLogLevel(t),enableConsoleLogging(i),enableFileLogging(o,r,n)}function setLogLevel(e){Number.isInteger(e)&&e>=0&&e<=logging.levelsDesc.length&&(logging.level=e)}function enableConsoleLogging(e){logging.toConsole=!!e}function enableFileLogging(e,t,o){logging.toFile=!!o,logging.toFile&&(logging.dest=e||"log",logging.file=t||"highcharts-export-server.log")}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:["Object","string","null"],envLink:"EXPORT_INSTR",description:"Overrides the `infile` with JSON, stringified JSON, or SVG input",promptOptions:{type:"text"}},options:{value:null,types:["Object","string","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"}},validation:{value:!0,types:["boolean"],envLink:"OTHER_VALIDATION",description:"Whether or not to enable validation of options types",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"}}}};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","1","false","0","undefined","null",""]).transform((e=>["undefined","null",""].includes(e)?null:"true"===e||"1"===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 r=z.string().trim().array(),i=z.string().trim().transform((e=>(e.startsWith("[")&&(e=e.slice(1)),e.endsWith("]")&&(e=e.slice(0,-1)),e.split(t)))),n=t=>t.map((e=>e.trim())).filter(e);return o?r.transform(n):z.union([i,r]).transform(n).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.startsWith("{")&&e.endsWith("}")||["undefined","null",""].includes(e)),{params:{errorMessage:"The value must be a string that starts with '{' and ends with '}'"}}).transform((e=>["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()},validators={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 '}"}}),r=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,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?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),validation: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:validators.args(e)}).partial(),HighchartsSchema=e=>z.object({version:validators.version(e),cdnUrl:validators.cdnUrl(e),forceFetch:validators.forceFetch(e),cachePath:validators.cachePath(e),coreScripts:validators.coreScripts(e),moduleScripts:validators.moduleScripts(e),indicatorScripts:validators.indicatorScripts(e),customScripts:validators.customScripts(e)}).partial(),ExportSchema=e=>z.object({infile:validators.infile(e),instr:validators.instr(),options:validators.options(),svg:validators.svg(),outfile:validators.outfile(e),type:validators.type(e),constr:validators.constr(e),b64:validators.b64(e),noDownload:validators.noDownload(e),defaultHeight:validators.defaultHeight(e),defaultWidth:validators.defaultWidth(e),defaultScale:validators.defaultScale(e),height:validators.height(e),width:validators.width(e),scale:validators.scale(e),globalOptions:validators.globalOptions(),themeOptions:validators.themeOptions(),batch:validators.batch(!1),rasterizationTimeout:validators.rasterizationTimeout(e)}).partial(),CustomLogicSchema=e=>z.object({allowCodeExecution:validators.allowCodeExecution(e),allowFileResources:validators.allowFileResources(e),customCode:validators.customCode(!1),callback:validators.callback(!1),resources:validators.resources(e),loadConfig:validators.loadConfig(!1),createConfig:validators.createConfig(!1)}).partial(),ProxySchema=e=>z.object({host:validators.proxyHost(!1),port:validators.proxyPort(e),timeout:validators.proxyTimeout(e)}).partial(),RateLimitingSchema=e=>z.object({enable:validators.enableRateLimiting(e),maxRequests:validators.maxRequests(e),window:validators.window(e),delay:validators.delay(e),trustProxy:validators.trustProxy(e),skipKey:validators.skipKey(!1),skipToken:validators.skipToken(!1)}).partial(),SslSchema=e=>z.object({enable:validators.enableSsl(e),force:validators.sslForce(e),port:validators.sslPort(e),certPath:validators.sslCertPath(!1)}).partial(),ServerSchema=e=>z.object({enable:validators.enableServer(e).optional(),host:validators.host(e).optional(),port:validators.port(e).optional(),uploadLimit:validators.uploadLimit(e).optional(),benchmarking:validators.serverBenchmarking(e).optional(),proxy:ProxySchema(e).optional(),rateLimiting:RateLimitingSchema(e).optional(),ssl:SslSchema(e).optional()}),PoolSchema=e=>z.object({minWorkers:validators.minWorkers(e),maxWorkers:validators.maxWorkers(e),workLimit:validators.workLimit(e),acquireTimeout:validators.acquireTimeout(e),createTimeout:validators.createTimeout(e),destroyTimeout:validators.destroyTimeout(e),idleTimeout:validators.idleTimeout(e),createRetryInterval:validators.createRetryInterval(e),reaperInterval:validators.reaperInterval(e),benchmarking:validators.poolBenchmarking(e)}).partial(),LoggingSchema=e=>z.object({level:validators.logLevel(e),file:validators.logFile(e),dest:validators.logDest(e),toConsole:validators.logToConsole(e),toFile:validators.logToFile(e)}).partial(),UiSchema=e=>z.object({enable:validators.enableUi(e),route:validators.uiRoute(e)}).partial(),OtherSchema=e=>z.object({nodeEnv:validators.nodeEnv(e),listenToProcessExits:validators.listenToProcessExits(e),noLogo:validators.noLogo(e),hardResetPage:validators.hardResetPage(e),browserShellMode:validators.browserShellMode(e),validation:validators.validation(e)}).partial(),DebugSchema=e=>z.object({enable:validators.enableDebug(e),headless:validators.headless(e),devtools:validators.devtools(e),listenToConsole:validators.listenToConsole(e),dumpio:validators.dumpio(e),slowMo:validators.slowMo(e),debuggingPort:validators.debuggingPort(e)}).partial(),StrictConfigSchema=z.object({requestId:validators.requestId(),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({requestId:validators.requestId(),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:validators.args(!1),HIGHCHARTS_VERSION:validators.version(!1),HIGHCHARTS_CDN_URL:validators.cdnUrl(!1),HIGHCHARTS_FORCE_FETCH:validators.forceFetch(!1),HIGHCHARTS_CACHE_PATH:validators.cachePath(!1),HIGHCHARTS_ADMIN_TOKEN:validators.adminToken(!1),HIGHCHARTS_CORE_SCRIPTS:validators.coreScripts(!1),HIGHCHARTS_MODULE_SCRIPTS:validators.moduleScripts(!1),HIGHCHARTS_INDICATOR_SCRIPTS:validators.indicatorScripts(!1),HIGHCHARTS_CUSTOM_SCRIPTS:validators.customScripts(!1),EXPORT_INFILE:validators.infile(!1),EXPORT_INSTR:validators.instr(),EXPORT_OPTIONS:validators.options(),EXPORT_SVG:validators.svg(),EXPORT_BATCH:validators.batch(!1),EXPORT_OUTFILE:validators.outfile(!1),EXPORT_TYPE:validators.type(!1),EXPORT_CONSTR:validators.constr(!1),EXPORT_B64:validators.b64(!1),EXPORT_NO_DOWNLOAD:validators.noDownload(!1),EXPORT_HEIGHT:validators.height(!1),EXPORT_WIDTH:validators.width(!1),EXPORT_SCALE:validators.scale(!1),EXPORT_DEFAULT_HEIGHT:validators.defaultHeight(!1),EXPORT_DEFAULT_WIDTH:validators.defaultWidth(!1),EXPORT_DEFAULT_SCALE:validators.defaultScale(!1),EXPORT_GLOBAL_OPTIONS:validators.globalOptions(),EXPORT_THEME_OPTIONS:validators.themeOptions(),EXPORT_RASTERIZATION_TIMEOUT:validators.rasterizationTimeout(!1),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:validators.allowCodeExecution(!1),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:validators.allowFileResources(!1),CUSTOM_LOGIC_CUSTOM_CODE:validators.customCode(!1),CUSTOM_LOGIC_CALLBACK:validators.callback(!1),CUSTOM_LOGIC_RESOURCES:validators.resources(!1),CUSTOM_LOGIC_LOAD_CONFIG:validators.loadConfig(!1),CUSTOM_LOGIC_CREATE_CONFIG:validators.createConfig(!1),SERVER_ENABLE:validators.enableServer(!1),SERVER_HOST:validators.host(!1),SERVER_PORT:validators.port(!1),SERVER_UPLOAD_LIMIT:validators.uploadLimit(!1),SERVER_BENCHMARKING:validators.serverBenchmarking(!1),SERVER_PROXY_HOST:validators.proxyHost(!1),SERVER_PROXY_PORT:validators.proxyPort(!1),SERVER_PROXY_TIMEOUT:validators.proxyTimeout(!1),SERVER_RATE_LIMITING_ENABLE:validators.enableRateLimiting(!1),SERVER_RATE_LIMITING_MAX_REQUESTS:validators.maxRequests(!1),SERVER_RATE_LIMITING_WINDOW:validators.window(!1),SERVER_RATE_LIMITING_DELAY:validators.delay(!1),SERVER_RATE_LIMITING_TRUST_PROXY:validators.trustProxy(!1),SERVER_RATE_LIMITING_SKIP_KEY:validators.skipKey(!1),SERVER_RATE_LIMITING_SKIP_TOKEN:validators.skipToken(!1),SERVER_SSL_ENABLE:validators.enableSsl(!1),SERVER_SSL_FORCE:validators.sslForce(!1),SERVER_SSL_PORT:validators.sslPort(!1),SERVER_SSL_CERT_PATH:validators.sslCertPath(!1),POOL_MIN_WORKERS:validators.minWorkers(!1),POOL_MAX_WORKERS:validators.maxWorkers(!1),POOL_WORK_LIMIT:validators.workLimit(!1),POOL_ACQUIRE_TIMEOUT:validators.acquireTimeout(!1),POOL_CREATE_TIMEOUT:validators.createTimeout(!1),POOL_DESTROY_TIMEOUT:validators.destroyTimeout(!1),POOL_IDLE_TIMEOUT:validators.idleTimeout(!1),POOL_CREATE_RETRY_INTERVAL:validators.createRetryInterval(!1),POOL_REAPER_INTERVAL:validators.reaperInterval(!1),POOL_BENCHMARKING:validators.poolBenchmarking(!1),LOGGING_LEVEL:validators.logLevel(!1),LOGGING_FILE:validators.logFile(!1),LOGGING_DEST:validators.logDest(!1),LOGGING_TO_CONSOLE:validators.logToConsole(!1),LOGGING_TO_FILE:validators.logToFile(!1),UI_ENABLE:validators.enableUi(!1),UI_ROUTE:validators.uiRoute(!1),OTHER_NODE_ENV:validators.nodeEnv(!1),OTHER_LISTEN_TO_PROCESS_EXITS:validators.listenToProcessExits(!1),OTHER_NO_LOGO:validators.noLogo(!1),OTHER_HARD_RESET_PAGE:validators.hardResetPage(!1),OTHER_BROWSER_SHELL_MODE:validators.browserShellMode(!1),OTHER_VALIDATION:validators.validation(!1),DEBUG_ENABLE:validators.enableDebug(!1),DEBUG_HEADLESS:validators.headless(!1),DEBUG_DEVTOOLS:validators.devtools(!1),DEBUG_LISTEN_TO_CONSOLE:validators.listenToConsole(!1),DEBUG_DUMPIO:validators.dumpio(!1),DEBUG_SLOW_MO:validators.slowMo(!1),DEBUG_DEBUGGING_PORT:validators.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 _customErrorMap(e,t){const o=e.path.join("."),r=`Invalid value for the ${o}`;if(e.code===z.ZodIssueCode.invalid_type)return e.received===z.ZodParsedType.undefined?{message:`${r} - No value was provided.`}:{message:`${r} - Invalid type. ${t.defaultError}.`};if(e.code===z.ZodIssueCode.custom&&e.params?.errorMessage)return{message:`${r} - ${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:`${r} - ${t.defaultError}.`}}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 globalOptions=_initOptions(defaultConfig),nestedProps=_createNestedProps(defaultConfig),absoluteProps=_createAbsoluteProps(defaultConfig);function getOptions(e=!0){return e?deepCopy(globalOptions):globalOptions}function updateOptions(e,t=!1,o=!0){return _mergeOptions(getOptions(t),validateOptions(e,o))}function mapToNewOptions(e){const t={};if(isObject(e))for(const[o,r]of Object.entries(e)){const e=nestedProps[o]?nestedProps[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}else log(2,"[config] No correct object with options was provided. Returning an empty object.");return t}function validateOption(e,t,o=!0){if(!getOptions().other.validation)return t;try{return validators[e](o).parse(t)}catch(t){throw logZodIssues(1,t.issues,`[validation] The ${e} option validation error`),new ExportError(`[validation] The ${e} option validation error`,400)}}function validateOptions(e,t=!0){if(!getOptions().other.validation)return e;try{return t?strictValidate(e):looseValidate(e)}catch(e){throw logZodIssues(1,e.issues,"[validation] Options validation error"),new ExportError("[validation] Options validation error",400)}}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 _initOptions(e){const t={};for(const[o,r]of Object.entries(e))Object.prototype.hasOwnProperty.call(r,"value")?void 0!==envs[r.envLink]&&null!==envs[r.envLink]?t[o]=envs[r.envLink]:t[o]=r.value:t[o]=_initOptions(r);return t}function _mergeOptions(e,t){if(isObject(e)&&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]||null;return e}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 _createNestedProps(e,t={},o=""){return Object.keys(e).forEach((r=>{const i=e[r];void 0===i.value?_createNestedProps(i,t,`${o}.${r}`):(t[i.cliName||r]=`${o}.${r}`.substring(1),void 0!==i.legacyName&&(t[i.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}async function get$1(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}const cache={cdnUrl:"https://code.highcharts.com",activeManifest:{},sources:"",hcVersion:""};async function checkCache(e,t){try{let o;const r=getCachePath(),i=join(r,"manifest.json"),n=join(r,"sources.js");if(!existsSync(r)&&mkdirSync(r,{recursive:!0}),!existsSync(i)||e.forceFetch)log(3,"[cache] Fetching and caching Highcharts dependencies."),o=await _updateCache(e,t,n);else{let r=!1;const s=JSON.parse(readFileSync(i),"utf8");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,n):(log(3,"[cache] Dependency cache is up to date, proceeding."),cache.sources=readFileSync(n,"utf8"),o=s.modules,cache.hcVersion=_extractHcVersion(cache.sources))}await _saveConfigToManifest(e.version,o)}catch(e){throw new ExportError("[cache] Could not configure cache and create or update the config manifest.",500).setError(e)}}function getHcVersion(){return cache.hcVersion}async function updateHcVersion(e){const t=updateOptions({highcharts:{version:e}});await checkCache(t.highcharts,t.server.proxy)}function getCachePath(){return getAbsolutePath(getOptions().highcharts.cachePath)}async function _saveConfigToManifest(e,t={}){cache.activeManifest={version:e,modules:t},log(3,"[cache] Writing a new manifest.");try{writeFileSync(join(getCachePath(),"manifest.json"),JSON.stringify(cache.activeManifest),"utf8")}catch(e){throw new ExportError("[cache] Error writing the cache manifest.",500).setError(e)}}async function _updateCache(e,t,o){try{const r="latest"===e.version?null:`${e.version}`;log(3,`[cache] Updating cache version to Highcharts: ${r||"latest"}.`);const i=e.cdnUrl||cache.cdnUrl,n=_configureRequest(t),s={};return cache.sources=(await Promise.all([...e.coreScripts.map((e=>_fetchScript(r?`${i}/${r}/${e}`:`${i}/${e}`,n,s,!0))),...e.moduleScripts.map((e=>_fetchScript("map"===e?r?`${i}/maps/${r}/modules/${e}`:`${i}/maps/modules/${e}`:r?`${i}/${r}/modules/${e}`:`${i}/modules/${e}`,n,s))),...e.indicatorScripts.map((e=>_fetchScript(r?`${i}/stock/${r}/indicators/${e}`:`${i}/stock/indicators/${e}`,n,s))),...e.customScripts.map((e=>_fetchScript(`${e}`,n)))])).join(";\n"),cache.hcVersion=_extractHcVersion(cache.sources),writeFileSync(o,cache.sources),s}catch(e){throw new ExportError("[cache] Unable to update the local Highcharts cache.",500).setError(e)}}async function _fetchScript(e,t,o,r=!1){e.endsWith(".js")&&(e=e.substring(0,e.length-3)),log(4,`[cache] Fetching script - ${e}.js`);const i=await get$1(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[_extractModuleName(e)]=1}return i.text}if(r)throw new ExportError(`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,404).setError(i);log(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`)}function _configureRequest(e){const t=e.host,o=e.port;if(t&&o)try{return{agent:new HttpsProxyAgent({host:t,port:o}),timeout:e.timeout}}catch(e){throw new ExportError("[cache] Could not create a Proxy Agent.",500).setError(e)}return{}}function _extractHcVersion(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 setupHighcharts(){Highcharts.animObject=function(){return{duration:0}}}async function createChart(e,t){const{getOptions:o,setOptions:r,merge:i,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),window.isRenderComplete=!1,n(Highcharts.Chart.prototype,"init",(function(e,t,o){((t=i(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,o])})),n(Highcharts.Series.prototype,"init",(function(e,t,o){e.apply(this,[t,o])}));const s={chart:{animation:!1,height:e.height,width:e.width},exporting:{enabled:!1}},a=new Function(`return ${e.instr}`)(),l=new Function(`return ${e.themeOptions}`)(),c=i(!1,l,a,s),p=t.callback?new Function(`return ${t.callback}`)():null;t.customCode&&new Function("options",t.customCode)(a);const u=new Function(`return ${e.globalOptions}`)();u&&r(u),Highcharts[e.constr]("container",c,p);const d=Array.from(document.querySelectorAll(".highcharts-container image"));await Promise.race([Promise.all(d.map((e=>e.complete&&0!==e.naturalHeight?Promise.resolve():new Promise((t=>e.addEventListener("load",t,{once:!0})))))),new Promise((e=>setTimeout(e,2e3)))]);const g=o();for(const e in g)"function"!=typeof g[e]&&delete g[e];r(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const pageTemplate=readFileSync(join(__dirname,"templates","template.html"),"utf8");let browser=null;async function createBrowser(e){const{debug:t,other:o}=getOptions(),{enable:r,...i}=t,n={headless:!o.browserShellMode||"shell",userDataDir:"tmp",args:e||[],handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!browser){let e=0;const t=async()=>{try{log(3,`[browser] Attempting to launch and get a browser instance (try ${++e}).`),browser=await puppeteer.launch(n)}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"===n.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 i=[];if(r.js&&i.push({content:r.js}),r.files)for(const e of r.files){const t=!e.startsWith("http");i.push(t?{content:readFileSync(getAbsolutePath(e),"utf8")}:{url:e})}for(const t of i)try{o.push(await e.addScriptTag(t))}catch(e){logWithStack(2,e,"[browser] The JS resource cannot be loaded.")}i.length=0;const n=[];if(r.css){const i=r.css.match(/@import\s*([^;]*);/g);if(i)for(let e of i)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?n.push({url:e}):t.allowFileResources&&n.push({path:getAbsolutePath(e)}));n.push({content:r.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of n)try{o.push(await e.addStyleTag(t))}catch(e){logWithStack(2,e,"[browser] The CSS resource cannot be loaded.")}n.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(pageTemplate,{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,o){const r=[];try{let i=!1;if(t.svg){if(log(4,"[export] Treating as SVG input."),"svg"===t.type)return t.svg;i=!0,await e.setContent(svgTemplate(t.svg),{waitUntil:"domcontentloaded"})}else log(4,"[export] Treating as JSON config."),await e.evaluate(createChart,t,o);r.push(...await addPageResources(e,o));const n=await _getChartSize(e,i,t.scale),{x:s,y:a}=await _getClipRegion(e),l=Math.abs(Math.ceil(n.chartHeight||t.height)),c=Math.abs(Math.ceil(n.chartWidth||t.width));let p;switch(await e.setViewport({height:l,width:c,deviceScaleFactor:i?1:parseFloat(t.scale)}),t.type){case"svg":p=await _createSVG(e);break;case"png":case"jpeg":p=await _createImage(e,t.type,{width:c,height:l,x:s,y:a},t.rasterizationTimeout);break;case"pdf":p=await _createPDF(e,l,c,t.rasterizationTimeout);break;default:throw new ExportError(`[export] Unsupported output format: ${t.type}.`,400)}return await clearPageResources(e,r),p}catch(t){return await clearPageResources(e,r),t}}async function _getClipRegion(e){return e.$eval("#chart-container",(e=>{const{x:t,y:o,width:r,height:i}=e.getBoundingClientRect();return{x:t,y:o,width:r,height:Math.trunc(i>1?i:500)}}))}async function _getChartSize(e,t,o){return t?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(o)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}}))}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,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,e.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,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`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);log(4,`[pool] Pool resource [${t.id}] - Starting work on this pool entry.`);const r=measureTime(),i=await puppeteerExport(t.page,e.export,e.customLogic);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);return e.server.benchmarking&&log(5,"[benchmark] "+(e.requestId?`Request [${e.requestId}] - `:""),`Exporting a chart sucessfully took ${r()}ms.`),pool.release(t),poolStats.timeSpent+=r(),poolStats.timeSpentAverage=poolStats.timeSpent/++poolStats.exportsPerformed,log(4,`[pool] Work completed in ${r()}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:i,pendingAcquires:n,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: ${i}.`),log(5,`[pool] The number of resources waiting to be acquired: ${n}.`),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({export:e.export,customLogic:e.customLogic},(async(e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r||`chart.${i}`,"svg"!==i?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({export:{...e.export,infile:o[0],outfile:o[1]},customLogic:e.customLogic},((e,t)=>{if(e)throw e;const{b64:o,outfile:r,type:i}=t.options.export;try{o?writeFileSync(`${r.split(".").shift()||"chart"}.txt`,getBase64(t.result,i)):writeFileSync(r,"svg"!==i?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{if(!isObject(e))throw new ExportError("[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.",400);const o=updateOptions({export:e.export,customLogic:e.customLogic},!0),r=o.export;if(log(4,"[chart] Starting the exporting process."),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=validateOption("svg",e);else{if(!r.infile.endsWith(".json"))throw new ExportError("[chart] Incorrect value of the `infile` option.",400);r.instr=validateOption("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.options=null,t.export.instr=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.options=null,t.export.svg=null,_prepareExport(t)}async function _prepareExport(e){const{export:t,customLogic:o}=e;return t.constr=_fixConstr(t.constr),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),_handleGlobalAndTheme(t,o),_handleSize(t),_checkDataSize({export:t,customLogic:o}),postWork(e)}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||"png"}`}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 _handleSize(e){const{chart:t,exporting:o}=isAllowedConfig(e.instr)||!1,{chart:r,exporting:i}=isAllowedConfig(e.globalOptions)||!1,{chart:n,exporting:s}=isAllowedConfig(e.themeOptions)||!1,a=e.height||o?.sourceHeight||t?.height||i?.sourceHeight||r?.height||s?.sourceHeight||n?.height||e.defaultHeight||400,l=e.width||o?.sourceWidth||t?.width||i?.sourceWidth||r?.width||s?.sourceWidth||n?.width||e.defaultWidth||600,c=roundNumber(Math.max(.1,Math.min(e.scale||o?.scale||i?.scale||s?.scale||e.defaultScale||1,5)),2);e.height=a,e.width=l,e.scale=c;for(let t of["height","width","scale"])"string"==typeof e[t]&&(e[t]=+e[t].replace(/px|%/gi,""))}function _handleCustomLogic(e){if(e.allowCodeExecution){try{e.resources=_handleResources(e.resources,e.allowFileResources,!0),e.resources=validateOption("resources",e.resources)}catch(t){log(2,"[chart] The `resources` cannot be loaded."),e.resources=null}try{e.customCode=_handleCustomCode(e.customCode,e.allowFileResources),e.customCode=validateOption("customCode",e.customCode)}catch(t){logWithStack(2,t,"[chart] The `customCode` cannot be loaded."),e.customCode=null}try{e.callback=_handleCustomCode(e.callback,e.allowFileResources,!0),e.callback=validateOption("callback",e.callback)}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){let r=e;r||(e="resources.json");const i=["js","css","files"];let n=!1;t&&"string"==typeof e&&e.endsWith(".json")?r=isAllowedConfig(readFileSync(getAbsolutePath(e),"utf8"),!1,o):(r=isAllowedConfig(e,!1,o),r&&!t&&delete r.files);for(const e in r)i.includes(e)?n||(n=!0):delete r[e];return n?(r.files&&(r.files=r.files.map((e=>e.trim())),(!r.files||r.files.length<=0)&&delete r.files),r):null}function _handleCustomCode(e,t,o=!1){if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?t?_handleCustomCode(readFileSync(getAbsolutePath(e),"utf8"),t,o):null:!o&&(e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>"))?`(${e})()`:e.replace(/;$/,"")}function _handleGlobalAndTheme(e,t){const{allowFileResources:o,allowCodeExecution:r}=t;["globalOptions","themeOptions"].forEach((t=>{try{e[t]&&(o&&"string"==typeof e[t]&&e[t].endsWith(".json")?e[t]=isAllowedConfig(readFileSync(getAbsolutePath(e[t]),"utf8"),!0,r):e[t]=isAllowedConfig(e[t],!0,r),e[t]=validateOption(t,e[t]))}catch(o){logWithStack(2,o,`[chart] The \`${t}\` cannot be loaded.`),e[t]=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.")}function _checkDataSize(e){const t=Buffer.byteLength(JSON.stringify(e),"utf-8");if(log(3,`[chart] The current total size of the data for the export process is around ${(t/1048576).toFixed(2)}MB.`),t>=104857600)throw new ExportError("[chart] The data for the export process exceeds 100MB limit.")}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:i,stack:n}=e,s=e.statusCode||400;o.status(s).json({statusCode:s,message:i,stack:n})}function errorMiddleware(e){e.use(logErrorMiddleware),e.use(returnErrorMiddleware)}function rateLimitingMiddleware(e,t){try{if(e&&t.enable){const o="Too many requests, you have been rate limited. Please try again later.",r={window:t.window||1,maxRequests:t.maxRequests||30,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||null,skipToken:t.skipToken||null};r.trustProxy&&e.enable("trust proxy");const i=rateLimit({windowMs:60*r.window*1e3,limit:r.maxRequests,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>null!==r.skipKey&&null!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(log(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),log(3,`[rate limiting] Enabled rate limiting with ${r.maxRequests} 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)}}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 ExportError("[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();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 ExportError(`[validation] Request [${r}] - 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 i=getAllowCodeExecution(),n=isAllowedConfig(t.instr||t.options||t.infile||t.data,!0,i);if(null===n&&!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 ExportError(`[validation] Request [${r}] - 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 ExportError(`[validation] Request [${r}] - 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:n,svg:t.svg,outfile:t.outfile||`${e.params.filename||"chart"}.${t.type||"png"}`,type:t.type,constr:t.constr,b64:t.b64,noDownload:t.noDownload,height:t.height,width:t.width,scale:t.scale,globalOptions:isAllowedConfig(t.globalOptions,!0,i),themeOptions:isAllowedConfig(t.themeOptions,!0,i)},customLogic:{allowCodeExecution:i,allowFileResources:!1,customCode:t.customCode,callback:t.callback,resources:isAllowedConfig(t.resources,!0,i)}},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 i=e.validatedOptions,n=i.requestId;log(4,`[export] Request [${n}] - Got an incoming HTTP request.`),await startExport(i,((i,s)=>{if(e.socket.removeAllListeners("close"),r)log(3,`[export] Request [${n}] - The client closed the connection before the chart finished processing.`);else{if(i)throw i;if(!s||!s.result)throw log(2,`[export] Request [${n}] - Request from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Received result is ${s.result}.`),new ExportError(`[export] Request [${n}] - Unexpected return of the export result from the chart generation. Please check your request data.`,400);if(s.result){log(3,`[export] Request [${n}] - The whole exporting process took ${o()}ms.`);const{type:e,b64:r,noDownload:i,outfile:a}=s.options.export;return r?t.send(getBase64(s.result,e)):(t.header("Content-Type",reversedMime[e]||"image/png"),i||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"),"utf8")),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:getHcVersion(),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){getOptions().ui.enable&&e.get(getOptions().ui.route||"/",((e,t,o)=>{try{log(4,"[ui] Returning UI for the export."),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{log(4,"[version] Changing Highcharts version.");const o=envs.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new ExportError("[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 ExportError("[version] Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new ExportError("[version] No new version supplied.",400);try{await updateHcVersion(i)}catch(e){throw new ExportError(`[version] Version change: ${e.message}`,400).setError(e)}t.status(200).send({statusCode:200,highchartsVersion:getHcVersion(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){return o(e)}}))}const activeServers=new Map,app=express();async function startServer(e={}){try{const t=updateOptions({server:e});if(!(e=t.server).enable||!app)throw new ExportError("[server] Server cannot be started (not enabled or no correct Express app found).",500);const o=1024*e.uploadLimit*1024,r=multer.memoryStorage(),i=multer({storage:r,limits:{fieldSize:o}});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:o})),app.use(express.urlencoded({extended:!0,limit:o})),app.use(i.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=readFileSync(join(getAbsolutePath(e.ssl.certPath),"server.key"),"utf8"),o=readFileSync(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),exportRoutes(app),healthRoutes(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){const t=updateOptions({server:{rateLimiting:e}});rateLimitingMiddleware(app,t.server.rateLimitingOptions)}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=0){await Promise.allSettled([clearAllTimers(),closeServers(),killPool()]),process.exit(e)}async function initExport(e={}){const t=updateOptions(e);setAllowCodeExecution(t.customLogic.allowCodeExecution),initLogging(t.logging),t.other.listenToProcessExits&&_attachProcessExitListeners(),await checkCache(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()})),process.on("SIGTERM",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("SIGHUP",(async(e,t)=>{log(4,`[process] The ${e} event with code: ${t}.`),await shutdownCleanUp()})),process.on("uncaughtException",(async(e,t)=>{logWithStack(1,e,`[process] The ${t} error.`),await shutdownCleanUp(1)}))}var index={...server,getOptions:getOptions,updateOptions:updateOptions,mapToNewOptions:mapToNewOptions,validateOption:validateOption,validateOptions:validateOptions,initExport:initExport,singleExport:singleExport,batchExport:batchExport,startExport:startExport,killPool:killPool,shutdownCleanUp:shutdownCleanUp,log:log,logWithStack:logWithStack,logZodIssues:logZodIssues,setLogLevel:function(e){setLogLevel(updateOptions({logging:{level:e}}).logging.level)},enableConsoleLogging:function(e){enableConsoleLogging(updateOptions({logging:{toConsole:e}}).logging.toConsole)},enableFileLogging:function(e,t,o){const r=updateOptions({logging:{dest:e,file:t,toFile:o}});enableFileLogging(r.logging.dest,r.logging.file,r.logging.toFile)}};export{index as default,initExport}; -//# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map deleted file mode 100644 index 9e201678..00000000 --- a/dist/index.esm.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/utils.js","../lib/logger.js","../lib/schemas/config.js","../lib/validation.js","../lib/errors/ExportError.js","../lib/config.js","../lib/fetch.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/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 { isAbsolute, normalize, resolve } 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 * Checks if the given path is relative or absolute and returns the corrected,\r\n * absolute path.\r\n *\r\n * @function getAbsolutePath\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) ? normalize(path) : resolve(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} Returns `true` if the item is an object, `false`\r\n * 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} Returns `true` if the item is an empty object, `false`\r\n * 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} Returns `true` if a private IP range URL is found, `false`\r\n * 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\nexport default {\r\n __dirname,\r\n clearText,\r\n deepCopy,\r\n expBackoff,\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};\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 with a specified log level. Accepts a variable number\r\n * of arguments. The arguments after the `level` are passed to `console.log`\r\n * and/or used to construct and append messages to a 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 remaining are strings used to build the log message.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than 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 along with its stack trace. Optionally, a custom\r\n * message 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 containing the stack trace.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside the error.\r\n *\r\n * @returns {void} Exits the function execution if attempting to log at a level\r\n * higher than allowed.\r\n */\r\nexport function logWithStack(newLevel, error, customMessage) {\r\n // Get the main message\r\n const mainMessage = customMessage || (error && 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 && 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 related to Zod validation issues. Optionally, a custom\r\n * 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 - An array of Zod validation issues.\r\n * @param {string} customMessage - An optional custom message to be included\r\n * in the log alongside 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 || '[validation] Validation error'} - 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 - The configuration object containing\r\n * `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 // Reset flags to the default values\r\n logging.pathCreated = false;\r\n logging.pathToLog = '';\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 (\r\n Number.isInteger(level) &&\r\n level >= 0 &&\r\n level <= logging.levelsDesc.length\r\n ) {\r\n // Update the module logging's `level` option\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 the module logging's `toConsole` option\r\n logging.toConsole = !!toConsole;\r\n}\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file name.\r\n *\r\n * @function enableFileLogging\r\n *\r\n * @param {string} dest - The destination path where the log file should\r\n * be saved.\r\n * @param {string} file - The name of the log file.\r\n * @param {boolean} toFile - A flag indicating whether logging should\r\n * be directed to a file.\r\n */\r\nexport function enableFileLogging(dest, file, toFile) {\r\n // Update the module logging's `toFile` option\r\n logging.toFile = !!toFile;\r\n\r\n // Set the `dest` and `file` options only if the file logging is enabled\r\n if (logging.toFile) {\r\n logging.dest = dest || 'log';\r\n logging.file = file || 'highcharts-export-server.log';\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 * It provides a default configuration object with predefined default values,\r\n * descriptions, and characteristics for each option used in the Export Server.\r\n */\r\n\r\n/**\r\n * The default 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\nconst 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: ['Object', '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', 'string', '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 validation: {\r\n value: true,\r\n types: ['boolean'],\r\n envLink: 'OTHER_VALIDATION',\r\n description: 'Whether or not to enable validation of options types',\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\nexport default defaultConfig;\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', '1', 'false', '0', 'undefined', 'null', and ''.\r\n * The strings 'undefined', 'null', and '' will be transformed to null,\r\n * the string 'true' will be transformed to the boolean value true,\r\n * and 'false' will 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', '1', 'false', '0', 'undefined', 'null', ''])\r\n .transform((value) =>\r\n !['undefined', 'null', ''].includes(value)\r\n ? value === 'true' || value === '1'\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.startsWith('{') && value.endsWith('}')) ||\r\n ['undefined', 'null', ''].includes(value),\r\n {\r\n params: {\r\n errorMessage:\r\n \"The value must be a string that 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 * 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:\r\n \"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\nexport const validators = {\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:\r\n '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:\r\n '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:\r\n \"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:\r\n '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:\r\n '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:\r\n \"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 `validation` 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 validation\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 `validation`\r\n * option.\r\n */\r\n validation(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 z\r\n .string()\r\n .uuid({ message: 'The value must be a stringified UUID' })\r\n .nullable();\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: validators.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: validators.version(strictCheck),\r\n cdnUrl: validators.cdnUrl(strictCheck),\r\n forceFetch: validators.forceFetch(strictCheck),\r\n cachePath: validators.cachePath(strictCheck),\r\n coreScripts: validators.coreScripts(strictCheck),\r\n moduleScripts: validators.moduleScripts(strictCheck),\r\n indicatorScripts: validators.indicatorScripts(strictCheck),\r\n customScripts: validators.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: validators.infile(strictCheck),\r\n instr: validators.instr(),\r\n options: validators.options(),\r\n svg: validators.svg(),\r\n outfile: validators.outfile(strictCheck),\r\n type: validators.type(strictCheck),\r\n constr: validators.constr(strictCheck),\r\n b64: validators.b64(strictCheck),\r\n noDownload: validators.noDownload(strictCheck),\r\n defaultHeight: validators.defaultHeight(strictCheck),\r\n defaultWidth: validators.defaultWidth(strictCheck),\r\n defaultScale: validators.defaultScale(strictCheck),\r\n height: validators.height(strictCheck),\r\n width: validators.width(strictCheck),\r\n scale: validators.scale(strictCheck),\r\n globalOptions: validators.globalOptions(),\r\n themeOptions: validators.themeOptions(),\r\n batch: validators.batch(false),\r\n rasterizationTimeout: validators.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: validators.allowCodeExecution(strictCheck),\r\n allowFileResources: validators.allowFileResources(strictCheck),\r\n customCode: validators.customCode(false),\r\n callback: validators.callback(false),\r\n resources: validators.resources(strictCheck),\r\n loadConfig: validators.loadConfig(false),\r\n createConfig: validators.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: validators.proxyHost(false),\r\n port: validators.proxyPort(strictCheck),\r\n timeout: validators.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: validators.enableRateLimiting(strictCheck),\r\n maxRequests: validators.maxRequests(strictCheck),\r\n window: validators.window(strictCheck),\r\n delay: validators.delay(strictCheck),\r\n trustProxy: validators.trustProxy(strictCheck),\r\n skipKey: validators.skipKey(false),\r\n skipToken: validators.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: validators.enableSsl(strictCheck),\r\n force: validators.sslForce(strictCheck),\r\n port: validators.sslPort(strictCheck),\r\n certPath: validators.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: validators.enableServer(strictCheck).optional(),\r\n host: validators.host(strictCheck).optional(),\r\n port: validators.port(strictCheck).optional(),\r\n uploadLimit: validators.uploadLimit(strictCheck).optional(),\r\n benchmarking: validators.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: validators.minWorkers(strictCheck),\r\n maxWorkers: validators.maxWorkers(strictCheck),\r\n workLimit: validators.workLimit(strictCheck),\r\n acquireTimeout: validators.acquireTimeout(strictCheck),\r\n createTimeout: validators.createTimeout(strictCheck),\r\n destroyTimeout: validators.destroyTimeout(strictCheck),\r\n idleTimeout: validators.idleTimeout(strictCheck),\r\n createRetryInterval: validators.createRetryInterval(strictCheck),\r\n reaperInterval: validators.reaperInterval(strictCheck),\r\n benchmarking: validators.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: validators.logLevel(strictCheck),\r\n file: validators.logFile(strictCheck),\r\n dest: validators.logDest(strictCheck),\r\n toConsole: validators.logToConsole(strictCheck),\r\n toFile: validators.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: validators.enableUi(strictCheck),\r\n route: validators.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: validators.nodeEnv(strictCheck),\r\n listenToProcessExits: validators.listenToProcessExits(strictCheck),\r\n noLogo: validators.noLogo(strictCheck),\r\n hardResetPage: validators.hardResetPage(strictCheck),\r\n browserShellMode: validators.browserShellMode(strictCheck),\r\n validation: validators.validation(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: validators.enableDebug(strictCheck),\r\n headless: validators.headless(strictCheck),\r\n devtools: validators.devtools(strictCheck),\r\n listenToConsole: validators.listenToConsole(strictCheck),\r\n dumpio: validators.dumpio(strictCheck),\r\n slowMo: validators.slowMo(strictCheck),\r\n debuggingPort: validators.debuggingPort(strictCheck)\r\n })\r\n .partial();\r\n\r\n// Strict schema for the config\r\nexport const StrictConfigSchema = z.object({\r\n requestId: validators.requestId(),\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});\r\n\r\n// Loose schema for the config\r\nexport const LooseConfigSchema = z.object({\r\n requestId: validators.requestId(),\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});\r\n\r\n// Schema for the environment variables config\r\nexport const EnvSchema = z.object({\r\n // puppeteer\r\n PUPPETEER_ARGS: validators.args(false),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: validators.version(false),\r\n HIGHCHARTS_CDN_URL: validators.cdnUrl(false),\r\n HIGHCHARTS_FORCE_FETCH: validators.forceFetch(false),\r\n HIGHCHARTS_CACHE_PATH: validators.cachePath(false),\r\n HIGHCHARTS_ADMIN_TOKEN: validators.adminToken(false),\r\n HIGHCHARTS_CORE_SCRIPTS: validators.coreScripts(false),\r\n HIGHCHARTS_MODULE_SCRIPTS: validators.moduleScripts(false),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: validators.indicatorScripts(false),\r\n HIGHCHARTS_CUSTOM_SCRIPTS: validators.customScripts(false),\r\n\r\n // export\r\n EXPORT_INFILE: validators.infile(false),\r\n EXPORT_INSTR: validators.instr(),\r\n EXPORT_OPTIONS: validators.options(),\r\n EXPORT_SVG: validators.svg(),\r\n EXPORT_BATCH: validators.batch(false),\r\n EXPORT_OUTFILE: validators.outfile(false),\r\n EXPORT_TYPE: validators.type(false),\r\n EXPORT_CONSTR: validators.constr(false),\r\n EXPORT_B64: validators.b64(false),\r\n EXPORT_NO_DOWNLOAD: validators.noDownload(false),\r\n EXPORT_HEIGHT: validators.height(false),\r\n EXPORT_WIDTH: validators.width(false),\r\n EXPORT_SCALE: validators.scale(false),\r\n EXPORT_DEFAULT_HEIGHT: validators.defaultHeight(false),\r\n EXPORT_DEFAULT_WIDTH: validators.defaultWidth(false),\r\n EXPORT_DEFAULT_SCALE: validators.defaultScale(false),\r\n EXPORT_GLOBAL_OPTIONS: validators.globalOptions(),\r\n EXPORT_THEME_OPTIONS: validators.themeOptions(),\r\n EXPORT_RASTERIZATION_TIMEOUT: validators.rasterizationTimeout(false),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: validators.allowCodeExecution(false),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: validators.allowFileResources(false),\r\n CUSTOM_LOGIC_CUSTOM_CODE: validators.customCode(false),\r\n CUSTOM_LOGIC_CALLBACK: validators.callback(false),\r\n CUSTOM_LOGIC_RESOURCES: validators.resources(false),\r\n CUSTOM_LOGIC_LOAD_CONFIG: validators.loadConfig(false),\r\n CUSTOM_LOGIC_CREATE_CONFIG: validators.createConfig(false),\r\n\r\n // server\r\n SERVER_ENABLE: validators.enableServer(false),\r\n SERVER_HOST: validators.host(false),\r\n SERVER_PORT: validators.port(false),\r\n SERVER_UPLOAD_LIMIT: validators.uploadLimit(false),\r\n SERVER_BENCHMARKING: validators.serverBenchmarking(false),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: validators.proxyHost(false),\r\n SERVER_PROXY_PORT: validators.proxyPort(false),\r\n SERVER_PROXY_TIMEOUT: validators.proxyTimeout(false),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: validators.enableRateLimiting(false),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: validators.maxRequests(false),\r\n SERVER_RATE_LIMITING_WINDOW: validators.window(false),\r\n SERVER_RATE_LIMITING_DELAY: validators.delay(false),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: validators.trustProxy(false),\r\n SERVER_RATE_LIMITING_SKIP_KEY: validators.skipKey(false),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: validators.skipToken(false),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: validators.enableSsl(false),\r\n SERVER_SSL_FORCE: validators.sslForce(false),\r\n SERVER_SSL_PORT: validators.sslPort(false),\r\n SERVER_SSL_CERT_PATH: validators.sslCertPath(false),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: validators.minWorkers(false),\r\n POOL_MAX_WORKERS: validators.maxWorkers(false),\r\n POOL_WORK_LIMIT: validators.workLimit(false),\r\n POOL_ACQUIRE_TIMEOUT: validators.acquireTimeout(false),\r\n POOL_CREATE_TIMEOUT: validators.createTimeout(false),\r\n POOL_DESTROY_TIMEOUT: validators.destroyTimeout(false),\r\n POOL_IDLE_TIMEOUT: validators.idleTimeout(false),\r\n POOL_CREATE_RETRY_INTERVAL: validators.createRetryInterval(false),\r\n POOL_REAPER_INTERVAL: validators.reaperInterval(false),\r\n POOL_BENCHMARKING: validators.poolBenchmarking(false),\r\n\r\n // logging\r\n LOGGING_LEVEL: validators.logLevel(false),\r\n LOGGING_FILE: validators.logFile(false),\r\n LOGGING_DEST: validators.logDest(false),\r\n LOGGING_TO_CONSOLE: validators.logToConsole(false),\r\n LOGGING_TO_FILE: validators.logToFile(false),\r\n\r\n // ui\r\n UI_ENABLE: validators.enableUi(false),\r\n UI_ROUTE: validators.uiRoute(false),\r\n\r\n // other\r\n OTHER_NODE_ENV: validators.nodeEnv(false),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: validators.listenToProcessExits(false),\r\n OTHER_NO_LOGO: validators.noLogo(false),\r\n OTHER_HARD_RESET_PAGE: validators.hardResetPage(false),\r\n OTHER_BROWSER_SHELL_MODE: validators.browserShellMode(false),\r\n OTHER_VALIDATION: validators.validation(false),\r\n\r\n // debugger\r\n DEBUG_ENABLE: validators.enableDebug(false),\r\n DEBUG_HEADLESS: validators.headless(false),\r\n DEBUG_DEVTOOLS: validators.devtools(false),\r\n DEBUG_LISTEN_TO_CONSOLE: validators.listenToConsole(false),\r\n DEBUG_DUMPIO: validators.dumpio(false),\r\n DEBUG_SLOW_MO: validators.slowMo(false),\r\n DEBUG_DEBUGGING_PORT: validators.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 * 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 validators,\r\n StrictConfigSchema,\r\n LooseConfigSchema,\r\n EnvSchema,\r\n envs,\r\n strictValidate,\r\n looseValidate\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 // Set the `message` and `stackMessage` with provided message\r\n this.message = message;\r\n this.stackMessage = message;\r\n\r\n // Set the `statusCode` if provided\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 // Save the provided error\r\n this.error = error;\r\n\r\n // Set the error's name if present\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n\r\n // Set the error's status code if present\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n\r\n // Set the error's stack and stack's message if present\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n\r\n // Return updated `ExportError` instance\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 This module manages configuration for the Highcharts Export Server\r\n * by loading and merging options from multiple sources, such as the default\r\n * settings, environment variables, user-provided options, and command-line\r\n * arguments. Ensures the global options are up-to-date with the highest\r\n * priority values. Provides functions for accessing and updating configuration.\r\n */\r\n\r\nimport { readFileSync } from 'fs';\r\n\r\nimport { log, logWithStack, logZodIssues } from './logger.js';\r\nimport { deepCopy, getAbsolutePath, isObject } from './utils.js';\r\nimport {\r\n envs,\r\n looseValidate,\r\n strictValidate,\r\n validators\r\n} from './validation.js';\r\n\r\nimport defaultConfig from './schemas/config.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Sets the global options with initial values from the default config\r\nconst globalOptions = _initOptions(defaultConfig);\r\n\r\n// Properties nesting level of all options\r\nconst nestedProps = _createNestedProps(defaultConfig);\r\n\r\n// Properties names that should not be recursively merged\r\nconst absoluteProps = _createAbsoluteProps(defaultConfig);\r\n\r\n/**\r\n * Retrieves a copy of the global options object or an original global options\r\n * object, based on the `getCopy` flag.\r\n *\r\n * @function getOptions\r\n *\r\n * @param {boolean} [getCopy=true] - Specifies whether to return a copied\r\n * object of the global options (`true`) or a reference to the global options\r\n * object (`false`). The default value is `true`.\r\n *\r\n * @returns {Object} A copy of the global options object, or a reference\r\n * to the global options object.\r\n */\r\nexport function getOptions(getCopy = true) {\r\n // Return a copy or an original global options object\r\n return getCopy ? deepCopy(globalOptions) : globalOptions;\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object or a copy of the global options\r\n * object, based on the `getCopy` flag. The `newOptions` object can be\r\n * strictly validated depending on the `strictCheck` flag.\r\n *\r\n * @function updateOptions\r\n *\r\n * @param {Object} newOptions - An object containing the new options to be\r\n * merged into the global options.\r\n * @param {boolean} [getCopy=false] - Determines whether to merge the new\r\n * options into a copy of the global options object (`true`) or directly into\r\n * the global options object (`false`). The default value is `false`.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The updated options object, either the modified global\r\n * options or a modified copy, based on the value of `getCopy`.\r\n */\r\nexport function updateOptions(newOptions, getCopy = false, strictCheck = true) {\r\n // Merge new options to the global options or its copy and return the result\r\n return _mergeOptions(\r\n // First, get the options\r\n getOptions(getCopy),\r\n // Next, validate the new options\r\n validateOptions(newOptions, strictCheck)\r\n );\r\n}\r\n\r\n/**\r\n * Updates and returns the global options object with values provided through\r\n * the CLI, keeping the principle of options load priority. The function accepts\r\n * a `cliArgs` array containing arguments from the CLI, which will be validated\r\n * and applied if provided.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from the command line interface (CLI).\r\n * 2. Values from a custom JSON file (loaded by the `--loadConfig` option).\r\n *\r\n * @function setCliOptions\r\n *\r\n * @param {Array} cliArgs - An array of command line arguments used\r\n * for additional configuration.\r\n *\r\n * @returns {Object} The updated global options object, reflecting the merged\r\n * configuration from sources provided through the CLI.\r\n */\r\nexport function setCliOptions(cliArgs) {\r\n // Only for the CLI usage\r\n if (cliArgs && Array.isArray(cliArgs) && cliArgs.length) {\r\n try {\r\n // Get options from the custom JSON loaded via the `--loadConfig`\r\n const configOptions = _loadConfigFile(cliArgs);\r\n\r\n // Update global options with validated values from the `configOptions`\r\n updateOptions(configOptions);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the `--loadConfig` option.');\r\n }\r\n\r\n try {\r\n // Get options from the CLI\r\n const cliOptions = _pairArgumentValue(cliArgs);\r\n\r\n // Update global options with validated values from the `cliOptions`\r\n updateOptions(cliOptions, false, false);\r\n } catch (error) {\r\n log(2, '[validation] No options added from the CLI arguments.');\r\n }\r\n }\r\n\r\n // Return reference to the global options\r\n return getOptions(false);\r\n}\r\n\r\n/**\r\n * Maps old-structured configuration options (PhantomJS-based) to a new format\r\n * (Puppeteer-based). This function converts flat, old-structured options into\r\n * a new, nested configuration format based on a predefined mapping provided\r\n * in the `nestedProps` object. The new format is used for Puppeteer, while\r\n * the old format 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 the `nestedProps` object or an empty object\r\n * if the provided `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 (isObject(oldOptions)) {\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 } else {\r\n log(\r\n 2,\r\n '[config] No correct object with options was provided. Returning an empty object.'\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 a specified option using the corresponding validator from the\r\n * configuration object. Returns the original option if the validation\r\n * is disabled globally.\r\n *\r\n * @function validateOption\r\n *\r\n * @param {string} name - The name of the option to validate.\r\n * @param {any} configOption - The value of the option to validate.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {any} The parsed and validated value of the option.\r\n */\r\nexport function validateOption(name, configOption, strictCheck = true) {\r\n // Return the original option if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOption;\r\n }\r\n\r\n try {\r\n // Return validated option\r\n return validators[name](strictCheck).parse(configOption);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(\r\n 1,\r\n error.issues,\r\n `[validation] The ${name} option validation error`\r\n );\r\n\r\n // Throw validation error\r\n throw new ExportError(\r\n `[validation] The ${name} option validation error`,\r\n 400\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Validates the provided configuration options for the exporting process.\r\n * Returns the original option if the validation is disabled globally.\r\n *\r\n * @function validateOptions\r\n *\r\n * @param {Object} configOptions - The configuration options to be validated.\r\n * @param {boolean} [strictCheck=true] - Determines if stricter validation\r\n * should be applied. The default value is `true`.\r\n *\r\n * @returns {Object} The parsed and validated configuration options object.\r\n */\r\nexport function validateOptions(configOptions, strictCheck = true) {\r\n // Return the original config if the validation is disabled\r\n if (!getOptions().other.validation) {\r\n return configOptions;\r\n }\r\n\r\n try {\r\n // Return validated options\r\n return strictCheck\r\n ? strictValidate(configOptions)\r\n : looseValidate(configOptions);\r\n } catch (error) {\r\n // Log Zod issues\r\n logZodIssues(1, error.issues, '[validation] Options validation error');\r\n\r\n // Throw validation error\r\n throw new ExportError('[validation] Options validation error', 400);\r\n }\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 * Initializes and returns the global options object based on the provided\r\n * configuration, setting values from nested properties recursively.\r\n *\r\n * The function prioritizes values in the following order:\r\n *\r\n * 1. Values from environment variables (specified in the `.env` file).\r\n * 2. Values from the `./lib/schemas/config.js` file (defaults).\r\n *\r\n * @function _initOptions\r\n *\r\n * @param {Object} config - The configuration object used for initializing\r\n * the global options. It should include nested properties with a `value`\r\n * and an `envLink` for linking to environment variables.\r\n *\r\n * @returns {Object} The initialized global options object, populated with\r\n * values based on the provided configuration and the established priority\r\n * order.\r\n */\r\nfunction _initOptions(config) {\r\n // Init the object for options\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 if (Object.prototype.hasOwnProperty.call(item, 'value')) {\r\n // Set the correct value based on the established priority order\r\n if (envs[item.envLink] !== undefined && envs[item.envLink] !== null) {\r\n // The environment variables value\r\n options[name] = envs[item.envLink];\r\n } else {\r\n // The value from the config file\r\n options[name] = item.value;\r\n }\r\n } else {\r\n // Create a category of options in the `options` object\r\n options[name] = _initOptions(item);\r\n }\r\n }\r\n\r\n // Return the created `options` object\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively merges two sets of configuration options, taking into account\r\n * properties specified in the `absoluteProps` array that require absolute\r\n * merging. The `originalOptions` object will be extended with options from\r\n * the `newOptions` object.\r\n *\r\n * @function _mergeOptions\r\n *\r\n * @param {Object} originalOptions - The original configuration options object\r\n * to be extended.\r\n * @param {Object} newOptions - The new configuration options object to merge.\r\n *\r\n * @returns {Object} The extended `originalOptions` object.\r\n */\r\nfunction _mergeOptions(originalOptions, newOptions) {\r\n // Check if the `originalOptions` and `newOptions` are correct objects\r\n if (isObject(originalOptions) && 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] || null;\r\n }\r\n }\r\n\r\n // Return the original (modified or not) options\r\n return originalOptions;\r\n}\r\n\r\n/**\r\n * Converts the provided options object to a JSON string with the option\r\n * to preserve functions. In order for a function to be preserved, it needs\r\n * to follow the format `function (...) {...}`. Such a function can also\r\n * 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\r\n * to take 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\nfunction _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 the `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 // Get the allow flags for the custom logic check\r\n const { allowCodeExecution, allowFileResources } = getOptions().customLogic;\r\n\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 && allowFileResources) {\r\n try {\r\n // Load an optional custom JSON config file\r\n return isAllowedConfig(\r\n readFileSync(getAbsolutePath(configFileName), 'utf8'),\r\n false,\r\n allowCodeExecution\r\n );\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 in the `nestedProps` object.\r\n *\r\n * @function _pairArgumentValue\r\n *\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(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 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 * should 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 getOptions,\r\n updateOptions,\r\n setCliOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions,\r\n isAllowedConfig\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 * Sends a GET request to the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @async\r\n * @function get\r\n *\r\n * @param {string} url - The URL to get 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 get(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n // Decide on the protocol\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\r\n // Get the full result and resolve the request\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 // Decide on the protocol\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 // Get the full result and resolve the request\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 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 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, updateOptions } from './config.js';\r\nimport { get } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { 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 checkCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n */\r\nexport async function checkCache(highchartsOptions, serverProxyOptions) {\r\n try {\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\r\n // The initial cache update\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), 'utf8');\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 } =\r\n 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 // Check the Highcharts 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 (\r\n Object.keys(manifest.modules || {}).length !== numberOfModules\r\n ) {\r\n // Check the number of modules\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 = _extractHcVersion(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.version, fetchedModules);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Could not configure cache and create or update the config manifest.',\r\n 500\r\n ).setError(error);\r\n }\r\n}\r\n\r\n/**\r\n * Gets the version of Highcharts from the cache.\r\n *\r\n * @function getHcVersion\r\n *\r\n * @returns {string} The cached Highcharts version.\r\n */\r\nexport function getHcVersion() {\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 scripts of a new version.\r\n *\r\n * @async\r\n * @function updateHcVersion\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n */\r\nexport async function updateHcVersion(newVersion) {\r\n // Update to the new version\r\n const options = updateOptions({\r\n highcharts: {\r\n version: newVersion\r\n }\r\n });\r\n\r\n // Check if cache needs to be updated\r\n await checkCache(options.highcharts, options.server.proxy);\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, 'utf8'); // #562\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 {number} version - The currently used Highcharts version.\r\n * @param {Object} [fetchedModules={}] - An object which tracks which modules\r\n * 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(version, fetchedModules = {}) {\r\n // Update cache object with the current modules\r\n cache.activeManifest = {\r\n version,\r\n modules: fetchedModules\r\n };\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(cache.activeManifest),\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 * Updates the local cache with Highcharts scripts content and information,\r\n * and used Highcharts version.\r\n *\r\n * @async\r\n * @function _updateCache\r\n *\r\n * @param {Object} highchartsOptions - The configuration object containing\r\n * `highcharts` options.\r\n * @param {Object} serverProxyOptions - The configuration object containing\r\n * `server.proxy` 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 try {\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 log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n // Get the CDN url for scripts\r\n const cdnUrl = highchartsOptions.cdnUrl || cache.cdnUrl;\r\n\r\n // Prepare options for a request\r\n const requestOptions = _configureRequest(serverProxyOptions);\r\n\r\n // An object to record which scripts are fetched\r\n const fetchedModules = {};\r\n\r\n // Join all fetched scripts and save in the manifest's sources\r\n cache.sources = (\r\n await Promise.all([\r\n // Highcharts core scripts fetch\r\n ...highchartsOptions.coreScripts.map((cs) =>\r\n _fetchScript(\r\n hcVersion ? `${cdnUrl}/${hcVersion}/${cs}` : `${cdnUrl}/${cs}`,\r\n requestOptions,\r\n fetchedModules,\r\n true\r\n )\r\n ),\r\n // Highcharts module scripts fetch\r\n ...highchartsOptions.moduleScripts.map((ms) =>\r\n _fetchScript(\r\n ms === 'map'\r\n ? hcVersion\r\n ? `${cdnUrl}/maps/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/maps/modules/${ms}`\r\n : hcVersion\r\n ? `${cdnUrl}/${hcVersion}/modules/${ms}`\r\n : `${cdnUrl}/modules/${ms}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Highcharts indicator scripts fetch\r\n ...highchartsOptions.indicatorScripts.map((is) =>\r\n _fetchScript(\r\n hcVersion\r\n ? `${cdnUrl}/stock/${hcVersion}/indicators/${is}`\r\n : `${cdnUrl}/stock/indicators/${is}`,\r\n requestOptions,\r\n fetchedModules\r\n )\r\n ),\r\n // Custom scripts fetch\r\n ...highchartsOptions.customScripts.map((cs) =>\r\n _fetchScript(`${cs}`, requestOptions)\r\n )\r\n ])\r\n ).join(';\\n');\r\n\r\n // Extract and save version of currently used Highcharts\r\n cache.hcVersion = _extractHcVersion(cache.sources);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n\r\n // Return the fetched modules\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\n/**\r\n * Fetches a single script and updates the `fetchedModules` accordingly.\r\n *\r\n * @async\r\n * @function _fetchScript\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional requests options.\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 _fetchScript(\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 get(`${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 * Configures a proxy agent for outgoing HTTP requests based on the provided\r\n * `server.proxy` options. If a valid `host` and `port` are specified, it tries\r\n * to create an `HttpsProxyAgent`. If the creation fails, an `ExportError`\r\n * is thrown. If no proxy is configured, an empty object is returned.\r\n *\r\n * @function _configureRequest\r\n *\r\n * @param {Object} serverProxyOptions- The configuration object containing\r\n * `server.proxy` options.\r\n *\r\n * @returns {Object} The request options, including the proxy agent if created,\r\n * or an empty object if no proxy configuration is provided.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the proxy agent creation\r\n * fails.\r\n */\r\nfunction _configureRequest(serverProxyOptions) {\r\n // Get the `host` and `port` of the proxy\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 // Create the agent\r\n const proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n\r\n // Add the agent to the request's options\r\n return {\r\n agent: proxyAgent,\r\n timeout: serverProxyOptions.timeout\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 // Return an empty object when no proxy agent is created\r\n return {};\r\n}\r\n\r\n/**\r\n * Extracts Highcharts version from the cache's sources string.\r\n *\r\n * @function _extractHcVersion\r\n *\r\n * @param {Object} cacheSources - The cache sources object.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nfunction _extractHcVersion(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` property.\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\nfunction _extractModuleName(scriptPath) {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n}\r\n\r\nexport default {\r\n checkCache,\r\n getHcVersion,\r\n updateHcVersion,\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} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n *\r\n */\r\nexport async function createChart(exportOptions, customLogicOptions) {\r\n // Get required functions\r\n const { getOptions, setOptions, merge, 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 the `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 the `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: exportOptions.height,\r\n width: exportOptions.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 ${exportOptions.instr}`)();\r\n\r\n // Get the `themeOptions` option\r\n const themeOptions = new Function(`return ${exportOptions.themeOptions}`)();\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 = customLogicOptions.callback\r\n ? new Function(`return ${customLogicOptions.callback}`)()\r\n : null;\r\n\r\n // Trigger the `customCode` option\r\n if (customLogicOptions.customCode) {\r\n new Function('options', customLogicOptions.customCode)(userOptions);\r\n }\r\n\r\n // Get the `globalOptions` option\r\n const globalOptions = new Function(`return ${exportOptions.globalOptions}`)();\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[exportOptions.constr]('container', finalOptions, finalCallback);\r\n\r\n // Get all images from within the chart\r\n const images = Array.from(\r\n document.querySelectorAll('.highcharts-container image')\r\n );\r\n\r\n // Wait for all images for 2 seconds\r\n await Promise.race([\r\n Promise.all(\r\n images.map((image) =>\r\n image.complete && image.naturalHeight !== 0\r\n ? Promise.resolve()\r\n : new Promise((resolve) =>\r\n image.addEventListener('load', resolve, { once: true })\r\n )\r\n )\r\n ),\r\n // Proceed further even if images did not load\r\n new Promise((resolve) => setTimeout(resolve, 2000))\r\n ]);\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 JS and CSS resources,\r\n * and setting up Highcharts for server-side rendering. The module ensures\r\n * that the browser and pages are correctly managed and can handle failures\r\n * during 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 pageTemplate = 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 * browser's 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 const openBrowser = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to launch and 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 openBrowser();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n // Try to open a browser\r\n await openBrowser();\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 // No correct browser\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 configuration object containing\r\n * `customLogic` 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 the content of the `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') ? false : true;\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 // The actual injection of collected scripts\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 const 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: getAbsolutePath(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 // The actual injection of collected CSS\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(pageTemplate, { 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} exportOptions - The configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` 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, exportOptions, customLogicOptions) {\r\n // Injected resources array (additional JS and CSS)\r\n const injectedResources = [];\r\n\r\n try {\r\n let isSVG = false;\r\n\r\n // Decide on the export method\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 page.setContent(svgTemplate(exportOptions.svg), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n log(4, '[export] Treating as JSON config.');\r\n\r\n // Options export\r\n await page.evaluate(createChart, exportOptions, customLogicOptions);\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, customLogicOptions))\r\n );\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = await _getChartSize(page, isSVG, exportOptions.scale);\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 * 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 * Retrieves the real chart dimensions from a Puppeteer page. The function\r\n * behaves differently based on whether the export type is SVG or another\r\n * format.\r\n *\r\n * @async\r\n * @function _getChartSize\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {boolean} isSVG - Determines whether the chart being processed\r\n * is an SVG or another format.\r\n * @param {number} scale - The scale factor to be applied to the chart\r\n * dimensions.\r\n *\r\n * @returns {Promise} A Promise that resolves to an object containing\r\n * the actual height and width of the chart after scaling.\r\n */\r\nasync function _getChartSize(page, isSVG, scale) {\r\n // Trigger appropriate function based on the `isSvg` flag to get chart size\r\n return 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(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\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 { clearPage, createBrowser, closeBrowser, newPage } from './browser.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 - The configuration object containing `pool`\r\n * options.\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer\r\n * launch.\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(poolOptions, puppeteerArgs) {\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 * Terminates 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 once all workers are\r\n * terminated, the pool is destroyed, and the browser is successfully 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 configuration 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 (options.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 `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\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 log(\r\n 4,\r\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\r\n );\r\n\r\n // Start measuring export time\r\n const exportCounter = measureTime();\r\n\r\n // Perform an export on a puppeteer level\r\n const exportResult = await puppeteerExport(\r\n workerHandle.page,\r\n options.export,\r\n options.customLogic\r\n );\r\n\r\n // Check if it's an error\r\n if (exportResult 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 // 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 (exportResult.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 exportResult.name === 'TimeoutError' ||\r\n exportResult.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(exportResult);\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(exportResult);\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 `[benchmark] ${options.requestId ? `Request [${options.requestId}] - ` : ''}`,\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 // Update statistics\r\n poolStats.timeSpent += exportCounter();\r\n poolStats.timeSpentAverage =\r\n poolStats.timeSpent / ++poolStats.exportsPerformed;\r\n\r\n log(4, `[pool] Work completed in ${exportCounter()}ms.`);\r\n\r\n // Otherwise return an object with the result and options\r\n return {\r\n result: exportResult,\r\n options\r\n };\r\n } catch (error) {\r\n ++poolStats.exportsDropped;\r\n\r\n // Try to release the worker, if it exists\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\nfunction _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`, `destroy`\r\n * functions for the pool instance.\r\n *\r\n * @function _factory\r\n *\r\n * @param {Object} poolOptions - The configuration object containing `pool`\r\n * 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 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, allowing for the `foreignObject` elements\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 that prepare for the exporting\r\n * charts 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 { isAllowedConfig, updateOptions, validateOption } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { getPoolStats, killPool, postWork } from './pool.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport { getAbsolutePath, getBase64, isObject, roundNumber } 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 resulting image to the provided output file.\r\n *\r\n * @async\r\n * @function singleExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. The object must contain at least one\r\n * of the following `export` properties: `infile`, `instr`, `options`, or `svg`\r\n * 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(\r\n { export: options.export, customLogic: options.customLogic },\r\n 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 );\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 information\r\n * provided in the `batch` option. The `batch` is a string in the following\r\n * format: \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\". Results\r\n * are saved to the specified output files.\r\n *\r\n * @async\r\n * @function batchExport\r\n *\r\n * @param {Object} options - The `options` object, which should include settings\r\n * from the `export` and `customLogic` sections. It can be a partial or complete\r\n * set of options from these sections. It must contain the `batch` option from\r\n * the `export` section to generate 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 export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n },\r\n customLogic: options.customLogic\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 `imageOptions` parameter is an object that\r\n * should include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If partial\r\n * options are provided, missing values will be merged with the current global\r\n * options.\r\n *\r\n * The `endCallback` function is invoked upon the completion of the export,\r\n * either successfully or with an error. The `error` object is provided\r\n * as the first argument, and the `data` object is the second, containing\r\n * the Base64 representation of the chart in the `result` property\r\n * and the complete set of options in the `options` property.\r\n *\r\n * @async\r\n * @function startExport\r\n *\r\n * @param {Object} imageOptions - The `imageOptions` object, which should\r\n * include settings from the `export` and `customLogic` sections. It can\r\n * be a partial or complete set of options from these sections. If the provided\r\n * options are partial, missing values will be merged with the current global\r\n * options.\r\n * @param {Function} endCallback - The callback function to be invoked upon\r\n * finalizing the export process or upon encountering an error. The first\r\n * argument is the `error` object, and the second argument is the `data` object,\r\n * which includes the Base64 representation of the chart in the `result`\r\n * property and the full set of 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(imageOptions, endCallback) {\r\n try {\r\n // Check if provided options are in an object\r\n if (!isObject(imageOptions)) {\r\n throw new ExportError(\r\n '[chart] Incorrect value of the provided `imageOptions`. Needs to be an object.',\r\n 400\r\n );\r\n }\r\n\r\n // Merge additional options to the copy of the instance options\r\n const options = updateOptions(\r\n {\r\n export: imageOptions.export,\r\n customLogic: imageOptions.customLogic\r\n },\r\n true\r\n );\r\n\r\n // Get the `export` options\r\n const exportOptions = options.export;\r\n\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\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 = validateOption('svg', fileContent);\r\n } else if (exportOptions.infile.endsWith('.json')) {\r\n // Set to the `instr` option\r\n exportOptions.instr = validateOption('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 boolean 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 configuration 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.options = null;\r\n options.export.instr = 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 configuration 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.options = null;\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 configuration 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 // Get the `export` and `customLogic` options\r\n const { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n // Prepare the `constr` option\r\n exportOptions.constr = _fixConstr(exportOptions.constr);\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(\r\n exportOptions.type,\r\n exportOptions.outfile\r\n );\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 `customCode`, `callback`, and `resources` options\r\n _handleCustomLogic(customLogicOptions);\r\n\r\n // Prepare the `globalOptions` and `themeOptions` options\r\n _handleGlobalAndTheme(exportOptions, customLogicOptions);\r\n\r\n // Prepare the `height`, `width`, and `scale` options\r\n _handleSize(exportOptions);\r\n\r\n // Check if the image options object does not exceed the size limit\r\n _checkDataSize({ export: exportOptions, customLogic: customLogicOptions });\r\n\r\n // Post the work to the pool\r\n return postWork(options);\r\n}\r\n\r\n/**\r\n * Handles adjusting the constructor name by transforming and normalizing\r\n * it based on common chart types.\r\n *\r\n * @function _fixConstr\r\n *\r\n * @param {string} constr - The original constructor name to be adjusted.\r\n *\r\n * @returns {string} The corrected constructor name, or 'chart' if the input\r\n * is not recognized.\r\n */\r\nfunction _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 * Handles fixing 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, or 'chart.png' if the input\r\n * is not recognized.\r\n */\r\nfunction _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 || 'png'}`;\r\n}\r\n\r\n/**\r\n * Handles fixing 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, or 'png' if the input\r\n * is not recognized.\r\n */\r\nfunction _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 * Handle calculating 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 *\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 _handleSize\r\n *\r\n * @param {Object} exportOptions - The configuration object containing `export`\r\n * options.\r\n */\r\nfunction _handleSize(exportOptions) {\r\n // Check the `options` and `instr` for chart and exporting sections\r\n const { chart: optionsChart, exporting: optionsExporting } =\r\n 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 `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 // Find the `scale` value:\r\n // - Cannot be lower than 0.1\r\n // - Cannot be higher than 5.0\r\n // - 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 // Update `height`, `width`, and `scale` information in the `export` options\r\n exportOptions.height = height;\r\n exportOptions.width = width;\r\n exportOptions.scale = scale;\r\n\r\n // Get rid of potential `px` and `%`\r\n for (let param of ['height', 'width', 'scale']) {\r\n if (typeof exportOptions[param] === 'string') {\r\n exportOptions[param] = +exportOptions[param].replace(/px|%/gi, '');\r\n }\r\n }\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 configuration object containing\r\n * `customLogic` options.\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) {\r\n // In case of allowing code execution\r\n if (customLogicOptions.allowCodeExecution) {\r\n // Process the `resources` option\r\n try {\r\n // Try to handle resources\r\n customLogicOptions.resources = _handleResources(\r\n customLogicOptions.resources,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate option\r\n customLogicOptions.resources = validateOption(\r\n 'resources',\r\n customLogicOptions.resources\r\n );\r\n } catch (error) {\r\n log(2, '[chart] The `resources` cannot be loaded.');\r\n\r\n // In case of an error, set the option with null\r\n customLogicOptions.resources = null;\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 = _handleCustomCode(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.customCode = validateOption(\r\n 'customCode',\r\n customLogicOptions.customCode\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 = _handleCustomCode(\r\n customLogicOptions.callback,\r\n customLogicOptions.allowFileResources,\r\n true\r\n );\r\n\r\n // Validate the option\r\n customLogicOptions.callback = validateOption(\r\n 'callback',\r\n customLogicOptions.callback\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 let handledResources = resources;\r\n\r\n // If no resources found, try to load the default resources\r\n if (!handledResources) {\r\n resources = 'resources.json';\r\n }\r\n\r\n // List of allowed sections in the resources JSON\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n // A flag that decides based to return resources or `null`\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (\r\n allowFileResources &&\r\n typeof resources === 'string' &&\r\n resources.endsWith('.json')\r\n ) {\r\n handledResources = isAllowedConfig(\r\n readFileSync(getAbsolutePath(resources), 'utf8'),\r\n false,\r\n allowCodeExecution\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 custom code to execute it safely.\r\n *\r\n * @function _handleCustomCode\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\nfunction _handleCustomCode(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 ? _handleCustomCode(\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\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 configuration object containing `export`\r\n * options.\r\n * @param {Object} customLogicOptions - The configuration object containing\r\n * `customLogic` options.\r\n */\r\nfunction _handleGlobalAndTheme(exportOptions, customLogicOptions) {\r\n // Get the `allowFileResources` and `allowCodeExecution` flags\r\n const { allowFileResources, allowCodeExecution } = customLogicOptions;\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 // Validate the option\r\n exportOptions[optionsName] = validateOption(\r\n optionsName,\r\n exportOptions[optionsName]\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\n/**\r\n * Validates the size of the data for the export process against a fixed limit\r\n * of 100MB.\r\n *\r\n * @function _checkDataSize\r\n *\r\n * @param {Object} imageOptions - The data object, which includes options from\r\n * the `export` and `customLogic` sections and will be sent to a Puppeteer page.\r\n *\r\n * @throws {ExportError} Throws an `ExportError` if the size of the data for\r\n * the export process object exceeds the 100MB limit.\r\n */\r\nfunction _checkDataSize(imageOptions) {\r\n // Set the fixed data limit (100MB) for the dev-tools protocol\r\n const dataLimit = 100 * 1024 * 1024;\r\n\r\n // Get the size of the data\r\n const totalSize = Buffer.byteLength(JSON.stringify(imageOptions), 'utf-8');\r\n\r\n // Log the size in MB\r\n log(\r\n 3,\r\n `[chart] The current total size of the data for the export process is around ${(\r\n totalSize /\r\n (1024 * 1024)\r\n ).toFixed(2)}MB.`\r\n );\r\n\r\n // Check the size of data before passing to a page\r\n if (totalSize >= dataLimit) {\r\n throw new ExportError(\r\n `[chart] The data for the export process exceeds 100MB limit.`\r\n );\r\n }\r\n}\r\n\r\nexport default {\r\n singleExport,\r\n batchExport,\r\n startExport,\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 to avoid potential\r\n * memory leaks, unintended behavior or a process from being stopped.\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 { 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 * @param {Object} rateLimitingOptions - The configuration object containing\r\n * `rateLimiting` options.\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(app, rateLimitingOptions) {\r\n try {\r\n // Check if the rate limiting is enabled and the app exists\r\n if (app && rateLimitingOptions.enable) {\r\n const message =\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 window: rateLimitingOptions.window || 1,\r\n maxRequests: rateLimitingOptions.maxRequests || 30,\r\n delay: rateLimitingOptions.delay || 0,\r\n trustProxy: rateLimitingOptions.trustProxy || false,\r\n skipKey: rateLimitingOptions.skipKey || null,\r\n skipToken: rateLimitingOptions.skipToken || null\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 // Time frame for which requests are checked and remembered\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per `windowMs`\r\n limit: rateOptions.maxRequests,\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 });\r\n },\r\n default: () => {\r\n response.status(429).send(message);\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 !== null &&\r\n rateOptions.skipToken !== null &&\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.maxRequests} 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\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 { isObjectEmpty, isPrivateRangeUrlFound } from '../../utils.js';\r\n\r\nimport ExportError from '../../errors/ExportError.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 {ExportError} Throws an `ExportError` 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 ExportError(\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 {ExportError} Throws an `ExportError` if the body is not correct.\r\n * @throws {ExportError} Throws an `ExportError` if the chart data from the body\r\n * is not correct.\r\n * @throws {ExportError} Throws an `ExportError` in case of the private range\r\n * url 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();\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 ExportError(\r\n `[validation] Request [${requestId}] - 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 ExportError(\r\n `[validation] Request [${requestId}] - 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 ExportError(\r\n `[validation] Request [${requestId}] - 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 and pre-validate the options and store them in the request\r\n request.validatedOptions = {\r\n // Set the created ID as a `requestId` property in the options\r\n 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'}.${body.type || 'png'}`,\r\n type: body.type,\r\n constr: 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 ExportError from '../../errors/ExportError.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 options = request.validatedOptions;\r\n\r\n // Get the request id\r\n const requestId = options.requestId;\r\n\r\n // Info about an incoming request with correct data\r\n log(4, `[export] Request [${requestId}] - Got an incoming HTTP request.`);\r\n\r\n // Start the export process\r\n await startExport(options, (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 ExportError(\r\n `[export] Request [${requestId}] - 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 { getHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { getPoolInfoJSON, getPoolStats } 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(\r\n readFileSync(join(__dirname, 'package.json'), 'utf8')\r\n);\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: getHcVersion(),\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 { log } from '../../logger.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 // Add the UI endpoint only if required\r\n if (getOptions().ui.enable) {\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 log(4, '[ui] Returning UI for the export.');\r\n\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\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 { getHcVersion, updateHcVersion } from '../../cache.js';\r\nimport { log } from '../../logger.js';\r\nimport { envs } from '../../validation.js';\r\n\r\nimport ExportError from '../../errors/ExportError.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 log(4, '[version] Changing Highcharts version.');\r\n\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 ExportError(\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 ExportError(\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 // Get the new version from the params\r\n const newVersion = request.params.newVersion;\r\n\r\n // Update version\r\n if (newVersion) {\r\n try {\r\n await updateHcVersion(newVersion);\r\n } catch (error) {\r\n throw new ExportError(\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: getHcVersion(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new ExportError('[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, middlewares 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 { readFileSync } from 'fs';\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 { updateOptions } 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 an HTTP and/or HTTPS server based on the provided configuration.\r\n * The `serverOptions` object contains server-related properties (refer\r\n * to the `server` section in the `./lib/schemas/config.js` file for details).\r\n *\r\n * @async\r\n * @function startServer\r\n *\r\n * @param {Object} [serverOptions={}] - The configuration object containing\r\n * `server` options. This object may include a partial or complete set\r\n * of the `server` options. If the options are partial, missing values will\r\n * default to the current global configuration. The default value is an empty\r\n * object.\r\n *\r\n * @returns {Promise} A Promise that resolves when the server is either\r\n * not enabled or no valid Express app is found, signaling the end of the\r\n * function's execution.\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 = {}) {\r\n try {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: serverOptions\r\n });\r\n\r\n // Use validated options\r\n serverOptions = options.server;\r\n\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 = readFileSync(\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 = readFileSync(\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 exportRoutes(app);\r\n healthRoutes(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 - The configuration object containing\r\n * `rateLimiting` options. This object may include a partial or complete set\r\n * of the `rateLimiting` options. If the options are partial, missing values\r\n * will default to the current global configuration.\r\n */\r\nexport function enableRateLimiting(rateLimitingOptions) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n server: {\r\n rateLimiting: rateLimitingOptions\r\n }\r\n });\r\n\r\n // Set the rate limiting options\r\n rateLimitingMiddleware(app, options.server.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\n\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Performs cleanup operations to ensure a graceful shutdown of the process.\r\n * This includes clearing all registered timeouts/intervals, closing active\r\n * servers, terminating resources (pages) of the pool, pool itself, and closing\r\n * the browser.\r\n *\r\n * @function shutdownCleanUp\r\n *\r\n * @param {number} [exitCode=0] - The exit code to use with `process.exit()`.\r\n * The default value is `0`.\r\n */\r\nexport async function shutdownCleanUp(exitCode = 0) {\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 This core module initializes and manages the Highcharts Export\r\n * Server. The main `initExport` function handles logging, script caching,\r\n * resource pooling, browser startup, and ensures graceful process cleanup\r\n * on exit. Additionally, it provides API functions for using it as a Node.js\r\n * module, offering functionalities for processing options, configuring\r\n * and performing exports, and setting up server.\r\n */\r\n\r\nimport 'colors';\r\n\r\nimport { checkCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n singleExport,\r\n startExport,\r\n setAllowCodeExecution\r\n} from './chart.js';\r\nimport {\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n validateOption,\r\n validateOptions\r\n} from './config.js';\r\nimport {\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n initLogging,\r\n enableConsoleLogging,\r\n enableFileLogging,\r\n setLogLevel\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resourceRelease.js';\r\n\r\nimport server 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.\r\n *\r\n * 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} [initOptions={}] - The `initOptions` object, which may\r\n * be a partial or complete set of options. If the options are partial, missing\r\n * values will default to the current global configuration. The default value\r\n * is an empty object.\r\n */\r\nexport async function initExport(initOptions = {}) {\r\n // Init, validate and update the options object\r\n const options = updateOptions(initOptions);\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 the current status of cache\r\n await checkCache(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();\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();\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();\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\r\n // Options\r\n getOptions,\r\n updateOptions,\r\n mapToNewOptions,\r\n\r\n // Validation\r\n validateOption,\r\n validateOptions,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Release\r\n killPool,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n logZodIssues,\r\n setLogLevel: function (level) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n level\r\n }\r\n });\r\n\r\n // Call the function\r\n setLogLevel(options.logging.level);\r\n },\r\n enableConsoleLogging: function (toConsole) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n toConsole\r\n }\r\n });\r\n\r\n // Call the function\r\n enableConsoleLogging(options.logging.toConsole);\r\n },\r\n enableFileLogging: function (dest, file, toFile) {\r\n // Update the instance options object\r\n const options = updateOptions({\r\n logging: {\r\n dest,\r\n file,\r\n toFile\r\n }\r\n });\r\n\r\n // Call the function\r\n enableFileLogging(\r\n options.logging.dest,\r\n options.logging.file,\r\n options.logging.toFile\r\n );\r\n }\r\n};\r\n"],"names":["__dirname","fileURLToPath","URL","url","deepCopy","objArr","objArrCopy","Array","isArray","key","Object","prototype","hasOwnProperty","call","getAbsolutePath","path","isAbsolute","normalize","resolve","getBase64","input","type","Buffer","from","toString","getNewDate","Date","split","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","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","shift","logZodIssues","issues","map","issue","join","initLogging","loggingOptions","dest","file","setLogLevel","enableConsoleLogging","enableFileLogging","isInteger","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","outfile","hint","choices","constr","b64","noDownload","height","width","scale","defaultHeight","defaultWidth","defaultScale","min","max","globalOptions","themeOptions","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","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","validation","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","dotenv","config","z","setErrorMap","_customErrorMap","v","boolean","strictCheck","union","enum","transform","includes","nullable","string","refine","params","errorMessage","values","stringArray","filterCallback","arraySchema","array","stringSchema","startsWith","slice","endsWith","transformCallback","filter","positiveNum","number","positive","isNaN","nonNegativeNum","nonnegative","prefixes","chartConfig","object","passthrough","additionalOptions","validators","adminToken","indexOf","gte","lte","this","objectSchema","js","css","files","partial","stringSchema1","stringSchema2","enableServer","serverBenchmarking","proxyHost","proxyPort","proxyTimeout","enableRateLimiting","enableSsl","sslForce","sslPort","sslCertPath","poolBenchmarking","resourcesInterval","logLevel","int","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","OTHER_VALIDATION","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","envs","parse","env","strictValidate","configOptions","looseValidate","context","propertyName","propertyInfo","code","ZodIssueCode","invalid_type","received","ZodParsedType","defaultError","custom","data","invalid_union","unionErrors","forEach","index","substring","ExportError","Error","constructor","statusCode","super","setError","name","_initOptions","nestedProps","_createNestedProps","absoluteProps","_createAbsoluteProps","getOptions","getCopy","updateOptions","newOptions","_mergeOptions","validateOptions","mapToNewOptions","oldOptions","entries","propertiesChain","reduce","obj","prop","validateOption","configOption","isAllowedConfig","allowFunctions","objectConfig","eval","JSON","stringifiedOptions","_optionsStringify","parsedOptions","_","originalOptions","stringifyFunctions","stringify","replaceAll","propChain","entry","async","get","requestOptions","Promise","reject","_getProtocolModule","response","responseData","on","chunk","text","https","http","cache","activeManifest","sources","hcVersion","checkCache","highchartsOptions","serverProxyOptions","fetchedModules","getCachePath","manifestPath","sourcePath","recursive","_updateCache","requestUpdate","manifest","readFileSync","modules","moduleMap","m","numberOfModules","moduleName","_extractHcVersion","_saveConfigToManifest","getHcVersion","updateHcVersion","newVersion","writeFileSync","_configureRequest","all","cs","_fetchScript","ms","is","script","shouldThrowError","_extractModuleName","agent","HttpsProxyAgent","cacheSources","replace","scriptPath","setupHighcharts","Highcharts","animObject","duration","createChart","exportOptions","customLogicOptions","setOptions","merge","wrap","setOptionsObj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","animation","onHighchartsRender","addEvent","Series","chart","Function","finalOptions","finalCallback","images","document","querySelectorAll","race","image","complete","naturalHeight","addEventListener","once","setTimeout","defaultOptions","pageTemplate","browser","createBrowser","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","openBrowser","launch","closeBrowser","connected","close","newPage","poolResource","page","setCacheEnabled","_setPageContent","_setPageEvents","isClosed","clearPage","hardReset","goto","waitUntil","evaluate","body","innerHTML","id","workCount","addPageResources","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","isSVG","size","_getChartSize","x","y","_getClipRegion","viewportHeight","abs","ceil","chartHeight","viewportWidth","chartWidth","result","setViewport","deviceScaleFactor","parseFloat","_createSVG","_createImage","_createPDF","$eval","getBoundingClientRect","trunc","svgElement","querySelector","baseVal","style","zoom","margin","outerHTML","clip","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","i","acquire","promise","release","killPool","worker","used","destroyed","postWork","workerHandle","_getPoolInfo","acquireCounter","exportCounter","exportResult","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","imageOptions","endCallback","fileContent","_exportFromSvg","_exportFromOptions","getAllowCodeExecution","setAllowCodeExecution","inputToExport","_prepareExport","_fixConstr","_fixType","_fixOutfile","_handleCustomLogic","_handleGlobalAndTheme","_handleSize","_checkDataSize","fixedConstr","toLowerCase","mimeTypes","formats","outType","pop","find","t","optionsChart","optionsExporting","globalOptionsChart","globalOptionsExporting","themeOptionsChart","themeOptionsExporting","sourceHeight","sourceWidth","param","_handleResources","_handleCustomCode","handledResources","allowedProps","correctResources","propName","isCallback","optionsName","totalSize","byteLength","toFixed","timerIds","addTimer","clearAllTimers","clearInterval","clearTimeout","logErrorMiddleware","request","next","returnErrorMiddleware","status","json","errorMiddleware","app","use","rateLimitingMiddleware","rateLimitingOptions","rateOptions","limiter","rateLimit","windowMs","limit","delayMs","handler","format","send","default","skip","query","access_token","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","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","urlencoded","extended","none","static","httpServer","createServer","_attachServerErrorHandlers","listen","cert","httpsServer","closeServers","delete","getServers","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","exit","initExport","initOptions","_attachProcessExitListeners"],"mappings":"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SAGVwF,WAAY,CACV9D,OAAO,EACPqD,MAAO,CAAC,WACRC,QAAS,yBACTE,YAAa,kDACbC,cAAe,CACbnF,KAAM,WAGVyF,UAAW,CACT/D,MAAO,SACPqD,MAAO,CAAC,UACRC,QAAS,wBACTE,YAAa,+CACbC,cAAe,CACbnF,KAAM,SAGV0F,YAAa,CACXhE,MAAO,CAAC,aAAc,kBAAmB,iBACzCqD,MAAO,CAAC,YACRC,QAAS,0BACTE,YAAa,mCACbC,cAAe,CACbnF,KAAM,cACN2F,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,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBE,iBAAkB,CAChBnE,MAAO,CAAC,kBACRqD,MAAO,CAAC,YACRC,QAAS,+BACTE,YAAa,wCACbC,cAAe,CACbnF,KAAM,cACN2F,aAAc,0DAGlBG,cAAe,CACbpE,MAAO,CACL,wEACA,kGAEFqD,MAAO,CAAC,YACRC,QAAS,4BACTE,YAAa,qDACbC,cAAe,CACbnF,KAAM,OACNoF,UAAW,OAIjBW,OAAQ,CACNC,OAAQ,CACNtE,MAAO,KACPqD,MAAO,CAAC,SAAU,QAClBC,QAAS,gBACTE,YACE,+DACFC,cAAe,CACbnF,KAAM,SAGViG,MAAO,CACLvE,MAAO,KACPqD,MAAO,CAAC,SAAU,SAAU,QAC5BC,QAAS,eACTE,YACE,mEACFC,cAAe,CACbnF,KAAM,SAGVkG,QAAS,CACPxE,MAAO,KACPqD,MAAO,CAAC,SAAU,S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"} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index ae550f9b..72b7272d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1371,258 +1371,6 @@ } } }, - "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.34.0.tgz", - "integrity": "sha512-Eeao7ewDq79jVEsrtWIj5RNqB8p2knlm9fhR6uJ2gqP7UfbLrTrxevudVrEPDM7Wkpn/HpRC2QfazH7MXLz3vQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-android-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.34.0.tgz", - "integrity": "sha512-yVh0Kf1f0Fq4tWNf6mWcbQBCLDpDrDEl88lzPgKhrgTcDrTtlmun92ywEF9dCjmYO3EFiSuJeeo9cYRxl2FswA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ] - }, - "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.34.0.tgz", - "integrity": "sha512-gCs0ErAZ9s0Osejpc3qahTsqIPUDjSKIyxK/0BGKvL+Tn0n3Kwvj8BrCv7Y5sR1Ypz1K2qz9Ny0VvkVyoXBVUQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.34.0.tgz", - "integrity": "sha512-aIB5Anc8hngk15t3GUkiO4pv42ykXHfmpXGS+CzM9CTyiWyT8HIS5ygRAy7KcFb/wiw4Br+vh1byqcHRTfq2tQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.34.0.tgz", - "integrity": "sha512-kpdsUdMlVJMRMaOf/tIvxk8TQdzHhY47imwmASOuMajg/GXpw8GKNd8LNwIHE5Yd1onehNpcUB9jHY6wgw9nHQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.34.0.tgz", - "integrity": "sha512-D0RDyHygOBCQiqookcPevrvgEarN0CttBecG4chOeIYCNtlKHmf5oi5kAVpXV7qs0Xh/WO2RnxeicZPtT50V0g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.34.0.tgz", - "integrity": "sha512-mCIw8j5LPDXmCOW8mfMZwT6F/Kza03EnSr4wGYEswrEfjTfVsFOxvgYfuRMxTuUF/XmRb9WSMD5GhCWDe2iNrg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.34.0.tgz", - "integrity": "sha512-AwwldAu4aCJPob7zmjuDUMvvuatgs8B/QiVB0KwkUarAcPB3W+ToOT+18TQwY4z09Al7G0BvCcmLRop5zBLTag==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.34.0.tgz", - "integrity": "sha512-e7kDUGVP+xw05pV65ZKb0zulRploU3gTu6qH1qL58PrULDGxULIS0OSDQJLH7WiFnpd3ZKUU4VM3u/Z7Zw+e7Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.34.0.tgz", - "integrity": "sha512-SXYJw3zpwHgaBqTXeAZ31qfW/v50wq4HhNVvKFhRr5MnptRX2Af4KebLWR1wpxGJtLgfS2hEPuALRIY3LPAAcA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.34.0.tgz", - "integrity": "sha512-e5XiCinINCI4RdyU3sFyBH4zzz7LiQRvHqDtRe9Dt8o/8hTBaYpdPimayF00eY2qy5j4PaaWK0azRgUench6WQ==", - "cpu": [ - "loong64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.34.0.tgz", - "integrity": "sha512-3SWN3e0bAsm9ToprLFBSro8nJe6YN+5xmB11N4FfNf92wvLye/+Rh5JGQtKOpwLKt6e61R1RBc9g+luLJsc23A==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.34.0.tgz", - "integrity": "sha512-B1Oqt3GLh7qmhvfnc2WQla4NuHlcxAD5LyueUi5WtMc76ZWY+6qDtQYqnxARx9r+7mDGfamD+8kTJO0pKUJeJA==", - "cpu": [ - "riscv64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.34.0.tgz", - "integrity": "sha512-UfUCo0h/uj48Jq2lnhX0AOhZPSTAq3Eostas+XZ+GGk22pI+Op1Y6cxQ1JkUuKYu2iU+mXj1QjPrZm9nNWV9rg==", - "cpu": [ - "s390x" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.34.0.tgz", - "integrity": "sha512-chZLTUIPbgcpm+Z7ALmomXW8Zh+wE2icrG+K6nt/HenPLmtwCajhQC5flNSk1Xy5EDMt/QAOz2MhzfOfJOLSiA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.34.0.tgz", - "integrity": "sha512-jo0UolK70O28BifvEsFD/8r25shFezl0aUk2t0VJzREWHkq19e+pcLu4kX5HiVXNz5qqkD+aAq04Ct8rkxgbyQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.34.0.tgz", - "integrity": "sha512-Vmg0NhAap2S54JojJchiu5An54qa6t/oKT7LmDaWggpIcaiL8WcWHEN6OQrfTdL6mQ2GFyH7j2T5/3YPEDOOGA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.34.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.34.0.tgz", - "integrity": "sha512-CV2aqhDDOsABKHKhNcs1SZFryffQf8vK2XrxP6lxC99ELZAdvsDgPklIBfd65R8R+qvOm1SmLaZ/Fdq961+m7A==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@rollup/rollup-win32-x64-msvc": { "version": "4.34.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.34.0.tgz", @@ -4319,21 +4067,6 @@ "dev": true, "license": "ISC" }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" - } - }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",