diff --git a/CHANGELOG.md b/CHANGELOG.md index 0bbd3691..1c27b07c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,9 @@ _Fixes:_ - Fixed an issue where the chart constructor was sometimes incorrectly set, causing the export to fail - Added referrers to CDN cache fetches on first startup/install. - Fixed an issue that would sometimes cause cause a crash due to fail due to `Accept-Ranges` headers -- Corrected the `Node.js Module` example in the README. +- Wrapped the `clearPageResources` function in a try-catch to handle potential page resources errors. +- Secured against errors caused by `dev-tools` protocol data size limitations. +- Corrected the `Node.js Module` example in the README. - Fixed the warning message when the the default `resources.json` file is not found. - Fixed the problem with the lack of the `instr` value, when the `options` is set instead @@ -20,7 +22,6 @@ _New Features:_ - Added proxy authentication [(#631)](https://github.com/highcharts/node-export-server/issues/631). - Made the temporary Puppeteer directory (`PUPPETEER_TEMP_DIR`) (till now, `'./tmp'`) configurable by the user [(#567)](https://github.com/highcharts/node-export-server/issues/567). - # 4.0.2 _Hotfix_: diff --git a/dist/index.cjs b/dist/index.cjs index 70ce65cd..858eadf1 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -1,3 +1,3 @@ -"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),h=require("puppeteer"),u=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;const b={core:["highcharts","highcharts-more","highcharts-3d"],modules:["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"],indicators:["indicators-all"],custom:["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"]},w={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"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:b.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:b.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:b.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:b.custom,type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{maxUploadSize:{value:3,type:"number",cliName:"maxUploadSize",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in megabytes, for the server"},enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},E={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:w.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:w.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:w.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:w.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:w.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:w.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${w.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${w.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:w.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:w.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:w.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:w.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:w.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:w.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:w.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:w.server.host.value},{type:"number",name:"port",message:"Server port",initial:w.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:w.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:w.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:w.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:w.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:w.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:w.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:w.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:w.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:w.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:w.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:w.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:w.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:w.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:w.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:w.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:w.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:w.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:w.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:w.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:w.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:w.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:w.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:w.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:w.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:w.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:w.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:w.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:w.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:w.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:w.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:w.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:w.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:w.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:w.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:w.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:w.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:w.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:w.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:w.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:w.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:w.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:w.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:w.debug.debuggingPort.value}]},T=["options","globalOptions","themeOptions","resources","payload"],S={},x=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?x(o,`${t}.${r}`):(S[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(S[o.legacyName]=`${t}.${r}`.substring(1)))}}))};x(w),i.config();const R=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),L=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),_=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),k=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),I=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),C=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:R(b.core),HIGHCHARTS_MODULE_SCRIPTS:R(b.modules),HIGHCHARTS_INDICATOR_SCRIPTS:R(b.indicators),HIGHCHARTS_FORCE_FETCH:L(),HIGHCHARTS_CACHE_PATH:_(),HIGHCHARTS_ADMIN_TOKEN:_(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:k(),EXPORT_DEFAULT_WIDTH:k(),EXPORT_DEFAULT_SCALE:k(),EXPORT_RASTERIZATION_TIMEOUT:I(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:L(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:L(),SERVER_ENABLE:L(),SERVER_HOST:_(),SERVER_PORT:k(),SERVER_BENCHMARKING:L(),SERVER_PROXY_HOST:_(),SERVER_PROXY_PORT:k(),SERVER_PROXY_TIMEOUT:I(),SERVER_RATE_LIMITING_ENABLE:L(),SERVER_RATE_LIMITING_MAX_REQUESTS:I(),SERVER_RATE_LIMITING_WINDOW:I(),SERVER_RATE_LIMITING_DELAY:I(),SERVER_RATE_LIMITING_TRUST_PROXY:L(),SERVER_RATE_LIMITING_SKIP_KEY:_(),SERVER_RATE_LIMITING_SKIP_TOKEN:_(),SERVER_SSL_ENABLE:L(),SERVER_SSL_FORCE:L(),SERVER_SSL_PORT:k(),SERVER_SSL_CERT_PATH:_(),POOL_MIN_WORKERS:I(),POOL_MAX_WORKERS:I(),POOL_WORK_LIMIT:k(),POOL_ACQUIRE_TIMEOUT:I(),POOL_CREATE_TIMEOUT:I(),POOL_DESTROY_TIMEOUT:I(),POOL_IDLE_TIMEOUT:I(),POOL_CREATE_RETRY_INTERVAL:I(),POOL_REAPER_INTERVAL:I(),POOL_BENCHMARKING:L(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:_(),LOGGING_DEST:_(),LOGGING_TO_CONSOLE:L(),LOGGING_TO_FILE:L(),UI_ENABLE:L(),UI_ROUTE:_(),OTHER_NODE_ENV:O(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:L(),OTHER_NO_LOGO:L(),OTHER_HARD_RESET_PAGE:L(),OTHER_BROWSER_SHELL_MODE:L(),DEBUG_ENABLE:L(),DEBUG_HEADLESS:L(),DEBUG_DEVTOOLS:L(),DEBUG_LISTEN_TO_CONSOLE:L(),DEBUG_DUMPIO:L(),DEBUG_SLOW_MO:I(),DEBUG_DEBUGGING_PORT:k()}).partial().parse(process.env),N=["red","yellow","blue","gray","green"];let A={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:N[0]},{title:"warning",color:N[1]},{title:"notice",color:N[2]},{title:"verbose",color:N[3]},{title:"benchmark",color:N[4]}],listeners:[]};const P=(t,r)=>{A.pathCreated||(!e.existsSync(A.dest)&&e.mkdirSync(A.dest),A.pathCreated=!0),e.appendFile(`${A.dest}${A.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),A.toFile=!1)}))},H=(...e)=>{const[t,...r]=e,{levelsDesc:o,level:i}=A;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;A.listeners.forEach((e=>{e(n,r.join(" "))})),A.toConsole&&console.log.apply(void 0,[n.toString()[A.levelsDesc[t-1].color]].concat(r)),A.toFile&&P(r,n)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=A;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];A.toConsole&&console.log.apply(void 0,[s.toString()[A.levelsDesc[e-1].color]].concat([o[N[e-1]],"\n",a])),A.listeners.forEach((e=>{e(s,l.join(" "))})),A.toFile&&P(l,s)},G=e=>{e>=0&&e<=A.levelsDesc.length&&(A.level=e)},D=(e,t)=>{if(A={...A,dest:e||A.dest,file:t||A.file,toFile:!0},0===A.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");A.dest.endsWith("/")||(A.dest+="/")},U=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&"SCRIPT"===y.tagName.toUpperCase()&&y.src||new URL("index.cjs",document.baseURI).href)),F=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},j=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=M(e.readFileSync(t,"utf8"))}catch(e){return $(2,e,"[cli] No resources found.")}else i=M(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):H(3,"[cli] No resources found.")};function M(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const q=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=q(e[r]));return t},W=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function V(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const B=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,z=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&z(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},X=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let K={};const J=()=>K,Y=(e,t,r=[])=>{const o=q(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Y(o[e],n,r);var i;return o};function Z(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?Z(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in C&&void 0!==C[i.envLink]&&(i.value=C[i.envLink]))}))}function Q(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:Q(o);return t}function ee(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ee(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function te(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,Object.assign({headers:{"User-Agent":"highcharts/export",Referer:"highcharts/export"}},t||{}),(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class re extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}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 oe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ie=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ne=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const i=await te(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new re(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return H(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},se=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||oe.cdnURL;H(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return oe.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,l=i.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new re("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:C.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ne(`${e}`,c,n,!0))),...t.map((e=>ne(`${e}`,c,n))),...o.map((e=>ne(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,l),oe.hcVersion=ie(oe),e.writeFileSync(i,oe.sources),l}catch(e){throw new re("[cache] Unable to update the local Highcharts cache.").setError(e)}},ae=async r=>{const{highcharts:o,server:i}=r,n=t.join(U,o.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),s=await se(o,i.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=o,h=n.length+c.length+p.length;r.version!==o.version?(H(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==h?(H(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return H(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await se(o,i.proxy,l):(H(3,"[cache] Dependency cache is up to date, proceeding."),oe.sources=e.readFileSync(l,"utf8"),s=r.modules,oe.hcVersion=ie(oe))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};oe.activeManifest=i,H(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(U,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new re("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},le=()=>t.join(U,J().highcharts.cachePath),ce=()=>oe.hcVersion;function pe(){Highcharts.animObject=function(){return{duration:0}}}async function he(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o());const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((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,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e;t.customLogic.customCode&&new Function("options",t.customLogic.customCode)(l);const c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&n(h);let u=t.export.constr||"chart";u=void 0!==Highcharts[u]?u:"chart",Highcharts[u]("container",c,p);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ue=e.readFileSync(U+"/templates/template.html","utf8");let de;async function ge(){if(!de)return!1;const e=await de.newPage();return await e.setCacheEnabled(!1),await fe(e),function(e){const{debug:t}=J();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{e.isClosed()||await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function me(e,t){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"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function fe(e){await e.setContent(ue,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${le()}/sources.js`}),await e.evaluate(pe)}const ve=async(e,t,r,o)=>e.evaluate(he,t,r,o);var ye=async(r,o,i)=>{let n=[];try{H(4,"[export] Determining export path.");const s=i.export,a=s?.options?.chart?.displayErrors&&oe.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===s.type)return o;l=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else H(4,"[export] Treating as config."),s.strInj?await ve(r,{chart:{height:s.height,width:s.width}},i,a):(o.chart.height=s.height,o.chart.width=s.width,await ve(r,o,i,a));n=await async function(r,o){const i=[],n=o.customLogic.resources;if(n){const s=[];if(n.js&&s.push({content:n.js}),n.files)for(const t of n.files){const r=!t.startsWith("http");s.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of s)try{i.push(await r.addScriptTag(e))}catch(e){$(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(n.css){let e=n.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?a.push({url:r}):o.customLogic.allowFileResources&&a.push({path:t.join(U,r)}));a.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){$(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(r,i);const c=l?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.abs(Math.ceil(c.chartHeight||s.height)),h=Math.abs(Math.ceil(c.chartWidth||s.width)),{x:u,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let g;if(await r.setViewport({height:p,width:h,deviceScaleFactor:l?1:parseFloat(s.scale)}),"svg"===s.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(s.type))g=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout"))),i||1500)))]))(r,s.type,"base64",{width:h,height:p,x:u,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new re(`[export] Unsupported output format ${s.type}.`);g=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o,timeout:i||1500})))(r,p,h,"base64",s.rasterizationTimeout)}return await me(r,n),g}catch(e){return await me(r,n),e}};let be=!1;const we={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ee={};const Te={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new re("The page is invalid or closed.");H(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new re("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Ee.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Ee.workLimit&&++e.workCount>Ee.workLimit)||(H(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ee.workLimit}).`),!1)),destroy:async e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},Se=async e=>{if(Ee=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=J(),{enable:o,...i}=t,n={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!de){let e=0;const t=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),de=await h.launch(n)}catch(r){if($(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;H(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&&H(3,"[browser] Launched browser in shell mode."),o&&H(3,"[browser] Launched browser in debug mode.")}catch(e){throw new re("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!de)throw new re("[browser] Cannot find a browser to open.")}return de}(e.puppeteerArgs),H(3,`[pool] Initializing pool with workers: min ${Ee.minWorkers}, max ${Ee.maxWorkers}.`),be)return H(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ee.minWorkers)>parseInt(Ee.maxWorkers)&&(Ee.minWorkers=Ee.maxWorkers);try{be=new c.Pool({...Te,min:parseInt(Ee.minWorkers),max:parseInt(Ee.maxWorkers),acquireTimeoutMillis:Ee.acquireTimeout,createTimeoutMillis:Ee.createTimeout,destroyTimeoutMillis:Ee.destroyTimeout,idleTimeoutMillis:Ee.idleTimeout,createRetryIntervalMillis:Ee.createRetryInterval,reapIntervalMillis:Ee.reaperInterval,propagateCreateError:!1}),be.on("release",(async e=>{const t=await async function(e,t=!1){try{if(e&&!e.isClosed())return t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await fe(e)):await e.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(e){$(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);H(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),be.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{be.release(e)})),H(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new re("[pool] Could not create the pool of workers.").setError(e)}};async function xe(){if(H(3,"[pool] Killing pool with all workers and closing browser."),be){for(const e of be.used)be.release(e.resource);be.destroyed||(await be.destroy(),H(4,"[browser] Destroyed the pool of resources."))}await async function(){de?.connected&&await de.close(),H(4,"[browser] Closed the browser.")}()}const Re=async(e,t)=>{let r;try{if(H(4,"[pool] Work received, starting to process."),++we.exportAttempts,Ee.benchmarking&&Oe(),!be)throw new re("Work received, but pool has not been started.");const o=X();try{H(4,"[pool] Acquiring a worker handle."),r=await be.acquire().promise,t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(H(4,"[pool] Acquired a worker handle."),!r.page)throw new re("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=X(),s=await ye(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.workCount=Ee.workLimit+1,r.page=null),"TimeoutError"===s.name||"Rasterization timeout"===s.message?new re("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(s):new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),be.release(r);const a=(new Date).getTime()-i;return we.timeSpent+=a,we.spentAverage=we.timeSpent/++we.performedExports,H(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++we.droppedExports,r&&be.release(r),new re(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Le=()=>({min:be.min,max:be.max,all:be.numFree()+be.numUsed(),available:be.numFree(),used:be.numUsed(),pending:be.numPendingAcquires()});function Oe(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Le();H(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(5,`[pool] The number of all created resources: ${r}.`),H(5,`[pool] The number of available resources: ${o}.`),H(5,`[pool] The number of acquired resources: ${i}.`),H(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var _e=Le,ke=()=>we;let Ie=!1;const Ce=async(t,r)=>{H(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=q(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Y(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,J()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{H(4,"[chart] Attempting to export from a SVG input.");const e=He(function(e){const t=new u.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:["xlink:href"]})}(o.payload.svg),o,r);return++we.exportFromSvgAttempts,e}catch(e){return r(new re("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return H(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),He(o.export.instr.trim(),o,r)}catch(e){return r(new re("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return H(4,"[chart] Attempting to export from a raw input."),B(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?He(i.instr.trim(),o,r):Ae(o,i.instr||i.options,r)}catch(e){return r(new re("[chart] Error loading raw input.").setError(e))}return r(new re("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ne=e=>{const{chart:t,exporting:r}=e.export?.options||M(e.export?.instr),o=M(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},Ae=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ie;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=j(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=j(r,B(t.customLogic.allowFileResources))}catch(e){$(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new re("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=F(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=M(e.readFileSync(n[t],"utf8"),!0):n[t]=M(n[t],!0))}catch(e){n[t]={},$(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=z(s.customCode,s.allowFileResources)}catch(e){$(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,$(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ne(t)};try{return o(!1,await Re(n.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=W(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ae(e,!1,t)}catch(r){return t(new re(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},He=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),Ae(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ae(t,o,r)}catch(e){return B(o)?Pe(t,r):r(new re("[chart] Only JSON 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 flag.").setError(e))}},$e=[],Ge=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of $e)clearInterval(e)},De=(e,t,r,o)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,o(e)},Ue=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,l=i||n||400;r.status(l).json({statusCode:l,message:s,stack:a})};var Fe=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(H(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),H(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class je extends re{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Me=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=C.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new je("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new je("No new version supplied.",400);try{await(async e=>{const t=J();t?.highcharts&&(t.highcharts.version=e),await ae(t)})(i)}catch(e){throw new je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ce(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let We=0;const Ve=[],Be=[],ze=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Xe=async(e,t,r)=>{try{const r=X(),i=p.v4().replace(/-/g,""),n=J(),s=e.body,a=++We;let l=F(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=M(s.infile||s.options||s.data);if(!c&&!s.svg)throw H(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect:\n Content-Type: ${e.headers["content-type"]}. \n Chart constructor: ${s.constr}.\n Dimensions: ${s.width}x${s.height} @ ${s.scale} scale.\n Type: ${l}.\n Is SVG set? ${void 0!==s.svg}.\n B64? ${void 0!==s.b64}.\n No download? ${void 0!==s.noDownload}.\n\n Payload received: ${JSON.stringify(s.infile||s.options||s.data||s.svg)}\n\n `),new je("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);let h=!1;if(h=ze(Ve,e,t,{id:a,uniqueId:i,type:l,body:s}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(e=>{e&&(u=!0)})),H(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:M(s.globalOptions,!0),themeOptions:M(s.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:M(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=W(c,d.customLogic.allowCodeExecution));const g=Y(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/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))))(g.payload.svg))throw new je("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);await Ce(g,((o,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&H(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),u)return H(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ze(Be,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",qe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const Ke=JSON.parse(e.readFileSync(t.join(U,"package.json"))),Je=new Date,Ye=[];function Ze(e){if(!e)return!1;var t;t=setInterval((()=>{const e=ke(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ye.push(t),Ye.length>30&&Ye.shift()}),6e4),$e.push(t),e.get("/health",((e,t)=>{const r=ke(),o=Ye.length,i=Ye.reduce(((e,t)=>e+t),0)/Ye.length;H(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Je,uptime:Math.floor(((new Date).getTime()-Je.getTime())/1e3/60)+" minutes",version:Ke.version,highchartsVersion:ce(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:_e(),period:o,movingAverage:i,message:isNaN(i)||!Ye.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const Qe=new Map,et=m();et.disable("x-powered-by"),et.use(g()),et.use(((e,t,r)=>{t.set("Accept-Ranges","none"),r()}));const tt=e=>{e.on("clientError",((e,t)=>{$(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{$(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{$(1,e,`[server] Socket error: ${e.message}`)}))}))},rt=async r=>{try{const o=1024*(r.maxUploadSize||3)*1024,i=f.memoryStorage(),n=f({storage:i,limits:{fieldSize:o}});if(et.use(m.json({limit:o})),et.use(m.urlencoded({extended:!0,limit:o})),et.use(n.none()),!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(et);tt(e),e.listen(r.port,r.host),Qe.set(r.port,e),H(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){H(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},et);tt(e),e.listen(r.ssl.port,r.host),Qe.set(r.ssl.port,e),H(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Fe(et,r.rateLimiting),et.use(m.static(t.posix.join(U,"public"))),Ze(et),(e=>{e.post("/",Xe),e.post("/:filename",Xe)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(U,"public","index.html"),{acceptRanges:!1})}))})(et),Me(et),(e=>{e.use(De),e.use(Ue)})(et)}catch(e){throw new re("[server] Could not configure and start the server.").setError(e)}},ot=()=>{H(4,"[server] Closing all servers.");for(const[e,t]of Qe)t.close((()=>{Qe.delete(e),H(4,`[server] Closed server on port: ${e}.`)}))};var it={startServer:rt,closeServers:ot,getServers:()=>Qe,enableRateLimiting:e=>Fe(et,e),getExpress:()=>m,getApp:()=>et,use:(e,...t)=>{et.use(e,...t)},get:(e,...t)=>{et.get(e,...t)},post:(e,...t)=>{et.post(e,...t)}};const nt=async e=>{await Promise.allSettled([Ge(),ot(),xe()]),process.exit(e)};var st={server:it,startServer:rt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=B(t),(e=>{for(const[t,r]of Object.entries(e))A[t]=r;G(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&D(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(H(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{H(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGTERM",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGHUP",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("uncaughtException",(async(e,t)=>{$(1,e,`The ${t} error.`),await nt(1)}))),await ae(e),await Se({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await xe()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await xe()}catch(e){throw new re("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Se,killPool:xe,setOptions:(t,r)=>(r?.length&&(K=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){$(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Z(w,K),K=Q(w),t&&(K=Y(K,t,T)),r?.length&&(K=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=B(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(H(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&V();return e}(K,r,w)),K),shutdownCleanUp:nt,log:H,logWithStack:$,setLogLevel:G,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=S[r]?S[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(E).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)E[e]=E[e].map((t=>({...t,section:e}))),a=[...a,...E[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=ee(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){$(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(U,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(U+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:V};module.exports=st; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBQb3NzaWJsZSBuYW1lcyBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcbiAgbW9kdWxlczogW1xuICAgICdzdG9jaycsXG4gICAgJ21hcCcsXG4gICAgJ2dhbnR0JyxcbiAgICAnZXhwb3J0aW5nJyxcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxuICAgICdhY2Nlc3NpYmlsaXR5JyxcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICdib29zdC1jYW52YXMnLFxuICAgICdib29zdCcsXG4gICAgJ2RhdGEnLFxuICAgICdkYXRhLXRvb2xzJyxcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgJ3N0YXRpYy1zY2FsZScsXG4gICAgJ2Jyb2tlbi1heGlzJyxcbiAgICAnaGVhdG1hcCcsXG4gICAgJ3RpbGVtYXAnLFxuICAgICd0aWxlZHdlYm1hcCcsXG4gICAgJ3RpbWVsaW5lJyxcbiAgICAndHJlZW1hcCcsXG4gICAgJ3RyZWVncmFwaCcsXG4gICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAnZHJpbGxkb3duJyxcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXG4gICAgJ2J1bGxldCcsXG4gICAgJ2Z1bm5lbCcsXG4gICAgJ2Z1bm5lbDNkJyxcbiAgICAnZ2VvaGVhdG1hcCcsXG4gICAgJ3B5cmFtaWQzZCcsXG4gICAgJ25ldHdvcmtncmFwaCcsXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxuICAgICdwYXJldG8nLFxuICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICdwaWN0b3JpYWwnLFxuICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICdzYW5rZXknLFxuICAgICdhcmMtZGlhZ3JhbScsXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICdzZXJpZXMtb24tcG9pbnQnLFxuICAgICdzb2xpZC1nYXVnZScsXG4gICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcbiAgICAnc3RyZWFtZ3JhcGgnLFxuICAgICdzdW5idXJzdCcsXG4gICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgJ3Zhcml3aWRlJyxcbiAgICAndmVjdG9yJyxcbiAgICAndmVubicsXG4gICAgJ3dpbmRiYXJiJyxcbiAgICAnd29yZGNsb3VkJyxcbiAgICAneHJhbmdlJyxcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcbiAgICAnZHJhZy1wYW5lcycsXG4gICAgJ2RlYnVnZ2VyJyxcbiAgICAnZHVtYmJlbGwnLFxuICAgICdsb2xsaXBvcCcsXG4gICAgJ2N5bGluZGVyJyxcbiAgICAnb3JnYW5pemF0aW9uJyxcbiAgICAnZG90cGxvdCcsXG4gICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcbiAgICAnaGVpa2luYXNoaScsXG4gICAgJ2Zsb3dtYXAnLFxuICAgICdleHBvcnQtZGF0YScsXG4gICAgJ25hdmlnYXRvcicsXG4gICAgJ3RleHRwYXRoJ1xuICBdLFxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gIGN1c3RvbTogW1xuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICBdXG59O1xuXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xuICBwdXBwZXRlZXI6IHtcbiAgICBhcmdzOiB7XG4gICAgICB2YWx1ZTogW1xuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxuICAgICAgICAnLS1uby1waW5ncycsXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXG4gICAgICAgICctLW5vLXp5Z290ZScsXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXG4gICAgICBdLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcbiAgICB9XG4gIH0sXG4gIGhpZ2hjaGFydHM6IHtcbiAgICB2ZXJzaW9uOiB7XG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgY2RuVVJMOiB7XG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGNvcmVTY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIG1vZHVsZVNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBjdXN0b21TY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXG4gICAgfSxcbiAgICBjYWNoZVBhdGg6IHtcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvdXRmaWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRTY2FsZToge1xuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXG4gICAgfSxcbiAgICBoZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xuICAgIH0sXG4gICAgc2NhbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXG4gICAgfSxcbiAgICBiYXRjaDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xuICAgIH0sXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAxNTAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Mb2dpYzoge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjcmVhdGVDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjoge1xuICAgIG1heFVwbG9hZFNpemU6IHtcbiAgICAgIHZhbHVlOiAzLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBjbGlOYW1lOiAnbWF4VXBsb2FkU2l6ZScsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX01BWF9VUExPQURfU0laRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBtYXhpbXVtIHVwbG9hZCBzaXplLCBpbiBtZWdhYnl0ZXMsIGZvciB0aGUgc2VydmVyJ1xuICAgICAgXG4gICAgfSxcbiAgICBlbmFibGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcbiAgICB9LFxuICAgIGhvc3Q6IHtcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xuICAgIH0sXG4gICAgcG9ydDoge1xuICAgICAgdmFsdWU6IDc4MDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xuICAgIH0sXG4gICAgYmVuY2htYXJraW5nOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xuICAgIH0sXG4gICAgcHJveHk6IHtcbiAgICAgIGhvc3Q6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9LFxuICAgICAgcG9ydDoge1xuICAgICAgICB2YWx1ZTogODA4MCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVBvcnQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xuICAgICAgfSxcbiAgICAgIHRpbWVvdXQ6IHtcbiAgICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9XG4gICAgfSxcbiAgICByYXRlTGltaXRpbmc6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXG4gICAgICB9LFxuICAgICAgbWF4UmVxdWVzdHM6IHtcbiAgICAgICAgdmFsdWU6IDEwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xuICAgICAgfSxcbiAgICAgIHdpbmRvdzoge1xuICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcbiAgICAgIH0sXG4gICAgICBkZWxheToge1xuICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXG4gICAgICB9LFxuICAgICAgdHJ1c3RQcm94eToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXG4gICAgICB9LFxuICAgICAgc2tpcEtleToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcbiAgICAgIH0sXG4gICAgICBza2lwVG9rZW46IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXG4gICAgICB9XG4gICAgfSxcbiAgICBzc2w6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgU1NMIHByb3RvY29sLidcbiAgICAgIH0sXG4gICAgICBmb3JjZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xuICAgICAgfSxcbiAgICAgIHBvcnQ6IHtcbiAgICAgICAgdmFsdWU6IDQ0MyxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcbiAgICAgIH0sXG4gICAgICBjZXJ0UGF0aDoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXG4gICAgICB9XG4gICAgfVxuICB9LFxuICBwb29sOiB7XG4gICAgbWluV29ya2Vyczoge1xuICAgICAgdmFsdWU6IDQsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXG4gICAgfSxcbiAgICBtYXhXb3JrZXJzOiB7XG4gICAgICB2YWx1ZTogOCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1heGltdW0gcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcbiAgICB9LFxuICAgIHdvcmtMaW1pdDoge1xuICAgICAgdmFsdWU6IDQwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcbiAgICB9LFxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXG4gICAgfSxcbiAgICBpZGxlVGltZW91dDoge1xuICAgICAgdmFsdWU6IDMwMDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xuICAgIH0sXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xuICAgICAgdmFsdWU6IDIwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgYmVmb3JlIHJldHJ5aW5nIHRoZSBjcmVhdGUgcHJvY2VzcyBpbiBjYXNlIG9mIGEgZmFpbHVyZS4nXG4gICAgfSxcbiAgICByZWFwZXJJbnRlcnZhbDoge1xuICAgICAgdmFsdWU6IDEwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcbiAgICB9LFxuICAgIGJlbmNobWFya2luZzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnSW5kaWNhdGUgd2hldGhlciB0byBzaG93IHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcyBvciBub3QuJ1xuICAgIH1cbiAgfSxcbiAgbG9nZ2luZzoge1xuICAgIGxldmVsOiB7XG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGxvZ2dpbmcgbGV2ZWwgdG8gYmUgdXNlZC4nXG4gICAgfSxcbiAgICBmaWxlOiB7XG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGBsb2dUb0ZpbGVgIGFuZCBgbG9nRGVzdGAgb3B0aW9ucyBhbHNvIG5lZWQgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xuICAgIH0sXG4gICAgZGVzdDoge1xuICAgICAgdmFsdWU6ICdsb2cvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhlIGBsb2dUb0ZpbGVgIG9wdGlvbiBhbHNvIG5lZWRzIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nLidcbiAgICB9LFxuICAgIHRvQ29uc29sZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0NvbnNvbGUnLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHNob3dpbmcgbG9ncyBpbiB0aGUgY29uc29sZS4nXG4gICAgfSxcbiAgICB0b0ZpbGU6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fRklMRScsXG4gICAgICBjbGlOYW1lOiAnbG9nVG9GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyBjcmVhdGlvbiBvZiB0aGUgbG9nIGRpcmVjdG9yeSBhbmQgc2F2aW5nIHRoZSBsb2cgaW50byBhIC5sb2cgZmlsZS4nXG4gICAgfVxuICB9LFxuICB1aToge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIGZvciB0aGUgZXhwb3J0IHNlcnZlci4nXG4gICAgfSxcbiAgICByb3V0ZToge1xuICAgICAgdmFsdWU6ICcvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXG4gICAgfVxuICB9LFxuICBvdGhlcjoge1xuICAgIG5vZGVFbnY6IHtcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT0RFX0VOVicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xuICAgIH0sXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcbiAgICB9LFxuICAgIG5vTG9nbzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcbiAgICB9LFxuICAgIGhhcmRSZXNldFBhZ2U6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5LidcbiAgICB9LFxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZS4nXG4gICAgfVxuICB9LFxuICBkZWJ1Zzoge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXIuJ1xuICAgIH0sXG4gICAgaGVhZGxlc3M6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXG4gICAgfSxcbiAgICBkZXZ0b29sczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBEZXZUb29scyB3aGVuIHRoZSBicm93c2VyIGlzIGluIGEgaGVhZGZ1bCBzdGF0ZS4nXG4gICAgfSxcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0RlY2lkZXMgd2hldGhlciB0byBlbmFibGUgYSBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBzZW50IGZyb20gdGhlIGJyb3dzZXIuJ1xuICAgIH0sXG4gICAgZHVtcGlvOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xuICAgIH0sXG4gICAgc2xvd01vOiB7XG4gICAgICB2YWx1ZTogMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTbG93cyBkb3duIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4nXG4gICAgfSxcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XG4gICAgICB2YWx1ZTogOTIyMixcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3BlY2lmaWVzIHRoZSBkZWJ1Z2dpbmcgcG9ydC4nXG4gICAgfVxuICB9XG59O1xuXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxuLy8gKiBJbml0aWFsIHZhbHVlXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcbiAgcHVwcGV0ZWVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ2xpc3QnLFxuICAgICAgbmFtZTogJ2FyZ3MnLFxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH1cbiAgXSxcbiAgaGlnaGNoYXJ0czogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgQ0ROJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBjb3JlIHNjcmlwdHMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdtb2R1bGVTY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdsaXN0JyxcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdjYWNoZVBhdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgZXhwb3J0OiBbXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAndHlwZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZXhwb3J0IGZpbGUgdHlwZScsXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXG4gICAgICBpbml0aWFsOiAwLFxuICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxuICAgICAgbmFtZTogJ2NvbnN0cicsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXG4gICAgICBpbml0aWFsOiAwLFxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcbiAgICAgIG1pbjogMC4xLFxuICAgICAgbWF4OiA1XG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlbmRlcmluZyB3ZWJwYWdlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXG4gICAgfVxuICBdLFxuICBjdXN0b21Mb2dpYzogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMudmFsdWVcbiAgICB9XG4gIF0sXG4gIHNlcnZlcjogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdob3N0JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncG9ydCcsXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdwcm94eS5ob3N0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwcm94eS5wb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwcm94eS50aW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3NzbC5wb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXG4gICAgfVxuICBdLFxuICBwb29sOiBbXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXG4gICAgICBtZXNzYWdlOiAnVGhlIGluaXRpYWwgbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdjcmVhdGVUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZXN0cm95VGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnaWRsZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnY3JlYXRlUmV0cnlJbnRlcnZhbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVSZXRyeUludGVydmFsLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHJlYXBlciBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgdHJpZ2dlcmluZyB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3knLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBiZW5jaG1hcmtpbmcgZm9yIGEgcmVzb3VyY2UgcG9vbCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXG4gICAgfVxuICBdLFxuICBsb2dnaW5nOiBbXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSwgNTogYmVuY2htYXJrKScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXG4gICAgICByb3VuZDogMCxcbiAgICAgIG1pbjogMCxcbiAgICAgIG1heDogNVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2ZpbGUnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0EgbG9nIGZpbGUgbmFtZS4gU2V0IHdpdGggLS10b0ZpbGUgYW5kIC0tbG9nRGVzdCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnZGVzdCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gYSBsb2cgZmlsZSB3aGVuIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAndG9Db25zb2xlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgbG9nZ2luZyB0byB0aGUgY29uc29sZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcudG9Db25zb2xlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICd0b0ZpbGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgbG9nZ2luZyB0byBhIGZpbGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLnRvRmlsZS52YWx1ZVxuICAgIH1cbiAgXSxcbiAgdWk6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyb3V0ZScsXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIG90aGVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ25vZGVFbnYnLFxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub2RlRW52LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdub0xvZ28nLFxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2hhcmRSZXNldFBhZ2UnLFxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5oYXJkUmVzZXRQYWdlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdicm93c2VyU2hlbGxNb2RlJyxcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBicm93c2VyIHJ1bnMgaW4gdGhlIHNoZWxsIG1vZGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5icm93c2VyU2hlbGxNb2RlLnZhbHVlXG4gICAgfVxuICBdLFxuICBkZWJ1ZzogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnaGVhZGxlc3MnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtb2RlIHNldHRpbmcgZm9yIHRoZSBicm93c2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2RldnRvb2xzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgRGV2VG9vbHMgZm9yIHRoZSBoZWFkZnVsIGJyb3dzZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Db25zb2xlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZXZlbnQgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZHVtcGlvJyxcbiAgICAgIG1lc3NhZ2U6ICdSZWRpcmVjdHMgdGhlIGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gTm9kZUpTIHByb2Nlc3MnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Nsb3dNbycsXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIG9wZXJhdGlvbnMgc2xvdyBkb3duIGluIG1pbGxpc2Vjb25kcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVidWdnaW5nUG9ydCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgbnVtYmVyIGZvciBkZWJ1Z2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXG4gICAgfVxuICBdXG59O1xuXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcbiAgJ29wdGlvbnMnLFxuICAnZ2xvYmFsT3B0aW9ucycsXG4gICd0aGVtZU9wdGlvbnMnLFxuICAncmVzb3VyY2VzJyxcbiAgJ3BheWxvYWQnXG5dO1xuXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxuICovXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xuXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufTtcblxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcbiIsIi8qKlxuICogQGZpbGVvdmVydmlld1xuICogVGhpcyBmaWxlIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgd2l0aCB0aGUgJ3pvZCdcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi4gV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHlcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxuICpcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxuICovXG5cbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcblxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXG5kb3RlbnYuY29uZmlnKCk7XG5cbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb25cbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XG5jb25zdCB2ID0ge1xuICAvLyBTcGxpdHMgc3RyaW5nIHZhbHVlIGludG8gZWxlbWVudHMgaW4gYW4gYXJyYXksIHRyaW1zIGV2ZXJ5IGVsZW1lbnQsIGNoZWNrc1xuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxuICBhcnJheTogKGZpbHRlckFycmF5KSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XG4gICAgICAgIHZhbHVlXG4gICAgICAgICAgLnNwbGl0KCcsJylcbiAgICAgICAgICAubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKVxuICAgICAgICAgIC5maWx0ZXIoKHZhbHVlKSA9PiBmaWx0ZXJBcnJheS5pbmNsdWRlcyh2YWx1ZSkpXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlLmxlbmd0aCA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxuICAvLyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsIGJlIHVuZGVmaW5lZFxuICBib29sZWFuOiAoKSA9PlxuICAgIHpcbiAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICcnXSlcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgPT09ICd0cnVlJyA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBwYXNzZWQgdmFsdWVzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcbiAgLy8gYmUgdW5kZWZpbmVkXG4gIGVudW06ICh2YWx1ZXMpID0+XG4gICAgelxuICAgICAgLmVudW0oWy4uLnZhbHVlcywgJyddKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIFRyaW1zIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNoZWNrcyBpZiBpdCBpcyBlbXB0eSBvciBjb250YWlucyBzdHJpbmdpZmllZFxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXG4gIHN0cmluZzogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nXS5pbmNsdWRlcyh2YWx1ZSkgfHxcbiAgICAgICAgICB2YWx1ZSA9PT0gJycsXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHN0cmluZyBjb250YWlucyBmb3JiaWRkZW4gdmFsdWVzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcbiAgLy8gYmUgdW5kZWZpbmVkXG4gIHBvc2l0aXZlTnVtOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+IDApLFxuICAgICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxuICAvLyB3aWxsIGJlIHVuZGVmaW5lZFxuICBub25OZWdhdGl2ZU51bTogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCksXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpXG59O1xuXG5leHBvcnQgY29uc3QgQ29uZmlnID0gei5vYmplY3Qoe1xuICAvLyBoaWdoY2hhcnRzXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcbiAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgfSlcbiAgICApXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcbiAgICAuc3RyaW5nKClcbiAgICAudHJpbSgpXG4gICAgLnJlZmluZShcbiAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcbiAgICAgICAgdmFsdWUgPT09ICcnLFxuICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgfSlcbiAgICApXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuICBISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuY29yZSksXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzKSxcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdi5ib29sZWFuKCksXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogdi5zdHJpbmcoKSxcblxuICAvLyBleHBvcnRcbiAgRVhQT1JUX1RZUEU6IHYuZW51bShbJ2pwZWcnLCAncG5nJywgJ3BkZicsICdzdmcnXSksXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9ERUZBVUxUX1dJRFRIOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcblxuICAvLyBjdXN0b21cbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2LmJvb2xlYW4oKSxcblxuICAvLyBzZXJ2ZXJcbiAgU0VSVkVSX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcblxuICAvLyBzZXJ2ZXIgcHJveHlcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG5cbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZOiB2LnN0cmluZygpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxuXG4gIC8vIHNlcnZlciBzc2xcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1NTTF9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxuXG4gIC8vIHBvb2xcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX01BWF9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfV09SS19MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfUkVBUEVSX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcblxuICAvLyBsb2dnZXJcbiAgTE9HR0lOR19MRVZFTDogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PlxuICAgICAgICB2YWx1ZSA9PT0gJycgfHxcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwICYmXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPD0gNSksXG4gICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBMT0dHSU5HX0xFVkVMLiBXZSBvbmx5IGFjY2VwdCB2YWx1ZXMgZnJvbSAwIHRvIDUgYXMgbG9nZ2luZyBsZXZlbHMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXG4gIExPR0dJTkdfRklMRTogdi5zdHJpbmcoKSxcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxuICBMT0dHSU5HX1RPX0ZJTEU6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHVpXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxuXG4gIC8vIG90aGVyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdi5ib29sZWFuKCksXG5cbiAgLy8gZGVidWdnZXJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXG59KTtcblxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XG5cbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XG5cbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXG5sZXQgbG9nZ2luZyA9IHtcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXG4gIHRvQ29uc29sZTogdHJ1ZSxcbiAgdG9GaWxlOiBmYWxzZSxcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxuICAvLyBMb2cgbGV2ZWxzXG4gIGxldmVsc0Rlc2M6IFtcbiAgICB7XG4gICAgICB0aXRsZTogJ2Vycm9yJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXG4gICAgICBjb2xvcjogY29sb3JzWzFdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ25vdGljZScsXG4gICAgICBjb2xvcjogY29sb3JzWzJdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxuICAgICAgY29sb3I6IGNvbG9yc1szXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxuICAgIH1cbiAgXSxcbiAgLy8gTG9nIGxpc3RlbmVyc1xuICBsaXN0ZW5lcnM6IFtdXG59O1xuXG4vKipcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXG4gKi9cbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XG4gIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxuICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XG5cbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXG4gICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XG4gIH1cblxuICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXG4gIGFwcGVuZEZpbGUoXG4gICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXG4gICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcbiAgICAoZXJyb3IpID0+IHtcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgKTtcbn07XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxuICovXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xuXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXG4gIGlmIChcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXG4gICkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XG5cbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcblxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xuICB9KTtcblxuICAvLyBMb2cgdG8gY29uc29sZVxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcbiAgICBjb25zb2xlLmxvZy5hcHBseShcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcbiAgICApO1xuICB9XG5cbiAgLy8gTG9nIHRvIGZpbGVcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XG4gICAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xuICB9XG59O1xuXG4vKipcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxuICogY2FuIGJlIHByb3ZpZGVkLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xuICogd2l0aCB0aGUgZXJyb3IuXG4gKi9cbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlO1xuXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XG5cbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcblxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxuICAgIGVycm9yLm1lc3NhZ2UgIT09IGVycm9yLnN0YWNrTWVzc2FnZSB8fCBlcnJvci5zdGFja01lc3NhZ2UgPT09IHVuZGVmaW5lZFxuICAgICAgPyBlcnJvci5zdGFja1xuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XG5cbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XG5cbiAgLy8gTG9nIHRvIGNvbnNvbGVcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XG4gICAgY29uc29sZS5sb2cuYXBwbHkoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xuICAgICAgICBtYWluTWVzc2FnZVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXG4gICAgICAgICdcXG4nLFxuICAgICAgICBzdGFja01lc3NhZ2VcbiAgICAgIF0pXG4gICAgKTtcbiAgfVxuXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XG4gIH0pO1xuXG4gIC8vIExvZyB0byBmaWxlXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xuICAgIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcbiAgfVxufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXG4gKi9cbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xuICB9XG59O1xuXG4vKipcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0Rlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgbG9nIGZpbGVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xuICBsb2dnaW5nID0ge1xuICAgIC4uLmxvZ2dpbmcsXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXG4gICAgdG9GaWxlOiB0cnVlXG4gIH07XG5cbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XG4gIH1cblxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcbiAgfVxufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0TG9nZ2luZyA9IChsb2dnaW5nT3B0aW9ucykgPT4ge1xuICAvLyBTZXQgYWxsIHRoZSBsb2dnaW5nIG9wdGlvbnMgb24gb3VyIGxvZ2dpbmcgbW9kdWxlIG9iamVjdFxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhsb2dnaW5nT3B0aW9ucykpIHtcbiAgICBsb2dnaW5nW2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXG4gIHNldExvZ0xldmVsKGxvZ2dpbmdPcHRpb25zICYmIHBhcnNlSW50KGxvZ2dpbmdPcHRpb25zLmxldmVsKSk7XG5cbiAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXG4gIGlmIChsb2dnaW5nT3B0aW9ucyAmJiBsb2dnaW5nT3B0aW9ucy5kZXN0ICYmIGxvZ2dpbmdPcHRpb25zLnRvRmlsZSkge1xuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxuICAgICAgbG9nZ2luZ09wdGlvbnMuZGVzdCxcbiAgICAgIGxvZ2dpbmdPcHRpb25zLmZpbGUgfHwgJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gdG8gdGhlIGxvZ2dpbmcgc3lzdGVtLlxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxuICovXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuICBpbml0TG9nZ2luZyxcbiAgbGlzdGVuXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xuXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XG5cbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcblxuLyoqXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXG4gKiB3aGl0ZXNwYWNlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cbiAqIEBwYXJhbSB7UmVnRXhwfSBbcnVsZT0vXFxzXFxzKy9nXSAtIFRoZSByZWd1bGFyIGV4cHJlc3Npb24gcnVsZSB0byBtYXRjaFxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xuXG4vKipcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxuICogYSBjZXJ0YWluIG51bWJlciBvZiBhdHRlbXB0cyBhcmUgcmVhY2hlZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uXG4gKiBpZiBzdWNjZXNzZnVsLlxuICpcbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcbiAqIGlzIHJlYWNoZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBleHBCYWNrb2ZmID0gYXN5bmMgKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykgPT4ge1xuICB0cnkge1xuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xuXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cblxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xuICAgIGxvZyhcbiAgICAgIDMsXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXG4gICAgKTtcblxuICAgIC8vIFRyeSBhZ2FpblxuICAgIHJldHVybiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0LCAuLi5hcmdzKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxuICovXG5leHBvcnQgY29uc3QgZml4VHlwZSA9ICh0eXBlLCBvdXRmaWxlKSA9PiB7XG4gIC8vIE1JTUUgdHlwZXNcbiAgY29uc3QgbWltZVR5cGVzID0ge1xuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xuICB9O1xuXG4gIC8vIEZvcm1hdHNcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xuXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxuICBpZiAob3V0ZmlsZSkge1xuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XG5cbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcbiAgICAgIHR5cGUgPSAnanBlZyc7XG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IHJlc291cmNlcyAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC4gQ2FuIGJlIGVpdGhlclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxuICogZmlsZXMuXG4gKlxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxuICogcmVzb3VyY2VzIGFyZSBmb3VuZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XG5cbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XG5cbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgdHJ5IHtcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xuICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcbiAgfVxuXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiByZXNvdXJjZXNcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XG59O1xuXG4vKipcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cbiAqIG9mIHRoZSBwYXJzZWQgSlNPTi5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXG4gKiBvciBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xuICB0cnkge1xuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcbiAgICApO1xuXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xuICAgIH1cblxuICAgIC8vIFJldHVybiBhIEpTT05cbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcbiAgaXRlbSAhPT0gbnVsbCAmJlxuICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDA7XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXG4gKiBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXG4gIF07XG5cbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXG4gKlxuICogQHJldHVybnMge09iamVjdHxBcnJheX0gLSBUaGUgZGVlcCBjb3B5IG9mIHRoZSBwcm92aWRlZCBvYmplY3Qgb3IgYXJyYXkuXG4gKi9cbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcbiAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBvYmo7XG4gIH1cblxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcblxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBjb3B5O1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxuICogaW4gdGhlIG91dHB1dC5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxuICovXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xuXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXG4gICAgICBpZiAoXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JylcbiAgICAgICkge1xuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXG4gICAgICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXG4gICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxuICAgICAgOiB2YWx1ZTtcbiAgfTtcblxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXG4gICAgL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcbiAgICAnJ1xuICApO1xufTtcblxuLyoqXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uLlxuICpcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XG4gKiB0aGUgbG9nby5cbiAqL1xuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxuICApLnZlcnNpb247XG5cbiAgLy8gUHJpbnQgdGV4dCBvbmx5XG4gIGlmIChub0xvZ28pIHtcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIFByaW50IHRoZSBsb2dvXG4gIGNvbnNvbGUubG9nKFxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxuICApO1xufTtcblxuLyoqXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XG4gIGNvbnN0IHBhZCA9IDQ4O1xuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XG5cbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cbiAgY29uc29sZS5sb2coXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxuICAgICdcXG4tLS0tLS0nLFxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcbiAgKTtcblxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cbiAgICAgICAgfSBgO1xuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBkZXNjTmFtZSxcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xuICAgIH1cbiAgfSk7XG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXG4gKlxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXG4gKi9cbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXG4gICAgPyBmYWxzZVxuICAgIDogISFpdGVtO1xuXG4vKipcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xuICogZmFpbHMuXG4gKi9cbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XG5cbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxuICAgICAgICA6IGZhbHNlO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXG4gICAgKSB7XG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcbiAgICB9XG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XG4gIH1cbn07XG5cbi8qKlxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cbiAqXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcbiAqIGluIG1pbGxpc2Vjb25kcy5cbiAqL1xuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgX19kaXJuYW1lLFxuICBjbGVhclRleHQsXG4gIGV4cEJhY2tvZmYsXG4gIGZpeFR5cGUsXG4gIGhhbmRsZVJlc291cmNlcyxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNPYmplY3QsXG4gIGlzT2JqZWN0RW1wdHksXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZSxcbiAgcm91bmROdW1iZXIsXG4gIHRvQm9vbGVhbixcbiAgd3JhcEFyb3VuZCxcbiAgbWVhc3VyZVRpbWVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcblxuaW1wb3J0IHtcbiAgYWJzb2x1dGVQcm9wcyxcbiAgZGVmYXVsdENvbmZpZyxcbiAgbmVzdGVkQXJncyxcbiAgcHJvbXB0c0NvbmZpZ1xufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xuXG4vKipcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXG4gKiBhbmQgYXJncyBmcm9tIHRoZSBDTEkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxuICogKENMSSB1c2FnZSkuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XG4gIH1cblxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XG5cbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XG5cbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcbiAgaWYgKHVzZXJPcHRpb25zKSB7XG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgYWJzb2x1dGVQcm9wc1xuICAgICk7XG4gIH1cblxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xuICB9XG5cbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XG59O1xuXG4vKipcbiAqIEFsbG93cyBtYW51YWwgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBzcGVjaWZpZWQgcHJvbXB0cyBhbmQgc2F2ZXNcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxuICogY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZWQgYW5kIHNhdmVkLlxuICovXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XG4gIC8vIFByZXBhcmUgYSBjb25maWcgb2JqZWN0XG4gIGxldCBjb25maWdGaWxlID0ge307XG5cbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgY29uZmlnIGZpbGUgZXhpc3RzXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XG4gIH1cblxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcbiAgY29uc3Qgb25TdWJtaXQgPSBhc3luYyAocCwgY2F0ZWdvcmllcykgPT4ge1xuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XG5cbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcbiAgICAgIC8vIE1hcmsgZWFjaCBvcHRpb24gd2l0aCBhIHNlY3Rpb25cbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xuICAgICAgICAuLi5vcHRpb24sXG4gICAgICAgIHNlY3Rpb25cbiAgICAgIH0pKTtcblxuICAgICAgLy8gQ29sbGVjdCB0aGUgcXVlc3Rpb25zXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcbiAgICB9XG5cbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xuICAgICAgICAvLyBHZXQgdGhlIGRlZmF1bHQgbW9kdWxlIHNjcmlwdHNcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XG5cbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxuICAgICAgICAgICAgICAndXRmOCdcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgICAgICAgICAgMSxcbiAgICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXG4gICAgdmFsdWU6IGNob2ljZVxuICB9KSk7XG5cbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XG4gIHJldHVybiBwcm9tcHRzKFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxuICAgICAgY2hvaWNlc1xuICAgIH0sXG4gICAgeyBvblN1Ym1pdCB9XG4gICk7XG59O1xuXG4vKipcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxuICogKFB1cHBldGVlcikuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcbiAqIG1hcHBpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcblxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxuICAgICAgICAob2JqW3Byb3BdID1cbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXG4gICAgICBuZXdPcHRpb25zXG4gICAgKTtcbiAgfVxuICByZXR1cm4gbmV3T3B0aW9ucztcbn07XG5cbi8qKlxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcblxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxuICAgICAgICAgID8gdmFsdWVcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcbiAgfVxuXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xuICogYW5kIGdlbmVyYWxPcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xuICBsZXQgb3B0aW9ucyA9IHt9O1xuXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIGV4cG9ydE9wdGlvbnMsXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXG4gICAgICBhYnNvbHV0ZVByb3BzXG4gICAgKTtcbiAgfVxuXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XG4gIHJldHVybiBvcHRpb25zO1xufTtcblxuLyoqXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xuICApO1xuXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgICAgMixcbiAgICAgICAgZXJyb3IsXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxuICByZXR1cm4ge307XG59XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xuICogZHVyaW5nIHJlY3Vyc2lvbi5cbiAqL1xuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XG5cbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgdXBkYXRlRGVmYXVsdENvbmZpZyhlbnRyeSwgY3VzdG9tVmFsdWUsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXG4gICAgICBpZiAoY3VzdG9tVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBlbnRyeS52YWx1ZSA9IGVudnNbZW50cnkuZW52TGlua107XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcbiAqIG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGluaXRPcHRpb25zKGl0ZW1zKSB7XG4gIGxldCBvcHRpb25zID0ge307XG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcbiAgICAgID8gaXRlbS52YWx1ZVxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcbiAgfVxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXG4gKiB1cGRhdGluZyB0aGUgb3B0aW9ucyBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBjb250YWluaW5nIHZhbHVlcyBmb3Igc3BlY2lmaWNcbiAqIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxuICovXG5mdW5jdGlvbiBwYWlyQXJndW1lbnRWYWx1ZShvcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKSB7XG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qgb3B0aW9uID0gYXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcblxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1tvcHRpb25dXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXG4gICAgICA6IFtdO1xuXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xuICAgIGxldCBhcmd1bWVudFR5cGU7XG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmpbcHJvcF07XG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XG5cbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XG4gICAgICAgIC8vIEZpbmRzIGFuIG9wdGlvbiBhbmQgc2V0IGEgY29ycmVzcG9uZGluZyB2YWx1ZVxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XG4gICAgICAgICAgICBpZiAoYXJndW1lbnRUeXBlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9ICthcmdzW2ldO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbG9nKFxuICAgICAgICAgICAgICAyLFxuICAgICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlICcke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmpbcHJvcF07XG4gICAgfSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcbiAgaWYgKHNob3dVc2FnZSkge1xuICAgIHByaW50VXNhZ2UoZGVmYXVsdENvbmZpZyk7XG4gIH1cblxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xuICogdGhlIGZpbmFsIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIGZpbmFsIHZhbHVlIHRvIGJlIGFzc2lnbmVkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxuICovXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSBuZXN0ZWROYW1lcy5zaGlmdCgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3RUb1VwZGF0ZSwgcHJvcE5hbWUpKSB7XG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcbiAgICB9XG5cbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0pLFxuICAgICAgbmVzdGVkTmFtZXMsXG4gICAgICB2YWx1ZVxuICAgICk7XG5cbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG4gIH1cblxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXG4gIG9iamVjdFRvVXBkYXRlW25lc3RlZE5hbWVzWzBdXSA9IHZhbHVlO1xuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZ2V0T3B0aW9ucyxcbiAgc2V0T3B0aW9ucyxcbiAgbWFudWFsQ29uZmlnLFxuICBtYXBUb05ld0NvbmZpZyxcbiAgbWVyZ2VDb25maWdPcHRpb25zLFxuICBpbml0RXhwb3J0U2V0dGluZ3Ncbn07XG4iLCIvKipcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXG4gKi9cblxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxuICovXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XG5cbi8qKlxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcblxuICAgIHByb3RvY29sXG4gICAgICAuZ2V0KFxuICAgICAgICB1cmwsXG4gICAgICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAge1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdoaWdoY2hhcnRzL2V4cG9ydCcsXG4gICAgICAgICAgICAgIFJlZmVyZXI6ICdoaWdoY2hhcnRzL2V4cG9ydCdcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlcXVlc3RPcHRpb25zIHx8IHt9XG4gICAgICAgICksXG4gICAgICAgIChyZXMpID0+IHtcbiAgICAgICAgICBsZXQgZGF0YSA9ICcnO1xuXG4gICAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIClcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xuXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxuICAgICAge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlcXVlc3RPcHRpb25zXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xuXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxuICAgIHJlcS53cml0ZShkYXRhKTtcbiAgICByZXEuZW5kKCk7XG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XG4iLCJjbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XG4gIH1cblxuICBzZXRFcnJvcihlcnJvcikge1xuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcbiAgICBpZiAoZXJyb3IubmFtZSkge1xuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcbiAgICB9XG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XG4gICAgfVxuICAgIGlmIChlcnJvci5zdGFjaykge1xuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcblxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcblxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG5jb25zdCBjYWNoZSA9IHtcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcbiAgc291cmNlczogJycsXG4gIGhjVmVyc2lvbjogJydcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcbiAgICAucmVwbGFjZSgnLyonLCAnJylcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxuICAgIC50cmltKCk7XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxuICAgICcnXG4gICk7XG59O1xuXG4vKipcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XG4gKiBmaWxlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzLXJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXG4gKi9cbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XG4gIH07XG5cbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcblxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcbiAgdHJ5IHtcbiAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXG4gICAgICAndXRmOCdcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcbiAqIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxuICBzY3JpcHQsXG4gIHJlcXVlc3RPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlcyxcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXG4pID0+IHtcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XG4gIH1cblxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XG5cbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcbiAgfVxuXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XG4gIH0gZWxzZSB7XG4gICAgbG9nKFxuICAgICAgMixcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxuICAgICk7XG4gIH1cblxuICByZXR1cm4gJyc7XG59O1xuXG4vKipcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvcmVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxuICogKGZ1bGwgVVJMcykuXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcbiAqIGEgcmVxdWVzdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxuICBjb3JlU2NyaXB0cyxcbiAgbW9kdWxlU2NyaXB0cyxcbiAgY3VzdG9tU2NyaXB0cyxcbiAgcHJveHlPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlc1xuKSA9PiB7XG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcbiAgbGV0IHByb3h5QWdlbnQ7XG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xuICBjb25zdCBwcm94eVBvcnQgPSBwcm94eU9wdGlvbnMucG9ydDtcblxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcbiAgICB0cnkge1xuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xuICAgICAgICBob3N0OiBwcm94eUhvc3QsXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXG4gICAgICAgIGVycm9yXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcbiAgICA/IHtcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcbiAgICAgIH1cbiAgICA6IHt9O1xuXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcbiAgICApLFxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcbiAgICApLFxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxuICAgIClcbiAgXTtcblxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXG4gIHByb3h5T3B0aW9ucyxcbiAgc291cmNlUGF0aFxuKSA9PiB7XG4gIGNvbnN0IHZlcnNpb24gPSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uO1xuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXG4gICk7XG5cbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcbiAgdHJ5IHtcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxuICAgICAgW1xuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcbiAgICAgIF0sXG4gICAgICBbXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxuICAgICAgICAgIG0gPT09ICdtYXAnXG4gICAgICAgICAgICA/IGAke2NkblVSTH1tYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgKSxcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXG4gICAgICAgIClcbiAgICAgIF0sXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxuICAgICAgcHJveHlPcHRpb25zLFxuICAgICAgZmV0Y2hlZE1vZHVsZXNcbiAgICApO1xuXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xuXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwob2JqZWN0fGJvb2xlYW4pPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZFxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXG4gKiBleGlzdHMuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcbiAgaWYgKG9wdGlvbnM/LmhpZ2hjaGFydHMpIHtcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XG4gIH1cbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXG4gKiBhbmQgdXBkYXRlZC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAob3B0aW9ucykgPT4ge1xuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcblxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xuXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XG5cbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiBtYW5pZmVzdC5qc29uIGRvZXMgbm90IGV4aXN0XG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XG4gIH0gZWxzZSB7XG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcblxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcbiAgICB9XG5cbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xuXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXG4gICAgICApO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xuICAgICAgbG9nKFxuICAgICAgICAyLFxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xuICAgICAgKTtcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcbiAgICAgICAgICBsb2coXG4gICAgICAgICAgICAyLFxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XG5cbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcblxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcblxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XG4gIGpvaW4oX19kaXJuYW1lLCBnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xuXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGUgPSAoKSA9PiBjYWNoZTtcblxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xuXG5leHBvcnQgY29uc3QgdmVyc2lvbiA9ICgpID0+IGNhY2hlLmhjVmVyc2lvbjtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxuICBnZXRDYWNoZVBhdGgsXG4gIHVwZGF0ZVZlcnNpb24sXG4gIGdldENhY2hlLFxuICBoaWdoY2hhcnRzLFxuICB2ZXJzaW9uXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXG5cbi8qKlxuICogU2V0dGluZyB0aGUgYW5pbU9iamVjdC4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XG4gIH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIGNoYXJ0LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjaGFydE9wdGlvbnMgLSBUaGUgb3B0aW9ucyBmb3IgdGhlIEhpZ2hjaGFydHMgY2hhcnQuXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucy5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0cmlnZ2VyRXhwb3J0KGNoYXJ0T3B0aW9ucywgb3B0aW9ucywgZGlzcGxheUVycm9ycykge1xuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXG4gIHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGRpc3BsYXlFcnJvcnM7XG5cbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xuICBjb25zdCB7IGdldE9wdGlvbnMsIG1lcmdlLCBzZXRPcHRpb25zLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xuXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cbiAgLy8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcblxuICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxuICBjb25zdCBjaGFydCA9IHtcbiAgICBhbmltYXRpb246IGZhbHNlXG4gIH07XG5cbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XG4gIGlmIChvcHRpb25zLmV4cG9ydC5zdHJJbmopIHtcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xuICB9XG5cbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcbiAgICAgIGV4cG9ydGluZzoge1xuICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIHBsb3RPcHRpb25zOiB7XG4gICAgICAgIHNlcmllczoge1xuICAgICAgICAgIGxhYmVsOiB7XG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXG4gICAgICAgICovXG4gICAgICB0b29sdGlwOiB7fVxuICAgIH0pO1xuXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XG4gICAgfSk7XG5cbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcbiAgfSk7XG5cbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcbiAgfSk7XG5cbiAgLy8gR2V0IHRoZSB1c2VyIG9wdGlvbnNcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcbiAgICA6IGNoYXJ0T3B0aW9ucztcblxuICAvLyBUcmlnZ2VyIGN1c3RvbSBjb2RlXG4gIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpIHtcbiAgICBuZXcgRnVuY3Rpb24oJ29wdGlvbnMnLCBvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcbiAgfVxuXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxuICBjb25zdCBmaW5hbE9wdGlvbnMgPSBtZXJnZShcbiAgICBmYWxzZSxcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXG4gICAgdXNlck9wdGlvbnMsXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xuICAgIHsgY2hhcnQgfVxuICApO1xuXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9ucyk7XG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcbiAgfVxuXG4gIGxldCBjb25zdHIgPSBvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0JztcbiAgY29uc3RyID0gdHlwZW9mIEhpZ2hjaGFydHNbY29uc3RyXSAhPT0gJ3VuZGVmaW5lZCcgPyBjb25zdHIgOiAnY2hhcnQnO1xuXG4gIEhpZ2hjaGFydHNbY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcblxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XG4gICAgfVxuICB9XG5cbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XG5cbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XG59XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcblxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXG5jb25zdCB0ZW1wbGF0ZSA9IHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJywgJ3V0ZjgnKTtcblxubGV0IGJyb3dzZXI7XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxuICogaW5zdGFuY2UuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXG4gKiBjcmVhdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xuICBpZiAoIWJyb3dzZXIpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJyk7XG4gIH1cbiAgcmV0dXJuIGJyb3dzZXI7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcbiAgLy8gR2V0IGRlYnVnIGFuZCBvdGhlciBvcHRpb25zXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XG5cbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcbiAgfTtcblxuICAvLyBDcmVhdGUgYSBicm93c2VyXG4gIGlmICghYnJvd3Nlcikge1xuICAgIGxldCB0cnlDb3VudCA9IDA7XG5cbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXG4gICAgICAgICk7XG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgIDEsXG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBvcGVuKCk7XG5cbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cblxuICAgIGlmICghYnJvd3Nlcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXG4gIHJldHVybiBicm93c2VyO1xufVxuXG4vKipcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcbiAqIGlzIGNsb3NlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcbiAgaWYgKGJyb3dzZXI/LmNvbm5lY3RlZCkge1xuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgfVxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cbiAqXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxuICpcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXG4gKlxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgcGFnZVxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XG5cbiAgLy8gRGlzYWJsZSBjYWNoZVxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XG5cbiAgLy8gU2V0IHRoZSBjb250ZW50XG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xuXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xuICBzZXRQYWdlRXZlbnRzKHBhZ2UpO1xuXG4gIHJldHVybiBwYWdlO1xufVxuXG4vKipcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvICdhYm91dDpibGFuaycgYW5kIHJlc2V0cyBjb250ZW50XG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcbiAqIHN0cnVjdHVyZS5cbiAqXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwYWdlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xuICB0cnkge1xuICAgIGlmIChwYWdlICYmICFwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2dXaXRoU3RhY2soXG4gICAgICAyLFxuICAgICAgZXJyb3IsXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcbiAqIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsIGJlXG4gKiBhZGRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8T2JqZWN0Pj59IC0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gYXJyYXkgb2YgaW5qZWN0ZWRcbiAqIHJlc291cmNlcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucykge1xuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcblxuICAvLyBVc2UgcmVzb3VyY2VzXG4gIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xuICBpZiAocmVzb3VyY2VzKSB7XG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xuXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcbiAgICAgIGluamVjdGVkSnMucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xuICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcblxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xuICAgICAgICBpbmplY3RlZEpzLnB1c2goXG4gICAgICAgICAgaXNMb2NhbFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xuXG4gICAgLy8gTG9hZCBDU1NcbiAgICBjb25zdCBpbmplY3RlZENzcyA9IFtdO1xuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XG4gICAgICBpZiAoY3NzSW1wb3J0cykge1xuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XG4gICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXG4gICAgICAgICAgICAgIC50cmltKCk7XG5cbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXG4gICAgICB9KTtcblxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xufVxuXG4vKipcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gUmVtb3Zlc1xuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxuICogaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcbiAqIGJlIGNsZWFyZWQuXG4gKiBAcGFyYW0ge0FycmF5PE9iamVjdD59IGluamVjdGVkUmVzb3VyY2VzIC0gQXJyYXkgb2YgaW5qZWN0ZWQgcmVzb3VyY2VzXG4gKiB0byBiZSBjbGVhcmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKSB7XG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcbiAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XG4gIH1cblxuICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXG4gICAgLy8gZXhwb3J0c1xuICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XG5cbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XG4gICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xuICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcblxuICAgIC8vIFJlbW92ZSB0YWdzXG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcbiAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxuICAgICAgLi4ubGlua3NUb1JlbW92ZVxuICAgIF0pIHtcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXG4gKiBhbmQgZGlzcGxheSBlcnJvcnMgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxuICogaXMgYmVpbmcgc2V0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcblxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcblxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XG59XG5cbi8qKlxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gc2V0IGV2ZW50cyB0by5cbiAqL1xuZnVuY3Rpb24gc2V0UGFnZUV2ZW50cyhwYWdlKSB7XG4gIC8vIEdldCBkZWJ1ZyBvcHRpb25zXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xuICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xuICAgIC8vIEl0IHdvdWxkIHNlZW0gbGlrZSB0aGlzIG1heSBmaXJlIGF0IHRoZSBzYW1lIHRpbWUgb3Igc2hvcnRseSBiZWZvcmVcbiAgICAvLyBhIHBhZ2UgaXMgY2xvc2VkLlxuICAgIGlmIChwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXG4gICAgYXdhaXQgcGFnZS4kZXZhbChcbiAgICAgICcjY29udGFpbmVyJyxcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjogPC9oMT4ke2Vycm9yLnRvU3RyaW5nKCl9YFxuICAgICk7XG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGdldCxcbiAgY3JlYXRlLFxuICBjbG9zZSxcbiAgbmV3UGFnZSxcbiAgY2xlYXJQYWdlLFxuICBhZGRQYWdlUmVzb3VyY2VzLFxuICBjbGVhclBhZ2VSZXNvdXJjZXNcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCBjb250YWluaW5nXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxuICovXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgeCxcbiAgICAgIHksXG4gICAgICB3aWR0aCxcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxuICAgIH07XG4gIH0pO1xuXG4vKipcbiAqIENyZWF0ZXMgYW4gaW1hZ2UgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBzY3JlZW5zaG90IGZ1bmN0aW9uYWxpdHkgd2l0aFxuICogc3BlY2lmaWVkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxuICogaW4gbWlsbGlzZWNvbmRzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxuICovXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XG4gIFByb21pc2UucmFjZShbXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcbiAgICAgIHR5cGUsXG4gICAgICBlbmNvZGluZyxcbiAgICAgIGNsaXAsXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXG4gICAgICBmdWxsUGFnZTogZmFsc2UsXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxuXG4gICAgICAvLyAjNDQ3LCAjNDYzIC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGVcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXG4gICAgfSksXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XG4gICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcbiAgICAgIClcbiAgICApXG4gIF0pO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxuICogb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxuICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gUERGIHdpZHRoLlxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQREYgYnVmZmVyLlxuICovXG5jb25zdCBjcmVhdGVQREYgPSBhc3luYyAoXG4gIHBhZ2UsXG4gIGhlaWdodCxcbiAgd2lkdGgsXG4gIGVuY29kaW5nLFxuICByYXN0ZXJpemF0aW9uVGltZW91dFxuKSA9PiB7XG4gIGF3YWl0IHBhZ2UuZW11bGF0ZU1lZGlhVHlwZSgnc2NyZWVuJyk7XG5cbiAgcmV0dXJuIHBhZ2UucGRmKHtcbiAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcbiAgICBoZWlnaHQ6IGhlaWdodCArIDEsXG4gICAgd2lkdGgsXG4gICAgZW5jb2RpbmcsXG4gICAgdGltZW91dDogcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxuICB9KTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhbiBTVkcgc3RyaW5nIGJ5IGV2YWx1YXRpbmcgdGhlIG91dGVySFRNTCBvZiB0aGUgZmlyc3QgJ3N2ZycgZWxlbWVudFxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXG4gKi9cbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcblxuLyoqXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XG4gKiBmdW5jdGlvbiB3aXRoaW4gdGhlIHdpbmRvdyBjb250ZXh0IHVzaW5nIHBhZ2UuZXZhbHVhdGUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IHRvIGJlIGNvbmZpZ3VyZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBQcm9taXNlIHJlc29sdmluZyBhZnRlciB0aGUgY29uZmlndXJhdGlvbiBpcyBzZXQuXG4gKi9cbmNvbnN0IHNldEFzQ29uZmlnID0gYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSA9PlxuICBwYWdlLmV2YWx1YXRlKHRyaWdnZXJFeHBvcnQsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcblxuLyoqXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcbiAgbGV0IGluamVjdGVkUmVzb3VyY2VzID0gW107XG5cbiAgdHJ5IHtcbiAgICBsb2coNCwgJ1tleHBvcnRdIERldGVybWluaW5nIGV4cG9ydCBwYXRoLicpO1xuXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xuXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxuICAgICAgZXhwb3J0T3B0aW9ucz8ub3B0aW9ucz8uY2hhcnQ/LmRpc3BsYXlFcnJvcnMgJiZcbiAgICAgIGdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcblxuICAgIGxldCBpc1NWRztcbiAgICBpZiAoXG4gICAgICBjaGFydC5pbmRleE9mICYmXG4gICAgICAoY2hhcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHwgY2hhcnQuaW5kZXhPZignPD94bWwnKSA+PSAwKVxuICAgICkge1xuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIFNWRy4nKTtcblxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgICAgICByZXR1cm4gY2hhcnQ7XG4gICAgICB9XG5cbiAgICAgIGlzU1ZHID0gdHJ1ZTtcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCksIHtcbiAgICAgICAgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCdcbiAgICAgIH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBKU09OIGNvbmZpZyBoYW5kbGluZ1xuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XG5cbiAgICAgIC8vIE5lZWQgdG8gcGVyZm9ybSBzdHJhaWdodCBpbmplY3RcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcoXG4gICAgICAgICAgcGFnZSxcbiAgICAgICAgICB7XG4gICAgICAgICAgICBjaGFydDoge1xuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgICBkaXNwbGF5RXJyb3JzXG4gICAgICAgICk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBCYXNpYyBjb25maWd1cmF0aW9uIGV4cG9ydFxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xuXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcbiAgICAvLyBJdCdzIFZJVEFMIHRoYXQgYWxsIGFkZGVkIHJlc291cmNlcyBlbmRzIHVwIGhlcmUgc28gd2UgY2FuIGNsZWFyIHRoaW5nc1xuICAgIC8vIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxuICAgIGluamVjdGVkUmVzb3VyY2VzID0gYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKTtcblxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcbiAgICBjb25zdCBzaXplID0gaXNTVkdcbiAgICAgID8gYXdhaXQgcGFnZS5ldmFsdWF0ZSgoc2NhbGUpID0+IHtcbiAgICAgICAgICBjb25zdCBzdmdFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXG4gICAgICAgICAgY29uc3QgY2hhcnRIZWlnaHQgPSBzdmdFbGVtZW50LmhlaWdodC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XG4gICAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xuXG4gICAgICAgICAgLy8gSW4gY2FzZSBvZiBTVkcgdGhlIHpvb20gbXVzdCBiZSBzZXQgZGlyZWN0bHkgZm9yIGJvZHlcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSBzY2FsZTtcblxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXG4gICAgICAgICAgICBjaGFydFdpZHRoXG4gICAgICAgICAgfTtcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xuXG4gICAgICAgICAgLy8gTm8gbmVlZCBmb3Igc3VjaCBzY2FsZSBtYW5pcHVsYXRpb24gaW4gY2FzZSBvZiBvdGhlciB0eXBlcyBvZiBleHBvcnRzXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gMTtcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjaGFydEhlaWdodCxcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcbiAgICAgICAgICB9O1xuICAgICAgICB9KTtcblxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxuICAgIGNvbnN0IHZpZXdwb3J0SGVpZ2h0ID0gTWF0aC5hYnMoXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodClcbiAgICApO1xuICAgIGNvbnN0IHZpZXdwb3J0V2lkdGggPSBNYXRoLmFicyhcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aClcbiAgICApO1xuXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcbiAgICBjb25zdCB7IHgsIHkgfSA9IGF3YWl0IGdldENsaXBSZWdpb24ocGFnZSk7XG5cbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XG4gICAgYXdhaXQgcGFnZS5zZXRWaWV3cG9ydCh7XG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICBkZXZpY2VTY2FsZUZhY3RvcjogaXNTVkcgPyAxIDogcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKVxuICAgIH0pO1xuXG4gICAgbGV0IGRhdGE7XG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcbiAgICAgIC8vIFNWR1xuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XG4gICAgICAvLyBQTkcgb3IgSlBFR1xuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxuICAgICAgICBwYWdlLFxuICAgICAgICBleHBvcnRPcHRpb25zLnR5cGUsXG4gICAgICAgICdiYXNlNjQnLFxuICAgICAgICB7XG4gICAgICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcbiAgICAgICAgICB4LFxuICAgICAgICAgIHlcbiAgICAgICAgfSxcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcbiAgICAgIC8vIFBERlxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVBERihcbiAgICAgICAgcGFnZSxcbiAgICAgICAgdmlld3BvcnRIZWlnaHQsXG4gICAgICAgIHZpZXdwb3J0V2lkdGgsXG4gICAgICAgICdiYXNlNjQnLFxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XG4gICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIGBbZXhwb3J0XSBVbnN1cHBvcnRlZCBvdXRwdXQgZm9ybWF0ICR7ZXhwb3J0T3B0aW9ucy50eXBlfS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xuICAgIHJldHVybiBkYXRhO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XG4gICAgcmV0dXJuIGVycm9yO1xuICB9XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxuPCFET0NUWVBFIGh0bWw+XG48aHRtbCBsYW5nPSdlbi1VUyc+XG4gIDxoZWFkPlxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cbiAgPC9oZWFkPlxuICA8c3R5bGU+XG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxuICA8L3N0eWxlPlxuICA8Ym9keT5cbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XG4gICAgICAke2NoYXJ0fVxuICAgIDwvZGl2PlxuICA8L2JvZHk+XG48L2h0bWw+XG5cbmA7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgUG9vbCB9IGZyb20gJ3Rhcm4nO1xuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xuXG5pbXBvcnQge1xuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcbiAgY2xvc2UgYXMgY2xvc2VCcm93c2VyLFxuICBuZXdQYWdlLFxuICBjbGVhclBhZ2Vcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcbmltcG9ydCBwdXBwZXRlZXJFeHBvcnQgZnJvbSAnLi9leHBvcnQuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxubGV0IHBvb2wgPSBmYWxzZTtcblxuLy8gUG9vbCBzdGF0aXN0aWNzXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXG4gIHRpbWVTcGVudDogMCxcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXG4gIHNwZW50QXZlcmFnZTogMFxufTtcblxubGV0IHBvb2xDb25maWcgPSB7fTtcblxuY29uc3QgZmFjdG9yeSA9IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cbiAgICpcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxuICAgKlxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xuICAgKiBwYWdlLlxuICAgKi9cbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcblxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgdHJ5IHtcbiAgICAgIHBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XG5cbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcbiAgICAgIH1cblxuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXG4gICAgICAgIH0gbXMuYFxuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBpZCxcbiAgICAgIHBhZ2UsXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XG4gICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxuICAgIH07XG4gIH0sXG5cbiAgLyoqXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXG4gICAqIHRoZSB3b3JrIGxpbWl0LlxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxuICAgKiB3b3JrZXIncyBJRCwgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZSwgYW5kIHdvcmsgY291bnQuXG4gICAqXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cbiAgICogdGhlIHdvcmsgbGltaXQ7IG90aGVyd2lzZSwgcmV0dXJucyBmYWxzZS5cbiAgICovXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XG4gICAgLy8gTk9URTogSW4gY2VydGFpbiBjYXNlcyBhY3F1aXJpbmcgdGhyb3dzIGEgVGFyZ2V0Q2xvc2VFcnJvciwgd2hpY2ggbWF5XG4gICAgLy8gICAgICAgYmUgY2F1c2VkIGJ5IHR3byB0aGluZ3M6XG4gICAgLy8gICAgICAgICAtIFRoZSBwYWdlIGlzIGNsb3NlZCBhbmQgYXR0ZW1wdGVkIHRvIGJlIHJldXNlZC5cbiAgICAvLyAgICAgICAgIC0gTG9zdCBjb250YWN0IHdpdGggdGhlIGJyb3dzZXJcbiAgICAvLyAgICAgICBXaGF0IHdlJ3JlIHNlZWluZyBpbiBsb2dzIGlzIHRoYXQgc3VjY2Vzc2l2ZSBleHBvcnRzIHR5cGljYWxseVxuICAgIC8vICAgICAgIHN1Y2NlZWRzLCBhbmQgdGhlIHNlcnZlciByZWNvdmVycywgaW5kaWNhdGluZyB0aGF0IGl0J3MgbGlrZWx5XG4gICAgLy8gICAgICAgdGhlIGZpcnN0IGNhc2UuIFRoaXMgaXMgYW4gYXR0ZW1wdCBhdCBhbGxpZXZhdGluZyB0aGUgaXNzdWUgYnlcbiAgICAvLyAgICAgICBzaW1wbHkgbm90IHZhbGlkYXRpbmcgdGhlIHdvcmtlciBpZiB0aGUgcGFnZSBpcyBudWxsIG9yIGNsb3NlZC5cbiAgICAvL1xuICAgIC8vICAgICAgIFRoZSBhY3R1YWwgcmVzdWx0IGZyb20gd2hlbiB0aGlzIGhhcHBlbmVkLCB3YXMgdGhhdCBhIHdvcmtlciB3b3VsZFxuICAgIC8vICAgICAgIGJlIGNvbXBsZXRlbHkgbG9ja2VkLCBzdG9wcGluZyBpdCBmcm9tIGJlaW5nIGFjcXVpcmVkIHVudGlsXG4gICAgLy8gICAgICAgaXRzIHdvcmsgY291bnQgcmVhY2hlZCB0aGUgbGltaXQuXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSB8fCB3b3JrZXJIYW5kbGUucGFnZT8uaXNDbG9zZWQoKSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXG4gICAgICArK3dvcmtlckhhbmRsZS53b3JrQ291bnQgPiBwb29sQ29uZmlnLndvcmtMaW1pdFxuICAgICkge1xuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcbiAgICAgICk7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xuICB9LFxuXG4gIC8qKlxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXG4gICAqL1xuICBkZXN0cm95OiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XG4gICAgbG9nKDMsIGBbcG9vbF0gRGVzdHJveWluZyBwb29sIGVudHJ5ICR7d29ya2VySGFuZGxlLmlkfS5gKTtcblxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSAmJiAhd29ya2VySGFuZGxlLnBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgYXdhaXQgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcbiAgICB9XG4gIH1cblxuICAvLyBsb2c6IChtZXNzYWdlLCBsZXZlbCkgPT4gbG9nKDEsICdbdGFybl0gJyArICBtZXNzYWdlKVxufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xuXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXG4gICk7XG5cbiAgaWYgKHBvb2wpIHtcbiAgICByZXR1cm4gbG9nKFxuICAgICAgNCxcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXG4gICAgKTtcbiAgfVxuXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xuICAgICAgLi4uZmFjdG9yeSxcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgLy8gU2V0IGV2ZW50c1xuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcbiAgICAgIC8vIENsZWFyIHBhZ2VcbiAgICAgIGNvbnN0IHIgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xuICAgICAgbG9nKFxuICAgICAgICA0LFxuICAgICAgICBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LiBDbGVhciBwYWdlIHN0YXR1czogJHtyfS5gXG4gICAgICApO1xuICAgIH0pO1xuXG4gICAgcG9vbC5vbignZGVzdHJveVN1Y2Nlc3MnLCAoZXZlbnRJZCwgcmVzb3VyY2UpID0+IHtcbiAgICAgIGxvZyg0LCBgW3Bvb2xdIERlc3Ryb3llZCBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LmApO1xuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XG4gICAgfSk7XG5cbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XG4gICAgLy8gQ3JlYXRlIGFuIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlc1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc291cmNlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGFuIGluaXRpYWwgcmVzb3VyY2UuJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XG4gICAgICBwb29sLnJlbGVhc2UocmVzb3VyY2UpO1xuICAgIH0pO1xuXG4gICAgbG9nKFxuICAgICAgMyxcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXG4gICAgKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgdGhlIHBvb2wgb2Ygd29ya2Vycy4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogS2lsbHMgYWxsIHdvcmtlcnMgaW4gdGhlIHBvb2wsIGRlc3Ryb3lzIHRoZSBwb29sLCBhbmQgY2xvc2VzIHRoZSBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgYWZ0ZXIgdGhlIHdvcmtlcnMgYXJlXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGtpbGxQb29sKCkge1xuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xuXG4gIC8vIElmIHN0aWxsIGFsaXZlLCBkZXN0cm95IHRoZSBwb29sIG9mIHBhZ2VzIGJlZm9yZSBjbG9zaW5nIGEgYnJvd3NlclxuICBpZiAocG9vbCkge1xuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcbiAgICBmb3IgKGNvbnN0IHdvcmtlciBvZiBwb29sLnVzZWQpIHtcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xuICAgIH1cblxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xuICAgICAgYXdhaXQgcG9vbC5kZXN0cm95KCk7XG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xuICAgIH1cbiAgfVxuXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXG4gIGF3YWl0IGNsb3NlQnJvd3NlcigpO1xufVxuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXG4gKiB0aGUgd29ya2VyIGhhbmRsZSBiYWNrIHRvIHRoZSBwb29sLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFydCAtIFRoZSBjaGFydCBkYXRhIG9yIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGV4cG9ydCByZXN1bHRhbmRcbiAqIG9wdGlvbnMuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IElmIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICovXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcbiAgbGV0IHdvcmtlckhhbmRsZTtcblxuICB0cnkge1xuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XG5cbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xuICAgIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xuICAgICAgZ2V0UG9vbEluZm8oKTtcbiAgICB9XG5cbiAgICBpZiAoIXBvb2wpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XG4gICAgfVxuXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcblxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICA1LFxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXG4gICAgICAgICAgOiAnJykgK1xuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICB9XG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xuXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTYXZlIHRoZSBzdGFydCB0aW1lXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gICAgbG9nKDQsIGBbcG9vbF0gU3RhcnRpbmcgd29yayBvbiBwb29sIGVudHJ5IHdpdGggSUQgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xuXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcbiAgICBjb25zdCBleHBvcnRDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcblxuICAgIC8vIENoZWNrIGlmIGl0J3MgYW4gZXJyb3JcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgIC8vIE5PVEU6IElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cbiAgICAgIC8vICAgICAgIFRoaXMgaXMgYmVjYXVzZSB0aGUgcGFnZSBtYXkgYmUgaW4gYSBzdGF0ZSB3aGVyZSBpdCdzIHdhaXRpbmcgZm9yXG4gICAgICAvLyAgICAgICB0aGUgc2NyZWVuc2hvdCB0byBmaW5pc2ggZXZlbiB0aG91Z2ggdGhlIHRpbWVvdXQgaGFzIG9jY3VyZWQuXG4gICAgICAvLyAgICAgICBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXG4gICAgICAvLyAgICAgICBhbmQgcGFnZSBjb25zaXN0ZW5jeS5cbiAgICAgIC8vXG4gICAgICAvLyBOT1RFOiBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcbiAgICAgIC8vICAgICAgIGhhbmRsZWQgYnkgdGhlIHBhZ2UucGRmIGZ1bmN0aW9uIGl0c2VsZi5cbiAgICAgIC8vXG4gICAgICAvLyAgICAgICAuLi55ZXMsIHRoaXMgaXMgdWdseS5cbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcbiAgICAgICAgd29ya2VySGFuZGxlLndvcmtDb3VudCA9IHBvb2xDb25maWcud29ya0xpbWl0ICsgMTtcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBudWxsO1xuICAgICAgfVxuXG4gICAgICBpZiAoXG4gICAgICAgIHJlc3VsdC5uYW1lID09PSAnVGltZW91dEVycm9yJyB8fFxuICAgICAgICByZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCdcbiAgICAgICkge1xuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgJ1Jhc3Rlcml6YXRpb24gdGltZW91dDogeW91ciBjaGFydCBtYXkgYmUgdG9vIGNvbXBsZXggb3IgbGFyZ2UsIGFuZCBmYWlsZWQgdG8gcmVuZGVyIHdpdGhpbiB0aGUgYWxsb3R0ZWQgdGltZS4nXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXG4gICAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXG4gICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xuICAgICAgbG9nKFxuICAgICAgICA1LFxuICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcbiAgICAgICAgYEV4cG9ydGVkIGEgY2hhcnQgc3VjZXNzZnVsbHk6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xuXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cbiAgICBjb25zdCB3b3JrRW5kID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XG4gICAgc3RhdHMuc3BlbnRBdmVyYWdlID0gc3RhdHMudGltZVNwZW50IC8gKytzdGF0cy5wZXJmb3JtZWRFeHBvcnRzO1xuXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcblxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxuICAgIHJldHVybiB7XG4gICAgICByZXN1bHQsXG4gICAgICBvcHRpb25zXG4gICAgfTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICArK3N0YXRzLmRyb3BwZWRFeHBvcnRzO1xuXG4gICAgaWYgKHdvcmtlckhhbmRsZSkge1xuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XG4gICAgfVxuXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbcG9vbF0gSW4gcG9vbC5wb3N0V29yazogJHtlcnJvci5tZXNzYWdlfWApLnNldEVycm9yKFxuICAgICAgZXJyb3JcbiAgICApO1xuICB9XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R8bnVsbH0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRQb29sID0gKCkgPT4gcG9vbDtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxuICovXG5leHBvcnQgY29uc3QgZ2V0UG9vbEluZm9KU09OID0gKCkgPT4gKHtcbiAgbWluOiBwb29sLm1pbixcbiAgbWF4OiBwb29sLm1heCxcbiAgYWxsOiBwb29sLm51bUZyZWUoKSArIHBvb2wubnVtVXNlZCgpLFxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcbiAgcGVuZGluZzogcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKVxufSk7XG5cbi8qKlxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcbiAqIHJlcXVlc3RzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XG4gIGNvbnN0IHsgbWluLCBtYXgsIGFsbCwgYXZhaWxhYmxlLCB1c2VkLCBwZW5kaW5nIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcblxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkIHJlc291cmNlczogJHthbGx9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhY3F1aXJlZCByZXNvdXJjZXM6ICR7dXNlZH0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgYWNxdWlyZWQ6ICR7cGVuZGluZ30uYCk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgaW5pdFBvb2wsXG4gIGtpbGxQb29sLFxuICBwb3N0V29yayxcbiAgZ2V0UG9vbCxcbiAgZ2V0UG9vbEluZm8sXG4gIGdldFBvb2xJbmZvSlNPTixcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcblxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcbmltcG9ydCB7XG4gIGZpeFR5cGUsXG4gIGhhbmRsZVJlc291cmNlcyxcbiAgaXNDb3JyZWN0SlNPTixcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgcm91bmROdW1iZXIsXG4gIHRvQm9vbGVhbixcbiAgd3JhcEFyb3VuZFxufSBmcm9tICcuL3V0aWxzLmpzJztcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XG5cbi8qKlxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXG4gKiBmcm9tIGFsbCBwb3NzaWJsZSBzb3VyY2VzIChjb25maWcsIGVudiwgY2xpLCBqc29uKS4gVGhlIGBlbmRDYWxsYmFja2AgaXNcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XG4gKiBjb25maWd1cmF0aW9uLlxuICogQHBhcmFtIHtmdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBUaGUgY2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCB1cG9uXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHt2b2lkfSBUaGlzIGZ1bmN0aW9uIGRvZXMgbm90IHJldHVybiBhIHZhbHVlIGRpcmVjdGx5OyBpbnN0ZWFkLFxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cbiAqL1xuZXhwb3J0IGNvbnN0IHN0YXJ0RXhwb3J0ID0gYXN5bmMgKHNldHRpbmdzLCBlbmRDYWxsYmFjaykgPT4ge1xuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XG5cbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XG5cbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XG5cbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XG5cbiAgICAgIGNvbnN0IHJlc3VsdCA9IGV4cG9ydEFzU3RyaW5nKFxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxuICAgICAgICBvcHRpb25zLFxuICAgICAgICBlbmRDYWxsYmFja1xuICAgICAgKTtcblxuICAgICAgKytzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHM7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gRXhwb3J0IHVzaW5nIG9wdGlvbnMgZnJvbSB0aGUgZmlsZVxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xuICAgICAgcmV0dXJuIGV4cG9ydEFzU3RyaW5nKG9wdGlvbnMuZXhwb3J0Lmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIGlucHV0IGZpbGUuJykuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXG4gIGlmIChcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXG4gICkge1xuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcblxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgICB9XG5cbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcbiAgICAgICAgOiBkb0V4cG9ydChcbiAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXG4gICAgICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xuICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcbiAgICApXG4gICk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgYmF0Y2ggZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcblxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICBleHBvcnQ6IHtcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcblxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgc2luZ2xlIGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxuICovXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XG5cbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cblxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcbiAgICApO1xuXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogY2hhcnQgZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXG4gKi9cbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcblxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XG5cbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXG4gIGxldCBzY2FsZSA9XG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XG4gICAgMTtcblxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XG5cbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcblxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXG4gIGNvbnN0IHNpemUgPSB7XG4gICAgaGVpZ2h0OlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxuICAgICAgNDAwLFxuICAgIHdpZHRoOlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBjaGFydD8ud2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxuICAgICAgNjAwLFxuICAgIHNjYWxlXG4gIH07XG5cbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcbiAgICBzaXplW3BhcmFtXSA9XG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xuICB9XG4gIHJldHVybiBzaXplO1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xuICogaXMgY29tcGxldGVkLlxuICovXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICAgIHJlc291cmNlcyxcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgMixcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGlmIChcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcbiAgICApIHtcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xuICB9XG5cbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cbiAgaWYgKGNoYXJ0SnNvbikge1xuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcbiAgfVxuXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xuICB9XG5cbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcbiAgICAgICAgKSB7XG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXG4gICAgICAgICAgICB0cnVlXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xuICAgIHRyeSB7XG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICB9XG4gIH1cblxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXG4gIGlmIChcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcbiAgKSB7XG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxuICAgICAgICAgICd1dGY4J1xuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLy8gU2l6ZSBzZWFyY2hcbiAgb3B0aW9ucy5leHBvcnQgPSB7XG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxuICB9O1xuXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcbiAgdHJ5IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXG4gICAgICBvcHRpb25zXG4gICAgKTtcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxuICpcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XG4gKiB0byBiZSBpbmplY3RlZC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXG4gKlxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxuICovXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XG4gIHRyeSB7XG4gICAgbGV0IHN0ckluajtcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xuXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxuICAgICAgICBpbnN0cixcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICApO1xuICAgIH1cbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xuICAgIH1cblxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXG4gKi9cbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcblxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcbiAgaWYgKFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXG4gICkge1xuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XG5cbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xuICAgICAgICApLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxuICpcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XG5cbi8qKlxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxuICovXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGJhdGNoRXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzdGFydEV4cG9ydCxcbiAgZmluZENoYXJ0U2l6ZVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vKipcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXG4gKiovXG5cbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xuXG4vKipcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxuICogb2NjdXJyZW5jZXMgb2YgPHNjcmlwdD4uLi48L3NjcmlwdD4gdGFncyBhbmQgYW55IGNvbnRlbnQgd2l0aGluIHRoZW0uXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSBUaGUgc2FuaXRpemVkIEhUTUwgc3RyaW5nLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7XG4gICAgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddLFxuICAgIC8vIERpc3NhbG93IGFsbCB4bGlua3MgaW4gaW5jb21pbmcgU1ZHXG4gICAgRk9SQklEX0FUVFI6IFsneGxpbms6aHJlZiddXG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5cbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcblxuLyoqXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXG4gKi9cbmV4cG9ydCBjb25zdCBhZGRJbnRlcnZhbCA9IChpZCkgPT4ge1xuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcbn07XG5cbi8qKlxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxuICovXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xuICBmb3IgKGNvbnN0IGlkIG9mIGludGVydmFsSWRzKSB7XG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XG4gIH1cbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgYWRkSW50ZXJ2YWwsXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXG59O1xuIiwiaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uL2VudnMuanMnO1xuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxuICovXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gIC8vIERpc3BsYXkgdGhlIGVycm9yIHdpdGggc3RhY2sgaW4gYSBjb3JyZWN0IGZvcm1hdFxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xuXG4gIC8vIERlbGV0ZSB0aGUgc3RhY2sgZm9yIHRoZSBlbnZpcm9ubWVudCBvdGhlciB0aGFuIHRoZSBkZXZlbG9wbWVudFxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcbiAgfVxuXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxuICBuZXh0KGVycm9yKTtcbn07XG5cbi8qKlxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXG4gKi9cbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcbiAgLy8gR2F0aGVyIGFsbCByZXF1aWVkIGluZm9ybWF0aW9uIGZvciB0aGUgcmVzcG9uc2VcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA0MDA7XG5cbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XG4gIC8vIEFkZCBsb2cgZXJyb3IgbWlkZGxld2FyZVxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XG5cbiAgLy8gQWRkIHNldCBzdGF0dXMgYW5kIHJldHVybiBlcnJvciBtaWRkbGV3YXJlXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xuXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuXG4vKipcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cbiAqXG4gKiBAcGFyYW0ge0V4cHJlc3N9IGFwcCAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCwgbGltaXRDb25maWcpID0+IHtcbiAgY29uc3QgbXNnID1cbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XG5cbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcbiAgICBtYXg6IGxpbWl0Q29uZmlnLm1heFJlcXVlc3RzIHx8IDMwLFxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXG4gICAgdHJ1c3RQcm94eTogbGltaXRDb25maWcudHJ1c3RQcm94eSB8fCBmYWxzZSxcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXG4gIH07XG5cbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XG4gIGlmIChyYXRlT3B0aW9ucy50cnVzdFByb3h5KSB7XG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XG4gICAgd2luZG93TXM6IHJhdGVPcHRpb25zLndpbmRvdyAqIDYwICogMTAwMCxcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcbiAgICAvLyBEaXNhYmxlIGRlbGF5aW5nLCBmdWxsIHNwZWVkIHVudGlsIHRoZSBtYXggbGltaXQgaXMgcmVhY2hlZFxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgcmVzcG9uc2UuZm9ybWF0KHtcbiAgICAgICAganNvbjogKCkgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH0sXG4gICAgc2tpcDogKHJlcXVlc3QpID0+IHtcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XG4gICAgICBpZiAoXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBLZXkgIT09IGZhbHNlICYmXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5hY2Nlc3NfdG9rZW4gPT09IHJhdGVPcHRpb25zLnNraXBUb2tlblxuICAgICAgKSB7XG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICB9KTtcblxuICAvLyBVc2UgYSBsaW1pdGVyIGFzIGEgbWlkZGxld2FyZVxuICBhcHAudXNlKGxpbWl0ZXIpO1xuXG4gIGxvZyhcbiAgICAzLFxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXG4gICk7XG59O1xuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xuXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xuICAgIHN1cGVyKG1lc3NhZ2UpO1xuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xuICB9XG5cbiAgc2V0U3RhdHVzKHN0YXR1cykge1xuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyB1cGRhdGVWZXJzaW9uLCB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xuXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xuXG4vKipcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxuICpcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxuICAhYXBwXG4gICAgPyBmYWxzZVxuICAgIDogYXBwLnBvc3QoXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcblxuICAgICAgICAgICAgLy8gQ2hlY2sgdGhlIGV4aXN0ZW5jZSBvZiB0aGUgdG9rZW5cbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICAgICAgICAnVGhlIHNlcnZlciBpcyBub3QgY29uZmlndXJlZCB0byBwZXJmb3JtIHJ1bi10aW1lIHZlcnNpb24gY2hhbmdlczogSElHSENIQVJUU19BRE1JTl9UT0tFTiBpcyBub3Qgc2V0LicsXG4gICAgICAgICAgICAgICAgNDAxXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxuICAgICAgICAgICAgY29uc3QgdG9rZW4gPSByZXF1ZXN0LmdldCgnaGMtYXV0aCcpO1xuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAgICAgICAgICdJbnZhbGlkIG9yIG1pc3NpbmcgdG9rZW46IFNldCB0aGUgdG9rZW4gaW4gdGhlIGhjLWF1dGggaGVhZGVyLicsXG4gICAgICAgICAgICAgICAgNDAxXG4gICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcbiAgICAgICAgICAgIGNvbnN0IG5ld1ZlcnNpb24gPSByZXF1ZXN0LnBhcmFtcy5uZXdWZXJzaW9uO1xuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcbiAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXG4gICAgICAgICAgICAgICAgYXdhaXQgdXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcbiAgICAgICAgICAgICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIFN1Y2Nlc3NcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxuICAgICAgICAgICAgICAgIHZlcnNpb246IHZlcnNpb24oKSxcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xuXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQge1xuICBmaXhUeXBlLFxuICBpc0NvcnJlY3RKU09OLFxuICBpc09iamVjdEVtcHR5LFxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxuICBvcHRpb25zU3RyaW5naWZ5LFxuICBtZWFzdXJlVGltZVxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG5cbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XG5cbi8vIFJldmVyc2VkIE1JTUUgdHlwZXNcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcbiAganBlZzogJ2ltYWdlL2pwZWcnLFxuICBnaWY6ICdpbWFnZS9naWYnLFxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxuICBzdmc6ICdpbWFnZS9zdmcreG1sJ1xufTtcblxuLy8gVGhlIHJlcXVlc3RzIGNvdW50ZXJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xuXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYmVmb3JlIGEgcmVxdWVzdFxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xuXG4vLyBUaGUgYXJyYXkgb2YgY2FsbGJhY2tzIHRvIGNhbGwgYWZ0ZXIgYSByZXF1ZXN0XG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcblxuLyoqXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXG4gKiB0byBiZSBleGVjdXRlZC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxuICogdHlwZSwgYW5kIGJvZHkuXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcbiAqIG9mIHRoZSBjYWxsYmFjayBpbnZvY2F0aW9ucy5cbiAqL1xuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xuICBsZXQgcmVzdWx0ID0gdHJ1ZTtcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XG5cbiAgY2FsbGJhY2tzLnNvbWUoKGNhbGxiYWNrKSA9PiB7XG4gICAgaWYgKGNhbGxiYWNrKSB7XG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XG5cbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXG4gKlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xuICogaXMgY29tcGxldGUuXG4gKi9cbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcbiAgdHJ5IHtcbiAgICAvLyBTdGFydCBjb3VudGluZyB0aW1lXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgdW5pcXVlIElEIGZvciBhIHJlcXVlc3RcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcblxuICAgIC8vIEdldCB0aGUgY3VycmVudCBzZXJ2ZXIncyBnZW5lcmFsIG9wdGlvbnNcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcblxuICAgIGNvbnN0IGJvZHkgPSByZXF1ZXN0LmJvZHk7XG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcblxuICAgIGxldCB0eXBlID0gZml4VHlwZShib2R5LnR5cGUpO1xuXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcbiAgICBpZiAoIWJvZHkgfHwgaXNPYmplY3RFbXB0eShib2R5KSkge1xuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXG4gICAgICAgIDQwMFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcblxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xuICAgICAgbG9nKFxuICAgICAgICAyLFxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XG4gICAgICAgICAgcmVxdWVzdC5oZWFkZXJzWyd4LWZvcndhcmRlZC1mb3InXSB8fCByZXF1ZXN0LmNvbm5lY3Rpb24ucmVtb3RlQWRkcmVzc1xuICAgICAgICB9IHdhcyBpbmNvcnJlY3Q6XG4gIENvbnRlbnQtVHlwZTogJHtyZXF1ZXN0LmhlYWRlcnNbJ2NvbnRlbnQtdHlwZSddfS4gXG4gIENoYXJ0IGNvbnN0cnVjdG9yOiAke2JvZHkuY29uc3RyfS5cbiAgRGltZW5zaW9uczogJHtib2R5LndpZHRofXgke2JvZHkuaGVpZ2h0fSBAICR7Ym9keS5zY2FsZX0gc2NhbGUuXG4gIFR5cGU6ICR7dHlwZX0uXG4gIElzIFNWRyBzZXQ/ICR7dHlwZW9mIGJvZHkuc3ZnICE9PSAndW5kZWZpbmVkJ30uXG4gIEI2ND8gJHt0eXBlb2YgYm9keS5iNjQgIT09ICd1bmRlZmluZWQnfS5cbiAgTm8gZG93bmxvYWQ/ICR7dHlwZW9mIGJvZHkubm9Eb3dubG9hZCAhPT0gJ3VuZGVmaW5lZCd9LlxuXG4gIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSB8fCBib2R5LnN2Zyl9XG5cbiAgYFxuICAgICAgKTtcblxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xuXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcbiAgICAgIGlkLFxuICAgICAgdW5pcXVlSWQsXG4gICAgICB0eXBlLFxuICAgICAgYm9keVxuICAgIH0pO1xuXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XG4gICAgfVxuXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XG5cbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKGhhZEVycm9ycykgPT4ge1xuICAgICAgaWYgKGhhZEVycm9ycykge1xuICAgICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcblxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XG5cbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xuICAgICAgZXhwb3J0OiB7XG4gICAgICAgIGluc3RyLFxuICAgICAgICB0eXBlLFxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxuICAgICAgfSxcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYgKGluc3RyKSB7XG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXG4gICAgICAgIGluc3RyLFxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcblxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xuXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcbiAgICB9O1xuXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xuXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICA1LFxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xuICAgICAgICByZXR1cm4gbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXG4gICAgICAgICAgNDAwXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XG5cbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XG5cbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XG4gICAgICAgIGlmIChib2R5LmI2NCkge1xuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcblxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xuICAgICAgICAgICAgfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xuICAgICAgfVxuICAgIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIG5leHQoZXJyb3IpO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XG4gIC8qKlxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cbiAgICovXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XG5cbiAgLyoqXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxuICAgKi9cbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XG5cbmltcG9ydCB7IHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBhZGRJbnRlcnZhbCB9IGZyb20gJy4uLy4uL2ludGVydmFscy5qcyc7XG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xuXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xuXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwOyAvLyByZWNvcmQgZXZlcnkgbWludXRlXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcblxuLyoqXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcbiAqIGFycmF5LlxuICpcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXG4gKi9cbmZ1bmN0aW9uIGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XG59XG5cbi8qKlxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cbiAqIGFuZCBnYXRoZXJzXG4gKlxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XG4gIHNldEludGVydmFsKCgpID0+IHtcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcbiAgICAgICAgPyAxXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XG5cbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XG4gICAgfVxuICB9LCByZWNvcmRJbnRlcnZhbCk7XG5cbi8qKlxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcbiAgaWYgKCFhcHApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXG4gIGFkZEludGVydmFsKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XG5cbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XG5cbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XG5cbiAgICByZXMuc2VuZCh7XG4gICAgICBzdGF0dXM6ICdPSycsXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxuICAgICAgdXB0aW1lOlxuICAgICAgICBNYXRoLmZsb29yKFxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IHZlcnNpb24oKSxcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKSxcblxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcbiAgICAgIHBlcmlvZCxcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxuICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xuICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcblxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcbiAgICAgIHN2Z0V4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHMsXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcbiAgICB9KTtcbiAgfSk7XG59XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XG5cbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XG5cbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcblxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcblxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxuYXBwLnVzZShjb3JzKCkpO1xuXG4vLyBHZXR0aW5nIGEgbG90IG9mIFJhbmdlTm90U2F0aXNmaWFibGVFcnJvciBleGNlcHRpb24uXG4vLyBFdmVuIHRob3VnaCB0aGlzIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlLlxuYXBwLnVzZSgoX3JlcSwgcmVzLCBuZXh0KSA9PiB7XG4gIHJlcy5zZXQoJ0FjY2VwdC1SYW5nZXMnLCAnbm9uZScpO1xuICBuZXh0KCk7XG59KTtcblxuLyoqXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXG4gKi9cbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xuICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgIDEsXG4gICAgICBlcnJvcixcbiAgICAgIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX0sIGRlc3Ryb3lpbmcgc29ja2V0LmBcbiAgICApO1xuICAgIHNvY2tldC5kZXN0cm95KCk7XG4gIH0pO1xuXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfSk7XG5cbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgIH0pO1xuICB9KTtcbn07XG5cbi8qKlxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXG4gKiBhbmQgc3RhcnRlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xuICB0cnkge1xuICAgIC8vIFRPRE86IFJlYWQgZnJvbSBjb25maWcvZW52XG4gICAgLy8gTk9URTpcbiAgICAvLyBUb28gYmlnIGxpbWl0cyBsZWFkIHRvIHRpbWVvdXRzIGluIHRoZSBleHBvcnQgcHJvY2VzcyB3aGVuIHRoZVxuICAgIC8vIHJhc3Rlcml6YXRpb24gdGltZW91dCBpcyBzZXQgdG9vIGxvdy5cbiAgICBjb25zdCB1cGxvYWRMaW1pdE1pQiA9IHNlcnZlckNvbmZpZy5tYXhVcGxvYWRTaXplIHx8IDM7XG4gICAgY29uc3QgdXBsb2FkTGltaXRCeXRlcyA9IHVwbG9hZExpbWl0TWlCICogMTAyNCAqIDEwMjQ7XG5cbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXG4gICAgY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XG4gICAgY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcbiAgICAgIHN0b3JhZ2UsXG4gICAgICBsaW1pdHM6IHtcbiAgICAgICAgZmllbGRTaXplOiB1cGxvYWRMaW1pdEJ5dGVzXG4gICAgICB9XG4gICAgfSk7XG5cbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXJcbiAgICBhcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzIH0pKTtcbiAgICBhcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogdXBsb2FkTGltaXRCeXRlcyB9KSk7XG5cbiAgICAvLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcbiAgICBhcHAudXNlKHVwbG9hZC5ub25lKCkpO1xuXG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcblxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcblxuICAgICAgLy8gTGlzdGVuXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcblxuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cbiAgICAgIGxldCBrZXksIGNlcnQ7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXG4gICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMixcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcblxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xuXG4gICAgICAgIC8vIExpc3RlblxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XG5cbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcblxuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xuICAgIGlmIChcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcbiAgICApIHtcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xuICAgIH1cblxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcblxuICAgIC8vIFNldCB1cCByb3V0ZXNcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xuICAgIHVpUm91dGUoYXBwKTtcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcblxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcbiAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XG4gICAgfSk7XG4gIH1cbn07XG5cbi8qKlxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7QXJyYXl9IC0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcblxuLyoqXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cbiAqL1xuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xuXG4vKipcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XG5cbi8qKlxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcblxuLyoqXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbi8qKlxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxuICovXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxuICovXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIHN0YXJ0U2VydmVyLFxuICBjbG9zZVNlcnZlcnMsXG4gIGdldFNlcnZlcnMsXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcbiAgZ2V0RXhwcmVzcyxcbiAgZ2V0QXBwLFxuICB1c2UsXG4gIGdldCxcbiAgcG9zdFxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuLyoqXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAuZ2V0KCcvJywgKF9yZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJyksIHtcbiAgICAgICAgICBhY2NlcHRSYW5nZXM6IGZhbHNlXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgY2xlYXJBbGxJbnRlcnZhbHMgfSBmcm9tICcuL2ludGVydmFscy5qcyc7XG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xuXG4vKipcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBzaHV0ZG93bkNsZWFuVXAgPSBhc3luYyAoZXhpdENvZGUpID0+IHtcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXG4gIGF3YWl0IFByb21pc2UuYWxsU2V0dGxlZChbXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcblxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cbiAgICBjbG9zZVNlcnZlcnMoKSxcblxuICAgIC8vIENsb3NlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2UsIGlmIGV4aXN0c1xuICAgIGtpbGxQb29sKClcbiAgXSk7XG5cbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcbiAgcHJvY2Vzcy5leGl0KGV4aXRDb2RlKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgc2h1dGRvd25DbGVhblVwXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCAnY29sb3JzJztcblxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xuaW1wb3J0IHtcbiAgYmF0Y2hFeHBvcnQsXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc2luZ2xlRXhwb3J0LFxuICBzdGFydEV4cG9ydFxufSBmcm9tICcuL2NoYXJ0LmpzJztcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQge1xuICBpbml0TG9nZ2luZyxcbiAgbG9nLFxuICBsb2dXaXRoU3RhY2ssXG4gIHNldExvZ0xldmVsLFxuICBlbmFibGVGaWxlTG9nZ2luZ1xufSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcbmltcG9ydCBzZXJ2ZXIsIHsgc3RhcnRTZXJ2ZXIgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbi8qKlxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxuICogJ3VuY2F1Z2h0RXhjZXB0aW9uJyBldmVudHMuXG4gKi9cbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xuICBsb2coMywgJ1twcm9jZXNzXSBBdHRhY2hpbmcgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MuJyk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xuICBwcm9jZXNzLm9uKCdleGl0JywgKGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xuICB9KTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xuICB9KTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgVGhlICR7bmFtZX0gZXJyb3IuYCk7XG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xuICB9KTtcbn07XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwcm9jZXNzLiBUYXNrcyBzdWNoIGFzIGNvbmZpZ3VyaW5nIGxvZ2dpbmcsIGNoZWNraW5nXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWQgZXhwb3J0IG9wdGlvbnMuXG4gKi9cbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xuICAvLyBTZXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBwZXIgZXhwb3J0IG1vZHVsZSBzY29wZVxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxuICApO1xuXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcbiAgaW5pdExvZ2dpbmcob3B0aW9ucy5sb2dnaW5nKTtcblxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcbiAgaWYgKG9wdGlvbnMub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMpIHtcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xuICB9XG5cbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xuXG4gIC8vIEluaXQgdGhlIHBvb2xcbiAgYXdhaXQgaW5pdFBvb2woe1xuICAgIHBvb2w6IG9wdGlvbnMucG9vbCB8fCB7XG4gICAgICBtaW5Xb3JrZXJzOiAxLFxuICAgICAgbWF4V29ya2VyczogMVxuICAgIH0sXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxuICB9KTtcblxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXG4gIHJldHVybiBvcHRpb25zO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICAvLyBTZXJ2ZXJcbiAgc2VydmVyLFxuICBzdGFydFNlcnZlcixcblxuICAvLyBFeHBvcnRpbmdcbiAgaW5pdEV4cG9ydCxcbiAgc2luZ2xlRXhwb3J0LFxuICBiYXRjaEV4cG9ydCxcbiAgc3RhcnRFeHBvcnQsXG5cbiAgLy8gUG9vbFxuICBpbml0UG9vbCxcbiAga2lsbFBvb2wsXG5cbiAgLy8gT3RoZXJcbiAgc2V0T3B0aW9ucyxcbiAgc2h1dGRvd25DbGVhblVwLFxuXG4gIC8vIExvZ3NcbiAgbG9nLFxuICBsb2dXaXRoU3RhY2ssXG4gIHNldExvZ0xldmVsLFxuICBlbmFibGVGaWxlTG9nZ2luZyxcblxuICAvLyBVdGlsc1xuICBtYXBUb05ld0NvbmZpZyxcbiAgbWFudWFsQ29uZmlnLFxuICBwcmludExvZ28sXG4gIHByaW50VXNhZ2Vcbn07XG4iXSwibmFtZXMiOlsic2NyaXB0c05hbWVzIiwiY29yZSIsIm1vZHVsZXMiLCJpbmRpY2F0b3JzIiwiY3VzdG9tIiwiZGVmYXVsdENvbmZpZyIsInB1cHBldGVlciIsImFyZ3MiLCJ2YWx1ZSIsInR5cGUiLCJkZXNjcmlwdGlvbiIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiZW52TGluayIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsIm1heFVwbG9hZFNpemUiLCJjbGlOYW1lIiwiZW5hYmxlIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidG9Db25zb2xlIiwidG9GaWxlIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwibG9nVG9GaWxlIiwidGV4dHMiLCJwcmVmaXgiLCJleGlzdHNTeW5jIiwibWtkaXJTeW5jIiwiYXBwZW5kRmlsZSIsImNvbmNhdCIsImVycm9yIiwiY29uc29sZSIsImxvZyIsIm5ld0xldmVsIiwiRGF0ZSIsInRvU3RyaW5nIiwiZm4iLCJhcHBseSIsImxvZ1dpdGhTdGFjayIsImN1c3RvbU1lc3NhZ2UiLCJtYWluTWVzc2FnZSIsInN0YWNrTWVzc2FnZSIsInN0YWNrIiwic2xpY2UiLCJzZXRMb2dMZXZlbCIsImVuYWJsZUZpbGVMb2dnaW5nIiwibG9nRGVzdCIsImxvZ0ZpbGUiLCJlbmRzV2l0aCIsIl9fZGlybmFtZSIsImZpbGVVUkxUb1BhdGgiLCJVUkwiLCJkb2N1bWVudCIsInJlcXVpcmUiLCJwYXRoVG9GaWxlVVJMIiwiX19maWxlbmFtZSIsImhyZWYiLCJfZG9jdW1lbnRDdXJyZW50U2NyaXB0IiwidGFnTmFtZSIsInRvVXBwZXJDYXNlIiwic3JjIiwiYmFzZVVSSSIsImZpeFR5cGUiLCJmb3JtYXRzIiwib3V0VHlwZSIsInBvcCIsImZpbmQiLCJ0IiwiaGFuZGxlUmVzb3VyY2VzIiwiYWxsb3dlZFByb3BzIiwiaGFuZGxlZFJlc291cmNlcyIsImNvcnJlY3RSZXNvdXJjZXMiLCJpc0NvcnJlY3RKU09OIiwicmVhZEZpbGVTeW5jIiwiZmlsZXMiLCJwcm9wTmFtZSIsIml0ZW0iLCJkYXRhIiwicGFyc2VkRGF0YSIsIkpTT04iLCJzdHJpbmdpZnkiLCJkZWVwQ29weSIsImNvcHkiLCJBcnJheSIsImlzQXJyYXkiLCJrZXkiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJvcHRpb25zU3RyaW5naWZ5IiwiYWxsb3dGdW5jdGlvbnMiLCJyZXBsYWNlQWxsIiwicHJpbnRVc2FnZSIsImJvbGQiLCJ5ZWxsb3ciLCJjeWNsZUNhdGVnb3JpZXMiLCJvcHRpb24iLCJlbnRyaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsImhlYWRlcnMiLCJSZWZlcmVyIiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJjaGFydCIsImFuaW1hdGlvbiIsInN0ckluaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJGdW5jdGlvbiIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50IiwiaXNDbG9zZWQiLCIkZXZhbCIsImVsZW1lbnQiLCJlcnJvck1lc3NhZ2UiLCJpbm5lckhUTUwiLCJzZXRQYWdlRXZlbnRzIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJldmFsdWF0ZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwic2V0Q29udGVudCIsIndhaXRVbnRpbCIsImFkZFNjcmlwdFRhZyIsInBhdGgiLCJzZXRBc0NvbmZpZyIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInIiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiRk9SQklEX0FUVFIiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwidjQiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImI2NCIsIm5vRG93bmxvYWQiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsImhhZEVycm9ycyIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwiX3JlcSIsInNldCIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsInVwbG9hZExpbWl0Qnl0ZXMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwiZXhwb3J0Um91dGVzIiwiX3JlcXVlc3QiLCJzZW5kRmlsZSIsImFjY2VwdFJhbmdlcyIsInVpUm91dGUiLCJlcnJvckhhbmRsZXIiLCJjbG9zZVNlcnZlcnMiLCJkZWxldGUiLCJnZXRTZXJ2ZXJzIiwiZW5hYmxlUmF0ZUxpbWl0aW5nIiwiZ2V0RXhwcmVzcyIsImdldEFwcCIsIm1pZGRsZXdhcmVzIiwic2h1dGRvd25DbGVhblVwIiwiZXhpdENvZGUiLCJhbGxTZXR0bGVkIiwiZXhpdCIsImluZGV4IiwiaW5pdEV4cG9ydCIsImxvZ2dpbmdPcHRpb25zIiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiK2NBZU8sTUFBTUEsRUFBZSxDQUMxQkMsS0FBTSxDQUFDLGFBQWMsa0JBQW1CLGlCQUN4Q0MsUUFBUyxDQUNQLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsdUJBQ0EsZ0JBRUEsZUFDQSxRQUNBLE9BQ0EsYUFDQSxtQkFDQSxlQUNBLGNBQ0EsVUFDQSxVQUNBLGNBQ0EsV0FDQSxVQUNBLFlBQ0EsY0FDQSxZQUNBLHNCQUNBLFNBQ0EsU0FDQSxXQUNBLGFBQ0EsWUFDQSxlQUNBLHlCQUNBLFNBQ0EsZUFDQSxZQUNBLGtCQUNBLFNBQ0EsY0FDQSxtQkFDQSxlQUNBLGtCQUNBLGNBQ0EsZUFFQSxjQUNBLFdBQ0EsZUFDQSxXQUNBLFNBQ0EsT0FDQSxXQUNBLFlBQ0EsU0FDQSxxQkFDQSxhQUNBLFdBQ0EsV0FDQSxXQUNBLFdBQ0EsZUFDQSxVQUNBLGtCQUNBLG9CQUNBLGFBQ0EsVUFDQSxjQUNBLFlBQ0EsWUFFRkMsV0FBWSxDQUFDLGtCQUNiQyxPQUFRLENBQ04sd0VBQ0EsbUdBTVNDLEVBQWdCLENBQzNCQyxVQUFXLENBQ1RDLEtBQU0sQ0FDSkMsTUFBTyxDQUNMLG1DQUNBLGtCQUNBLDBDQUNBLDJCQUNBLGtDQUNBLGtDQUNBLHdDQUNBLDJDQUNBLHFCQUNBLDRCQUNBLDJDQUNBLHVEQUNBLDZCQUNBLHlCQUNBLDBCQUNBLCtCQUNBLHVCQUNBLHVGQUNBLHlCQUNBLG9DQUNBLG9CQUNBLDBCQUNBLDhDQUNBLDJCQUNBLDBCQUNBLDZCQUNBLG1DQUNBLHdDQUNBLG1DQUNBLDJCQUNBLGtDQUNBLHVCQUNBLGlCQUNBLHlCQUNBLDhCQUNBLG9C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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),n=require("zod"),s=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),h=require("puppeteer"),u=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;const b={core:["highcharts","highcharts-more","highcharts-3d"],modules:["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"],indicators:["indicators-all"],custom:["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"]},w={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"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:b.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:b.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:b.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:b.custom,type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{maxUploadSize:{value:3,type:"number",cliName:"maxUploadSize",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in megabytes, for the server"},enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},E={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:w.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:w.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:w.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:w.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:w.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:w.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${w.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${w.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:w.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:w.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:w.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:w.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:w.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:w.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:w.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:w.server.host.value},{type:"number",name:"port",message:"Server port",initial:w.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:w.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:w.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:w.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:w.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:w.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:w.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:w.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:w.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:w.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:w.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:w.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:w.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:w.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:w.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:w.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:w.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:w.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:w.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:w.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:w.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:w.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:w.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:w.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:w.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:w.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:w.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:w.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:w.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:w.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:w.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:w.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:w.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:w.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:w.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:w.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:w.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:w.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:w.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:w.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:w.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:w.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:w.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:w.debug.debuggingPort.value}]},T=["options","globalOptions","themeOptions","resources","payload"],S={},x=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?x(o,`${t}.${r}`):(S[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(S[o.legacyName]=`${t}.${r}`.substring(1)))}}))};x(w),i.config();const R=e=>n.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),L=()=>n.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>n.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),_=()=>n.z.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),k=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),I=()=>n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),C=n.z.object({HIGHCHARTS_VERSION:n.z.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:n.z.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:R(b.core),HIGHCHARTS_MODULE_SCRIPTS:R(b.modules),HIGHCHARTS_INDICATOR_SCRIPTS:R(b.indicators),HIGHCHARTS_FORCE_FETCH:L(),HIGHCHARTS_CACHE_PATH:_(),HIGHCHARTS_ADMIN_TOKEN:_(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:k(),EXPORT_DEFAULT_WIDTH:k(),EXPORT_DEFAULT_SCALE:k(),EXPORT_RASTERIZATION_TIMEOUT:I(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:L(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:L(),SERVER_ENABLE:L(),SERVER_HOST:_(),SERVER_PORT:k(),SERVER_BENCHMARKING:L(),SERVER_PROXY_HOST:_(),SERVER_PROXY_PORT:k(),SERVER_PROXY_TIMEOUT:I(),SERVER_RATE_LIMITING_ENABLE:L(),SERVER_RATE_LIMITING_MAX_REQUESTS:I(),SERVER_RATE_LIMITING_WINDOW:I(),SERVER_RATE_LIMITING_DELAY:I(),SERVER_RATE_LIMITING_TRUST_PROXY:L(),SERVER_RATE_LIMITING_SKIP_KEY:_(),SERVER_RATE_LIMITING_SKIP_TOKEN:_(),SERVER_SSL_ENABLE:L(),SERVER_SSL_FORCE:L(),SERVER_SSL_PORT:k(),SERVER_SSL_CERT_PATH:_(),POOL_MIN_WORKERS:I(),POOL_MAX_WORKERS:I(),POOL_WORK_LIMIT:k(),POOL_ACQUIRE_TIMEOUT:I(),POOL_CREATE_TIMEOUT:I(),POOL_DESTROY_TIMEOUT:I(),POOL_IDLE_TIMEOUT:I(),POOL_CREATE_RETRY_INTERVAL:I(),POOL_REAPER_INTERVAL:I(),POOL_BENCHMARKING:L(),LOGGING_LEVEL:n.z.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:_(),LOGGING_DEST:_(),LOGGING_TO_CONSOLE:L(),LOGGING_TO_FILE:L(),UI_ENABLE:L(),UI_ROUTE:_(),OTHER_NODE_ENV:O(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:L(),OTHER_NO_LOGO:L(),OTHER_HARD_RESET_PAGE:L(),OTHER_BROWSER_SHELL_MODE:L(),DEBUG_ENABLE:L(),DEBUG_HEADLESS:L(),DEBUG_DEVTOOLS:L(),DEBUG_LISTEN_TO_CONSOLE:L(),DEBUG_DUMPIO:L(),DEBUG_SLOW_MO:I(),DEBUG_DEBUGGING_PORT:k()}).partial().parse(process.env),N=["red","yellow","blue","gray","green"];let A={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:N[0]},{title:"warning",color:N[1]},{title:"notice",color:N[2]},{title:"verbose",color:N[3]},{title:"benchmark",color:N[4]}],listeners:[]};const P=(t,r)=>{A.pathCreated||(!e.existsSync(A.dest)&&e.mkdirSync(A.dest),A.pathCreated=!0),e.appendFile(`${A.dest}${A.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),A.toFile=!1)}))},H=(...e)=>{const[t,...r]=e,{levelsDesc:o,level:i}=A;if(5!==t&&(0===t||t>i||i>o.length))return;const n=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;A.listeners.forEach((e=>{e(n,r.join(" "))})),A.toConsole&&console.log.apply(void 0,[n.toString()[A.levelsDesc[t-1].color]].concat(r)),A.toFile&&P(r,n)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:n}=A;if(0===e||e>i||i>n.length)return;const s=`${(new Date).toString().split("(")[0].trim()} [${n[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[o,"\n",a];A.toConsole&&console.log.apply(void 0,[s.toString()[A.levelsDesc[e-1].color]].concat([o[N[e-1]],"\n",a])),A.listeners.forEach((e=>{e(s,l.join(" "))})),A.toFile&&P(l,s)},G=e=>{e>=0&&e<=A.levelsDesc.length&&(A.level=e)},D=(e,t)=>{if(A={...A,dest:e||A.dest,file:t||A.file,toFile:!0},0===A.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");A.dest.endsWith("/")||(A.dest+="/")},U=s.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&"SCRIPT"===y.tagName.toUpperCase()&&y.src||new URL("index.cjs",document.baseURI).href)),F=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},j=(t=!1,r)=>{const o=["js","css","files"];let i=t,n=!1;if(r&&t.endsWith(".json"))try{i=M(e.readFileSync(t,"utf8"))}catch(e){return $(2,e,"[cli] No resources found.")}else i=M(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?n||(n=!0):delete i[e];return n?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):H(3,"[cli] No resources found.")};function M(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const q=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=q(e[r]));return t},W=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function V(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const B=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,z=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&z(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},X=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let K={};const J=()=>K,Y=(e,t,r=[])=>{const o=q(e);for(const[e,n]of Object.entries(t))o[e]="object"!=typeof(i=n)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==n?n:o[e]:Y(o[e],n,r);var i;return o};function Z(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],n=t&&t[o];void 0===i.value?Z(i,n,`${r}.${o}`):(void 0!==n&&(i.value=n),i.envLink in C&&void 0!==C[i.envLink]&&(i.value=C[i.envLink]))}))}function Q(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:Q(o);return t}function ee(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ee(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function te(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,Object.assign({headers:{"User-Agent":"highcharts/export",Referer:"highcharts/export"}},t||{}),(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class re extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}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 oe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ie=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ne=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const i=await te(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new re(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return H(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},se=async(t,o,i)=>{const n=t.version,s="latest"!==n&&n?`${n}/`:"",a=t.cdnURL||oe.cdnURL;H(3,`[cache] Updating cache version to Highcharts: ${s||"latest"}.`);const l={};try{return oe.sources=await(async(e,t,o,i,n)=>{let s;const a=i.host,l=i.port;if(a&&l)try{s=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new re("[cache] Could not create a Proxy Agent.").setError(e)}const c=s?{agent:s,timeout:C.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ne(`${e}`,c,n,!0))),...t.map((e=>ne(`${e}`,c,n))),...o.map((e=>ne(`${e}`,c)))];return(await Promise.all(p)).join(";\n")})([...t.coreScripts.map((e=>`${a}${s}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${s}modules/${e}`:`${a}${s}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${s}indicators/${e}`))],t.customScripts,o,l),oe.hcVersion=ie(oe),e.writeFileSync(i,oe.sources),l}catch(e){throw new re("[cache] Unable to update the local Highcharts cache.").setError(e)}},ae=async r=>{const{highcharts:o,server:i}=r,n=t.join(U,o.cachePath);let s;const a=t.join(n,"manifest.json"),l=t.join(n,"sources.js");if(!e.existsSync(n)&&e.mkdirSync(n),!e.existsSync(a)||o.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),s=await se(o,i.proxy,l);else{let t=!1;const r=JSON.parse(e.readFileSync(a));if(r.modules&&Array.isArray(r.modules)){const e={};r.modules.forEach((t=>e[t]=1)),r.modules=e}const{coreScripts:n,moduleScripts:c,indicatorScripts:p}=o,h=n.length+c.length+p.length;r.version!==o.version?(H(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==h?(H(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return H(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?s=await se(o,i.proxy,l):(H(3,"[cache] Dependency cache is up to date, proceeding."),oe.sources=e.readFileSync(l,"utf8"),s=r.modules,oe.hcVersion=ie(oe))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};oe.activeManifest=i,H(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(U,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new re("[cache] Error writing the cache manifest.").setError(e)}})(o,s)},le=()=>t.join(U,J().highcharts.cachePath),ce=()=>oe.hcVersion;function pe(){Highcharts.animObject=function(){return{duration:0}}}async function he(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:n,wrap:s}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o());const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),window.isRenderComplete=!1,s(Highcharts.Chart.prototype,"init",(function(e,t,r){((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,r])})),s(Highcharts.Series.prototype,"init",(function(e,t,r){e.apply(this,[t,r])}));const l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e;t.customLogic.customCode&&new Function("options",t.customLogic.customCode)(l);const c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&n(h);let u=t.export.constr||"chart";u=void 0!==Highcharts[u]?u:"chart",Highcharts[u]("container",c,p);const d=o();for(const e in d)"function"!=typeof d[e]&&delete d[e];n(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ue=e.readFileSync(U+"/templates/template.html","utf8");let de;async function ge(){if(!de)return!1;const e=await de.newPage();return await e.setCacheEnabled(!1),await fe(e),function(e){const{debug:t}=J();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{e.isClosed()||await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function me(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"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}catch(e){$(2,e,"[browser] Could not clear page's resources.")}}async function fe(e){await e.setContent(ue,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${le()}/sources.js`}),await e.evaluate(pe)}const ve=async(e,t,r,o)=>{r.export.instr=null,r.export.infile=null;const i=Buffer.byteLength(r.export?.strInj?r.export?.strInj:JSON.stringify(t),"utf-8");if(H(3,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new re("[export] The data passed to a page exceeded 100MB.");return e.evaluate(he,t,r,o)};var ye=async(r,o,i)=>{let n=[];try{H(4,"[export] Determining export path.");const s=i.export,a=s?.options?.chart?.displayErrors&&oe.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===s.type)return o;l=!0,await r.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(o),{waitUntil:"domcontentloaded"})}else H(4,"[export] Treating as config."),s.strInj?await ve(r,{chart:{height:s.height,width:s.width}},i,a):(o.chart.height=s.height,o.chart.width=s.width,await ve(r,o,i,a));n=await async function(r,o){const i=[],n=o.customLogic.resources;if(n){const s=[];if(n.js&&s.push({content:n.js}),n.files)for(const t of n.files){const r=!t.startsWith("http");s.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of s)try{i.push(await r.addScriptTag(e))}catch(e){$(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(n.css){let e=n.css.match(/@import\s*([^;]*);/g);if(e)for(let r of e)r&&(r=r.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),r.startsWith("http")?a.push({url:r}):o.customLogic.allowFileResources&&a.push({path:t.join(U,r)}));a.push({content:n.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){$(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(r,i);const c=l?await r.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await r.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.abs(Math.ceil(c.chartHeight||s.height)),h=Math.abs(Math.ceil(c.chartWidth||s.width)),{x:u,y:d}=await(e=>e.$eval("#chart-container",(e=>{const{x:t,y:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,height:Math.trunc(i>1?i:500)}})))(r);let g;if(await r.setViewport({height:p,width:h,deviceScaleFactor:l?1:parseFloat(s.scale)}),"svg"===s.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(s.type))g=await((e,t,r,o,i)=>Promise.race([e.screenshot({type:t,encoding:r,clip:o,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout"))),i||1500)))]))(r,s.type,"base64",{width:h,height:p,x:u,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new re(`[export] Unsupported output format ${s.type}.`);g=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:r,encoding:o,timeout:i||1500})))(r,p,h,"base64",s.rasterizationTimeout)}return await me(r,n),g}catch(e){return await me(r,n),e}};let be=!1;const we={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ee={};const Te={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new re("The page is invalid or closed.");H(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new re("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Ee.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Ee.workLimit&&++e.workCount>Ee.workLimit)||(H(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ee.workLimit}).`),!1)),destroy:async e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},Se=async e=>{if(Ee=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=J(),{enable:o,...i}=t,n={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!de){let e=0;const t=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),de=await h.launch(n)}catch(r){if($(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;H(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&&H(3,"[browser] Launched browser in shell mode."),o&&H(3,"[browser] Launched browser in debug mode.")}catch(e){throw new re("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!de)throw new re("[browser] Cannot find a browser to open.")}return de}(e.puppeteerArgs),H(3,`[pool] Initializing pool with workers: min ${Ee.minWorkers}, max ${Ee.maxWorkers}.`),be)return H(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ee.minWorkers)>parseInt(Ee.maxWorkers)&&(Ee.minWorkers=Ee.maxWorkers);try{be=new c.Pool({...Te,min:parseInt(Ee.minWorkers),max:parseInt(Ee.maxWorkers),acquireTimeoutMillis:Ee.acquireTimeout,createTimeoutMillis:Ee.createTimeout,destroyTimeoutMillis:Ee.destroyTimeout,idleTimeoutMillis:Ee.idleTimeout,createRetryIntervalMillis:Ee.createRetryInterval,reapIntervalMillis:Ee.reaperInterval,propagateCreateError:!1}),be.on("release",(async e=>{const t=await async function(e,t=!1){try{if(e&&!e.isClosed())return t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await fe(e)):await e.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(e){$(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);H(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),be.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{be.release(e)})),H(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new re("[pool] Could not create the pool of workers.").setError(e)}};async function xe(){if(H(3,"[pool] Killing pool with all workers and closing browser."),be){for(const e of be.used)be.release(e.resource);be.destroyed||(await be.destroy(),H(4,"[browser] Destroyed the pool of resources."))}await async function(){de?.connected&&await de.close(),H(4,"[browser] Closed the browser.")}()}const Re=async(e,t)=>{let r;try{if(H(4,"[pool] Work received, starting to process."),++we.exportAttempts,Ee.benchmarking&&Oe(),!be)throw new re("Work received, but pool has not been started.");const o=X();try{H(4,"[pool] Acquiring a worker handle."),r=await be.acquire().promise,t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(H(4,"[pool] Acquired a worker handle."),!r.page)throw new re("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const n=X(),s=await ye(r.page,e,t);if(s instanceof Error)throw"Rasterization timeout"===s.message&&(r.workCount=Ee.workLimit+1,r.page=null),"TimeoutError"===s.name||"Rasterization timeout"===s.message?new re("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(s):new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${n()}ms.`).setError(s);t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${n()}ms.`),be.release(r);const a=(new Date).getTime()-i;return we.timeSpent+=a,we.spentAverage=we.timeSpent/++we.performedExports,H(4,`[pool] Work completed in ${a} ms.`),{result:s,options:t}}catch(e){throw++we.droppedExports,r&&be.release(r),new re(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Le=()=>({min:be.min,max:be.max,all:be.numFree()+be.numUsed(),available:be.numFree(),used:be.numUsed(),pending:be.numPendingAcquires()});function Oe(){const{min:e,max:t,all:r,available:o,used:i,pending:n}=Le();H(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(5,`[pool] The number of all created resources: ${r}.`),H(5,`[pool] The number of available resources: ${o}.`),H(5,`[pool] The number of acquired resources: ${i}.`),H(5,`[pool] The number of resources waiting to be acquired: ${n}.`)}var _e=Le,ke=()=>we;let Ie=!1;const Ce=async(t,r)=>{H(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=q(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Y(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,J()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{H(4,"[chart] Attempting to export from a SVG input.");const e=He(function(e){const t=new u.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:["xlink:href"]})}(o.payload.svg),o,r);return++we.exportFromSvgAttempts,e}catch(e){return r(new re("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return H(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),He(o.export.instr.trim(),o,r)}catch(e){return r(new re("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return H(4,"[chart] Attempting to export from a raw input."),B(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?He(i.instr.trim(),o,r):Ae(o,i.instr||i.options,r)}catch(e){return r(new re("[chart] Error loading raw input.").setError(e))}return r(new re("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ne=e=>{const{chart:t,exporting:r}=e.export?.options||M(e.export?.instr),o=M(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const n={height:e.export?.height||r?.sourceHeight||t?.height||o?.exporting?.sourceHeight||o?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||r?.sourceWidth||t?.width||o?.exporting?.sourceWidth||o?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(n))n[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return n},Ae=async(t,r,o,i)=>{let{export:n,customLogic:s}=t;const a="boolean"==typeof s.allowCodeExecution?s.allowCodeExecution:Ie;if(s){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=j(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=j(r,B(t.customLogic.allowFileResources))}catch(e){$(2,e,"[chart] Unable to load the default resources.json file.")}}else s=t.customLogic={};if(!a&&s){if(s.callback||s.resources||s.customCode)return o(new re("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));s.callback=!1,s.resources=!1,s.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),n.constr=n.constr||"chart",n.type=F(n.type,n.outfile),"svg"===n.type&&(n.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{n&&n[t]&&("string"==typeof n[t]&&n[t].endsWith(".json")?n[t]=M(e.readFileSync(n[t],"utf8"),!0):n[t]=M(n[t],!0))}catch(e){n[t]={},$(2,e,`[chart] The '${t}' cannot be loaded.`)}})),s.allowCodeExecution)try{s.customCode=z(s.customCode,s.allowFileResources)}catch(e){$(2,e,"[chart] The 'customCode' cannot be loaded.")}if(s&&s.callback&&s.callback?.indexOf("{")<0)if(s.allowFileResources)try{s.callback=e.readFileSync(s.callback,"utf8")}catch(e){s.callback=!1,$(2,e,"[chart] The 'callback' cannot be loaded.")}else s.callback=!1;t.export={...t.export,...Ne(t)};try{return o(!1,await Re(n.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=W(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ae(e,!1,t)}catch(r){return t(new re(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},He=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),Ae(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ae(t,o,r)}catch(e){return B(o)?Pe(t,r):r(new re("[chart] Only JSON 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 flag.").setError(e))}},$e=[],Ge=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of $e)clearInterval(e)},De=(e,t,r,o)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,o(e)},Ue=(e,t,r,o)=>{const{statusCode:i,status:n,message:s,stack:a}=e,l=i||n||400;r.status(l).json({statusCode:l,message:s,stack:a})};var Fe=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(H(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),H(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class je extends re{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Me=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=C.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new je("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new je("No new version supplied.",400);try{await(async e=>{const t=J();t?.highcharts&&(t.highcharts.version=e),await ae(t)})(i)}catch(e){throw new je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ce(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let We=0;const Ve=[],Be=[],ze=(e,t,r,o)=>{let i=!0;const{id:n,uniqueId:s,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,n,s,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Xe=async(e,t,r)=>{try{const r=X(),i=p.v4().replace(/-/g,""),n=J(),s=e.body,a=++We;let l=F(s.type);if(!s||"object"==typeof(o=s)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=M(s.infile||s.options||s.data);if(!c&&!s.svg)throw H(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect:\n Content-Type: ${e.headers["content-type"]}. \n Chart constructor: ${s.constr}.\n Dimensions: ${s.width}x${s.height} @ ${s.scale} scale.\n Type: ${l}.\n Is SVG set? ${void 0!==s.svg}.\n B64? ${void 0!==s.b64}.\n No download? ${void 0!==s.noDownload}.\n\n Payload received: ${JSON.stringify(s.infile||s.options||s.data||s.svg)}\n\n `),new je("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);let h=!1;if(h=ze(Ve,e,t,{id:a,uniqueId:i,type:l,body:s}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(e=>{e&&(u=!0)})),H(4,`[export] Got an incoming HTTP request with ID ${i}.`),s.constr="string"==typeof s.constr&&s.constr||"chart";const d={export:{instr:c,type:l,constr:s.constr[0].toLowerCase()+s.constr.substr(1),height:s.height,width:s.width,scale:s.scale||n.export.scale,globalOptions:M(s.globalOptions,!0),themeOptions:M(s.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:M(s.resources,!0),callback:s.callback,customCode:s.customCode}};c&&(d.export.instr=W(c,d.customLogic.allowCodeExecution));const g=Y(n,d);if(g.export.options=c,g.payload={svg:s.svg||!1,b64:s.b64||!1,noDownload:s.noDownload||!1,requestId:i},s.svg&&(e=>[/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))))(g.payload.svg))throw new je("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);await Ce(g,((o,c)=>{if(e.socket.removeAllListeners("close"),n.server.benchmarking&&H(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),u)return H(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,ze(Be,e,t,{id:a,body:c.result}),c.result?s.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",qe[l]||"image/png"),s.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){r(e)}var o};const Ke=JSON.parse(e.readFileSync(t.join(U,"package.json"))),Je=new Date,Ye=[];function Ze(e){if(!e)return!1;var t;t=setInterval((()=>{const e=ke(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ye.push(t),Ye.length>30&&Ye.shift()}),6e4),$e.push(t),e.get("/health",((e,t)=>{const r=ke(),o=Ye.length,i=Ye.reduce(((e,t)=>e+t),0)/Ye.length;H(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Je,uptime:Math.floor(((new Date).getTime()-Je.getTime())/1e3/60)+" minutes",version:Ke.version,highchartsVersion:ce(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:_e(),period:o,movingAverage:i,message:isNaN(i)||!Ye.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const Qe=new Map,et=m();et.disable("x-powered-by"),et.use(g()),et.use(((e,t,r)=>{t.set("Accept-Ranges","none"),r()}));const tt=e=>{e.on("clientError",((e,t)=>{$(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{$(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{$(1,e,`[server] Socket error: ${e.message}`)}))}))},rt=async r=>{try{const o=1024*(r.maxUploadSize||3)*1024,i=f.memoryStorage(),n=f({storage:i,limits:{fieldSize:o}});if(et.use(m.json({limit:o})),et.use(m.urlencoded({extended:!0,limit:o})),et.use(n.none()),!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(et);tt(e),e.listen(r.port,r.host),Qe.set(r.port,e),H(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){H(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},et);tt(e),e.listen(r.ssl.port,r.host),Qe.set(r.ssl.port,e),H(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Fe(et,r.rateLimiting),et.use(m.static(t.posix.join(U,"public"))),Ze(et),(e=>{e.post("/",Xe),e.post("/:filename",Xe)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(U,"public","index.html"),{acceptRanges:!1})}))})(et),Me(et),(e=>{e.use(De),e.use(Ue)})(et)}catch(e){throw new re("[server] Could not configure and start the server.").setError(e)}},ot=()=>{H(4,"[server] Closing all servers.");for(const[e,t]of Qe)t.close((()=>{Qe.delete(e),H(4,`[server] Closed server on port: ${e}.`)}))};var it={startServer:rt,closeServers:ot,getServers:()=>Qe,enableRateLimiting:e=>Fe(et,e),getExpress:()=>m,getApp:()=>et,use:(e,...t)=>{et.use(e,...t)},get:(e,...t)=>{et.get(e,...t)},post:(e,...t)=>{et.post(e,...t)}};const nt=async e=>{await Promise.allSettled([Ge(),ot(),xe()]),process.exit(e)};var st={server:it,startServer:rt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=B(t),(e=>{for(const[t,r]of Object.entries(e))A[t]=r;G(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&D(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(H(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{H(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGTERM",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGHUP",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("uncaughtException",(async(e,t)=>{$(1,e,`The ${t} error.`),await nt(1)}))),await ae(e),await Se({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await xe()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await xe()}catch(e){throw new re("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Se,killPool:xe,setOptions:(t,r)=>(r?.length&&(K=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){$(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Z(w,K),K=Q(w),t&&(K=Y(K,t,T)),r?.length&&(K=function(e,t,r){let o=!1;for(let i=0;i(s.length-1===r&&(a=e[t].type),e[t])),r),s.reduce(((e,r,l)=>(s.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=B(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(H(2,`[config] Missing value for the '${n}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&V();return e}(K,r,w)),K),shutdownCleanUp:nt,log:H,logWithStack:$,setLogLevel:G,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=S[r]?S[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(E).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,n)=>{let s=0,a=[];for(const e of n)E[e]=E[e].map((t=>({...t,section:e}))),a=[...a,...E[e]];return await o(a,{onSubmit:async(o,i)=>{if("moduleScripts"===o.name?(i=i.length?i.map((e=>o.choices[e])):o.choices,r[o.section][o.name]=i):r[o.section]=ee(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++s===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){$(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(U,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(U+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:V};module.exports=st; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBQb3NzaWJsZSBuYW1lcyBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcbiAgbW9kdWxlczogW1xuICAgICdzdG9jaycsXG4gICAgJ21hcCcsXG4gICAgJ2dhbnR0JyxcbiAgICAnZXhwb3J0aW5nJyxcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxuICAgICdhY2Nlc3NpYmlsaXR5JyxcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICdib29zdC1jYW52YXMnLFxuICAgICdib29zdCcsXG4gICAgJ2RhdGEnLFxuICAgICdkYXRhLXRvb2xzJyxcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgJ3N0YXRpYy1zY2FsZScsXG4gICAgJ2Jyb2tlbi1heGlzJyxcbiAgICAnaGVhdG1hcCcsXG4gICAgJ3RpbGVtYXAnLFxuICAgICd0aWxlZHdlYm1hcCcsXG4gICAgJ3RpbWVsaW5lJyxcbiAgICAndHJlZW1hcCcsXG4gICAgJ3RyZWVncmFwaCcsXG4gICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAnZHJpbGxkb3duJyxcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXG4gICAgJ2J1bGxldCcsXG4gICAgJ2Z1bm5lbCcsXG4gICAgJ2Z1bm5lbDNkJyxcbiAgICAnZ2VvaGVhdG1hcCcsXG4gICAgJ3B5cmFtaWQzZCcsXG4gICAgJ25ldHdvcmtncmFwaCcsXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxuICAgICdwYXJldG8nLFxuICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICdwaWN0b3JpYWwnLFxuICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICdzYW5rZXknLFxuICAgICdhcmMtZGlhZ3JhbScsXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICdzZXJpZXMtb24tcG9pbnQnLFxuICAgICdzb2xpZC1nYXVnZScsXG4gICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcbiAgICAnc3RyZWFtZ3JhcGgnLFxuICAgICdzdW5idXJzdCcsXG4gICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgJ3Zhcml3aWRlJyxcbiAgICAndmVjdG9yJyxcbiAgICAndmVubicsXG4gICAgJ3dpbmRiYXJiJyxcbiAgICAnd29yZGNsb3VkJyxcbiAgICAneHJhbmdlJyxcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcbiAgICAnZHJhZy1wYW5lcycsXG4gICAgJ2RlYnVnZ2VyJyxcbiAgICAnZHVtYmJlbGwnLFxuICAgICdsb2xsaXBvcCcsXG4gICAgJ2N5bGluZGVyJyxcbiAgICAnb3JnYW5pemF0aW9uJyxcbiAgICAnZG90cGxvdCcsXG4gICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcbiAgICAnaGVpa2luYXNoaScsXG4gICAgJ2Zsb3dtYXAnLFxuICAgICdleHBvcnQtZGF0YScsXG4gICAgJ25hdmlnYXRvcicsXG4gICAgJ3RleHRwYXRoJ1xuICBdLFxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gIGN1c3RvbTogW1xuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICBdXG59O1xuXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xuICBwdXBwZXRlZXI6IHtcbiAgICBhcmdzOiB7XG4gICAgICB2YWx1ZTogW1xuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxuICAgICAgICAnLS1uby1waW5ncycsXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXG4gICAgICAgICctLW5vLXp5Z290ZScsXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXG4gICAgICBdLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcbiAgICB9XG4gIH0sXG4gIGhpZ2hjaGFydHM6IHtcbiAgICB2ZXJzaW9uOiB7XG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgY2RuVVJMOiB7XG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGNvcmVTY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIG1vZHVsZVNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBjdXN0b21TY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXG4gICAgfSxcbiAgICBjYWNoZVBhdGg6IHtcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvdXRmaWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRTY2FsZToge1xuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXG4gICAgfSxcbiAgICBoZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xuICAgIH0sXG4gICAgc2NhbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXG4gICAgfSxcbiAgICBiYXRjaDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xuICAgIH0sXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAxNTAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Mb2dpYzoge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjcmVhdGVDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjoge1xuICAgIG1heFVwbG9hZFNpemU6IHtcbiAgICAgIHZhbHVlOiAzLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBjbGlOYW1lOiAnbWF4VXBsb2FkU2l6ZScsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX01BWF9VUExPQURfU0laRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBtYXhpbXVtIHVwbG9hZCBzaXplLCBpbiBtZWdhYnl0ZXMsIGZvciB0aGUgc2VydmVyJ1xuICAgICAgXG4gICAgfSxcbiAgICBlbmFibGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcbiAgICB9LFxuICAgIGhvc3Q6IHtcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfSE9TVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xuICAgIH0sXG4gICAgcG9ydDoge1xuICAgICAgdmFsdWU6IDc4MDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xuICAgIH0sXG4gICAgYmVuY2htYXJraW5nOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xuICAgIH0sXG4gICAgcHJveHk6IHtcbiAgICAgIGhvc3Q6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9LFxuICAgICAgcG9ydDoge1xuICAgICAgICB2YWx1ZTogODA4MCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVBvcnQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xuICAgICAgfSxcbiAgICAgIHRpbWVvdXQ6IHtcbiAgICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9XG4gICAgfSxcbiAgICByYXRlTGltaXRpbmc6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci4nXG4gICAgICB9LFxuICAgICAgbWF4UmVxdWVzdHM6IHtcbiAgICAgICAgdmFsdWU6IDEwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdyYXRlTGltaXQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xuICAgICAgfSxcbiAgICAgIHdpbmRvdzoge1xuICAgICAgICB2YWx1ZTogMSxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1cnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcbiAgICAgIH0sXG4gICAgICBkZWxheToge1xuICAgICAgICB2YWx1ZTogMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXG4gICAgICB9LFxuICAgICAgdHJ1c3RQcm94eToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXG4gICAgICB9LFxuICAgICAgc2tpcEtleToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50LidcbiAgICAgIH0sXG4gICAgICBza2lwVG9rZW46IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXG4gICAgICB9XG4gICAgfSxcbiAgICBzc2w6IHtcbiAgICAgIGVuYWJsZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVNzbCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgU1NMIHByb3RvY29sLidcbiAgICAgIH0sXG4gICAgICBmb3JjZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRk9SQ0UnLFxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xuICAgICAgfSxcbiAgICAgIHBvcnQ6IHtcbiAgICAgICAgdmFsdWU6IDQ0MyxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX1BPUlQnLFxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcbiAgICAgIH0sXG4gICAgICBjZXJ0UGF0aDoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBhdGggdG8gdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXkgZmlsZS4nXG4gICAgICB9XG4gICAgfVxuICB9LFxuICBwb29sOiB7XG4gICAgbWluV29ya2Vyczoge1xuICAgICAgdmFsdWU6IDQsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtaW5pbXVtIGFuZCBpbml0aWFsIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXG4gICAgfSxcbiAgICBtYXhXb3JrZXJzOiB7XG4gICAgICB2YWx1ZTogOCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxuICAgICAgbGVnYWN5TmFtZTogJ3dvcmtlcnMnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1heGltdW0gcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcbiAgICB9LFxuICAgIHdvcmtMaW1pdDoge1xuICAgICAgdmFsdWU6IDQwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9XT1JLX0xJTUlUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcbiAgICB9LFxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGRlc3Ryb3lUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfREVTVFJPWV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXG4gICAgfSxcbiAgICBpZGxlVGltZW91dDoge1xuICAgICAgdmFsdWU6IDMwMDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQuJ1xuICAgIH0sXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xuICAgICAgdmFsdWU6IDIwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgYmVmb3JlIHJldHJ5aW5nIHRoZSBjcmVhdGUgcHJvY2VzcyBpbiBjYXNlIG9mIGEgZmFpbHVyZS4nXG4gICAgfSxcbiAgICByZWFwZXJJbnRlcnZhbDoge1xuICAgICAgdmFsdWU6IDEwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX1JFQVBFUl9JTlRFUlZBTCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcbiAgICB9LFxuICAgIGJlbmNobWFya2luZzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnSW5kaWNhdGUgd2hldGhlciB0byBzaG93IHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcyBvciBub3QuJ1xuICAgIH1cbiAgfSxcbiAgbG9nZ2luZzoge1xuICAgIGxldmVsOiB7XG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0xldmVsJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGxvZ2dpbmcgbGV2ZWwgdG8gYmUgdXNlZC4nXG4gICAgfSxcbiAgICBmaWxlOiB7XG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19GSUxFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG5hbWUgb2YgYSBsb2cgZmlsZS4gVGhlIGBsb2dUb0ZpbGVgIGFuZCBgbG9nRGVzdGAgb3B0aW9ucyBhbHNvIG5lZWQgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xuICAgIH0sXG4gICAgZGVzdDoge1xuICAgICAgdmFsdWU6ICdsb2cvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXG4gICAgICBjbGlOYW1lOiAnbG9nRGVzdCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhlIGBsb2dUb0ZpbGVgIG9wdGlvbiBhbHNvIG5lZWRzIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nLidcbiAgICB9LFxuICAgIHRvQ29uc29sZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0NvbnNvbGUnLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHNob3dpbmcgbG9ncyBpbiB0aGUgY29uc29sZS4nXG4gICAgfSxcbiAgICB0b0ZpbGU6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fRklMRScsXG4gICAgICBjbGlOYW1lOiAnbG9nVG9GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyBjcmVhdGlvbiBvZiB0aGUgbG9nIGRpcmVjdG9yeSBhbmQgc2F2aW5nIHRoZSBsb2cgaW50byBhIC5sb2cgZmlsZS4nXG4gICAgfVxuICB9LFxuICB1aToge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1VJX0VOQUJMRScsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIGZvciB0aGUgZXhwb3J0IHNlcnZlci4nXG4gICAgfSxcbiAgICByb3V0ZToge1xuICAgICAgdmFsdWU6ICcvJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ1VJX1JPVVRFJyxcbiAgICAgIGNsaU5hbWU6ICd1aVJvdXRlJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGVuZHBvaW50IHJvdXRlIHRvIHdoaWNoIHRoZSB1c2VyIGludGVyZmFjZSAoVUkpIHNob3VsZCBiZSBhdHRhY2hlZC4nXG4gICAgfVxuICB9LFxuICBvdGhlcjoge1xuICAgIG5vZGVFbnY6IHtcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT0RFX0VOVicsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xuICAgIH0sXG4gICAgbGlzdGVuVG9Qcm9jZXNzRXhpdHM6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcbiAgICB9LFxuICAgIG5vTG9nbzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX05PX0xPR08nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIGEgc3RhcnR1cC4gV2lsbCBiZSByZXBsYWNlZCBieSBhIHNpbXBsZSB0ZXh0LidcbiAgICB9LFxuICAgIGhhcmRSZXNldFBhZ2U6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5LidcbiAgICB9LFxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZS4nXG4gICAgfVxuICB9LFxuICBkZWJ1Zzoge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxuICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSB1bmRlcmx5aW5nIGJyb3dzZXIuJ1xuICAgIH0sXG4gICAgaGVhZGxlc3M6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXG4gICAgfSxcbiAgICBkZXZ0b29sczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0RFVlRPT0xTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBEZXZUb29scyB3aGVuIHRoZSBicm93c2VyIGlzIGluIGEgaGVhZGZ1bCBzdGF0ZS4nXG4gICAgfSxcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0RlY2lkZXMgd2hldGhlciB0byBlbmFibGUgYSBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBzZW50IGZyb20gdGhlIGJyb3dzZXIuJ1xuICAgIH0sXG4gICAgZHVtcGlvOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xuICAgIH0sXG4gICAgc2xvd01vOiB7XG4gICAgICB2YWx1ZTogMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0RFQlVHX1NMT1dfTU8nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdTbG93cyBkb3duIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4nXG4gICAgfSxcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XG4gICAgICB2YWx1ZTogOTIyMixcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3BlY2lmaWVzIHRoZSBkZWJ1Z2dpbmcgcG9ydC4nXG4gICAgfVxuICB9XG59O1xuXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxuLy8gKiBUeXBlIG9mIGEgcHJvbXB0XG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxuLy8gKiBJbml0aWFsIHZhbHVlXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcbiAgcHVwcGV0ZWVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ2xpc3QnLFxuICAgICAgbmFtZTogJ2FyZ3MnLFxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBhcmd1bWVudHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH1cbiAgXSxcbiAgaGlnaGNoYXJ0czogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdIaWdoY2hhcnRzIHZlcnNpb24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBVUkwgb2YgQ0ROJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBjb3JlIHNjcmlwdHMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdtb2R1bGVTY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5tb2R1bGVTY3JpcHRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdsaXN0JyxcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdDdXN0b20gc2NyaXB0cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZm9yY2VGZXRjaCcsXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdjYWNoZVBhdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgZXhwb3J0OiBbXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAndHlwZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZXhwb3J0IGZpbGUgdHlwZScsXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXG4gICAgICBpbml0aWFsOiAwLFxuICAgICAgY2hvaWNlczogWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ11cbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxuICAgICAgbmFtZTogJ2NvbnN0cicsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQuY29uc3RyLnZhbHVlfWAsXG4gICAgICBpbml0aWFsOiAwLFxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdEhlaWdodCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0V2lkdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRTY2FsZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcbiAgICAgIG1pbjogMC4xLFxuICAgICAgbWF4OiA1XG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHJlbmRlcmluZyB3ZWJwYWdlIHRpbWVvdXQgaW4gbWlsbGlzZWNvbmRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXG4gICAgfVxuICBdLFxuICBjdXN0b21Mb2dpYzogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMudmFsdWVcbiAgICB9XG4gIF0sXG4gIHNlcnZlcjogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdob3N0JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncG9ydCcsXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdwcm94eS5ob3N0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwcm94eS5wb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwcm94eS50aW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmVuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcud2luZG93JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5kZWxheScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmRlbGF5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcudHJ1c3RQcm94eS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3NzbC5lbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnc3NsLmZvcmNlJyxcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3NzbC5wb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdzc2wuY2VydFBhdGgnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXG4gICAgfVxuICBdLFxuICBwb29sOiBbXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXG4gICAgICBtZXNzYWdlOiAnVGhlIGluaXRpYWwgbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdhY3F1aXJlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdjcmVhdGVUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZXN0cm95VGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnaWRsZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnY3JlYXRlUmV0cnlJbnRlcnZhbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVSZXRyeUludGVydmFsLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHJlYXBlciBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgdHJpZ2dlcmluZyB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3knLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBiZW5jaG1hcmtpbmcgZm9yIGEgcmVzb3VyY2UgcG9vbCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXG4gICAgfVxuICBdLFxuICBsb2dnaW5nOiBbXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBsb2cgbGV2ZWwgKDA6IHNpbGVudCwgMTogZXJyb3IsIDI6IHdhcm5pbmcsIDM6IG5vdGljZSwgNDogdmVyYm9zZSwgNTogYmVuY2htYXJrKScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXG4gICAgICByb3VuZDogMCxcbiAgICAgIG1pbjogMCxcbiAgICAgIG1heDogNVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2ZpbGUnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0EgbG9nIGZpbGUgbmFtZS4gU2V0IHdpdGggLS10b0ZpbGUgYW5kIC0tbG9nRGVzdCB0byBlbmFibGUgZmlsZSBsb2dnaW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnZGVzdCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gYSBsb2cgZmlsZSB3aGVuIHRoZSBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAndG9Db25zb2xlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgbG9nZ2luZyB0byB0aGUgY29uc29sZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcudG9Db25zb2xlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICd0b0ZpbGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgbG9nZ2luZyB0byBhIGZpbGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLnRvRmlsZS52YWx1ZVxuICAgIH1cbiAgXSxcbiAgdWk6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyb3V0ZScsXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkucm91dGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIG90aGVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ25vZGVFbnYnLFxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub2RlRW52LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub1Byb2Nlc3NFeGl0cycsXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdub0xvZ28nLFxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2hhcmRSZXNldFBhZ2UnLFxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5oYXJkUmVzZXRQYWdlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdicm93c2VyU2hlbGxNb2RlJyxcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBicm93c2VyIHJ1bnMgaW4gdGhlIHNoZWxsIG1vZGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5icm93c2VyU2hlbGxNb2RlLnZhbHVlXG4gICAgfVxuICBdLFxuICBkZWJ1ZzogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgYnJvd3NlciBpbnN0YW5jZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnaGVhZGxlc3MnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtb2RlIHNldHRpbmcgZm9yIHRoZSBicm93c2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2RldnRvb2xzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgRGV2VG9vbHMgZm9yIHRoZSBoZWFkZnVsIGJyb3dzZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Db25zb2xlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZXZlbnQgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgZnJvbSB0aGUgYnJvd3NlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZHVtcGlvJyxcbiAgICAgIG1lc3NhZ2U6ICdSZWRpcmVjdHMgdGhlIGJyb3dzZXIgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gTm9kZUpTIHByb2Nlc3MnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Nsb3dNbycsXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIG9wZXJhdGlvbnMgc2xvdyBkb3duIGluIG1pbGxpc2Vjb25kcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVidWdnaW5nUG9ydCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgbnVtYmVyIGZvciBkZWJ1Z2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXG4gICAgfVxuICBdXG59O1xuXG4vLyBBYnNvbHV0ZSBwcm9wcyB0aGF0LCBpbiBjYXNlIG9mIG1lcmdpbmcgcmVjdXJzaXZlbHksIG5lZWQgdG8gYmUgZm9yY2UgbWVyZ2VkXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcbiAgJ29wdGlvbnMnLFxuICAnZ2xvYmFsT3B0aW9ucycsXG4gICd0aGVtZU9wdGlvbnMnLFxuICAncmVzb3VyY2VzJyxcbiAgJ3BheWxvYWQnXG5dO1xuXG4vLyBBcmd1bWVudCBuZXN0aW5nIGxldmVsIG9mIGFsbCBleHBvcnQgc2VydmVyIG9wdGlvbnNcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iaiAtIFRoZSBvYmplY3QgY29udGFpbmluZyBuZXN0ZWQgYXJndW1lbnRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxuICovXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoaykpIHtcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgLy8gR28gZGVlcGVyIGluIHRoZSBuZXN0ZWQgYXJndW1lbnRzXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQ3JlYXRlIHRoZSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xuXG4gICAgICAgIC8vIFN1cHBvcnQgZm9yIHRoZSBsZWdhY3ksIFBoYW50b21KUyBwcm9wZXJ0aWVzIG5hbWVzXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufTtcblxuY3JlYXRlTmVzdGVkQXJncyhkZWZhdWx0Q29uZmlnKTtcbiIsIi8qKlxuICogQGZpbGVvdmVydmlld1xuICogVGhpcyBmaWxlIGlzIHJlc3BvbnNpYmxlIGZvciBwYXJzaW5nIHRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgd2l0aCB0aGUgJ3pvZCdcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi4gV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHlcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyB0aGVzZSB3b3VsZCBub3QgYmUgcGFyc2VkIHByb3Blcmx5LlxuICpcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuXG4gKiB0aGUgYXBwbGljYXRpb24gc3RhcnRzLiBXZSBzaG91bGQgd3JpdGUgYSBjdXN0b20gdmFsaWRhdG9yIG9yIGEgdHJhbnNmb3JtZXJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxuICovXG5cbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xuXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcblxuLy8gTG9hZCAuZW52IGludG8gZW52aXJvbm1lbnQgdmFyaWFibGVzXG5kb3RlbnYuY29uZmlnKCk7XG5cbi8vIE9iamVjdCB3aXRoIGN1c3RvbSB2YWxpZGF0b3JzIGFuZCB0cmFuc2Zvcm1lcnMsIHRvIGF2b2lkIHJlcGV0aXRpb25cbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XG5jb25zdCB2ID0ge1xuICAvLyBTcGxpdHMgc3RyaW5nIHZhbHVlIGludG8gZWxlbWVudHMgaW4gYW4gYXJyYXksIHRyaW1zIGV2ZXJ5IGVsZW1lbnQsIGNoZWNrc1xuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxuICBhcnJheTogKGZpbHRlckFycmF5KSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XG4gICAgICAgIHZhbHVlXG4gICAgICAgICAgLnNwbGl0KCcsJylcbiAgICAgICAgICAubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKVxuICAgICAgICAgIC5maWx0ZXIoKHZhbHVlKSA9PiBmaWx0ZXJBcnJheS5pbmNsdWRlcyh2YWx1ZSkpXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlLmxlbmd0aCA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxuICAvLyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsIGJlIHVuZGVmaW5lZFxuICBib29sZWFuOiAoKSA9PlxuICAgIHpcbiAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICcnXSlcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgPT09ICd0cnVlJyA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBwYXNzZWQgdmFsdWVzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcbiAgLy8gYmUgdW5kZWZpbmVkXG4gIGVudW06ICh2YWx1ZXMpID0+XG4gICAgelxuICAgICAgLmVudW0oWy4uLnZhbHVlcywgJyddKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIFRyaW1zIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNoZWNrcyBpZiBpdCBpcyBlbXB0eSBvciBjb250YWlucyBzdHJpbmdpZmllZFxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXG4gIHN0cmluZzogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nXS5pbmNsdWRlcyh2YWx1ZSkgfHxcbiAgICAgICAgICB2YWx1ZSA9PT0gJycsXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHN0cmluZyBjb250YWlucyBmb3JiaWRkZW4gdmFsdWVzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcbiAgLy8gYmUgdW5kZWZpbmVkXG4gIHBvc2l0aXZlTnVtOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+IDApLFxuICAgICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxuICAvLyB3aWxsIGJlIHVuZGVmaW5lZFxuICBub25OZWdhdGl2ZU51bTogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCksXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgICB9KVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpXG59O1xuXG5leHBvcnQgY29uc3QgQ29uZmlnID0gei5vYmplY3Qoe1xuICAvLyBoaWdoY2hhcnRzXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcbiAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgfSlcbiAgICApXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcbiAgICAuc3RyaW5nKClcbiAgICAudHJpbSgpXG4gICAgLnJlZmluZShcbiAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcbiAgICAgICAgdmFsdWUgPT09ICcnLFxuICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgfSlcbiAgICApXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuICBISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuY29yZSksXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzKSxcbiAgSElHSENIQVJUU19GT1JDRV9GRVRDSDogdi5ib29sZWFuKCksXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogdi5zdHJpbmcoKSxcblxuICAvLyBleHBvcnRcbiAgRVhQT1JUX1RZUEU6IHYuZW51bShbJ2pwZWcnLCAncG5nJywgJ3BkZicsICdzdmcnXSksXG4gIEVYUE9SVF9DT05TVFI6IHYuZW51bShbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddKSxcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9ERUZBVUxUX1dJRFRIOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9ERUZBVUxUX1NDQUxFOiB2LnBvc2l0aXZlTnVtKCksXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcblxuICAvLyBjdXN0b21cbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2LmJvb2xlYW4oKSxcblxuICAvLyBzZXJ2ZXJcbiAgU0VSVkVSX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9IT1NUOiB2LnN0cmluZygpLFxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcblxuICAvLyBzZXJ2ZXIgcHJveHlcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG5cbiAgLy8gc2VydmVyIHJhdGUgbGltaXRpbmdcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZOiB2LnN0cmluZygpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxuXG4gIC8vIHNlcnZlciBzc2xcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1NTTF9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxuXG4gIC8vIHBvb2xcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX01BWF9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfV09SS19MSU1JVDogdi5wb3NpdGl2ZU51bSgpLFxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfREVTVFJPWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfUkVBUEVSX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcblxuICAvLyBsb2dnZXJcbiAgTE9HR0lOR19MRVZFTDogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PlxuICAgICAgICB2YWx1ZSA9PT0gJycgfHxcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwICYmXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPD0gNSksXG4gICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBMT0dHSU5HX0xFVkVMLiBXZSBvbmx5IGFjY2VwdCB2YWx1ZXMgZnJvbSAwIHRvIDUgYXMgbG9nZ2luZyBsZXZlbHMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXG4gIExPR0dJTkdfRklMRTogdi5zdHJpbmcoKSxcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxuICBMT0dHSU5HX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxuICBMT0dHSU5HX1RPX0ZJTEU6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHVpXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxuXG4gIC8vIG90aGVyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXG4gIE9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXG4gIE9USEVSX0JST1dTRVJfU0hFTExfTU9ERTogdi5ib29sZWFuKCksXG5cbiAgLy8gZGVidWdnZXJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXG59KTtcblxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XG5cbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XG5cbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXG5sZXQgbG9nZ2luZyA9IHtcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXG4gIHRvQ29uc29sZTogdHJ1ZSxcbiAgdG9GaWxlOiBmYWxzZSxcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxuICAvLyBMb2cgbGV2ZWxzXG4gIGxldmVsc0Rlc2M6IFtcbiAgICB7XG4gICAgICB0aXRsZTogJ2Vycm9yJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXG4gICAgICBjb2xvcjogY29sb3JzWzFdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ25vdGljZScsXG4gICAgICBjb2xvcjogY29sb3JzWzJdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxuICAgICAgY29sb3I6IGNvbG9yc1szXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxuICAgIH1cbiAgXSxcbiAgLy8gTG9nIGxpc3RlbmVyc1xuICBsaXN0ZW5lcnM6IFtdXG59O1xuXG4vKipcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXG4gKi9cbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XG4gIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxuICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XG5cbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXG4gICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XG4gIH1cblxuICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXG4gIGFwcGVuZEZpbGUoXG4gICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXG4gICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcbiAgICAoZXJyb3IpID0+IHtcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xuICAgICAgICBsb2dnaW5nLnRvRmlsZSA9IGZhbHNlO1xuICAgICAgfVxuICAgIH1cbiAgKTtcbn07XG5cbi8qKlxuICogTG9ncyBhIG1lc3NhZ2UuIEFjY2VwdHMgYSB2YXJpYWJsZSBhbW91bnQgb2YgYXJndW1lbnRzLiBBcmd1bWVudHMgYWZ0ZXJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxuICogYW5kIGFwcGVuZGVkIHRvIHRoZSBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxuICogYW5kIHRoZSByZXN0IGFyZSBzdHJpbmdzIHRvIGJ1aWxkIGEgbWVzc2FnZSB3aXRoLlxuICovXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcbiAgY29uc3QgW25ld0xldmVsLCAuLi50ZXh0c10gPSBhcmdzO1xuXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXG4gIGNvbnN0IHsgbGV2ZWxzRGVzYywgbGV2ZWwgfSA9IGxvZ2dpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXG4gIGlmIChcbiAgICBuZXdMZXZlbCAhPT0gNSAmJlxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXG4gICkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XG5cbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcblxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xuICB9KTtcblxuICAvLyBMb2cgdG8gY29uc29sZVxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcbiAgICBjb25zb2xlLmxvZy5hcHBseShcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdCh0ZXh0cylcbiAgICApO1xuICB9XG5cbiAgLy8gTG9nIHRvIGZpbGVcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XG4gICAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xuICB9XG59O1xuXG4vKipcbiAqIExvZ3MgYW4gZXJyb3IgbWVzc2FnZSB3aXRoIGl0cyBzdGFjayB0cmFjZS4gT3B0aW9uYWxseSwgYSBjdXN0b20gbWVzc2FnZVxuICogY2FuIGJlIHByb3ZpZGVkLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBsZXZlbCAtIFRoZSBsb2cgbGV2ZWwuXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xuICogd2l0aCB0aGUgZXJyb3IuXG4gKi9cbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XG4gIC8vIEdldCB0aGUgbWFpbiBtZXNzYWdlXG4gIGNvbnN0IG1haW5NZXNzYWdlID0gY3VzdG9tTWVzc2FnZSB8fCBlcnJvci5tZXNzYWdlO1xuXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXG4gIGNvbnN0IHsgbGV2ZWwsIGxldmVsc0Rlc2MgfSA9IGxvZ2dpbmc7XG5cbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2VcbiAgaWYgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aCkge1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XG5cbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcblxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxuICBjb25zdCBzdGFja01lc3NhZ2UgPVxuICAgIGVycm9yLm1lc3NhZ2UgIT09IGVycm9yLnN0YWNrTWVzc2FnZSB8fCBlcnJvci5zdGFja01lc3NhZ2UgPT09IHVuZGVmaW5lZFxuICAgICAgPyBlcnJvci5zdGFja1xuICAgICAgOiBlcnJvci5zdGFjay5zcGxpdCgnXFxuJykuc2xpY2UoMSkuam9pbignXFxuJyk7XG5cbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxuICBjb25zdCB0ZXh0cyA9IFttYWluTWVzc2FnZSwgJ1xcbicsIHN0YWNrTWVzc2FnZV07XG5cbiAgLy8gTG9nIHRvIGNvbnNvbGVcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XG4gICAgY29uc29sZS5sb2cuYXBwbHkoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQoW1xuICAgICAgICBtYWluTWVzc2FnZVtjb2xvcnNbbmV3TGV2ZWwgLSAxXV0sXG4gICAgICAgICdcXG4nLFxuICAgICAgICBzdGFja01lc3NhZ2VcbiAgICAgIF0pXG4gICAgKTtcbiAgfVxuXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XG4gIH0pO1xuXG4gIC8vIExvZyB0byBmaWxlXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xuICAgIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcbiAgfVxufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxuICogMSA9IGVycm9yLCAyID0gd2FybmluZywgMyA9IG5vdGljZSwgNCA9IHZlcmJvc2Ugb3IgNSA9IGJlbmNobWFyaylcbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXG4gKi9cbmV4cG9ydCBjb25zdCBzZXRMb2dMZXZlbCA9IChuZXdMZXZlbCkgPT4ge1xuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XG4gICAgbG9nZ2luZy5sZXZlbCA9IG5ld0xldmVsO1xuICB9XG59O1xuXG4vKipcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0Rlc3QgLSBUaGUgZGVzdGluYXRpb24gcGF0aCBmb3IgbG9nIGZpbGVzLlxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGVuYWJsZUZpbGVMb2dnaW5nID0gKGxvZ0Rlc3QsIGxvZ0ZpbGUpID0+IHtcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xuICBsb2dnaW5nID0ge1xuICAgIC4uLmxvZ2dpbmcsXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXG4gICAgZmlsZTogbG9nRmlsZSB8fCBsb2dnaW5nLmZpbGUsXG4gICAgdG9GaWxlOiB0cnVlXG4gIH07XG5cbiAgaWYgKGxvZ2dpbmcuZGVzdC5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XG4gIH1cblxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XG4gICAgbG9nZ2luZy5kZXN0ICs9ICcvJztcbiAgfVxufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGxvZ2dpbmdPcHRpb25zIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0TG9nZ2luZyA9IChsb2dnaW5nT3B0aW9ucykgPT4ge1xuICAvLyBTZXQgYWxsIHRoZSBsb2dnaW5nIG9wdGlvbnMgb24gb3VyIGxvZ2dpbmcgbW9kdWxlIG9iamVjdFxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhsb2dnaW5nT3B0aW9ucykpIHtcbiAgICBsb2dnaW5nW2tleV0gPSB2YWx1ZTtcbiAgfVxuXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXG4gIHNldExvZ0xldmVsKGxvZ2dpbmdPcHRpb25zICYmIHBhcnNlSW50KGxvZ2dpbmdPcHRpb25zLmxldmVsKSk7XG5cbiAgLy8gU2V0IHRoZSBsb2cgZmlsZSBwYXRoIGFuZCBuYW1lXG4gIGlmIChsb2dnaW5nT3B0aW9ucyAmJiBsb2dnaW5nT3B0aW9ucy5kZXN0ICYmIGxvZ2dpbmdPcHRpb25zLnRvRmlsZSkge1xuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxuICAgICAgbG9nZ2luZ09wdGlvbnMuZGVzdCxcbiAgICAgIGxvZ2dpbmdPcHRpb25zLmZpbGUgfHwgJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gdG8gdGhlIGxvZ2dpbmcgc3lzdGVtLlxuICpcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGZuIC0gVGhlIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIGJlIGFkZGVkLlxuICovXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XG4gIGxvZ2dpbmcubGlzdGVuZXJzLnB1c2goZm4pO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuICBpbml0TG9nZ2luZyxcbiAgbGlzdGVuXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tICd1cmwnO1xuXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XG5cbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcblxuLyoqXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXG4gKiB3aGl0ZXNwYWNlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cbiAqIEBwYXJhbSB7UmVnRXhwfSBbcnVsZT0vXFxzXFxzKy9nXSAtIFRoZSByZWd1bGFyIGV4cHJlc3Npb24gcnVsZSB0byBtYXRjaFxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcbiAqIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xuXG4vKipcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxuICogYSBjZXJ0YWluIG51bWJlciBvZiBhdHRlbXB0cyBhcmUgcmVhY2hlZC5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxuICogQHBhcmFtIHtudW1iZXJ9IFthdHRlbXB0PTBdIC0gVGhlIGN1cnJlbnQgYXR0ZW1wdCBudW1iZXIuXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRoZSByZXN1bHQgb2YgdGhlIGZ1bmN0aW9uXG4gKiBpZiBzdWNjZXNzZnVsLlxuICpcbiAqIEB0aHJvd3Mge0Vycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgbWF4aW11bSBudW1iZXIgb2YgYXR0ZW1wdHNcbiAqIGlzIHJlYWNoZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBleHBCYWNrb2ZmID0gYXN5bmMgKGZuLCBhdHRlbXB0ID0gMCwgLi4uYXJncykgPT4ge1xuICB0cnkge1xuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxuICAgIHJldHVybiBhd2FpdCBmbiguLi5hcmdzKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcbiAgICBjb25zdCBkZWxheUluTXMgPSAyICoqIGF0dGVtcHQgKiAxMDAwO1xuXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxuICAgIGlmICgrK2F0dGVtcHQgPj0gTUFYX0JBQ0tPRkZfQVRURU1QVFMpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cblxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xuICAgIGxvZyhcbiAgICAgIDMsXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXG4gICAgKTtcblxuICAgIC8vIFRyeSBhZ2FpblxuICAgIHJldHVybiBleHBCYWNrb2ZmKGZuLCBhdHRlbXB0LCAuLi5hcmdzKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxuICovXG5leHBvcnQgY29uc3QgZml4VHlwZSA9ICh0eXBlLCBvdXRmaWxlKSA9PiB7XG4gIC8vIE1JTUUgdHlwZXNcbiAgY29uc3QgbWltZVR5cGVzID0ge1xuICAgICdpbWFnZS9wbmcnOiAncG5nJyxcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXG4gICAgJ2ltYWdlL3N2Zyt4bWwnOiAnc3ZnJ1xuICB9O1xuXG4gIC8vIEZvcm1hdHNcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xuXG4gIC8vIENoZWNrIGlmIHR5cGUgYW5kIG91dGZpbGUncyBleHRlbnNpb25zIGFyZSB0aGUgc2FtZVxuICBpZiAob3V0ZmlsZSkge1xuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XG5cbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcbiAgICAgIHR5cGUgPSAnanBlZyc7XG4gICAgfSBlbHNlIGlmIChmb3JtYXRzLmluY2x1ZGVzKG91dFR5cGUpICYmIHR5cGUgIT09IG91dFR5cGUpIHtcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxuICByZXR1cm4gbWltZVR5cGVzW3R5cGVdIHx8IGZvcm1hdHMuZmluZCgodCkgPT4gdCA9PT0gdHlwZSkgfHwgJ3BuZyc7XG59O1xuXG4vKipcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IHJlc291cmNlcyAtIFRoZSByZXNvdXJjZXMgdG8gYmUgaGFuZGxlZC4gQ2FuIGJlIGVpdGhlclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxuICogZmlsZXMuXG4gKlxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxuICogcmVzb3VyY2VzIGFyZSBmb3VuZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XG4gIGNvbnN0IGFsbG93ZWRQcm9wcyA9IFsnanMnLCAnY3NzJywgJ2ZpbGVzJ107XG5cbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XG4gIGxldCBjb3JyZWN0UmVzb3VyY2VzID0gZmFsc2U7XG5cbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXG4gIGlmIChhbGxvd0ZpbGVSZXNvdXJjZXMgJiYgcmVzb3VyY2VzLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgdHJ5IHtcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XG4gICAgaWYgKCFhbGxvd2VkUHJvcHMuaW5jbHVkZXMocHJvcE5hbWUpKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xuICAgICAgY29ycmVjdFJlc291cmNlcyA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xuICAgIHJldHVybiBsb2coMywgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcbiAgfVxuXG4gIC8vIEhhbmRsZSBmaWxlcyBzZWN0aW9uXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XG4gICAgaWYgKCFoYW5kbGVkUmVzb3VyY2VzLmZpbGVzIHx8IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubGVuZ3RoIDw9IDApIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiByZXNvdXJjZXNcbiAgcmV0dXJuIGhhbmRsZWRSZXNvdXJjZXM7XG59O1xuXG4vKipcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cbiAqIG9mIHRoZSBwYXJzZWQgSlNPTi5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXG4gKiBvciBmYWxzZSBpZiB2YWxpZGF0aW9uIGZhaWxzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xuICB0cnkge1xuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXG4gICAgICB0eXBlb2YgZGF0YSAhPT0gJ3N0cmluZycgPyBKU09OLnN0cmluZ2lmeShkYXRhKSA6IGRhdGFcbiAgICApO1xuXG4gICAgLy8gUmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb24gb2YgYSBKU09OIGlmIHJlcXVpcmVkXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xuICAgIH1cblxuICAgIC8vIFJldHVybiBhIEpTT05cbiAgICByZXR1cm4gcGFyc2VkRGF0YTtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG59XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSBpdGVtIHRvIGJlIGNoZWNrZWQuXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIG9iamVjdCBpcyBlbXB0eSwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiZcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcbiAgaXRlbSAhPT0gbnVsbCAmJlxuICBPYmplY3Qua2V5cyhpdGVtKS5sZW5ndGggPT09IDA7XG5cbi8qKlxuICogQ2hlY2tzIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQgaW4gdGhlIGdpdmVuIHN0cmluZy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXG4gKiBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/bG9jYWxob3N0XFxiLyxcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xNzJcXC4oMVs2LTldfDJbMC05XXwzWzAtMV0pXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXG4gIF07XG5cbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXG4gKlxuICogQHJldHVybnMge09iamVjdHxBcnJheX0gLSBUaGUgZGVlcCBjb3B5IG9mIHRoZSBwcm92aWRlZCBvYmplY3Qgb3IgYXJyYXkuXG4gKi9cbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcbiAgaWYgKG9iaiA9PT0gbnVsbCB8fCB0eXBlb2Ygb2JqICE9PSAnb2JqZWN0Jykge1xuICAgIHJldHVybiBvYmo7XG4gIH1cblxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcblxuICBmb3IgKGNvbnN0IGtleSBpbiBvYmopIHtcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBjb3B5O1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxuICogaW4gdGhlIG91dHB1dC5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxuICovXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XG4gICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xuXG4gICAgICAvLyBJZiBhbGxvd0Z1bmN0aW9ucyBpcyBzZXQgdG8gdHJ1ZSwgcHJlc2VydmUgZnVuY3Rpb25zXG4gICAgICBpZiAoXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXG4gICAgICAgIHZhbHVlLmVuZHNXaXRoKCd9JylcbiAgICAgICkge1xuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXG4gICAgICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXG4gICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxuICAgICAgOiB2YWx1ZTtcbiAgfTtcblxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXG4gICAgL1wiRVhQX0ZVTnxFWFBfRlVOXCIvZyxcbiAgICAnJ1xuICApO1xufTtcblxuLyoqXG4gKiBQcmludHMgdGhlIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciBsb2dvIGFuZCB2ZXJzaW9uIGluZm9ybWF0aW9uLlxuICpcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XG4gKiB0aGUgbG9nby5cbiAqL1xuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcbiAgLy8gR2V0IHBhY2thZ2UgdmVyc2lvbiBlaXRoZXIgZnJvbSBlbnYgb3IgZnJvbSBwYWNrYWdlLmpzb25cbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxuICApLnZlcnNpb247XG5cbiAgLy8gUHJpbnQgdGV4dCBvbmx5XG4gIGlmIChub0xvZ28pIHtcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xuICAgIHJldHVybjtcbiAgfVxuXG4gIC8vIFByaW50IHRoZSBsb2dvXG4gIGNvbnNvbGUubG9nKFxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxuICApO1xufTtcblxuLyoqXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XG4gIGNvbnN0IHBhZCA9IDQ4O1xuICBjb25zdCByZWFkbWUgPSAnaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvbm9kZS1leHBvcnQtc2VydmVyI3JlYWRtZSc7XG5cbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cbiAgY29uc29sZS5sb2coXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxuICAgICdcXG4tLS0tLS0nLFxuICAgIGBcXG5Gb3IgbW9yZSBkZXRhaWxlZCBpbmZvcm1hdGlvbiwgdmlzaXQgdGhlIHJlYWRtZSBhdDogJHtyZWFkbWUuYm9sZC55ZWxsb3d9LmBcbiAgKTtcblxuICBjb25zdCBjeWNsZUNhdGVnb3JpZXMgPSAob3B0aW9ucykgPT4ge1xuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxuICAgICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob3B0aW9uLCAndmFsdWUnKSkge1xuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGxldCBkZXNjTmFtZSA9IGAgIC0tJHtvcHRpb24uY2xpTmFtZSB8fCBuYW1lfSAke1xuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cbiAgICAgICAgfSBgO1xuICAgICAgICBpZiAoZGVzY05hbWUubGVuZ3RoIDwgcGFkKSB7XG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gRGlzcGxheSBjb3JyZWN0bHkgYWxpZ25lZCBtZXNzYWdlc1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICBkZXNjTmFtZSxcbiAgICAgICAgICBvcHRpb24uZGVzY3JpcHRpb24sXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cbiAgfTtcblxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XG4gICAgLy8gT25seSBwdXBwZXRlZXIgYW5kIGhpZ2hjaGFydHMgY2F0ZWdvcmllcyBjYW5ub3QgYmUgY29uZmlndXJlZCB0aHJvdWdoIENMSVxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XG4gICAgICBjeWNsZUNhdGVnb3JpZXMoZGVmYXVsdENvbmZpZ1tjYXRlZ29yeV0pO1xuICAgIH1cbiAgfSk7XG4gIGNvbnNvbGUubG9nKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IHZhbHVlIC0gVGhlIG51bWJlciB0byBiZSByb3VuZGVkLlxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXG4gKlxuICogQHJldHVybnMge251bWJlcn0gLSBUaGUgcm91bmRlZCBudW1iZXIuXG4gKi9cbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xuICBjb25zdCBtdWx0aXBsaWVyID0gTWF0aC5wb3coMTAsIHByZWNpc2lvbiB8fCAwKTtcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xufTtcblxuLyoqXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cbiAqXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRoZSBib29sZWFuIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBpbnB1dCB2YWx1ZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxuICBbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTicsICcwJywgJyddLmluY2x1ZGVzKGl0ZW0pXG4gICAgPyBmYWxzZVxuICAgIDogISFpdGVtO1xuXG4vKipcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xuICogZmFpbHMuXG4gKi9cbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcbiAgICBjdXN0b21Db2RlID0gY3VzdG9tQ29kZS50cmltKCk7XG5cbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcbiAgICAgIHJldHVybiBhbGxvd0ZpbGVSZXNvdXJjZXNcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxuICAgICAgICA6IGZhbHNlO1xuICAgIH0gZWxzZSBpZiAoXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpPT4nKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXG4gICAgKSB7XG4gICAgICByZXR1cm4gYCgke2N1c3RvbUNvZGV9KSgpYDtcbiAgICB9XG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XG4gIH1cbn07XG5cbi8qKlxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cbiAqXG4gKiBAcmV0dXJucyB7ZnVuY3Rpb24oKTogbnVtYmVyfSAtIEEgZnVuY3Rpb24gdG8gY2FsY3VsYXRlIHRoZSBlbGFwc2VkIHRpbWVcbiAqIGluIG1pbGxpc2Vjb25kcy5cbiAqL1xuZXhwb3J0IGNvbnN0IG1lYXN1cmVUaW1lID0gKCkgPT4ge1xuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgX19kaXJuYW1lLFxuICBjbGVhclRleHQsXG4gIGV4cEJhY2tvZmYsXG4gIGZpeFR5cGUsXG4gIGhhbmRsZVJlc291cmNlcyxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNPYmplY3QsXG4gIGlzT2JqZWN0RW1wdHksXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZSxcbiAgcm91bmROdW1iZXIsXG4gIHRvQm9vbGVhbixcbiAgd3JhcEFyb3VuZCxcbiAgbWVhc3VyZVRpbWVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgcHJvbXB0cyBmcm9tICdwcm9tcHRzJztcblxuaW1wb3J0IHtcbiAgYWJzb2x1dGVQcm9wcyxcbiAgZGVmYXVsdENvbmZpZyxcbiAgbmVzdGVkQXJncyxcbiAgcHJvbXB0c0NvbmZpZ1xufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5sZXQgZ2VuZXJhbE9wdGlvbnMgPSB7fTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xuXG4vKipcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXG4gKiBhbmQgYXJncyBmcm9tIHRoZSBDTEkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgZm9yIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvblxuICogKENMSSB1c2FnZSkuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVGhlIHVwZGF0ZWQgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxuICAgIGdlbmVyYWxPcHRpb25zID0gbG9hZENvbmZpZ0ZpbGUoYXJncyk7XG4gIH1cblxuICAvLyBVcGRhdGUgdGhlIGRlZmF1bHQgY29uZmlnIHdpdGggYSBjb3JyZWN0IG9wdGlvbiB2YWx1ZXNcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XG5cbiAgLy8gU2V0IHZhbHVlcyBmb3Igc2VydmVyJ3Mgb3B0aW9ucyBhbmQgcmV0dXJucyB0aGVtXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XG5cbiAgLy8gQXBwbHkgdXNlciBvcHRpb25zIGlmIHRoZXJlIGFyZSBhbnlcbiAgaWYgKHVzZXJPcHRpb25zKSB7XG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIHVzZXJPcHRpb25zLFxuICAgICAgYWJzb2x1dGVQcm9wc1xuICAgICk7XG4gIH1cblxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcbiAgICAvLyBQYWlyIHByb3ZpZGVkIGFyZ3VtZW50c1xuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xuICB9XG5cbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XG59O1xuXG4vKipcbiAqIEFsbG93cyBtYW51YWwgY29uZmlndXJhdGlvbiBiYXNlZCBvbiBzcGVjaWZpZWQgcHJvbXB0cyBhbmQgc2F2ZXNcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29uZmlnRmlsZU5hbWUgLSBUaGUgbmFtZSBvZiB0aGUgY29uZmlndXJhdGlvbiBmaWxlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxuICogY29uZmlndXJhdGlvbiBpcyBjb21wbGV0ZWQgYW5kIHNhdmVkLlxuICovXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XG4gIC8vIFByZXBhcmUgYSBjb25maWcgb2JqZWN0XG4gIGxldCBjb25maWdGaWxlID0ge307XG5cbiAgLy8gQ2hlY2sgaWYgcHJvdmlkZWQgY29uZmlnIGZpbGUgZXhpc3RzXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XG4gIH1cblxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcbiAgY29uc3Qgb25TdWJtaXQgPSBhc3luYyAocCwgY2F0ZWdvcmllcykgPT4ge1xuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XG5cbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcbiAgICAgIC8vIE1hcmsgZWFjaCBvcHRpb24gd2l0aCBhIHNlY3Rpb25cbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xuICAgICAgICAuLi5vcHRpb24sXG4gICAgICAgIHNlY3Rpb25cbiAgICAgIH0pKTtcblxuICAgICAgLy8gQ29sbGVjdCB0aGUgcXVlc3Rpb25zXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcbiAgICB9XG5cbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xuICAgICAgICAvLyBHZXQgdGhlIGRlZmF1bHQgbW9kdWxlIHNjcmlwdHNcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXG4gICAgICAgICAgICA/IGFuc3dlci5tYXAoKG1vZHVsZSkgPT4gcHJvbXB0LmNob2ljZXNbbW9kdWxlXSlcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XG5cbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXVtwcm9tcHQubmFtZV0gPSBhbnN3ZXI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oe30sIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dIHx8IHt9KSxcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCsrcXVlc3Rpb25zQ291bnRlciA9PT0gYWxsUXVlc3Rpb25zLmxlbmd0aCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcbiAgICAgICAgICAgICAgY29uZmlnRmlsZU5hbWUsXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxuICAgICAgICAgICAgICAndXRmOCdcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgICAgICAgICAgMSxcbiAgICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHRydWU7XG4gIH07XG5cbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XG4gICAgdGl0bGU6IGAke2Nob2ljZX0gb3B0aW9uc2AsXG4gICAgdmFsdWU6IGNob2ljZVxuICB9KSk7XG5cbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XG4gIHJldHVybiBwcm9tcHRzKFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxuICAgICAgbWVzc2FnZTogJ1doaWNoIGNhdGVnb3J5IGRvIHlvdSB3YW50IHRvIGNvbmZpZ3VyZT8nLFxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxuICAgICAgY2hvaWNlc1xuICAgIH0sXG4gICAgeyBvblN1Ym1pdCB9XG4gICk7XG59O1xuXG4vKipcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxuICogKFB1cHBldGVlcikuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBOZXcgb3B0aW9ucyBzdHJ1Y3R1cmVkIGJhc2VkIG9uIHRoZSBkZWZpbmVkIG5lc3RlZEFyZ3NcbiAqIG1hcHBpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBtYXBUb05ld0NvbmZpZyA9IChvbGRPcHRpb25zKSA9PiB7XG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG9sZE9wdGlvbnMpKSB7XG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcblxuICAgIC8vIFBvcHVsYXRlIG9iamVjdCBpbiBjb3JyZWN0IHByb3BlcnRpZXMgbGV2ZWxzXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxuICAgICAgICAob2JqW3Byb3BdID1cbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXG4gICAgICBuZXdPcHRpb25zXG4gICAgKTtcbiAgfVxuICByZXR1cm4gbmV3T3B0aW9ucztcbn07XG5cbi8qKlxuICogTWVyZ2VzIHR3byBzZXRzIG9mIGNvbmZpZ3VyYXRpb24gb3B0aW9ucywgY29uc2lkZXJpbmcgYWJzb2x1dGUgcHJvcGVydGllcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXdPcHRpb25zIC0gTmV3IGNvbmZpZ3VyYXRpb24gb3B0aW9ucyB0byBiZSBtZXJnZWQuXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBjb25zdCBtZXJnZUNvbmZpZ09wdGlvbnMgPSAob3B0aW9ucywgbmV3T3B0aW9ucywgYWJzb2x1dGVQcm9wcyA9IFtdKSA9PiB7XG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcblxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhuZXdPcHRpb25zKSkge1xuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcbiAgICAgICFhYnNvbHV0ZVByb3BzLmluY2x1ZGVzKGtleSkgJiZcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXG4gICAgICAgIDogdmFsdWUgIT09IHVuZGVmaW5lZFxuICAgICAgICAgID8gdmFsdWVcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcbiAgfVxuXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyBleHBvcnQgc2V0dGluZ3MgYmFzZWQgb24gcHJvdmlkZWQgZXhwb3J0T3B0aW9uc1xuICogYW5kIGdlbmVyYWxPcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBleHBvcnRPcHRpb25zIC0gT3B0aW9ucyBzcGVjaWZpYyB0byB0aGUgZXhwb3J0IHByb2Nlc3MuXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBleHBvcnQgc2V0dGluZ3MuXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xuICBsZXQgb3B0aW9ucyA9IHt9O1xuXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xuICAgIG9wdGlvbnMgPSBkZWVwQ29weShnZW5lcmFsT3B0aW9ucyk7XG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcbiAgICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcbiAgICAgIHN2ZzogZXhwb3J0T3B0aW9ucy5zdmdcbiAgICB9O1xuICB9IGVsc2Uge1xuICAgIG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcbiAgICAgIGV4cG9ydE9wdGlvbnMsXG4gICAgICAvLyBPbWl0IGdvaW5nIGRvd24gcmVjdXJzaXZlbHkgd2l0aCB0aGUgYmVsb3dzXG4gICAgICBhYnNvbHV0ZVByb3BzXG4gICAgKTtcbiAgfVxuXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vdXRmaWxlIHx8IGBjaGFydC4ke29wdGlvbnMuZXhwb3J0Py50eXBlIHx8ICdwbmcnfWA7XG4gIHJldHVybiBvcHRpb25zO1xufTtcblxuLyoqXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXG4gKiBvciBhbiBlbXB0eSBvYmplY3QgaWYgbm90IGZvdW5kIG9yIGludmFsaWQuXG4gKi9cbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBvcHRpb24gd2FzIHVzZWRcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xuICApO1xuXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcbiAgaWYgKGNvbmZpZ0luZGV4ID4gLTEgJiYgYXJnc1tjb25maWdJbmRleCArIDFdKSB7XG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XG4gICAgdHJ5IHtcbiAgICAgIC8vIENoZWNrIGlmIGFuIGFkZGl0aW9uYWwgY29uZmlnIGZpbGUgaXMgYSBjb3JyZWN0IEpTT04gZmlsZVxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcbiAgICAgICAgcmV0dXJuIEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGZpbGVOYW1lKSk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgICAgMixcbiAgICAgICAgZXJyb3IsXG4gICAgICAgIGBbY29uZmlnXSBVbmFibGUgdG8gbG9hZCB0aGUgY29uZmlndXJhdGlvbiBmcm9tIHRoZSAke2ZpbGVOYW1lfSBmaWxlLmBcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxuICByZXR1cm4ge307XG59XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFByb3BlcnR5IGNoYWluIGZvciB0cmFja2luZyBuZXN0ZWQgcHJvcGVydGllc1xuICogZHVyaW5nIHJlY3Vyc2lvbi5cbiAqL1xuZnVuY3Rpb24gdXBkYXRlRGVmYXVsdENvbmZpZyhjb25maWdPYmosIGN1c3RvbU9iaiA9IHt9LCBwcm9wQ2hhaW4gPSAnJykge1xuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XG4gICAgY29uc3QgY3VzdG9tVmFsdWUgPSBjdXN0b21PYmogJiYgY3VzdG9tT2JqW2tleV07XG5cbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgdXBkYXRlRGVmYXVsdENvbmZpZyhlbnRyeSwgY3VzdG9tVmFsdWUsIGAke3Byb3BDaGFpbn0uJHtrZXl9YCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXG4gICAgICBpZiAoY3VzdG9tVmFsdWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICBlbnRyeS52YWx1ZSA9IGVudnNbZW50cnkuZW52TGlua107XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcbiAqIG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIGluaXRPcHRpb25zKGl0ZW1zKSB7XG4gIGxldCBvcHRpb25zID0ge307XG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xuICAgIG9wdGlvbnNbbmFtZV0gPSBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwoaXRlbSwgJ3ZhbHVlJylcbiAgICAgID8gaXRlbS52YWx1ZVxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcbiAgfVxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXG4gKiB1cGRhdGluZyB0aGUgb3B0aW9ucyBvYmplY3QuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBjb250YWluaW5nIHZhbHVlcyBmb3Igc3BlY2lmaWNcbiAqIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxuICovXG5mdW5jdGlvbiBwYWlyQXJndW1lbnRWYWx1ZShvcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKSB7XG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgY29uc3Qgb3B0aW9uID0gYXJnc1tpXS5yZXBsYWNlKC8tL2csICcnKTtcblxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1tvcHRpb25dXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXG4gICAgICA6IFtdO1xuXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xuICAgIGxldCBhcmd1bWVudFR5cGU7XG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmpbcHJvcF07XG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XG5cbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XG4gICAgICAgIC8vIEZpbmRzIGFuIG9wdGlvbiBhbmQgc2V0IGEgY29ycmVzcG9uZGluZyB2YWx1ZVxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XG4gICAgICAgICAgICBpZiAoYXJndW1lbnRUeXBlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9ICthcmdzW2ldO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbG9nKFxuICAgICAgICAgICAgICAyLFxuICAgICAgICAgICAgICBgW2NvbmZpZ10gTWlzc2luZyB2YWx1ZSBmb3IgdGhlICcke29wdGlvbn0nIGFyZ3VtZW50LiBVc2luZyB0aGUgZGVmYXVsdCB2YWx1ZS5gXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBvYmpbcHJvcF07XG4gICAgfSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcbiAgaWYgKHNob3dVc2FnZSkge1xuICAgIHByaW50VXNhZ2UoZGVmYXVsdENvbmZpZyk7XG4gIH1cblxuICByZXR1cm4gb3B0aW9ucztcbn1cblxuLyoqXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xuICogdGhlIGZpbmFsIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIGZpbmFsIHZhbHVlIHRvIGJlIGFzc2lnbmVkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxuICovXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XG4gICAgY29uc3QgcHJvcE5hbWUgPSBuZXN0ZWROYW1lcy5zaGlmdCgpO1xuXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcbiAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3RUb1VwZGF0ZSwgcHJvcE5hbWUpKSB7XG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcbiAgICB9XG5cbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXG4gICAgICBPYmplY3QuYXNzaWduKHt9LCBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0pLFxuICAgICAgbmVzdGVkTmFtZXMsXG4gICAgICB2YWx1ZVxuICAgICk7XG5cbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG4gIH1cblxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXG4gIG9iamVjdFRvVXBkYXRlW25lc3RlZE5hbWVzWzBdXSA9IHZhbHVlO1xuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZ2V0T3B0aW9ucyxcbiAgc2V0T3B0aW9ucyxcbiAgbWFudWFsQ29uZmlnLFxuICBtYXBUb05ld0NvbmZpZyxcbiAgbWVyZ2VDb25maWdPcHRpb25zLFxuICBpbml0RXhwb3J0U2V0dGluZ3Ncbn07XG4iLCIvKipcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXG4gKi9cblxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuXG4vKipcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgKGh0dHAgb3IgaHR0cHMpLlxuICovXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XG5cbi8qKlxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcblxuICAgIHByb3RvY29sXG4gICAgICAuZ2V0KFxuICAgICAgICB1cmwsXG4gICAgICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAge1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdoaWdoY2hhcnRzL2V4cG9ydCcsXG4gICAgICAgICAgICAgIFJlZmVyZXI6ICdoaWdoY2hhcnRzL2V4cG9ydCdcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlcXVlc3RPcHRpb25zIHx8IHt9XG4gICAgICAgICksXG4gICAgICAgIChyZXMpID0+IHtcbiAgICAgICAgICBsZXQgZGF0YSA9ICcnO1xuXG4gICAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIClcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xuXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxuICAgICAge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlcXVlc3RPcHRpb25zXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xuXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxuICAgIHJlcS53cml0ZShkYXRhKTtcbiAgICByZXEuZW5kKCk7XG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XG4iLCJjbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XG4gIH1cblxuICBzZXRFcnJvcihlcnJvcikge1xuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcbiAgICBpZiAoZXJyb3IubmFtZSkge1xuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcbiAgICB9XG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XG4gICAgfVxuICAgIGlmIChlcnJvci5zdGFjaykge1xuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcblxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcblxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG5jb25zdCBjYWNoZSA9IHtcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcbiAgc291cmNlczogJycsXG4gIGhjVmVyc2lvbjogJydcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcbiAgICAucmVwbGFjZSgnLyonLCAnJylcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxuICAgIC50cmltKCk7XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxuICAgICcnXG4gICk7XG59O1xuXG4vKipcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XG4gKiBmaWxlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzLXJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXG4gKi9cbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XG4gIH07XG5cbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcblxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcbiAgdHJ5IHtcbiAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXG4gICAgICAndXRmOCdcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcbiAqIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxuICBzY3JpcHQsXG4gIHJlcXVlc3RPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlcyxcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXG4pID0+IHtcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XG4gIH1cblxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XG5cbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcbiAgfVxuXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XG4gIH0gZWxzZSB7XG4gICAgbG9nKFxuICAgICAgMixcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxuICAgICk7XG4gIH1cblxuICByZXR1cm4gJyc7XG59O1xuXG4vKipcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvcmVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxuICogKGZ1bGwgVVJMcykuXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcbiAqIGEgcmVxdWVzdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxuICBjb3JlU2NyaXB0cyxcbiAgbW9kdWxlU2NyaXB0cyxcbiAgY3VzdG9tU2NyaXB0cyxcbiAgcHJveHlPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlc1xuKSA9PiB7XG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcbiAgbGV0IHByb3h5QWdlbnQ7XG4gIGNvbnN0IHByb3h5SG9zdCA9IHByb3h5T3B0aW9ucy5ob3N0O1xuICBjb25zdCBwcm94eVBvcnQgPSBwcm94eU9wdGlvbnMucG9ydDtcblxuICAvLyBUcnkgdG8gY3JlYXRlIGEgUHJveHkgQWdlbnRcbiAgaWYgKHByb3h5SG9zdCAmJiBwcm94eVBvcnQpIHtcbiAgICB0cnkge1xuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xuICAgICAgICBob3N0OiBwcm94eUhvc3QsXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxuICAgICAgfSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXG4gICAgICAgIGVycm9yXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcbiAgICA/IHtcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcbiAgICAgIH1cbiAgICA6IHt9O1xuXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcbiAgICApLFxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcbiAgICApLFxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxuICAgIClcbiAgXTtcblxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXG4gIHByb3h5T3B0aW9ucyxcbiAgc291cmNlUGF0aFxuKSA9PiB7XG4gIGNvbnN0IHZlcnNpb24gPSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uO1xuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXG4gICk7XG5cbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcbiAgdHJ5IHtcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxuICAgICAgW1xuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcbiAgICAgIF0sXG4gICAgICBbXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxuICAgICAgICAgIG0gPT09ICdtYXAnXG4gICAgICAgICAgICA/IGAke2NkblVSTH1tYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgKSxcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXG4gICAgICAgIClcbiAgICAgIF0sXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxuICAgICAgcHJveHlPcHRpb25zLFxuICAgICAgZmV0Y2hlZE1vZHVsZXNcbiAgICApO1xuXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xuXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwob2JqZWN0fGJvb2xlYW4pPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZFxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXG4gKiBleGlzdHMuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcbiAgaWYgKG9wdGlvbnM/LmhpZ2hjaGFydHMpIHtcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XG4gIH1cbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXG4gKiBhbmQgdXBkYXRlZC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAob3B0aW9ucykgPT4ge1xuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcbiAgY29uc3QgY2FjaGVQYXRoID0gam9pbihfX2Rpcm5hbWUsIGhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcblxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XG4gIC8vIFByZXBhcmUgcGF0aHMgdG8gbWFuaWZlc3QgYW5kIHNvdXJjZXMgZnJvbSB0aGUgLmNhY2hlIGZvbGRlclxuICBjb25zdCBtYW5pZmVzdFBhdGggPSBqb2luKGNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKTtcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xuXG4gIC8vIENyZWF0ZSB0aGUgY2FjaGUgZGVzdGluYXRpb24gaWYgaXQgZG9lc24ndCBleGlzdCBhbHJlYWR5XG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XG5cbiAgLy8gRmV0Y2ggYWxsIHRoZSBzY3JpcHRzIGVpdGhlciBpZiBtYW5pZmVzdC5qc29uIGRvZXMgbm90IGV4aXN0XG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXG4gIGlmICghZXhpc3RzU3luYyhtYW5pZmVzdFBhdGgpIHx8IGhpZ2hjaGFydHMuZm9yY2VGZXRjaCkge1xuICAgIGxvZygzLCAnW2NhY2hlXSBGZXRjaGluZyBhbmQgY2FjaGluZyBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcy4nKTtcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XG4gIH0gZWxzZSB7XG4gICAgbGV0IHJlcXVlc3RVcGRhdGUgPSBmYWxzZTtcblxuICAgIC8vIFJlYWQgdGhlIG1hbmlmZXN0IEpTT05cbiAgICBjb25zdCBtYW5pZmVzdCA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKG1hbmlmZXN0UGF0aCkpO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIG1vZHVsZXMgaXMgYW4gYXJyYXksIGlmIHNvLCB3ZSByZXdyaXRlIGl0IHRvIGEgbWFwIHRvIG1ha2VcbiAgICAvLyBpdCBlYXNpZXIgdG8gcmVzb2x2ZSBtb2R1bGVzLlxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcbiAgICAgIGNvbnN0IG1vZHVsZU1hcCA9IHt9O1xuICAgICAgbWFuaWZlc3QubW9kdWxlcy5mb3JFYWNoKChtKSA9PiAobW9kdWxlTWFwW21dID0gMSkpO1xuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcbiAgICB9XG5cbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xuICAgIGNvbnN0IG51bWJlck9mTW9kdWxlcyA9XG4gICAgICBjb3JlU2NyaXB0cy5sZW5ndGggKyBtb2R1bGVTY3JpcHRzLmxlbmd0aCArIGluZGljYXRvclNjcmlwdHMubGVuZ3RoO1xuXG4gICAgLy8gQ29tcGFyZSB0aGUgbG9hZGVkIGhpZ2hjaGFydHMgY29uZmlnIHdpdGggdGhlIGNvbnRlbnRzIGluIGNhY2hlLlxuICAgIC8vIElmIHRoZXJlIGFyZSBjaGFuZ2VzLCBmZXRjaCByZXF1ZXN0ZWQgbW9kdWxlcyBhbmQgcHJvZHVjdHMsXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cbiAgICBpZiAobWFuaWZlc3QudmVyc2lvbiAhPT0gaGlnaGNoYXJ0cy52ZXJzaW9uKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgICdbY2FjaGVdIEEgSGlnaGNoYXJ0cyB2ZXJzaW9uIG1pc21hdGNoIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC4nXG4gICAgICApO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIGlmIChPYmplY3Qua2V5cyhtYW5pZmVzdC5tb2R1bGVzIHx8IHt9KS5sZW5ndGggIT09IG51bWJlck9mTW9kdWxlcykge1xuICAgICAgbG9nKFxuICAgICAgICAyLFxuICAgICAgICAnW2NhY2hlXSBUaGUgY2FjaGUgYW5kIHRoZSByZXF1ZXN0ZWQgbW9kdWxlcyBkbyBub3QgbWF0Y2gsIG5lZWQgdG8gcmUtZmV0Y2guJ1xuICAgICAgKTtcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBDaGVjayBlYWNoIG1vZHVsZSwgaWYgYW55dGhpbmcgaXMgbWlzc2luZyByZWZldGNoIGV2ZXJ5dGhpbmdcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xuICAgICAgICBpZiAoIW1hbmlmZXN0Lm1vZHVsZXNbbW9kdWxlTmFtZV0pIHtcbiAgICAgICAgICBsb2coXG4gICAgICAgICAgICAyLFxuICAgICAgICAgICAgYFtjYWNoZV0gVGhlICR7bW9kdWxlTmFtZX0gaXMgbWlzc2luZyBpbiB0aGUgY2FjaGUsIG5lZWQgdG8gcmUtZmV0Y2guYFxuICAgICAgICAgICk7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGlmIChyZXF1ZXN0VXBkYXRlKSB7XG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxvZygzLCAnW2NhY2hlXSBEZXBlbmRlbmN5IGNhY2hlIGlzIHVwIHRvIGRhdGUsIHByb2NlZWRpbmcuJyk7XG5cbiAgICAgIC8vIExvYWQgdGhlIHNvdXJjZXNcbiAgICAgIGNhY2hlLnNvdXJjZXMgPSByZWFkRmlsZVN5bmMoc291cmNlUGF0aCwgJ3V0ZjgnKTtcblxuICAgICAgLy8gR2V0IGN1cnJlbnQgbW9kdWxlcyBtYXBcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gbWFuaWZlc3QubW9kdWxlcztcblxuICAgICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmFsbHksIHNhdmUgdGhlIG5ldyBtYW5pZmVzdCwgd2hpY2ggaXMgYmFzaWNhbGx5IG91ciBjdXJyZW50IGNvbmZpZ1xuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcbiAgYXdhaXQgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QoaGlnaGNoYXJ0cywgZmV0Y2hlZE1vZHVsZXMpO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldENhY2hlUGF0aCA9ICgpID0+XG4gIGpvaW4oX19kaXJuYW1lLCBnZXRPcHRpb25zKCkuaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xuXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGUgPSAoKSA9PiBjYWNoZTtcblxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xuXG5leHBvcnQgY29uc3QgdmVyc2lvbiA9ICgpID0+IGNhY2hlLmhjVmVyc2lvbjtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBjaGVja0FuZFVwZGF0ZUNhY2hlLFxuICBnZXRDYWNoZVBhdGgsXG4gIHVwZGF0ZVZlcnNpb24sXG4gIGdldENhY2hlLFxuICBoaWdoY2hhcnRzLFxuICB2ZXJzaW9uXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8qIGVzbGludC1kaXNhYmxlIG5vLXVuZGVmICovXG5cbi8qKlxuICogU2V0dGluZyB0aGUgYW5pbU9iamVjdC4gQ2FsbGVkIHdoZW4gaW5pdGluZyB0aGUgcGFnZS5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNldHVwSGlnaGNoYXJ0cygpIHtcbiAgSGlnaGNoYXJ0cy5hbmltT2JqZWN0ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XG4gIH07XG59XG5cbi8qKlxuICogQ3JlYXRlcyB0aGUgYWN0dWFsIGNoYXJ0LlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjaGFydE9wdGlvbnMgLSBUaGUgb3B0aW9ucyBmb3IgdGhlIEhpZ2hjaGFydHMgY2hhcnQuXG4gKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucy5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiB0cmlnZ2VyRXhwb3J0KGNoYXJ0T3B0aW9ucywgb3B0aW9ucywgZGlzcGxheUVycm9ycykge1xuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXG4gIHdpbmRvdy5fZGlzcGxheUVycm9ycyA9IGRpc3BsYXlFcnJvcnM7XG5cbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xuICBjb25zdCB7IGdldE9wdGlvbnMsIG1lcmdlLCBzZXRPcHRpb25zLCB3cmFwIH0gPSBIaWdoY2hhcnRzO1xuXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cbiAgLy8gcHJldmVudCBmcm9tIHBvbGx1dGluZyBvdGhlciBleHBvcnRzIHRoYXQgY2FuIGhhcHBlbiBvbiB0aGUgc2FtZSBwYWdlXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IG1lcmdlKGZhbHNlLCB7fSwgZ2V0T3B0aW9ucygpKTtcblxuICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxuICBjb25zdCBjaGFydCA9IHtcbiAgICBhbmltYXRpb246IGZhbHNlXG4gIH07XG5cbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XG4gIGlmIChvcHRpb25zLmV4cG9ydC5zdHJJbmopIHtcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xuICB9XG5cbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcbiAgICAgIGV4cG9ydGluZzoge1xuICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIHBsb3RPcHRpb25zOiB7XG4gICAgICAgIHNlcmllczoge1xuICAgICAgICAgIGxhYmVsOiB7XG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXG4gICAgICAgICovXG4gICAgICB0b29sdGlwOiB7fVxuICAgIH0pO1xuXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XG4gICAgfSk7XG5cbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcbiAgfSk7XG5cbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcbiAgfSk7XG5cbiAgLy8gR2V0IHRoZSB1c2VyIG9wdGlvbnNcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcbiAgICA6IGNoYXJ0T3B0aW9ucztcblxuICAvLyBUcmlnZ2VyIGN1c3RvbSBjb2RlXG4gIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpIHtcbiAgICBuZXcgRnVuY3Rpb24oJ29wdGlvbnMnLCBvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKHVzZXJPcHRpb25zKTtcbiAgfVxuXG4gIC8vIE1lcmdlIHRoZSBnbG9iYWxPcHRpb25zLCB0aGVtZU9wdGlvbnMsIG9wdGlvbnMgZnJvbSB0aGUgd3JhcHBlZFxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxuICBjb25zdCBmaW5hbE9wdGlvbnMgPSBtZXJnZShcbiAgICBmYWxzZSxcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXG4gICAgdXNlck9wdGlvbnMsXG4gICAgLy8gUGxhY2VkIGl0IGhlcmUgaW5zdGVhZCBpbiB0aGUgaW5pdCBiZWNhdXNlIG9mIHRoZSBzaXplIGlzc3Vlc1xuICAgIHsgY2hhcnQgfVxuICApO1xuXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxuICAgIDogdW5kZWZpbmVkO1xuXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQuZ2xvYmFsT3B0aW9ucyk7XG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcbiAgfVxuXG4gIGxldCBjb25zdHIgPSBvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0JztcbiAgY29uc3RyID0gdHlwZW9mIEhpZ2hjaGFydHNbY29uc3RyXSAhPT0gJ3VuZGVmaW5lZCcgPyBjb25zdHIgOiAnY2hhcnQnO1xuXG4gIEhpZ2hjaGFydHNbY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcblxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcbiAgICBpZiAodHlwZW9mIGRlZmF1bHRPcHRpb25zW3Byb3BdICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XG4gICAgfVxuICB9XG5cbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xuICBzZXRPcHRpb25zKEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaik7XG5cbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0ge307XG59XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XG5cbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcblxuaW1wb3J0IHsgZ2V0Q2FjaGVQYXRoIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXG5jb25zdCB0ZW1wbGF0ZSA9IHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL3RlbXBsYXRlcy90ZW1wbGF0ZS5odG1sJywgJ3V0ZjgnKTtcblxubGV0IGJyb3dzZXI7XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxuICogaW5zdGFuY2UuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXG4gKiBjcmVhdGVkLlxuICovXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xuICBpZiAoIWJyb3dzZXIpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBObyB2YWxpZCBicm93c2VyIGhhcyBiZWVuIGNyZWF0ZWQuJyk7XG4gIH1cbiAgcmV0dXJuIGJyb3dzZXI7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcbiAgLy8gR2V0IGRlYnVnIGFuZCBvdGhlciBvcHRpb25zXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XG5cbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxuICAgIGhhbmRsZVNJR0lOVDogZmFsc2UsXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcbiAgICB3YWl0Rm9ySW5pdGlhbFBhZ2U6IGZhbHNlLFxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcbiAgfTtcblxuICAvLyBDcmVhdGUgYSBicm93c2VyXG4gIGlmICghYnJvd3Nlcikge1xuICAgIGxldCB0cnlDb3VudCA9IDA7XG5cbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xuICAgICAgdHJ5IHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXG4gICAgICAgICk7XG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgIDEsXG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfTtcblxuICAgIHRyeSB7XG4gICAgICBhd2FpdCBvcGVuKCk7XG5cbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIHNoZWxsIG1vZGUuYCk7XG4gICAgICB9XG5cbiAgICAgIC8vIERlYnVnIG1vZGUgaW5mb3JtXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAnW2Jyb3dzZXJdIE1heGltdW0gcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlciBpbnN0YW5jZSByZWFjaGVkLidcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cblxuICAgIGlmICghYnJvd3Nlcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXG4gIHJldHVybiBicm93c2VyO1xufVxuXG4vKipcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcbiAqIGlzIGNsb3NlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcbiAgaWYgKGJyb3dzZXI/LmNvbm5lY3RlZCkge1xuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgfVxuICBsb2coNCwgJ1ticm93c2VyXSBDbG9zZWQgdGhlIGJyb3dzZXIuJyk7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cbiAqXG4gKiBJZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3QgYXZhaWxhYmxlLCByZXR1cm5zIGZhbHNlLlxuICpcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xuICogc2V0UGFnZUNvbnRlbnQoKSwgYW5kIHJldHVybnMgdGhlIGNyZWF0ZWQgUHVwcGV0ZWVyIFBhZ2UuXG4gKlxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XG4gKiBhdmFpbGFibGUsIG9yIGEgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHJlcHJlc2VudGluZyB0aGUgbmV3bHkgY3JlYXRlZCBwYWdlLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgcGFnZVxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XG5cbiAgLy8gRGlzYWJsZSBjYWNoZVxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XG5cbiAgLy8gU2V0IHRoZSBjb250ZW50XG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xuXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xuICBzZXRQYWdlRXZlbnRzKHBhZ2UpO1xuXG4gIHJldHVybiBwYWdlO1xufVxuXG4vKipcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcbiAqIHRvIGJlIHBlcmZvcm1lZC4gSWYgdHJ1ZSwgbmF2aWdhdGVzIHRvICdhYm91dDpibGFuaycgYW5kIHJlc2V0cyBjb250ZW50XG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcbiAqIHN0cnVjdHVyZS5cbiAqXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZShwYWdlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xuICB0cnkge1xuICAgIGlmIChwYWdlICYmICFwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2dXaXRoU3RhY2soXG4gICAgICAyLFxuICAgICAgZXJyb3IsXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiBmYWxzZTtcbn1cblxuLyoqXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcbiAqIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsIGJlXG4gKiBhZGRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8T2JqZWN0Pj59IC0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gYXJyYXkgb2YgaW5qZWN0ZWRcbiAqIHJlc291cmNlcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucykge1xuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcblxuICAvLyBVc2UgcmVzb3VyY2VzXG4gIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xuICBpZiAocmVzb3VyY2VzKSB7XG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xuXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcbiAgICAgIGluamVjdGVkSnMucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xuICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcblxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xuICAgICAgICBpbmplY3RlZEpzLnB1c2goXG4gICAgICAgICAgaXNMb2NhbFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xuXG4gICAgLy8gTG9hZCBDU1NcbiAgICBjb25zdCBpbmplY3RlZENzcyA9IFtdO1xuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XG4gICAgICBpZiAoY3NzSW1wb3J0cykge1xuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XG4gICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXG4gICAgICAgICAgICAgIC50cmltKCk7XG5cbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXG4gICAgICB9KTtcblxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xufVxuXG4vKipcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gUmVtb3Zlc1xuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxuICogaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcbiAqIGJlIGNsZWFyZWQuXG4gKiBAcGFyYW0ge0FycmF5PE9iamVjdD59IGluamVjdGVkUmVzb3VyY2VzIC0gQXJyYXkgb2YgaW5qZWN0ZWQgcmVzb3VyY2VzXG4gKiB0byBiZSBjbGVhcmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKSB7XG4gIHRyeSB7XG4gICAgZm9yIChjb25zdCByZXNvdXJjZSBvZiBpbmplY3RlZFJlc291cmNlcykge1xuICAgICAgYXdhaXQgcmVzb3VyY2UuZGlzcG9zZSgpO1xuICAgIH1cblxuICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXG4gICAgICAvLyBleHBvcnRzXG4gICAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcblxuICAgICAgICAvLyBDaGVjayBpbiBhbnkgYWxyZWFkeSBleGlzdGluZyBjaGFydHNcbiAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XG4gICAgICAgICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzXG4gICAgICAgICAgZm9yIChjb25zdCBvbGRDaGFydCBvZiBvbGRDaGFydHMpIHtcbiAgICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgICAgSGlnaGNoYXJ0cy5jaGFydHMuc2hpZnQoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBbLi4uc2NyaXB0c1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzY3JpcHQnKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgIGNvbnN0IFsuLi5saW5rc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdsaW5rJyk7XG5cbiAgICAgIC8vIFJlbW92ZSB0YWdzXG4gICAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXG4gICAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxuICAgICAgICAuLi5saW5rc1RvUmVtb3ZlXG4gICAgICBdKSB7XG4gICAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciBwYWdlJ3MgcmVzb3VyY2VzLmApO1xuICB9XG59XG5cbi8qKlxuICogU2V0cyB0aGUgY29udGVudCBmb3IgYSBQdXBwZXRlZXIgUGFnZSB1c2luZyBhIHByZWRlZmluZWQgdGVtcGxhdGVcbiAqIGFuZCBhZGRpdGlvbmFsIHNjcmlwdHMuIEFsc28sIHNldHMgdGhlIHBhZ2VlcnJvciBpbiBvcmRlciB0byBjYXRjaFxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCBmb3Igd2hpY2ggdGhlIGNvbnRlbnRcbiAqIGlzIGJlaW5nIHNldC5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gc2V0UGFnZUNvbnRlbnQocGFnZSkge1xuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XG5cbiAgLy8gQWRkIGFsbCByZWdpc3RlcmVkIEhpZ2NoYXJ0cyBzY3JpcHRzLCBxdWl0ZSBkZW1hbmRpbmdcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XG5cbiAgLy8gU2V0IHRoZSBpbml0aWFsIGFuaW1PYmplY3RcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xufVxuXG4vKipcbiAqIFNldCBldmVudHMgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXG4gKi9cbmZ1bmN0aW9uIHNldFBhZ2VFdmVudHMocGFnZSkge1xuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xuICBjb25zdCB7IGRlYnVnIH0gPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcbiAgaWYgKGRlYnVnLmVuYWJsZSAmJiBkZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUpIHtcbiAgICBwYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBTZXQgdGhlIHBhZ2VlcnJvciBsaXN0ZW5lclxuICBwYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoZXJyb3IpID0+IHtcbiAgICAvLyBJdCB3b3VsZCBzZWVtIGxpa2UgdGhpcyBtYXkgZmlyZSBhdCB0aGUgc2FtZSB0aW1lIG9yIHNob3J0bHkgYmVmb3JlXG4gICAgLy8gYSBwYWdlIGlzIGNsb3NlZC5cbiAgICBpZiAocGFnZS5pc0Nsb3NlZCgpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xuICAgIC8vIG9uIHBhZ2UgZXJyb3JzLlxuICAgIGF3YWl0IHBhZ2UuJGV2YWwoXG4gICAgICAnI2NvbnRhaW5lcicsXG4gICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XG4gICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcbiAgICApO1xuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBnZXQsXG4gIGNyZWF0ZSxcbiAgY2xvc2UsXG4gIG5ld1BhZ2UsXG4gIGNsZWFyUGFnZSxcbiAgYWRkUGFnZVJlc291cmNlcyxcbiAgY2xlYXJQYWdlUmVzb3VyY2VzXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XG5pbXBvcnQgeyBnZXRDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xuaW1wb3J0IHsgdHJpZ2dlckV4cG9ydCB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5cbmltcG9ydCBzdmdUZW1wbGF0ZSBmcm9tICcuLy4uL3RlbXBsYXRlcy9zdmdfZXhwb3J0L3N2Z19leHBvcnQuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcbiAqIHRoZSBpZCAnY2hhcnQtY29udGFpbmVyJy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cbiAqL1xuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcbiAgICBjb25zdCB7IHgsIHksIHdpZHRoLCBoZWlnaHQgfSA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIHtcbiAgICAgIHgsXG4gICAgICB5LFxuICAgICAgd2lkdGgsXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcbiAgICB9O1xuICB9KTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gSW1hZ2UgZW5jb2RpbmcuXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cbiAqIGluIG1pbGxpc2Vjb25kcy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xuICogd2l0aCBhbiBFeHBvcnRFcnJvciBmb3IgdGltZW91dC5cbiAqL1xuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxuICBQcm9taXNlLnJhY2UoW1xuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XG4gICAgICB0eXBlLFxuICAgICAgZW5jb2RpbmcsXG4gICAgICBjbGlwLFxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxuICAgICAgZnVsbFBhZ2U6IGZhbHNlLFxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcblxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXG4gICAgICBvbWl0QmFja2dyb3VuZDogdHlwZSA9PSAncG5nJ1xuICAgIH0pLFxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxuICAgICAgc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXG4gICAgICApXG4gICAgKVxuICBdKTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcbiAqIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gUERGIGhlaWdodC5cbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cbiAqL1xuY29uc3QgY3JlYXRlUERGID0gYXN5bmMgKFxuICBwYWdlLFxuICBoZWlnaHQsXG4gIHdpZHRoLFxuICBlbmNvZGluZyxcbiAgcmFzdGVyaXphdGlvblRpbWVvdXRcbikgPT4ge1xuICBhd2FpdCBwYWdlLmVtdWxhdGVNZWRpYVR5cGUoJ3NjcmVlbicpO1xuXG4gIHJldHVybiBwYWdlLnBkZih7XG4gICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxuICAgIHdpZHRoLFxuICAgIGVuY29kaW5nLFxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcbiAgfSk7XG59O1xuXG4vKipcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxuICovXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XG5cbi8qKlxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxuICovXG5jb25zdCBzZXRBc0NvbmZpZyA9IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycykgPT4ge1xuICAvLyBHZXQgcmlkIG9mIHRoZSByZWR1bmFudCBzdHJpbmcgZGF0YVxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XG4gIG9wdGlvbnMuZXhwb3J0LmluZmlsZSA9IG51bGw7XG5cbiAgLy8gR2V0IHRoZSBzaXplIG9mIHRoZSBleHBvcnQgaW5wdXRcbiAgY29uc3QgdG90YWxTaXplID0gQnVmZmVyLmJ5dGVMZW5ndGgoXG4gICAgb3B0aW9ucy5leHBvcnQ/LnN0ckluaiA/IG9wdGlvbnMuZXhwb3J0Py5zdHJJbmogOiBKU09OLnN0cmluZ2lmeShjaGFydCksXG4gICAgJ3V0Zi04J1xuICApO1xuXG4gIC8vIExvZyB0aGUgc2l6ZSBpbiBNQlxuICBsb2coXG4gICAgMyxcbiAgICBgW2V4cG9ydF0gVGhlIGN1cnJlbnQgdG90YWwgc2l6ZSBvZiBkYXRhIHBhc3NlZCB0byBhIHBhZ2UgaXMgYXJvdW5kICR7KFxuICAgICAgdG90YWxTaXplIC9cbiAgICAgICgxMDI0ICogMTAyNClcbiAgICApLnRvRml4ZWQoMil9IE1CYFxuICApO1xuXG4gIC8vIENoZWNrIHRoZSBzaXplIG9mIGRhdGEgcGFzc2VkIHRvIHRoZSBwYWdlXG4gIGlmICh0b3RhbFNpemUgPj0gMTAwICogMTAyNCAqIDEwMjQpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtleHBvcnRdIFRoZSBkYXRhIHBhc3NlZCB0byBhIHBhZ2UgZXhjZWVkZWQgMTAwTUIuYCk7XG4gIH1cblxuICAvLyBUcmlnZ2VyIHRoZSBIaWdoY2hhcnRzIGNoYXJ0IGNyZWF0aW9uXG4gIHJldHVybiBwYWdlLmV2YWx1YXRlKHRyaWdnZXJFeHBvcnQsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcbn07XG5cbi8qKlxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cbiAqIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIEV4cG9ydEVycm9yLlxuICovXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXG4gIGxldCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xuXG4gIHRyeSB7XG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcblxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XG5cbiAgICBsZXQgaXNTVkc7XG4gICAgaWYgKFxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcbiAgICApIHtcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XG5cbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xuICAgICAgfVxuXG4gICAgICBpc1NWRyA9IHRydWU7XG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpLCB7XG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xuXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxuICAgICAgICAgIHBhZ2UsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY2hhcnQ6IHtcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcblxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXG4gICAgLy8gSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcbiAgICBpbmplY3RlZFJlc291cmNlcyA9IGF3YWl0IGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucyk7XG5cbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXG4gICAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxuICAgICAgICAgIGNvbnN0IGNoYXJ0SGVpZ2h0ID0gc3ZnRWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcblxuICAgICAgICAgIC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XG5cbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxuICAgICAgICAgICAgY2hhcnRXaWR0aFxuICAgICAgICAgIH07XG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcblxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXG4gICAgICAgICAgICBjaGFydFdpZHRoXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguYWJzKFxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRIZWlnaHQgfHwgZXhwb3J0T3B0aW9ucy5oZWlnaHQpXG4gICAgKTtcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5hYnMoXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydFdpZHRoIHx8IGV4cG9ydE9wdGlvbnMud2lkdGgpXG4gICAgKTtcblxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xuXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcbiAgICB9KTtcblxuICAgIGxldCBkYXRhO1xuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAvLyBTVkdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xuICAgICAgLy8gUE5HIG9yIEpQRUdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcbiAgICAgICAgcGFnZSxcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxuICAgICAgICAnYmFzZTY0JyxcbiAgICAgICAge1xuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0sXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XG4gICAgICAvLyBQREZcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXG4gICAgICAgIHBhZ2UsXG4gICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxuICAgICAgICAnYmFzZTY0JyxcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcbiAgICByZXR1cm4gZGF0YTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xuICAgIHJldHVybiBlcnJvcjtcbiAgfVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgY3NzVGVtcGxhdGUgZnJvbSAnLi9jc3MuanMnO1xuXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcbjwhRE9DVFlQRSBodG1sPlxuPGh0bWwgbGFuZz0nZW4tVVMnPlxuICA8aGVhZD5cbiAgICA8bWV0YSBodHRwLWVxdWl2PVwiQ29udGVudC1UeXBlXCIgY29udGVudD1cInRleHQvaHRtbDsgY2hhcnNldD11dGYtOFwiPlxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XG4gIDwvaGVhZD5cbiAgPHN0eWxlPlxuICAgICR7Y3NzVGVtcGxhdGUoKX1cbiAgPC9zdHlsZT5cbiAgPGJvZHk+XG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxuICAgICAgJHtjaGFydH1cbiAgICA8L2Rpdj5cbiAgPC9ib2R5PlxuPC9odG1sPlxuXG5gO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcblxuaW1wb3J0IHtcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXG4gIGNsb3NlIGFzIGNsb3NlQnJvd3NlcixcbiAgbmV3UGFnZSxcbiAgY2xlYXJQYWdlXG59IGZyb20gJy4vYnJvd3Nlci5qcyc7XG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgbWVhc3VyZVRpbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcbmxldCBwb29sID0gZmFsc2U7XG5cbi8vIFBvb2wgc3RhdGlzdGljc1xuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xuICBwZXJmb3JtZWRFeHBvcnRzOiAwLFxuICBleHBvcnRBdHRlbXB0czogMCxcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxuICB0aW1lU3BlbnQ6IDAsXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxuICBzcGVudEF2ZXJhZ2U6IDBcbn07XG5cbmxldCBwb29sQ29uZmlnID0ge307XG5cbmNvbnN0IGZhY3RvcnkgPSB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbmV3IHdvcmtlciBwYWdlIGZvciB0aGUgZXhwb3J0IHBvb2wuXG4gICAqXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXG4gICAqIGJyb3dzZXIgcGFnZSwgYW5kIGluaXRpYWwgd29yayBjb3VudC5cbiAgICpcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcbiAgICogcGFnZS5cbiAgICovXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xuICAgIGxldCBwYWdlID0gZmFsc2U7XG5cbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcbiAgICBjb25zdCBzdGFydERhdGUgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgIHRyeSB7XG4gICAgICBwYWdlID0gYXdhaXQgbmV3UGFnZSgpO1xuXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJyk7XG4gICAgICB9XG5cbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcbiAgICAgICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxuICAgICAgICB9IG1zLmBcbiAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaWQsXG4gICAgICBwYWdlLFxuICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcbiAgICB9O1xuICB9LFxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxuICAgKiB0aGUgd29yayBsaW1pdC5cbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxuICAgKlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXG4gICAqL1xuICB2YWxpZGF0ZTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xuICAgIC8vIE5PVEU6IEluIGNlcnRhaW4gY2FzZXMgYWNxdWlyaW5nIHRocm93cyBhIFRhcmdldENsb3NlRXJyb3IsIHdoaWNoIG1heVxuICAgIC8vICAgICAgIGJlIGNhdXNlZCBieSB0d28gdGhpbmdzOlxuICAgIC8vICAgICAgICAgLSBUaGUgcGFnZSBpcyBjbG9zZWQgYW5kIGF0dGVtcHRlZCB0byBiZSByZXVzZWQuXG4gICAgLy8gICAgICAgICAtIExvc3QgY29udGFjdCB3aXRoIHRoZSBicm93c2VyXG4gICAgLy8gICAgICAgV2hhdCB3ZSdyZSBzZWVpbmcgaW4gbG9ncyBpcyB0aGF0IHN1Y2Nlc3NpdmUgZXhwb3J0cyB0eXBpY2FsbHlcbiAgICAvLyAgICAgICBzdWNjZWVkcywgYW5kIHRoZSBzZXJ2ZXIgcmVjb3ZlcnMsIGluZGljYXRpbmcgdGhhdCBpdCdzIGxpa2VseVxuICAgIC8vICAgICAgIHRoZSBmaXJzdCBjYXNlLiBUaGlzIGlzIGFuIGF0dGVtcHQgYXQgYWxsaWV2YXRpbmcgdGhlIGlzc3VlIGJ5XG4gICAgLy8gICAgICAgc2ltcGx5IG5vdCB2YWxpZGF0aW5nIHRoZSB3b3JrZXIgaWYgdGhlIHBhZ2UgaXMgbnVsbCBvciBjbG9zZWQuXG4gICAgLy9cbiAgICAvLyAgICAgICBUaGUgYWN0dWFsIHJlc3VsdCBmcm9tIHdoZW4gdGhpcyBoYXBwZW5lZCwgd2FzIHRoYXQgYSB3b3JrZXIgd291bGRcbiAgICAvLyAgICAgICBiZSBjb21wbGV0ZWx5IGxvY2tlZCwgc3RvcHBpbmcgaXQgZnJvbSBiZWluZyBhY3F1aXJlZCB1bnRpbFxuICAgIC8vICAgICAgIGl0cyB3b3JrIGNvdW50IHJlYWNoZWQgdGhlIGxpbWl0LlxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UgfHwgd29ya2VySGFuZGxlLnBhZ2U/LmlzQ2xvc2VkKCkpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcbiAgICApIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSxcblxuICAvKipcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxuICAgKi9cbiAgZGVzdHJveTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UgJiYgIXdvcmtlckhhbmRsZS5wYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XG4gICAgfVxuICB9XG5cbiAgLy8gbG9nOiAobWVzc2FnZSwgbGV2ZWwpID0+IGxvZygxLCAnW3Rhcm5dICcgKyAgbWVzc2FnZSlcbn07XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxuICovXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcblxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxuICApO1xuXG4gIGlmIChwb29sKSB7XG4gICAgcmV0dXJuIGxvZyhcbiAgICAgIDQsXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xuICAgICk7XG4gIH1cblxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xuICAgIHBvb2wgPSBuZXcgUG9vbCh7XG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcbiAgICAgIC4uLmZhY3RvcnksXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcbiAgICB9KTtcblxuICAgIC8vIFNldCBldmVudHNcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XG4gICAgICAvLyBDbGVhciBwYWdlXG4gICAgICBjb25zdCByID0gYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcbiAgICAgIGxvZyhcbiAgICAgICAgNCxcbiAgICAgICAgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS4gQ2xlYXIgcGFnZSBzdGF0dXM6ICR7cn0uYFxuICAgICAgKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcbiAgICAgIHJlc291cmNlLnBhZ2UgPSBudWxsO1xuICAgIH0pO1xuXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcbiAgICB9KTtcblxuICAgIGxvZyhcbiAgICAgIDMsXG4gICAgICBgW3Bvb2xdIFRoZSBwb29sIGlzIHJlYWR5JHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aCA/IGAgd2l0aCAke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RofSBpbml0aWFsIHJlc291cmNlcyB3YWl0aW5nLmAgOiAnLid9YFxuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxuICogaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcblxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcbiAgaWYgKHBvb2wpIHtcbiAgICAvLyBGcmVlIHVwIG5vdCByZWxlYXNlZCB3b3JrZXJzXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcbiAgICB9XG5cbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcbiAgICB9XG4gIH1cblxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXG4gKiBvcHRpb25zLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIGxldCB3b3JrZXJIYW5kbGU7XG5cbiAgdHJ5IHtcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xuXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcbiAgICAgIGdldFBvb2xJbmZvKCk7XG4gICAgfVxuXG4gICAgaWYgKCFwb29sKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1dvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xuICAgIH1cblxuICAgIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxuICAgIGNvbnN0IGFjcXVpcmVDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcbiAgICAgIHdvcmtlckhhbmRsZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XG5cbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxuICAgICAgaWYgKG9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xuICAgICAgICBsb2coXG4gICAgICAgICAgNSxcbiAgICAgICAgICBvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXG4gICAgICAgICAgYEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxuICAgICAgICAgIDogJycpICtcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgfVxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcblxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgJ1Jlc29sdmVkIHdvcmtlciBwYWdlIGlzIGludmFsaWQ6IHRoZSBwb29sIHNldHVwIGlzIHdvbmt5LidcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcblxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XG5cbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAvLyBOT1RFOiBJZiB0aGVyZSdzIGEgcmFzdGVyaXphdGlvbiB0aW1lb3V0LCB3ZSB3YW50IG5lZWQgdG8gZmx1c2ggdGhlIHBhZ2UuXG4gICAgICAvLyAgICAgICBUaGlzIGlzIGJlY2F1c2UgdGhlIHBhZ2UgbWF5IGJlIGluIGEgc3RhdGUgd2hlcmUgaXQncyB3YWl0aW5nIGZvclxuICAgICAgLy8gICAgICAgdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxuICAgICAgLy8gICAgICAgV2hpY2ggb2YgY291cnNlIGNhdXNlcyBhIGxvdCBvZiBpc3N1ZXMgd2l0aCB0aGUgZXZlbnQgc3lzdGVtLFxuICAgICAgLy8gICAgICAgYW5kIHBhZ2UgY29uc2lzdGVuY3kuXG4gICAgICAvL1xuICAgICAgLy8gTk9URTogT25seSBwYWdlLnNjcmVlbnNob3Qgd2lsbCB0aHJvdyB0aGlzLCB0aW1lb3V0cyBmb3IgUERGJ3MgYXJlXG4gICAgICAvLyAgICAgICBoYW5kbGVkIGJ5IHRoZSBwYWdlLnBkZiBmdW5jdGlvbiBpdHNlbGYuXG4gICAgICAvL1xuICAgICAgLy8gICAgICAgLi4ueWVzLCB0aGlzIGlzIHVnbHkuXG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBwb29sQ29uZmlnLndvcmtMaW1pdCArIDE7XG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlID0gbnVsbDtcbiAgICAgIH1cblxuICAgICAgaWYgKFxuICAgICAgICByZXN1bHQubmFtZSA9PT0gJ1RpbWVvdXRFcnJvcicgfHxcbiAgICAgICAgcmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnXG4gICAgICApIHtcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQ6IHlvdXIgY2hhcnQgbWF5IGJlIHRvbyBjb21wbGV4IG9yIGxhcmdlLCBhbmQgZmFpbGVkIHRvIHJlbmRlciB3aXRoaW4gdGhlIGFsbG90dGVkIHRpbWUuJ1xuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgICA/IGBGb3IgcmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC0gYFxuICAgICAgICAgICAgOiAnJykgKyBgRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxuICAgICAgICApLnNldEVycm9yKHJlc3VsdCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgNSxcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcblxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdWx0LFxuICAgICAgb3B0aW9uc1xuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcblxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxuICovXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XG5cbi8qKlxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XG4gIG1pbjogcG9vbC5taW4sXG4gIG1heDogcG9vbC5tYXgsXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcbiAgdXNlZDogcG9vbC5udW1Vc2VkKCksXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcbn0pO1xuXG4vKipcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXG4gKiByZXF1ZXN0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XG5cbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhdmFpbGFibGUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGluaXRQb29sLFxuICBraWxsUG9vbCxcbiAgcG9zdFdvcmssXG4gIGdldFBvb2wsXG4gIGdldFBvb2xJbmZvLFxuICBnZXRQb29sSW5mb0pTT04sXG4gIGdldFN0YXRzOiAoKSA9PiBzdGF0c1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5cbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQge1xuICBmaXhUeXBlLFxuICBoYW5kbGVSZXNvdXJjZXMsXG4gIGlzQ29ycmVjdEpTT04sXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHJvdW5kTnVtYmVyLFxuICB0b0Jvb2xlYW4sXG4gIHdyYXBBcm91bmRcbn0gZnJvbSAnLi91dGlscy5qcyc7XG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xuXG4vKipcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxuICogY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cbiAqXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXG4gKi9cbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xuXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xuXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xuXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgZW5kQ2FsbGJhY2tcbiAgICAgICk7XG5cbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxuICBpZiAoXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxuICApIHtcbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XG5cbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgICAgfVxuXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXG4gICAgICAgIDogZG9FeHBvcnQoXG4gICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xuICAgICAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXG4gICAgKVxuICApO1xufTtcblxuLyoqXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXG4gKiBhIGJhdGNoIGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XG5cbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICBzdGFydEV4cG9ydChcbiAgICAgICAgICB7XG4gICAgICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICAgICAgZXhwb3J0OiB7XG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XG5cbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxuICAgIGF3YWl0IGtpbGxQb29sKCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXG4gKiBhIHNpbmdsZSBleHBvcnQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xuXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XG4gICAgKTtcblxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxuICAgIGF3YWl0IGtpbGxQb29sKCk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGNoYXJ0IGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxuICovXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XG5cbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xuXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxuICBsZXQgc2NhbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxuICAgIDE7XG5cbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xuXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XG5cbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxuICBjb25zdCBzaXplID0ge1xuICAgIGhlaWdodDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcbiAgICAgIDQwMCxcbiAgICB3aWR0aDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxuICAgICAgY2hhcnQ/LndpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcbiAgICAgIDYwMCxcbiAgICBzY2FsZVxuICB9O1xuXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XG4gICAgc2l6ZVtwYXJhbV0gPVxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcbiAgfVxuICByZXR1cm4gc2l6ZTtcbn07XG5cbi8qKlxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxuICogY29tcGxldGlvbiBvciBlcnJvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcbiAqIGlzIGNvbXBsZXRlZC5cbiAqL1xuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcblxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XG5cbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgICAgICByZXNvdXJjZXMsXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgIDIsXG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcbiAgICBpZiAoXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXG4gICAgKSB7XG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXG4gIGlmIChjaGFydEpzb24pIHtcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XG4gIH1cblxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcbiAgfVxuXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXG4gICAgICAgICkge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcbiAgICAgICAgICAgIHRydWVcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcbiAgICB0cnkge1xuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgfVxuICB9XG5cbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xuICBpZiAoXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXG4gICkge1xuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFNpemUgc2VhcmNoXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcbiAgfTtcblxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxuICAgICAgb3B0aW9uc1xuICAgICk7XG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cbiAqXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxuICogdG8gYmUgaW5qZWN0ZWQuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cbiAqL1xuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICB0cnkge1xuICAgIGxldCBzdHJJbmo7XG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcblxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgKTtcbiAgICB9XG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcbiAgICB9XG5cbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXG4gICAgICApLnNldEVycm9yKGVycm9yKVxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxuICovXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XG5cbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXG4gIGlmIChcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxuICApIHtcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xuXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcbiAgICAgICk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cbiAqXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxuICovXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xuXG4vKipcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXG4gKlxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2luZ2xlRXhwb3J0LFxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc3RhcnRFeHBvcnQsXG4gIGZpbmRDaGFydFNpemVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLyoqXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxuICoqL1xuXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcblxuLyoqXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwge1xuICAgIEFERF9UQUdTOiBbJ2ZvcmVpZ25PYmplY3QnXSxcbiAgICAvLyBEaXNzYWxvdyBhbGwgeGxpbmtzIGluIGluY29taW5nIFNWR1xuICAgIEZPUkJJRF9BVFRSOiBbJ3hsaW5rOmhyZWYnXVxuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgc2FuaXRpemU7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcbmNvbnN0IGludGVydmFsSWRzID0gW107XG5cbi8qKlxuICogQWRkcyBpZCBvZiBhIHNldEludGVydmFsIHRvIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cbiAqXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxuICovXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XG59O1xuXG4vKipcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYnkgaWRzIGdhdGhlcmVkIGluIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xuICBsb2coNCwgYFtzZXJ2ZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscy5gKTtcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGFkZEludGVydmFsLFxuICBjbGVhckFsbEludGVydmFsc1xufTtcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXG4gKlxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcblxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XG4gIH1cblxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcbiAgbmV4dChlcnJvcik7XG59O1xuXG4vKipcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxuICovXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNDAwO1xuXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xuXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXG4gKlxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XG4gIGNvbnN0IG1zZyA9XG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xuXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxuICB9O1xuXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XG4gIH1cblxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XG4gICAgICAgIGpzb246ICgpID0+IHtcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9LFxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxuICAgICAgaWYgKFxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cbiAgICAgICkge1xuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShsaW1pdGVyKTtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxuICApO1xufTtcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcblxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcbiAgfVxuXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgdXBkYXRlVmVyc2lvbiwgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcblxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcblxuLyoqXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cbiAqXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cbiAgIWFwcFxuICAgID8gZmFsc2VcbiAgICA6IGFwcC5wb3N0KFxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XG5cbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxuICAgICAgICAgICAgICAgIDQwMVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxuICAgICAgICAgICAgICAgIDQwMVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiB2ZXJzaW9uKCksXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgbmV4dChlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcblxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xuaW1wb3J0IHtcbiAgZml4VHlwZSxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNPYmplY3RFbXB0eSxcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgbWVhc3VyZVRpbWVcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xuXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xuXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XG4gIHBuZzogJ2ltYWdlL3BuZycsXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcbn07XG5cbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcblxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcblxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XG5cbi8qKlxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xuICogdG8gYmUgZXhlY3V0ZWQuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcbiAqIHR5cGUsIGFuZCBib2R5LlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXG4gKi9cbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcbiAgbGV0IHJlc3VsdCA9IHRydWU7XG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xuXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xuXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxuICpcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcbiAqIGlzIGNvbXBsZXRlLlxuICovXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcblxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XG5cbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XG5cbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XG5cbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcblxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XG5cbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMixcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0OlxuICBDb250ZW50LVR5cGU6ICR7cmVxdWVzdC5oZWFkZXJzWydjb250ZW50LXR5cGUnXX0uIFxuICBDaGFydCBjb25zdHJ1Y3RvcjogJHtib2R5LmNvbnN0cn0uXG4gIERpbWVuc2lvbnM6ICR7Ym9keS53aWR0aH14JHtib2R5LmhlaWdodH0gQCAke2JvZHkuc2NhbGV9IHNjYWxlLlxuICBUeXBlOiAke3R5cGV9LlxuICBJcyBTVkcgc2V0PyAke3R5cGVvZiBib2R5LnN2ZyAhPT0gJ3VuZGVmaW5lZCd9LlxuICBCNjQ/ICR7dHlwZW9mIGJvZHkuYjY0ICE9PSAndW5kZWZpbmVkJ30uXG4gIE5vIGRvd25sb2FkPyAke3R5cGVvZiBib2R5Lm5vRG93bmxvYWQgIT09ICd1bmRlZmluZWQnfS5cblxuICBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEgfHwgYm9keS5zdmcpfVxuXG4gIGBcbiAgICAgICk7XG5cbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcblxuICAgIC8vIENhbGwgdGhlIGJlZm9yZSByZXF1ZXN0IGZ1bmN0aW9uc1xuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XG4gICAgICBpZCxcbiAgICAgIHVuaXF1ZUlkLFxuICAgICAgdHlwZSxcbiAgICAgIGJvZHlcbiAgICB9KTtcblxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcbiAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xuICAgIH1cblxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xuXG4gICAgLy8gSW4gY2FzZSB0aGUgY29ubmVjdGlvbiBpcyBjbG9zZWQsIGZvcmNlIHRvIGFib3J0IGZ1cnRoZXIgYWN0aW9uc1xuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsIChoYWRFcnJvcnMpID0+IHtcbiAgICAgIGlmIChoYWRFcnJvcnMpIHtcbiAgICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XG5cbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xuXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgIGV4cG9ydDoge1xuICAgICAgICBpbnN0cixcbiAgICAgICAgdHlwZSxcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcbiAgICAgIH0sXG4gICAgICBjdXN0b21Mb2dpYzoge1xuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXG4gICAgICB9XG4gICAgfTtcblxuICAgIGlmIChpbnN0cikge1xuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxuICAgICAgICBpbnN0cixcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcblxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXG4gICAgfTtcblxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcblxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xuICAgICAgICBsb2coXG4gICAgICAgICAgNSxcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcbiAgICAgICAgcmV0dXJuIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxuICAgICAgICAgIDQwMFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xuXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xuXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XG5cbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcbiAgICAgICAgICAgIH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBuZXh0KGVycm9yKTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xuICAvKipcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXG4gICAqL1xuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xuXG4gIC8qKlxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cbiAgICovXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xuXG5pbXBvcnQgeyB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG5cbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcblxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcblxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXG4gKiBhcnJheS5cbiAqXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxuICovXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG4gIHJldHVybiBzdW0gLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xufVxuXG4vKipcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXG4gKiBhbmQgZ2F0aGVyc1xuICpcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cbiAqL1xuZXhwb3J0IGNvbnN0IHN0YXJ0U3VjY2Vzc1JhdGUgPSAoKSA9PlxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXG4gICAgICAgID8gMVxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xuXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xuICAgIH1cbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xuXG4vKipcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XG4gIGlmICghYXBwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xuXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xuXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xuXG4gICAgcmVzLnNlbmQoe1xuICAgICAgc3RhdHVzOiAnT0snLFxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcbiAgICAgIHVwdGltZTpcbiAgICAgICAgTWF0aC5mbG9vcihcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxuICAgICAgICApICsgJyBtaW51dGVzJyxcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiB2ZXJzaW9uKCksXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXG5cbiAgICAgIC8vIE1vdmluZyBhdmVyYWdlXG4gICAgICBwZXJpb2QsXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcbiAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcbiAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXG5cbiAgICAgIC8vIFNWRy9KU09OIGF0dGVtcHRzXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXG4gICAgfSk7XG4gIH0pO1xufVxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xuXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xuXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XG5cbi8vIENyZWF0ZSBleHByZXNzIGFwcFxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xuXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XG5cbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcbmFwcC51c2UoY29ycygpKTtcblxuLy8gR2V0dGluZyBhIGxvdCBvZiBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3IgZXhjZXB0aW9uLlxuLy8gRXZlbiB0aG91Z2ggdGhpcyBpcyBhIGRlcHJlY2F0ZWQgb3B0aW9ucywgbGV0J3MgdHJ5IHRvIHNldCBpdCB0byBmYWxzZS5cbmFwcC51c2UoKF9yZXEsIHJlcywgbmV4dCkgPT4ge1xuICByZXMuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcbiAgbmV4dCgpO1xufSk7XG5cbi8qKlxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxuICovXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yLCBzb2NrZXQpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soXG4gICAgICAxLFxuICAgICAgZXJyb3IsXG4gICAgICBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9LCBkZXN0cm95aW5nIHNvY2tldC5gXG4gICAgKTtcbiAgICBzb2NrZXQuZGVzdHJveSgpO1xuICB9KTtcblxuICBzZXJ2ZXIub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU2VydmVyIGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gIH0pO1xuXG4gIHNlcnZlci5vbignY29ubmVjdGlvbicsIChzb2NrZXQpID0+IHtcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTb2NrZXQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgICB9KTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBhbiBIVFRQIHNlcnZlciBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbi4gVGhlIGBzZXJ2ZXJDb25maWdgXG4gKiBvYmplY3QgY29udGFpbnMgYWxsIHNlcnZlciByZWxhdGVkIHByb3BlcnRpZXMgKHNlZSB0aGUgYHNlcnZlcmAgc2VjdGlvblxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc2VydmVyQ29uZmlnIC0gVGhlIHNlcnZlciBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIHNlcnZlciBjYW5ub3QgYmUgY29uZmlndXJlZFxuICogYW5kIHN0YXJ0ZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBzdGFydFNlcnZlciA9IGFzeW5jIChzZXJ2ZXJDb25maWcpID0+IHtcbiAgdHJ5IHtcbiAgICAvLyBUT0RPOiBSZWFkIGZyb20gY29uZmlnL2VudlxuICAgIC8vIE5PVEU6XG4gICAgLy8gVG9vIGJpZyBsaW1pdHMgbGVhZCB0byB0aW1lb3V0cyBpbiB0aGUgZXhwb3J0IHByb2Nlc3Mgd2hlbiB0aGVcbiAgICAvLyByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3cuXG4gICAgY29uc3QgdXBsb2FkTGltaXRNaUIgPSBzZXJ2ZXJDb25maWcubWF4VXBsb2FkU2l6ZSB8fCAzO1xuICAgIGNvbnN0IHVwbG9hZExpbWl0Qnl0ZXMgPSB1cGxvYWRMaW1pdE1pQiAqIDEwMjQgKiAxMDI0O1xuXG4gICAgLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxuICAgIGNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xuICAgIGNvbnN0IHVwbG9hZCA9IG11bHRlcih7XG4gICAgICBzdG9yYWdlLFxuICAgICAgbGltaXRzOiB7XG4gICAgICAgIGZpZWxkU2l6ZTogdXBsb2FkTGltaXRCeXRlc1xuICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gRW5hYmxlIGJvZHkgcGFyc2VyXG4gICAgYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogdXBsb2FkTGltaXRCeXRlcyB9KSk7XG4gICAgYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXMgfSkpO1xuXG4gICAgLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXG4gICAgYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcblxuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XG5cbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcbiAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XG5cbiAgICAgIC8vIExpc3RlblxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcblxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XG5cbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXG4gICAgICBsZXQga2V5LCBjZXJ0O1xuXG4gICAgICB0cnkge1xuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXG4gICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxuICAgICAgICAgICd1dGY4J1xuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDIsXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XG5cbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcblxuICAgICAgICAvLyBMaXN0ZW5cbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XG5cbiAgICAgICAgbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cbiAgICBpZiAoXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXG4gICAgKSB7XG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcbiAgICB9XG5cbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XG5cbiAgICAvLyBTZXQgdXAgcm91dGVzXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcbiAgICB1aVJvdXRlKGFwcCk7XG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XG5cbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xuICAgIH0pO1xuICB9XG59O1xuXG4vKipcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0U2VydmVycyA9ICgpID0+IGFjdGl2ZVNlcnZlcnM7XG5cbi8qKlxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcblxuLyoqXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xuXG4vKipcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XG5cbi8qKlxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXG4gKi9cbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG4vKipcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbi8qKlxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBzdGFydFNlcnZlcixcbiAgY2xvc2VTZXJ2ZXJzLFxuICBnZXRTZXJ2ZXJzLFxuICBlbmFibGVSYXRlTGltaXRpbmcsXG4gIGdldEV4cHJlc3MsXG4gIGdldEFwcCxcbiAgdXNlLFxuICBnZXQsXG4gIHBvc3Rcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG5cbi8qKlxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxuICAhYXBwXG4gICAgPyBmYWxzZVxuICAgIDogYXBwLmdldCgnLycsIChfcmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgICAgcmVzcG9uc2Uuc2VuZEZpbGUoam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnLCAnaW5kZXguaHRtbCcpLCB7XG4gICAgICAgICAgYWNjZXB0UmFuZ2VzOiBmYWxzZVxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xuaW1wb3J0IHsga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcblxuLyoqXG4gKiBDbGVhbiB1cCBmdW5jdGlvbiB0byB0cmlnZ2VyIGJlZm9yZSBlbmRpbmcgcHJvY2VzcyBmb3IgdGhlIGdyYWNlZnVsIHNodXRkb3duLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBleGl0Q29kZSAtIEFuIGV4aXQgY29kZSBmb3IgdGhlIHByb2Nlc3MuZXhpdCgpIGZ1bmN0aW9uLlxuICovXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XG4gIC8vIEF3YWl0IGZyZWVpbmcgYWxsIHJlc291cmNlc1xuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xuICAgIGNsZWFyQWxsSW50ZXJ2YWxzKCksXG5cbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXG4gICAgY2xvc2VTZXJ2ZXJzKCksXG5cbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcbiAgICBraWxsUG9vbCgpXG4gIF0pO1xuXG4gIC8vIEV4aXQgcHJvY2VzcyB3aXRoIGEgY29ycmVjdCBjb2RlXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIHNodXRkb3duQ2xlYW5VcFxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgJ2NvbG9ycyc7XG5cbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7XG4gIGJhdGNoRXhwb3J0LFxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXG4gIHNpbmdsZUV4cG9ydCxcbiAgc3RhcnRFeHBvcnRcbn0gZnJvbSAnLi9jaGFydC5qcyc7XG5pbXBvcnQgeyBtYXBUb05ld0NvbmZpZywgbWFudWFsQ29uZmlnLCBzZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHtcbiAgaW5pdExvZ2dpbmcsXG4gIGxvZyxcbiAgbG9nV2l0aFN0YWNrLFxuICBzZXRMb2dMZXZlbCxcbiAgZW5hYmxlRmlsZUxvZ2dpbmdcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcbmltcG9ydCB7IHNodXRkb3duQ2xlYW5VcCB9IGZyb20gJy4vcmVzb3VyY2VfcmVsZWFzZS5qcyc7XG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG4vKipcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcbiAqIGFuZCB0ZXJtaW5hdGlvbiBvbiBleGl0IHNpZ25hbHMuIEhhbmRsZXMgJ2V4aXQnLCAnU0lHSU5UJywgJ1NJR1RFUk0nLCBhbmRcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxuICovXG5jb25zdCBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycyA9ICgpID0+IHtcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnZXhpdCdcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXG4gIHByb2Nlc3Mub24oJ1NJR0lOVCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xuICB9KTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXG4gIHByb2Nlc3Mub24oJ1NJR1RFUk0nLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXG4gIHByb2Nlc3Mub24oJ1NJR0hVUCcsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xuICB9KTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xuICBwcm9jZXNzLm9uKCd1bmNhdWdodEV4Y2VwdGlvbicsIGFzeW5jIChlcnJvciwgbmFtZSkgPT4ge1xuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcbiAqIHRoaXMgc3RhZ2UuIEZ1bmN0aW9uIHRoYXQgaXMgcmVxdWlyZWQgdG8gYmUgY2FsbGVkIGJlZm9yZSB0cnlpbmcgdG8gZXhwb3J0IGNoYXJ0cyBvciBzZXR0aW5nIGEgc2VydmVyLiBUaGUgYG9wdGlvbnNgIGlzIGFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIGFsbCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxuICovXG5jb25zdCBpbml0RXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxuICAgIG9wdGlvbnMuY3VzdG9tTG9naWMgJiYgb3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cbiAgKTtcblxuICAvLyBJbml0IHRoZSBsb2dnaW5nXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XG5cbiAgLy8gQXR0YWNoIHByb2Nlc3MnIGV4aXQgbGlzdGVuZXJzXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcbiAgfVxuXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcblxuICAvLyBJbml0IHRoZSBwb29sXG4gIGF3YWl0IGluaXRQb29sKHtcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xuICAgICAgbWluV29ya2VyczogMSxcbiAgICAgIG1heFdvcmtlcnM6IDFcbiAgICB9LFxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MgfHwgW11cbiAgfSk7XG5cbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xuICByZXR1cm4gb3B0aW9ucztcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgLy8gU2VydmVyXG4gIHNlcnZlcixcbiAgc3RhcnRTZXJ2ZXIsXG5cbiAgLy8gRXhwb3J0aW5nXG4gIGluaXRFeHBvcnQsXG4gIHNpbmdsZUV4cG9ydCxcbiAgYmF0Y2hFeHBvcnQsXG4gIHN0YXJ0RXhwb3J0LFxuXG4gIC8vIFBvb2xcbiAgaW5pdFBvb2wsXG4gIGtpbGxQb29sLFxuXG4gIC8vIE90aGVyXG4gIHNldE9wdGlvbnMsXG4gIHNodXRkb3duQ2xlYW5VcCxcblxuICAvLyBMb2dzXG4gIGxvZyxcbiAgbG9nV2l0aFN0YWNrLFxuICBzZXRMb2dMZXZlbCxcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXG5cbiAgLy8gVXRpbHNcbiAgbWFwVG9OZXdDb25maWcsXG4gIG1hbnVhbENvbmZpZyxcbiAgcHJpbnRMb2dvLFxuICBwcmludFVzYWdlXG59O1xuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImN1c3RvbSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImVudkxpbmsiLCJjZG5VUkwiLCJjb3JlU2NyaXB0cyIsIm1vZHVsZVNjcmlwdHMiLCJpbmRpY2F0b3JTY3JpcHRzIiwiY3VzdG9tU2NyaXB0cyIsImZvcmNlRmV0Y2giLCJjYWNoZVBhdGgiLCJleHBvcnQiLCJpbmZpbGUiLCJpbnN0ciIsIm9wdGlvbnMiLCJvdXRmaWxlIiwiY29uc3RyIiwiZGVmYXVsdEhlaWdodCIsImRlZmF1bHRXaWR0aCIsImRlZmF1bHRTY2FsZSIsImhlaWdodCIsIndpZHRoIiwic2NhbGUiLCJnbG9iYWxPcHRpb25zIiwidGhlbWVPcHRpb25zIiwiYmF0Y2giLCJyYXN0ZXJpemF0aW9uVGltZW91dCIsImN1c3RvbUxvZ2ljIiwiYWxsb3dDb2RlRXhlY3V0aW9uIiwiYWxsb3dGaWxlUmVzb3VyY2VzIiwiY3VzdG9tQ29kZSIsImNhbGxiYWNrIiwicmVzb3VyY2VzIiwibG9hZENvbmZpZyIsImxlZ2FjeU5hbWUiLCJjcmVhdGVDb25maWciLCJzZXJ2ZXIiLCJtYXhVcGxvYWRTaXplIiwiY2xpTmFtZSIsImVuYWJsZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInRvQ29uc29sZSIsInRvRmlsZSIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInRhZ05hbWUiLCJ0b1VwcGVyQ2FzZSIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwib3B0aW9uIiwiZW50cmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJoZWFkZXJzIiwiUmVmZXJlciIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsImlzQ2xvc2VkIiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJ0b3RhbFNpemUiLCJCdWZmZXIiLCJieXRlTGVuZ3RoIiwidG9GaXhlZCIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInIiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiRk9SQklEX0FUVFIiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwidjQiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImI2NCIsIm5vRG93bmxvYWQiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsImhhZEVycm9ycyIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJfcmVxIiwic2V0IiwiYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsInN0YXJ0U2VydmVyIiwic2VydmVyQ29uZmlnIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsImxpc3RlbiIsImNlcnQiLCJmc1Byb21pc2VzIiwicmVhZEZpbGUiLCJwb3NpeCIsImh0dHBzU2VydmVyIiwiTmFOIiwic3RhdGljIiwiaGVhbHRoUm91dGUiLCJleHBvcnRSb3V0ZXMiLCJfcmVxdWVzdCIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidWlSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwibG9nZ2luZ09wdGlvbnMiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSx1QkFDQSxnQkFFQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVBQ0EseUJBQ0EsU0FDQSxlQUNBLFlBQ0Esa0JBQ0EsU0FDQSxjQUNBLG1CQUNBLGVBQ0Esa0JBQ0EsY0FDQSxlQUVBLGNBQ0EsV0FDQSxlQUNBLFdBQ0EsU0FDQSxPQUNBLFdBQ0EsWUFDQSxTQUNBLHFCQUNBLGFBQ0EsV0FDQSxXQUNBLFdBQ0EsV0FDQSxlQUNBLFVBQ0Esa0JBQ0Esb0JBQ0EsYUFDQSxVQUNBLGNBQ0EsWUFDQSxZQUVGQyxXQUFZLENBQUMsa0JBQ2JDLE9BQVEsQ0FDTix3RUFDQSxtR0FNU0MsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLENBQ0wsbUNBQ0Esa0JBQ0EsMENBQ0EsMkJBQ0Esa0NBQ0Esa0NBQ0Esd0NBQ0EsMkNBQ0EscUJBQ0EsNEJBQ0EsMkNBQ0EsdURBQ0EsNkJBQ0EseUJBQ0EsMEJBQ0EsK0JBQ0EsdUJBQ0EsdUZBQ0EseUJBQ0Esb0NBQ0Esb0JBQ0EsMEJBQ0EsOENBQ0EsMkJBQ0EsMEJBQ0EsNkJBQ0EsbUNBQ0Esd0NBQ0EsbUNBQ0EsMkJBQ0Esa0NBQ0EsdUJBQ0EsaUJB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 2be23da2..c412d164 100644 --- a/dist/index.esm.js +++ b/dist/index.esm.js @@ -1,2 +1,2 @@ -import"colors";import{existsSync as e,mkdirSync as t,appendFile as o,readFileSync as r,promises as i,writeFileSync as s}from"fs";import n,{join as a,posix as l}from"path";import{HttpsProxyAgent as c}from"https-proxy-agent";import p from"prompts";import h from"dotenv";import{z as u}from"zod";import{fileURLToPath as d}from"url";import g from"http";import m from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import y from"puppeteer";import{JSDOM as b}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import x from"express-rate-limit";const R={core:["highcharts","highcharts-more","highcharts-3d"],modules:["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"],indicators:["indicators-all"],custom:["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"]},O={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"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:R.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:R.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:R.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:R.custom,type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{maxUploadSize:{value:3,type:"number",cliName:"maxUploadSize",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in megabytes, for the server"},enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},L={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:O.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:O.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:O.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:O.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:O.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:O.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:O.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:O.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:O.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:O.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:O.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:O.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:O.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:O.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:O.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:O.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:O.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:O.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?I(r,`${t}.${o}`):(k[r.cliName||o]=`${t}.${o}`.substring(1),void 0!==r.legacyName&&(k[r.legacyName]=`${t}.${o}`.substring(1)))}}))};I(O),h.config();const C=e=>u.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),N=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),A=e=>u.enum([...e,""]).transform((e=>""!==e?e:void 0)),P=()=>u.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),H=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(R.core),HIGHCHARTS_MODULE_SCRIPTS:C(R.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(R.indicators),HIGHCHARTS_FORCE_FETCH:N(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:A(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:A(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:N(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:N(),SERVER_ENABLE:N(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:N(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:N(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:N(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:N(),SERVER_SSL_FORCE:N(),SERVER_SSL_PORT:H(),SERVER_SSL_CERT_PATH:P(),POOL_MIN_WORKERS:$(),POOL_MAX_WORKERS:$(),POOL_WORK_LIMIT:H(),POOL_ACQUIRE_TIMEOUT:$(),POOL_CREATE_TIMEOUT:$(),POOL_DESTROY_TIMEOUT:$(),POOL_IDLE_TIMEOUT:$(),POOL_CREATE_RETRY_INTERVAL:$(),POOL_REAPER_INTERVAL:$(),POOL_BENCHMARKING:N(),LOGGING_LEVEL:u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:P(),LOGGING_DEST:P(),LOGGING_TO_CONSOLE:N(),LOGGING_TO_FILE:N(),UI_ENABLE:N(),UI_ROUTE:P(),OTHER_NODE_ENV:A(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:N(),OTHER_NO_LOGO:N(),OTHER_HARD_RESET_PAGE:N(),OTHER_BROWSER_SHELL_MODE:N(),DEBUG_ENABLE:N(),DEBUG_HEADLESS:N(),DEBUG_DEVTOOLS:N(),DEBUG_LISTEN_TO_CONSOLE:N(),DEBUG_DUMPIO:N(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),D=["red","yellow","blue","gray","green"];let U={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:D[0]},{title:"warning",color:D[1]},{title:"notice",color:D[2]},{title:"verbose",color:D[3]},{title:"benchmark",color:D[4]}],listeners:[]};const j=(r,i)=>{U.pathCreated||(!e(U.dest)&&t(U.dest),U.pathCreated=!0),o(`${U.dest}${U.file}`,[i].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),U.toFile=!1)}))},M=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=U;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;U.listeners.forEach((e=>{e(s,o.join(" "))})),U.toConsole&&console.log.apply(void 0,[s.toString()[U.levelsDesc[t-1].color]].concat(o)),U.toFile&&j(o,s)},F=(e,t,o)=>{const r=o||t.message,{level:i,levelsDesc:s}=U;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[r,"\n",a];U.toConsole&&console.log.apply(void 0,[n.toString()[U.levelsDesc[e-1].color]].concat([r[D[e-1]],"\n",a])),U.listeners.forEach((e=>{e(n,l.join(" "))})),U.toFile&&j(l,n)},W=e=>{e>=0&&e<=U.levelsDesc.length&&(U.level=e)},V=(e,t)=>{if(U={...U,dest:e||U.dest,file:t||U.file,toFile:!0},0===U.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");U.dest.endsWith("/")||(U.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();"jpg"===r?e="jpeg":o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},X=(e=!1,t)=>{const o=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(r(e,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else i=K(e),i&&!t&&delete i.files;for(const e in i)o.includes(e)?s||(s=!0):delete i[e];return s?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):M(3,"[cli] No resources found.")};function K(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch{return!1}}const z=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]=z(e[o]));return t},J=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Y(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const Z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Q=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&Q(r(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ee=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let te={};const oe=()=>te,re=(e,t,o=[])=>{const r=z(e);for(const[e,s]of Object.entries(t))r[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==s?s:r[e]:re(r[e],s,o);var i;return r};function ie(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?ie(i,s,`${o}.${r}`):(void 0!==s&&(i.value=s),i.envLink in G&&void 0!==G[i.envLink]&&(i.value=G[i.envLink]))}))}function se(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:se(r);return t}function ne(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=ne(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function ae(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?m:g)(e);i.get(e,Object.assign({headers:{"User-Agent":"highcharts/export",Referer:"highcharts/export"}},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)}))}))}class le extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}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 ce={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},pe=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),he=async(e,t,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),M(4,`[cache] Fetching script - ${e}.js`);const i=await ae(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(r)throw new le(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return M(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ue=async(e,t,o)=>{const r=e.version,i="latest"!==r&&r?`${r}/`:"",n=e.cdnURL||ce.cdnURL;M(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ce.sources=await(async(e,t,o,r,i)=>{let s;const n=r.host,a=r.port;if(n&&a)try{s=new c({host:n,port:a})}catch(e){throw new le("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...o.map((e=>he(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...e.coreScripts.map((e=>`${n}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${n}maps/${i}modules/${e}`:`${n}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${n}stock/${i}indicators/${e}`))],e.customScripts,t,a),ce.hcVersion=pe(ce),s(o,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async o=>{const{highcharts:i,server:n}=o,l=a(q,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)M(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ue(i,n.proxy,h);else{let e=!1;const t=JSON.parse(r(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:o,moduleScripts:s,indicatorScripts:a}=i,l=o.length+s.length+a.length;t.version!==i.version?(M(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(M(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(s||[]).some((e=>{if(!t.modules[e])return M(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ue(i,n.proxy,h):(M(3,"[cache] Dependency cache is up to date, proceeding."),ce.sources=r(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const o={version:e.version,modules:t||{}};ce.activeManifest=o,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,oe().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(e,t,o){window._displayErrors=o;const{getOptions:r,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},r());const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),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 l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e;t.customLogic.customCode&&new Function("options",t.customLogic.customCode)(l);const c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&s(h);let u=t.export.constr||"chart";u=void 0!==Highcharts[u]?u:"chart",Highcharts[u]("container",c,p);const d=r();for(const e in d)"function"!=typeof d[e]&&delete d[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ye=r(q+"/templates/template.html","utf8");let be;async function we(){if(!be)return!1;const e=await be.newPage();return await e.setCacheEnabled(!1),await Te(e),function(e){const{debug:t}=oe();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{e.isClosed()||await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function Ee(e,t){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()}))}async function Te(e){await e.setContent(ye,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ge()}/sources.js`}),await e.evaluate(fe)}const Se=async(e,t,o,r)=>e.evaluate(ve,t,o,r);var xe=async(e,t,o)=>{let i=[];try{M(4,"[export] Determining export path.");const s=o.export,a=s?.options?.chart?.displayErrors&&ce.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(M(4,"[export] Treating as SVG."),"svg"===s.type)return t;l=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else M(4,"[export] Treating as config."),s.strInj?await Se(e,{chart:{height:s.height,width:s.width}},o,a):(t.chart.height=s.height,t.chart.width=s.width,await Se(e,t,o,a));i=await async function(e,t){const o=[],i=t.customLogic.resources;if(i){const s=[];if(i.js&&s.push({content:i.js}),i.files)for(const e of i.files){const t=!e.startsWith("http");s.push(t?{content:r(e,"utf8")}:{url:e})}for(const t of s)try{o.push(await e.addScriptTag(t))}catch(e){F(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(i.css){let r=i.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?a.push({url:e}):t.customLogic.allowFileResources&&a.push({path:n.join(q,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{o.push(await e.addStyleTag(t))}catch(e){F(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return o}(e,o);const c=l?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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.abs(Math.ceil(c.chartHeight||s.height)),h=Math.abs(Math.ceil(c.chartWidth||s.width)),{x:u,y:d}=await(e=>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)}})))(e);let g;if(await e.setViewport({height:p,width:h,deviceScaleFactor:l?1:parseFloat(s.scale)}),"svg"===s.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(s.type))g=await((e,t,o,r,i)=>Promise.race([e.screenshot({type:t,encoding:o,clip:r,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new le("Rasterization timeout"))),i||1500)))]))(e,s.type,"base64",{width:h,height:p,x:u,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new le(`[export] Unsupported output format ${s.type}.`);g=await(async(e,t,o,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:r,timeout:i||1500})))(e,p,h,"base64",s.rasterizationTimeout)}return await Ee(e,i),g}catch(t){return await Ee(e,i),t}};let Re=!1;const Oe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const _e={create:async()=>{let e=!1;const t=v(),o=(new Date).getTime();try{if(e=await we(),!e||e.isClosed())throw new le("The page is invalid or closed.");M(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw new le("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Le.workLimit&&++e.workCount>Le.workLimit)||(M(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1)),destroy:async e=>{M(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},ke=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:o}=oe(),{enable:r,...i}=t,s={headless:!o.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!be){let e=0;const t=async()=>{try{M(3,`[browser] Attempting to get a browser instance (try ${++e}).`),be=await y.launch(s)}catch(o){if(F(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;M(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===s.headless&&M(3,"[browser] Launched browser in shell mode."),r&&M(3,"[browser] Launched browser in debug mode.")}catch(e){throw new le("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!be)throw new le("[browser] Cannot find a browser to open.")}return be}(e.puppeteerArgs),M(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),Re)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{Re=new f({..._e,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),Re.on("release",(async e=>{const t=await async function(e,t=!1){try{if(e&&!e.isClosed())return t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(e){F(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);M(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),Re.on("destroySuccess",((e,t)=>{M(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{Re.release(e)})),M(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new le("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(M(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),M(4,"[browser] Destroyed the pool of resources."))}await async function(){be?.connected&&await be.close(),M(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let o;try{if(M(4,"[pool] Work received, starting to process."),++Oe.exportAttempts,Le.benchmarking&&Ae(),!Re)throw new le("Work received, but pool has not been started.");const r=ee();try{M(4,"[pool] Acquiring a worker handle."),o=await Re.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!o.page)throw new le("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();M(4,`[pool] Starting work on pool entry with ID ${o.id}.`);const s=ee(),n=await xe(o.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(o.workCount=Le.workLimit+1,o.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new le("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Re.release(o);const a=(new Date).getTime()-i;return Oe.timeSpent+=a,Oe.spentAverage=Oe.timeSpent/++Oe.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Oe.droppedExports,o&&Re.release(o),new le(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ne=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ae(){const{min:e,max:t,all:o,available:r,used:i,pending:s}=Ne();M(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),M(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),M(5,`[pool] The number of all created resources: ${o}.`),M(5,`[pool] The number of available resources: ${r}.`),M(5,`[pool] The number of acquired resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Pe=Ne,He=()=>Oe;let $e=!1;const Ge=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=z(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=re(t,e,_),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,oe()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{M(4,"[chart] Attempting to export from a SVG input.");const e=Me(function(e){const t=new b("").window;return w(t).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:["xlink:href"]})}(o.payload.svg),o,t);return++Oe.exportFromSvgAttempts,e}catch(e){return t(new le("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return M(4,"[chart] Attempting to export from an input file."),o.export.instr=r(i.infile,"utf8"),Me(o.export.instr.trim(),o,t)}catch(e){return t(new le("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return M(4,"[chart] Attempting to export from a raw input."),Z(o.customLogic?.allowCodeExecution)?je(o,t):"string"==typeof i.instr?Me(i.instr.trim(),o,t):Ue(o,i.instr||i.options,t)}catch(e){return t(new le("[chart] Error loading raw input.").setError(e))}return t(new le("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},De=e=>{const{chart:t,exporting:o}=e.export?.options||K(e.export?.instr),r=K(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2);const s={height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ue=async(e,t,o,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:$e;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=X(e.customLogic.resources,Z(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=r("resources.json","utf8");e.customLogic.resources=X(t,Z(e.customLogic.allowFileResources))}catch(e){F(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new le("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=B(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=K(r(s[e],"utf8"),!0):s[e]=K(s[e],!0))}catch(t){s[e]={},F(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Q(n.customCode,n.allowFileResources)}catch(e){F(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=r(n.callback,"utf8")}catch(e){n.callback=!1,F(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...De(e)};try{return o(!1,await Ce(s.strInj||t||i,e))}catch(e){return o(e)}},je=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=J(r,e.customLogic?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,Ue(e,!1,t)}catch(o){return t(new le(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(o))}},Me=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ue(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ue(t,r,o)}catch(e){return Z(r)?je(t,o):o(new le("[chart] Only JSON 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 flag.").setError(e))}},Fe=[],We=()=>{M(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},Ve=(e,t,o,r)=>{F(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,r(e)},qe=(e,t,o,r)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||400;o.status(l).json({statusCode:l,message:n,stack:a})};var Be=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=x({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class Xe extends le{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Ke=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,o)=>{try{const o=G.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new Xe("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 Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Xe("No new version supplied.",400);try{await(async e=>{const t=oe();t?.highcharts&&(t.highcharts.version=e),await de(t)})(i)}catch(e){throw new Xe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){o(e)}}));const ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Je=0;const Ye=[],Ze=[],Qe=(e,t,o,r)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,s,n,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},et=async(e,t,o)=>{try{const o=ee(),i=v().replace(/-/g,""),s=oe(),n=e.body,a=++Je;let l=B(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=K(n.infile||n.options||n.data);if(!c&&!n.svg)throw M(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect:\n Content-Type: ${e.headers["content-type"]}. \n Chart constructor: ${n.constr}.\n Dimensions: ${n.width}x${n.height} @ ${n.scale} scale.\n Type: ${l}.\n Is SVG set? ${void 0!==n.svg}.\n B64? ${void 0!==n.b64}.\n No download? ${void 0!==n.noDownload}.\n\n Payload received: ${JSON.stringify(n.infile||n.options||n.data||n.svg)}\n\n `),new Xe("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);let p=!1;if(p=Qe(Ye,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(e=>{e&&(h=!0)})),M(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:K(n.globalOptions,!0),themeOptions:K(n.themeOptions,!0)},customLogic:{allowCodeExecution:$e,allowFileResources:!1,resources:K(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=J(c,u.customLogic.allowCodeExecution));const d=re(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/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))))(d.payload.svg))throw new Xe("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);await Ge(d,((r,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),h)return M(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Qe(Ze,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){o(e)}var r};const tt=JSON.parse(r(a(q,"package.json"))),ot=new Date,rt=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;rt.push(t),rt.length>30&&rt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const o=He(),r=rt.length,i=rt.reduce(((e,t)=>e+t),0)/rt.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:me(),averageProcessingTime:o.spentAverage,performedExports:o.performedExports,failedExports:o.droppedExports,exportAttempts:o.exportAttempts,sucessRatio:o.performedExports/o.exportAttempts*100,pool:Pe(),period:r,movingAverage:i,message:isNaN(i)||!rt.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${r} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:o.exportFromSvgAttempts,jsonExportAttempts:o.performedExports-o.exportFromSvgAttempts})}))}const st=new Map,nt=T();nt.disable("x-powered-by"),nt.use(E()),nt.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()}));const at=e=>{e.on("clientError",((e,t)=>{F(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{F(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{F(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async e=>{try{const t=1024*(e.maxUploadSize||3)*1024,o=S.memoryStorage(),r=S({storage:o,limits:{fieldSize:t}});if(nt.use(T.json({limit:t})),nt.use(T.urlencoded({extended:!0,limit:t})),nt.use(r.none()),!e.enable)return!1;if(!e.ssl.force){const t=g.createServer(nt);at(t),t.listen(e.port,e.host),st.set(e.port,t),M(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,o;try{t=await i.readFile(l.join(e.ssl.certPath,"server.key"),"utf8"),o=await i.readFile(l.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){M(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=m.createServer({key:t,cert:o},nt);at(r),r.listen(e.ssl.port,e.host),st.set(e.ssl.port,r),M(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Be(nt,e.rateLimiting),nt.use(T.static(l.join(q,"public"))),it(nt),(e=>{e.post("/",et),e.post("/:filename",et)})(nt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(q,"public","index.html"),{acceptRanges:!1})}))})(nt),Ke(nt),(e=>{e.use(Ve),e.use(qe)})(nt)}catch(e){throw new le("[server] Could not configure and start the server.").setError(e)}},ct=()=>{M(4,"[server] Closing all servers.");for(const[e,t]of st)t.close((()=>{st.delete(e),M(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>st,enableRateLimiting:e=>Be(nt,e),getExpress:()=>T,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const ht=async e=>{await Promise.allSettled([We(),ct(),Ie()]),process.exit(e)};var ut={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,$e=Z(t),(e=>{for(const[t,o]of Object.entries(e))U[t]=o;W(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&V(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(M(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{M(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGTERM",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGHUP",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("uncaughtException",(async(e,t)=>{F(1,e,`The ${t} error.`),await ht(1)}))),await de(e),await ke({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:o,type:r}=t.options.export;s(o||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result),await Ie()}))},batchExport:async e=>{const t=[];for(let o of e.export.batch.split(";"))o=o.split("="),2===o.length&&t.push(Ge({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await Ie()}catch(e){throw new le("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,initPool:ke,killPool:Ie,setOptions:(e,t)=>(t?.length&&(te=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const o=e[t+1];try{if(o&&o.endsWith(".json"))return JSON.parse(r(o))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(t)),ie(O,te),te=se(O),e&&(te=re(te,e,_)),t?.length&&(te=function(e,t,o){let r=!1;for(let i=0;i(n.length-1===o&&(a=e[t].type),e[t])),o),n.reduce(((e,o,l)=>(n.length-1===l&&void 0!==e[o]&&(t[++i]?"boolean"===a?e[o]=Z(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&Y();return e}(te,t,O)),te),shutdownCleanUp:ht,log:M,logWithStack:F,setLogLevel:W,enableFileLogging:V,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=k[o]?k[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},manualConfig:async t=>{let o={};e(t)&&(o=JSON.parse(r(t,"utf8")));const s=Object.keys(L).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:s},{onSubmit:async(e,r)=>{let s=0,n=[];for(const e of r)L[e]=L[e].map((t=>({...t,section:e}))),n=[...n,...L[e]];return await p(n,{onSubmit:async(e,r)=>{if("moduleScripts"===e.name?(r=r.length?r.map((t=>e.choices[t])):e.choices,o[e.section][e.name]=r):o[e.section]=ne(Object.assign({},o[e.section]||{}),e.name.split("."),e.choices?e.choices[r]:r),++s===n.length){try{await i.writeFile(t,JSON.stringify(o,null,2),"utf8")}catch(e){F(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(r(a(q,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(r(q+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Y};export{ut as default}; -//# sourceMappingURL=index.esm.js.map +import"colors";import{existsSync as e,mkdirSync as t,appendFile as o,readFileSync as r,promises as i,writeFileSync as s}from"fs";import n,{join as a,posix as l}from"path";import{HttpsProxyAgent as c}from"https-proxy-agent";import p from"prompts";import h from"dotenv";import{z as u}from"zod";import{fileURLToPath as d}from"url";import g from"http";import m from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import y from"puppeteer";import{JSDOM as b}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import x from"express-rate-limit";const R={core:["highcharts","highcharts-more","highcharts-3d"],modules:["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"],indicators:["indicators-all"],custom:["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"]},O={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"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:R.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:R.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:R.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:R.custom,type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{maxUploadSize:{value:3,type:"number",cliName:"maxUploadSize",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in megabytes, for the server"},enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},L={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:O.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:O.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:O.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:O.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:O.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:O.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:O.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${O.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${O.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:O.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:O.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:O.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:O.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:O.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:O.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:O.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:O.server.host.value},{type:"number",name:"port",message:"Server port",initial:O.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:O.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:O.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:O.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:O.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:O.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:O.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:O.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:O.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:O.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:O.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:O.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:O.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:O.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:O.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:O.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:O.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:O.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:O.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:O.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:O.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:O.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:O.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:O.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:O.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:O.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:O.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:O.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:O.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:O.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:O.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:O.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:O.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:O.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:O.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:O.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:O.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:O.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:O.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:O.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:O.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:O.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:O.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:O.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:O.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?I(r,`${t}.${o}`):(k[r.cliName||o]=`${t}.${o}`.substring(1),void 0!==r.legacyName&&(k[r.legacyName]=`${t}.${o}`.substring(1)))}}))};I(O),h.config();const C=e=>u.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),N=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),A=e=>u.enum([...e,""]).transform((e=>""!==e?e:void 0)),P=()=>u.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),H=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(R.core),HIGHCHARTS_MODULE_SCRIPTS:C(R.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(R.indicators),HIGHCHARTS_FORCE_FETCH:N(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:A(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:A(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:N(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:N(),SERVER_ENABLE:N(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:N(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:N(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:N(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:N(),SERVER_SSL_FORCE:N(),SERVER_SSL_PORT:H(),SERVER_SSL_CERT_PATH:P(),POOL_MIN_WORKERS:$(),POOL_MAX_WORKERS:$(),POOL_WORK_LIMIT:H(),POOL_ACQUIRE_TIMEOUT:$(),POOL_CREATE_TIMEOUT:$(),POOL_DESTROY_TIMEOUT:$(),POOL_IDLE_TIMEOUT:$(),POOL_CREATE_RETRY_INTERVAL:$(),POOL_REAPER_INTERVAL:$(),POOL_BENCHMARKING:N(),LOGGING_LEVEL:u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:P(),LOGGING_DEST:P(),LOGGING_TO_CONSOLE:N(),LOGGING_TO_FILE:N(),UI_ENABLE:N(),UI_ROUTE:P(),OTHER_NODE_ENV:A(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:N(),OTHER_NO_LOGO:N(),OTHER_HARD_RESET_PAGE:N(),OTHER_BROWSER_SHELL_MODE:N(),DEBUG_ENABLE:N(),DEBUG_HEADLESS:N(),DEBUG_DEVTOOLS:N(),DEBUG_LISTEN_TO_CONSOLE:N(),DEBUG_DUMPIO:N(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),D=["red","yellow","blue","gray","green"];let U={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:D[0]},{title:"warning",color:D[1]},{title:"notice",color:D[2]},{title:"verbose",color:D[3]},{title:"benchmark",color:D[4]}],listeners:[]};const j=(r,i)=>{U.pathCreated||(!e(U.dest)&&t(U.dest),U.pathCreated=!0),o(`${U.dest}${U.file}`,[i].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),U.toFile=!1)}))},M=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=U;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;U.listeners.forEach((e=>{e(s,o.join(" "))})),U.toConsole&&console.log.apply(void 0,[s.toString()[U.levelsDesc[t-1].color]].concat(o)),U.toFile&&j(o,s)},F=(e,t,o)=>{const r=o||t.message,{level:i,levelsDesc:s}=U;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[r,"\n",a];U.toConsole&&console.log.apply(void 0,[n.toString()[U.levelsDesc[e-1].color]].concat([r[D[e-1]],"\n",a])),U.listeners.forEach((e=>{e(n,l.join(" "))})),U.toFile&&j(l,n)},W=e=>{e>=0&&e<=U.levelsDesc.length&&(U.level=e)},V=(e,t)=>{if(U={...U,dest:e||U.dest,file:t||U.file,toFile:!0},0===U.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");U.dest.endsWith("/")||(U.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();"jpg"===r?e="jpeg":o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},X=(e=!1,t)=>{const o=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(r(e,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else i=K(e),i&&!t&&delete i.files;for(const e in i)o.includes(e)?s||(s=!0):delete i[e];return s?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):M(3,"[cli] No resources found.")};function K(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch{return!1}}const z=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]=z(e[o]));return t},J=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Y(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(O).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(O[t]))})),console.log("\n")}const Z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Q=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&Q(r(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ee=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let te={};const oe=()=>te,re=(e,t,o=[])=>{const r=z(e);for(const[e,s]of Object.entries(t))r[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||o.includes(e)||void 0===r[e]?void 0!==s?s:r[e]:re(r[e],s,o);var i;return r};function ie(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?ie(i,s,`${o}.${r}`):(void 0!==s&&(i.value=s),i.envLink in G&&void 0!==G[i.envLink]&&(i.value=G[i.envLink]))}))}function se(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:se(r);return t}function ne(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=ne(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function ae(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?m:g)(e);i.get(e,Object.assign({headers:{"User-Agent":"highcharts/export",Referer:"highcharts/export"}},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)}))}))}class le extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}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 ce={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},pe=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),he=async(e,t,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),M(4,`[cache] Fetching script - ${e}.js`);const i=await ae(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(r)throw new le(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return M(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ue=async(e,t,o)=>{const r=e.version,i="latest"!==r&&r?`${r}/`:"",n=e.cdnURL||ce.cdnURL;M(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ce.sources=await(async(e,t,o,r,i)=>{let s;const n=r.host,a=r.port;if(n&&a)try{s=new c({host:n,port:a})}catch(e){throw new le("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...o.map((e=>he(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...e.coreScripts.map((e=>`${n}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${n}maps/${i}modules/${e}`:`${n}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${n}stock/${i}indicators/${e}`))],e.customScripts,t,a),ce.hcVersion=pe(ce),s(o,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async o=>{const{highcharts:i,server:n}=o,l=a(q,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)M(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ue(i,n.proxy,h);else{let e=!1;const t=JSON.parse(r(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:o,moduleScripts:s,indicatorScripts:a}=i,l=o.length+s.length+a.length;t.version!==i.version?(M(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(M(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(s||[]).some((e=>{if(!t.modules[e])return M(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ue(i,n.proxy,h):(M(3,"[cache] Dependency cache is up to date, proceeding."),ce.sources=r(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const o={version:e.version,modules:t||{}};ce.activeManifest=o,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,oe().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(e,t,o){window._displayErrors=o;const{getOptions:r,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},r());const a={animation:!1};t.export.strInj&&(a.height=e.chart.height,a.width=e.chart.width),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 l=t.export.strInj?new Function(`return ${t.export.strInj}`)():e;t.customLogic.customCode&&new Function("options",t.customLogic.customCode)(l);const c=i(!1,JSON.parse(t.export.themeOptions),l,{chart:a}),p=t.customLogic.callback?new Function(`return ${t.customLogic.callback}`)():void 0,h=JSON.parse(t.export.globalOptions);h&&s(h);let u=t.export.constr||"chart";u=void 0!==Highcharts[u]?u:"chart",Highcharts[u]("container",c,p);const d=r();for(const e in d)"function"!=typeof d[e]&&delete d[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ye=r(q+"/templates/template.html","utf8");let be;async function we(){if(!be)return!1;const e=await be.newPage();return await e.setCacheEnabled(!1),await Te(e),function(e){const{debug:t}=oe();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{e.isClosed()||await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function Ee(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){F(2,e,"[browser] Could not clear page's resources.")}}async function Te(e){await e.setContent(ye,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ge()}/sources.js`}),await e.evaluate(fe)}const Se=async(e,t,o,r)=>{o.export.instr=null,o.export.infile=null;const i=Buffer.byteLength(o.export?.strInj?o.export?.strInj:JSON.stringify(t),"utf-8");if(M(3,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new le("[export] The data passed to a page exceeded 100MB.");return e.evaluate(ve,t,o,r)};var xe=async(e,t,o)=>{let i=[];try{M(4,"[export] Determining export path.");const s=o.export,a=s?.options?.chart?.displayErrors&&ce.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(M(4,"[export] Treating as SVG."),"svg"===s.type)return t;l=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else M(4,"[export] Treating as config."),s.strInj?await Se(e,{chart:{height:s.height,width:s.width}},o,a):(t.chart.height=s.height,t.chart.width=s.width,await Se(e,t,o,a));i=await async function(e,t){const o=[],i=t.customLogic.resources;if(i){const s=[];if(i.js&&s.push({content:i.js}),i.files)for(const e of i.files){const t=!e.startsWith("http");s.push(t?{content:r(e,"utf8")}:{url:e})}for(const t of s)try{o.push(await e.addScriptTag(t))}catch(e){F(2,e,"[export] The JS resource cannot be loaded.")}s.length=0;const a=[];if(i.css){let r=i.css.match(/@import\s*([^;]*);/g);if(r)for(let e of r)e&&(e=e.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),e.startsWith("http")?a.push({url:e}):t.customLogic.allowFileResources&&a.push({path:n.join(q,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{o.push(await e.addStyleTag(t))}catch(e){F(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return o}(e,o);const c=l?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(s.scale)):await e.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.abs(Math.ceil(c.chartHeight||s.height)),h=Math.abs(Math.ceil(c.chartWidth||s.width)),{x:u,y:d}=await(e=>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)}})))(e);let g;if(await e.setViewport({height:p,width:h,deviceScaleFactor:l?1:parseFloat(s.scale)}),"svg"===s.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(e);else if(["png","jpeg"].includes(s.type))g=await((e,t,o,r,i)=>Promise.race([e.screenshot({type:t,encoding:o,clip:r,captureBeyondViewport:!0,fullPage:!1,optimizeForSpeed:!0,..."png"!==t?{quality:80}:{},omitBackground:"png"==t}),new Promise(((e,t)=>setTimeout((()=>t(new le("Rasterization timeout"))),i||1500)))]))(e,s.type,"base64",{width:h,height:p,x:u,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new le(`[export] Unsupported output format ${s.type}.`);g=await(async(e,t,o,r,i)=>(await e.emulateMediaType("screen"),e.pdf({height:t+1,width:o,encoding:r,timeout:i||1500})))(e,p,h,"base64",s.rasterizationTimeout)}return await Ee(e,i),g}catch(t){return await Ee(e,i),t}};let Re=!1;const Oe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const _e={create:async()=>{let e=!1;const t=v(),o=(new Date).getTime();try{if(e=await we(),!e||e.isClosed())throw new le("The page is invalid or closed.");M(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw new le("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Le.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Le.workLimit&&++e.workCount>Le.workLimit)||(M(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1)),destroy:async e=>{M(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},ke=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:o}=oe(),{enable:r,...i}=t,s={headless:!o.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!be){let e=0;const t=async()=>{try{M(3,`[browser] Attempting to get a browser instance (try ${++e}).`),be=await y.launch(s)}catch(o){if(F(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;M(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===s.headless&&M(3,"[browser] Launched browser in shell mode."),r&&M(3,"[browser] Launched browser in debug mode.")}catch(e){throw new le("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!be)throw new le("[browser] Cannot find a browser to open.")}return be}(e.puppeteerArgs),M(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),Re)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{Re=new f({..._e,min:parseInt(Le.minWorkers),max:parseInt(Le.maxWorkers),acquireTimeoutMillis:Le.acquireTimeout,createTimeoutMillis:Le.createTimeout,destroyTimeoutMillis:Le.destroyTimeout,idleTimeoutMillis:Le.idleTimeout,createRetryIntervalMillis:Le.createRetryInterval,reapIntervalMillis:Le.reaperInterval,propagateCreateError:!1}),Re.on("release",(async e=>{const t=await async function(e,t=!1){try{if(e&&!e.isClosed())return t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await Te(e)):await e.evaluate((()=>{document.body.innerHTML='
'})),!0}catch(e){F(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);M(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),Re.on("destroySuccess",((e,t)=>{M(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{Re.release(e)})),M(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new le("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(M(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),M(4,"[browser] Destroyed the pool of resources."))}await async function(){be?.connected&&await be.close(),M(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let o;try{if(M(4,"[pool] Work received, starting to process."),++Oe.exportAttempts,Le.benchmarking&&Ae(),!Re)throw new le("Work received, but pool has not been started.");const r=ee();try{M(4,"[pool] Acquiring a worker handle."),o=await Re.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!o.page)throw new le("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();M(4,`[pool] Starting work on pool entry with ID ${o.id}.`);const s=ee(),n=await xe(o.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(o.workCount=Le.workLimit+1,o.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new le("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Re.release(o);const a=(new Date).getTime()-i;return Oe.timeSpent+=a,Oe.spentAverage=Oe.timeSpent/++Oe.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Oe.droppedExports,o&&Re.release(o),new le(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ne=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ae(){const{min:e,max:t,all:o,available:r,used:i,pending:s}=Ne();M(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),M(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),M(5,`[pool] The number of all created resources: ${o}.`),M(5,`[pool] The number of available resources: ${r}.`),M(5,`[pool] The number of acquired resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Pe=Ne,He=()=>Oe;let $e=!1;const Ge=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=z(t),o.export.type=e.type||e.export.type,o.export.scale=e.scale||e.export.scale,o.export.outfile=e.outfile||e.export.outfile,o.payload={svg:e.svg}):o=re(t,e,_),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,oe()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{M(4,"[chart] Attempting to export from a SVG input.");const e=Me(function(e){const t=new b("").window;return w(t).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:["xlink:href"]})}(o.payload.svg),o,t);return++Oe.exportFromSvgAttempts,e}catch(e){return t(new le("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return M(4,"[chart] Attempting to export from an input file."),o.export.instr=r(i.infile,"utf8"),Me(o.export.instr.trim(),o,t)}catch(e){return t(new le("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return M(4,"[chart] Attempting to export from a raw input."),Z(o.customLogic?.allowCodeExecution)?je(o,t):"string"==typeof i.instr?Me(i.instr.trim(),o,t):Ue(o,i.instr||i.options,t)}catch(e){return t(new le("[chart] Error loading raw input.").setError(e))}return t(new le("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},De=e=>{const{chart:t,exporting:o}=e.export?.options||K(e.export?.instr),r=K(e.export?.globalOptions);let i=e.export?.scale||o?.scale||r?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const o=Math.pow(10,t||0);return Math.round(+e*o)/o})(i,2);const s={height:e.export?.height||o?.sourceHeight||t?.height||r?.exporting?.sourceHeight||r?.chart?.height||e.export?.defaultHeight||400,width:e.export?.width||o?.sourceWidth||t?.width||r?.exporting?.sourceWidth||r?.chart?.width||e.export?.defaultWidth||600,scale:i};for(let[e,t]of Object.entries(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Ue=async(e,t,o,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:$e;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=X(e.customLogic.resources,Z(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=r("resources.json","utf8");e.customLogic.resources=X(t,Z(e.customLogic.allowFileResources))}catch(e){F(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new le("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(t&&(t.chart=t.chart||{},t.exporting=t.exporting||{},t.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=B(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((e=>{try{s&&s[e]&&("string"==typeof s[e]&&s[e].endsWith(".json")?s[e]=K(r(s[e],"utf8"),!0):s[e]=K(s[e],!0))}catch(t){s[e]={},F(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=Q(n.customCode,n.allowFileResources)}catch(e){F(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=r(n.callback,"utf8")}catch(e){n.callback=!1,F(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...De(e)};try{return o(!1,await Ce(s.strInj||t||i,e))}catch(e){return o(e)}},je=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=J(r,e.customLogic?.allowCodeExecution)),o=r.replaceAll(/\t|\n|\r/g,"").trim(),";"===o[o.length-1]&&(o=o.substring(0,o.length-1)),e.export.strInj=o,Ue(e,!1,t)}catch(o){return t(new le(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(o))}},Me=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ue(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ue(t,r,o)}catch(e){return Z(r)?je(t,o):o(new le("[chart] Only JSON 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 flag.").setError(e))}},Fe=[],We=()=>{M(4,"[server] Clearing all registered intervals.");for(const e of Fe)clearInterval(e)},Ve=(e,t,o,r)=>{F(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,r(e)},qe=(e,t,o,r)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||400;o.status(l).json({statusCode:l,message:n,stack:a})};var Be=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=x({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class Xe extends le{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Ke=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,o)=>{try{const o=G.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new Xe("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 Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Xe("No new version supplied.",400);try{await(async e=>{const t=oe();t?.highcharts&&(t.highcharts.version=e),await de(t)})(i)}catch(e){throw new Xe(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:me(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){o(e)}}));const ze={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Je=0;const Ye=[],Ze=[],Qe=(e,t,o,r)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,s,n,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},et=async(e,t,o)=>{try{const o=ee(),i=v().replace(/-/g,""),s=oe(),n=e.body,a=++Je;let l=B(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=K(n.infile||n.options||n.data);if(!c&&!n.svg)throw M(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect:\n Content-Type: ${e.headers["content-type"]}. \n Chart constructor: ${n.constr}.\n Dimensions: ${n.width}x${n.height} @ ${n.scale} scale.\n Type: ${l}.\n Is SVG set? ${void 0!==n.svg}.\n B64? ${void 0!==n.b64}.\n No download? ${void 0!==n.noDownload}.\n\n Payload received: ${JSON.stringify(n.infile||n.options||n.data||n.svg)}\n\n `),new Xe("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);let p=!1;if(p=Qe(Ye,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let h=!1;e.socket.on("close",(e=>{e&&(h=!0)})),M(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const u={export:{instr:c,type:l,constr:n.constr[0].toLowerCase()+n.constr.substr(1),height:n.height,width:n.width,scale:n.scale||s.export.scale,globalOptions:K(n.globalOptions,!0),themeOptions:K(n.themeOptions,!0)},customLogic:{allowCodeExecution:$e,allowFileResources:!1,resources:K(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=J(c,u.customLogic.allowCodeExecution));const d=re(s,u);if(d.export.options=c,d.payload={svg:n.svg||!1,b64:n.b64||!1,noDownload:n.noDownload||!1,requestId:i},n.svg&&(e=>[/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))))(d.payload.svg))throw new Xe("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);await Ge(d,((r,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),h)return M(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Qe(Ze,e,t,{id:a,body:c.result}),c.result?n.b64?"pdf"===l||"svg"==l?t.send(Buffer.from(c.result,"utf8").toString("base64")):t.send(c.result):(t.header("Content-Type",ze[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){o(e)}var r};const tt=JSON.parse(r(a(q,"package.json"))),ot=new Date,rt=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;rt.push(t),rt.length>30&&rt.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const o=He(),r=rt.length,i=rt.reduce(((e,t)=>e+t),0)/rt.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:me(),averageProcessingTime:o.spentAverage,performedExports:o.performedExports,failedExports:o.droppedExports,exportAttempts:o.exportAttempts,sucessRatio:o.performedExports/o.exportAttempts*100,pool:Pe(),period:r,movingAverage:i,message:isNaN(i)||!rt.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${r} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:o.exportFromSvgAttempts,jsonExportAttempts:o.performedExports-o.exportFromSvgAttempts})}))}const st=new Map,nt=T();nt.disable("x-powered-by"),nt.use(E()),nt.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()}));const at=e=>{e.on("clientError",((e,t)=>{F(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{F(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{F(1,e,`[server] Socket error: ${e.message}`)}))}))},lt=async e=>{try{const t=1024*(e.maxUploadSize||3)*1024,o=S.memoryStorage(),r=S({storage:o,limits:{fieldSize:t}});if(nt.use(T.json({limit:t})),nt.use(T.urlencoded({extended:!0,limit:t})),nt.use(r.none()),!e.enable)return!1;if(!e.ssl.force){const t=g.createServer(nt);at(t),t.listen(e.port,e.host),st.set(e.port,t),M(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,o;try{t=await i.readFile(l.join(e.ssl.certPath,"server.key"),"utf8"),o=await i.readFile(l.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){M(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=m.createServer({key:t,cert:o},nt);at(r),r.listen(e.ssl.port,e.host),st.set(e.ssl.port,r),M(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Be(nt,e.rateLimiting),nt.use(T.static(l.join(q,"public"))),it(nt),(e=>{e.post("/",et),e.post("/:filename",et)})(nt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(q,"public","index.html"),{acceptRanges:!1})}))})(nt),Ke(nt),(e=>{e.use(Ve),e.use(qe)})(nt)}catch(e){throw new le("[server] Could not configure and start the server.").setError(e)}},ct=()=>{M(4,"[server] Closing all servers.");for(const[e,t]of st)t.close((()=>{st.delete(e),M(4,`[server] Closed server on port: ${e}.`)}))};var pt={startServer:lt,closeServers:ct,getServers:()=>st,enableRateLimiting:e=>Be(nt,e),getExpress:()=>T,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const ht=async e=>{await Promise.allSettled([We(),ct(),Ie()]),process.exit(e)};var ut={server:pt,startServer:lt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,$e=Z(t),(e=>{for(const[t,o]of Object.entries(e))U[t]=o;W(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&V(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(M(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{M(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGTERM",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGHUP",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("uncaughtException",(async(e,t)=>{F(1,e,`The ${t} error.`),await ht(1)}))),await de(e),await ke({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async e=>{e.export.instr=e.export.instr||e.export.options,await Ge(e,(async(e,t)=>{if(e)throw e;const{outfile:o,type:r}=t.options.export;s(o||`chart.${r}`,"svg"!==r?Buffer.from(t.result,"base64"):t.result),await Ie()}))},batchExport:async e=>{const t=[];for(let o of e.export.batch.split(";"))o=o.split("="),2===o.length&&t.push(Ge({...e,export:{...e.export,infile:o[0],outfile:o[1]}},((e,t)=>{if(e)throw e;s(t.options.export.outfile,"svg"!==t.options.export.type?Buffer.from(t.result,"base64"):t.result)})));try{await Promise.all(t),await Ie()}catch(e){throw new le("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,initPool:ke,killPool:Ie,setOptions:(e,t)=>(t?.length&&(te=function(e){const t=e.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(t>-1&&e[t+1]){const o=e[t+1];try{if(o&&o.endsWith(".json"))return JSON.parse(r(o))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(t)),ie(O,te),te=se(O),e&&(te=re(te,e,_)),t?.length&&(te=function(e,t,o){let r=!1;for(let i=0;i(n.length-1===o&&(a=e[t].type),e[t])),o),n.reduce(((e,o,l)=>(n.length-1===l&&void 0!==e[o]&&(t[++i]?"boolean"===a?e[o]=Z(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&Y();return e}(te,t,O)),te),shutdownCleanUp:ht,log:M,logWithStack:F,setLogLevel:W,enableFileLogging:V,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=k[o]?k[o].split("."):[];e.reduce(((t,o,i)=>t[o]=e.length-1===i?r:t[o]||{}),t)}return t},manualConfig:async t=>{let o={};e(t)&&(o=JSON.parse(r(t,"utf8")));const s=Object.keys(L).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:s},{onSubmit:async(e,r)=>{let s=0,n=[];for(const e of r)L[e]=L[e].map((t=>({...t,section:e}))),n=[...n,...L[e]];return await p(n,{onSubmit:async(e,r)=>{if("moduleScripts"===e.name?(r=r.length?r.map((t=>e.choices[t])):e.choices,o[e.section][e.name]=r):o[e.section]=ne(Object.assign({},o[e.section]||{}),e.name.split("."),e.choices?e.choices[r]:r),++s===n.length){try{await i.writeFile(t,JSON.stringify(o,null,2),"utf8")}catch(e){F(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(r(a(q,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(r(q+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Y};export{ut as default}; + diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index c8ae81f2..a5db725d 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1,2 +1,2 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Possible names for Highcharts scripts\nexport const scriptsNames = {\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n modules: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'parallel-coordinates',\n 'accessibility',\n // 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'data-tools',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'tiledwebmap',\n 'timeline',\n 'treemap',\n 'treegraph',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'geoheatmap',\n 'pyramid3d',\n 'networkgraph',\n 'overlapping-datalabels',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'series-on-point',\n 'solid-gauge',\n 'sonification',\n // 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi',\n 'flowmap',\n 'export-data',\n 'navigator',\n 'textpath'\n ],\n indicators: ['indicators-all'],\n custom: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\n ]\n};\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [\n '--allow-running-insecure-content',\n '--ash-no-nudges',\n '--autoplay-policy=user-gesture-required',\n '--block-new-web-contents',\n '--disable-accelerated-2d-canvas',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-checker-imaging',\n '--disable-client-side-phishing-detection',\n '--disable-component-extensions-with-background-pages',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-logging',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-search-engine-choice-screen',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-site-isolation-trials',\n '--disable-speech-api',\n '--disable-sync',\n '--enable-unsafe-webgpu',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-startup-window',\n '--no-zygote',\n '--password-store=basic',\n '--process-per-tab',\n '--use-mock-keychain'\n ],\n type: 'string[]',\n description: 'Arguments array to send to Puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n type: 'string',\n envLink: 'HIGHCHARTS_VERSION',\n description: 'The Highcharts version to be used.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n type: 'string',\n envLink: 'HIGHCHARTS_CDN_URL',\n description: 'The CDN URL for Highcharts scripts to be used.'\n },\n coreScripts: {\n value: scriptsNames.core,\n type: 'string[]',\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n description: 'The core Highcharts scripts to fetch.'\n },\n moduleScripts: {\n value: scriptsNames.modules,\n type: 'string[]',\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\n description: 'The modules of Highcharts to fetch.'\n },\n indicatorScripts: {\n value: scriptsNames.indicators,\n type: 'string[]',\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\n description: 'The indicators of Highcharts to fetch.'\n },\n customScripts: {\n value: scriptsNames.custom,\n type: 'string[]',\n description: 'Additional custom scripts or dependencies to fetch.'\n },\n forceFetch: {\n value: false,\n type: 'boolean',\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n description:\n 'The flag to determine whether to refetch all scripts after each server rerun.'\n },\n cachePath: {\n value: '.cache',\n type: 'string',\n envLink: 'HIGHCHARTS_CACHE_PATH',\n description:\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\n },\n type: {\n value: 'png',\n type: 'string',\n envLink: 'EXPORT_TYPE',\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\n },\n constr: {\n value: 'chart',\n type: 'string',\n envLink: 'EXPORT_CONSTR',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\n },\n defaultHeight: {\n value: 400,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n description:\n 'the default height of the exported chart. Used when no value is set.'\n },\n defaultWidth: {\n value: 600,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_WIDTH',\n description:\n 'The default width of the exported chart. Used when no value is set.'\n },\n defaultScale: {\n value: 1,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_SCALE',\n description:\n 'The default scale of the exported chart. Used when no value is set.'\n },\n height: {\n value: false,\n type: 'number',\n description:\n 'The height of the exported chart, overriding the option in the chart settings.'\n },\n width: {\n value: false,\n type: 'number',\n description:\n 'The width of the exported chart, overriding the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description:\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\n },\n rasterizationTimeout: {\n value: 1500,\n type: 'number',\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\n description:\n 'The duration in milliseconds to wait for rendering a webpage.'\n }\n },\n customLogic: {\n allowCodeExecution: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\n description:\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\n },\n allowFileResources: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\n description:\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description:\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n legacyName: 'fromFile',\n description: 'A file containing a pre-defined configuration to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Enables setting options through a prompt and saving them in a provided config file.'\n }\n },\n server: {\n maxUploadSize: {\n value: 3,\n type: 'number',\n cliName: 'maxUploadSize',\n envLink: 'SERVER_MAX_UPLOAD_SIZE',\n description:\n 'The maximum upload size, in megabytes, for the server'\n \n },\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_ENABLE',\n cliName: 'enableServer',\n description:\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\n },\n host: {\n value: '0.0.0.0',\n type: 'string',\n envLink: 'SERVER_HOST',\n description:\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\n },\n port: {\n value: 7801,\n type: 'number',\n envLink: 'SERVER_PORT',\n description: 'The server port when enabled.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_BENCHMARKING',\n cliName: 'serverBenchmarking',\n description:\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\n },\n proxy: {\n host: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_HOST',\n cliName: 'proxyHost',\n description: 'The host of the proxy server to use, if it exists.'\n },\n port: {\n value: 8080,\n type: 'number',\n envLink: 'SERVER_PROXY_PORT',\n cliName: 'proxyPort',\n description: 'The port of the proxy server to use, if it exists.'\n },\n timeout: {\n value: 5000,\n type: 'number',\n envLink: 'SERVER_PROXY_TIMEOUT',\n cliName: 'proxyTimeout',\n description: 'The timeout for the proxy server to use, if it exists.'\n }\n },\n rateLimiting: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting for the server.'\n },\n maxRequests: {\n value: 10,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\n legacyName: 'rateLimit',\n description: 'The maximum number of requests allowed in one minute.'\n },\n window: {\n value: 1,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\n description: 'The time window, in minutes, for the rate limiting.'\n },\n delay: {\n value: 0,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_DELAY',\n description:\n 'The delay duration for each successive request before reaching the maximum limit.'\n },\n trustProxy: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\n description: 'Set this to true if the server is behind a load balancer.'\n },\n skipKey: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\n },\n skipToken: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\n }\n },\n ssl: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_ENABLE',\n cliName: 'enableSsl',\n description: 'Enables or disables the SSL protocol.'\n },\n force: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_FORCE',\n cliName: 'sslForce',\n legacyName: 'sslOnly',\n description:\n 'When set to true, the server is forced to serve only over HTTPS.'\n },\n port: {\n value: 443,\n type: 'number',\n envLink: 'SERVER_SSL_PORT',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n value: false,\n type: 'string',\n envLink: 'SERVER_SSL_CERT_PATH',\n legacyName: 'sslPath',\n description: 'The path to the SSL certificate/key file.'\n }\n }\n },\n pool: {\n minWorkers: {\n value: 4,\n type: 'number',\n envLink: 'POOL_MIN_WORKERS',\n description: 'The number of minimum and initial pool workers to spawn.'\n },\n maxWorkers: {\n value: 8,\n type: 'number',\n envLink: 'POOL_MAX_WORKERS',\n legacyName: 'workers',\n description: 'The number of maximum pool workers to spawn.'\n },\n workLimit: {\n value: 40,\n type: 'number',\n envLink: 'POOL_WORK_LIMIT',\n description:\n 'The number of work pieces that can be performed before restarting the worker process.'\n },\n acquireTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_ACQUIRE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for acquiring a resource.'\n },\n createTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_CREATE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for creating a resource.'\n },\n destroyTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_DESTROY_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for destroying a resource.'\n },\n idleTimeout: {\n value: 30000,\n type: 'number',\n envLink: 'POOL_IDLE_TIMEOUT',\n description:\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\n },\n createRetryInterval: {\n value: 200,\n type: 'number',\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\n description:\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\n },\n reaperInterval: {\n value: 1000,\n type: 'number',\n envLink: 'POOL_REAPER_INTERVAL',\n description:\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'POOL_BENCHMARKING',\n cliName: 'poolBenchmarking',\n description:\n 'Indicate whether to show statistics for the pool of resources or not.'\n }\n },\n logging: {\n level: {\n value: 4,\n type: 'number',\n envLink: 'LOGGING_LEVEL',\n cliName: 'logLevel',\n description: 'The logging level to be used.'\n },\n file: {\n value: 'highcharts-export-server.log',\n type: 'string',\n envLink: 'LOGGING_FILE',\n cliName: 'logFile',\n description:\n 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.'\n },\n dest: {\n value: 'log/',\n type: 'string',\n envLink: 'LOGGING_DEST',\n cliName: 'logDest',\n description:\n 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.'\n },\n toConsole: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_CONSOLE',\n cliName: 'logToConsole',\n description: 'Enables or disables showing logs in the console.'\n },\n toFile: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_FILE',\n cliName: 'logToFile',\n description:\n 'Enables or disables creation of the log directory and saving the log into a .log file.'\n }\n },\n ui: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'UI_ENABLE',\n cliName: 'enableUi',\n description:\n 'Enables or disables the user interface (UI) for the export server.'\n },\n route: {\n value: '/',\n type: 'string',\n envLink: 'UI_ROUTE',\n cliName: 'uiRoute',\n description:\n 'The endpoint route to which the user interface (UI) should be attached.'\n }\n },\n other: {\n nodeEnv: {\n value: 'production',\n type: 'string',\n envLink: 'OTHER_NODE_ENV',\n description: 'The type of Node.js environment.'\n },\n listenToProcessExits: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\n description: 'Decides whether or not to attach process.exit handlers.'\n },\n noLogo: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_NO_LOGO',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n },\n hardResetPage: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_HARD_RESET_PAGE',\n description: 'Decides if the page content should be reset entirely.'\n },\n browserShellMode: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_BROWSER_SHELL_MODE',\n description: 'Decides if the browser runs in the shell mode.'\n }\n },\n debug: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_ENABLE',\n cliName: 'enableDebug',\n description: 'Enables or disables debug mode for the underlying browser.'\n },\n headless: {\n value: true,\n type: 'boolean',\n envLink: 'DEBUG_HEADLESS',\n description:\n 'Controls the mode in which the browser is launched when in the debug mode.'\n },\n devtools: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DEVTOOLS',\n description:\n 'Decides whether to enable DevTools when the browser is in a headful state.'\n },\n listenToConsole: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\n description:\n 'Decides whether to enable a listener for console messages sent from the browser.'\n },\n dumpio: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DUMPIO',\n description:\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\n },\n slowMo: {\n value: 0,\n type: 'number',\n envLink: 'DEBUG_SLOW_MO',\n description:\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\n },\n debuggingPort: {\n value: 9222,\n type: 'number',\n envLink: 'DEBUG_DEBUGGING_PORT',\n description: 'Specifies the debugging port.'\n }\n }\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The URL of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'coreScripts',\n message: 'Available core scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.coreScripts.value\n },\n {\n type: 'multiselect',\n name: 'moduleScripts',\n message: 'Available module scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.moduleScripts.value\n },\n {\n type: 'multiselect',\n name: 'indicatorScripts',\n message: 'Available indicator scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.indicatorScripts.value\n },\n {\n type: 'list',\n name: 'customScripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.customScripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Force re-fetch the scripts',\n initial: defaultConfig.highcharts.forceFetch.value\n },\n {\n type: 'text',\n name: 'cachePath',\n message: 'The path to the cache directory',\n initial: defaultConfig.highcharts.cachePath.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default export file type',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n },\n {\n type: 'number',\n name: 'rasterizationTimeout',\n message: 'The rendering webpage timeout in milliseconds',\n initial: defaultConfig.export.rasterizationTimeout.value\n }\n ],\n customLogic: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Enable execution of custom code',\n initial: defaultConfig.customLogic.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Enable file resources',\n initial: defaultConfig.customLogic.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts the server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'Server hostname',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'Server port',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable server benchmarking',\n initial: defaultConfig.server.benchmarking.value\n },\n {\n type: 'text',\n name: 'proxy.host',\n message: 'The host of the proxy server to use',\n initial: defaultConfig.server.proxy.host.value\n },\n {\n type: 'number',\n name: 'proxy.port',\n message: 'The port of the proxy server to use',\n initial: defaultConfig.server.proxy.port.value\n },\n {\n type: 'number',\n name: 'proxy.timeout',\n message: 'The timeout for the proxy server to use',\n initial: defaultConfig.server.proxy.timeout.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'The maximum requests allowed per minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The rate-limiting time window in minutes',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The delay for each successive request before reaching the maximum',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force serving only over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'SSL server port',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'The path to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'minWorkers',\n message: 'The initial number of workers to spawn',\n initial: defaultConfig.pool.minWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The maximum number of workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a Puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'number',\n name: 'createTimeout',\n message: 'The number of milliseconds to wait for creating a resource',\n initial: defaultConfig.pool.createTimeout.value\n },\n {\n type: 'number',\n name: 'destroyTimeout',\n message: 'The number of milliseconds to wait for destroying a resource',\n initial: defaultConfig.pool.destroyTimeout.value\n },\n {\n type: 'number',\n name: 'idleTimeout',\n message: 'The number of milliseconds after an idle resource is destroyed',\n initial: defaultConfig.pool.idleTimeout.value\n },\n {\n type: 'number',\n name: 'createRetryInterval',\n message:\n 'The retry interval in milliseconds after a create process fails',\n initial: defaultConfig.pool.createRetryInterval.value\n },\n {\n type: 'number',\n name: 'reaperInterval',\n message:\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\n initial: defaultConfig.pool.reaperInterval.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable benchmarking for a resource pool',\n initial: defaultConfig.pool.benchmarking.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 5\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A log file name. Set with --toFile and --logDest to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'The path to a log file when the file logging is enabled',\n initial: defaultConfig.logging.dest.value\n },\n {\n type: 'toggle',\n name: 'toConsole',\n message: 'Enable logging to the console',\n initial: defaultConfig.logging.toConsole.value\n },\n {\n type: 'toggle',\n name: 'toFile',\n message: 'Enables logging to a file',\n initial: defaultConfig.logging.toFile.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'text',\n name: 'nodeEnv',\n message: 'The type of Node.js environment',\n initial: defaultConfig.other.nodeEnv.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false to skip attaching process.exit handlers',\n initial: defaultConfig.other.listenToProcessExits.value\n },\n {\n type: 'toggle',\n name: 'noLogo',\n message: 'Skip printing the logo on startup. Replaced by simple text',\n initial: defaultConfig.other.noLogo.value\n },\n {\n type: 'toggle',\n name: 'hardResetPage',\n message: 'Decides if the page content should be reset entirely',\n initial: defaultConfig.other.hardResetPage.value\n },\n {\n type: 'toggle',\n name: 'browserShellMode',\n message: 'Decides if the browser runs in the shell mode',\n initial: defaultConfig.other.browserShellMode.value\n }\n ],\n debug: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enables debug mode for the browser instance',\n initial: defaultConfig.debug.enable.value\n },\n {\n type: 'toggle',\n name: 'headless',\n message: 'The mode setting for the browser',\n initial: defaultConfig.debug.headless.value\n },\n {\n type: 'toggle',\n name: 'devtools',\n message: 'The DevTools for the headful browser',\n initial: defaultConfig.debug.devtools.value\n },\n {\n type: 'toggle',\n name: 'listenToConsole',\n message: 'The event listener for console messages from the browser',\n initial: defaultConfig.debug.listenToConsole.value\n },\n {\n type: 'toggle',\n name: 'dumpio',\n message: 'Redirects the browser stdout and stderr to NodeJS process',\n initial: defaultConfig.debug.dumpio.value\n },\n {\n type: 'number',\n name: 'slowMo',\n message: 'Puppeteer operations slow down in milliseconds',\n initial: defaultConfig.debug.slowMo.value\n },\n {\n type: 'number',\n name: 'debuggingPort',\n message: 'The port number for debugging',\n initial: defaultConfig.debug.debuggingPort.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Recursively creates a chain of nested arguments from an object.\n *\n * @param {Object} obj - The object containing nested arguments.\n * @param {string} propChain - The current chain of nested properties\n * (used internally during recursion).\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n\n // Support for the legacy, PhantomJS properties names\n if (entry.legacyName !== undefined) {\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\n }\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/**\n * @fileoverview\n * This file is responsible for parsing the environment variables with the 'zod'\n * library. The parsed environment variables are then exported to be used\n * in the application as \"envs\". We should not use process.env directly\n * in the application as these would not be parsed properly.\n *\n * The environment variables are parsed and validated only once when\n * the application starts. We should write a custom validator or a transformer\n * for each of the options.\n */\n\nimport dotenv from 'dotenv';\nimport { z } from 'zod';\n\nimport { scriptsNames } from './schemas/config.js';\n\n// Load .env into environment variables\ndotenv.config();\n\n// Object with custom validators and transformers, to avoid repetition\n// in the Config object\nconst v = {\n // Splits string value into elements in an array, trims every element, checks\n // if an array is correct, if it is empty, and if it is, returns undefined\n array: (filterArray) =>\n z\n .string()\n .transform((value) =>\n value\n .split(',')\n .map((value) => value.trim())\n .filter((value) => filterArray.includes(value))\n )\n .transform((value) => (value.length ? value : undefined)),\n\n // Allows only true, false and correctly parse the value to boolean\n // or no value in which case the returned value will be undefined\n boolean: () =>\n z\n .enum(['true', 'false', ''])\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\n\n // Allows passed values or no value in which case the returned value will\n // be undefined\n enum: (values) =>\n z\n .enum([...values, ''])\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Trims the string value and checks if it is empty or contains stringified\n // values such as false, undefined, null, NaN, if it does, returns undefined\n string: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\n value === '',\n (value) => ({\n message: `The string contains forbidden values, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Allows positive numbers or no value in which case the returned value will\n // be undefined\n positiveNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\n (value) => ({\n message: `The value must be numeric and positive, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n\n // Allows non-negative numbers or no value in which case the returned value\n // will be undefined\n nonNegativeNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\n (value) => ({\n message: `The value must be numeric and non-negative, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\n};\n\nexport const Config = z.object({\n // highcharts\n HIGHCHARTS_VERSION: z\n .string()\n .trim()\n .refine(\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\n (value) => ({\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CDN_URL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value.startsWith('https://') ||\n value.startsWith('http://') ||\n value === '',\n (value) => ({\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\n HIGHCHARTS_CACHE_PATH: v.string(),\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\n\n // export\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\n\n // custom\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\n\n // server\n SERVER_ENABLE: v.boolean(),\n SERVER_HOST: v.string(),\n SERVER_PORT: v.positiveNum(),\n SERVER_BENCHMARKING: v.boolean(),\n\n // server proxy\n SERVER_PROXY_HOST: v.string(),\n SERVER_PROXY_PORT: v.positiveNum(),\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\n\n // server rate limiting\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\n\n // server ssl\n SERVER_SSL_ENABLE: v.boolean(),\n SERVER_SSL_FORCE: v.boolean(),\n SERVER_SSL_PORT: v.positiveNum(),\n SERVER_SSL_CERT_PATH: v.string(),\n\n // pool\n POOL_MIN_WORKERS: v.nonNegativeNum(),\n POOL_MAX_WORKERS: v.nonNegativeNum(),\n POOL_WORK_LIMIT: v.positiveNum(),\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\n POOL_BENCHMARKING: v.boolean(),\n\n // logger\n LOGGING_LEVEL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' ||\n (!isNaN(parseFloat(value)) &&\n parseFloat(value) >= 0 &&\n parseFloat(value) <= 5),\n (value) => ({\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n LOGGING_FILE: v.string(),\n LOGGING_DEST: v.string(),\n LOGGING_TO_CONSOLE: v.boolean(),\n LOGGING_TO_FILE: v.boolean(),\n\n // ui\n UI_ENABLE: v.boolean(),\n UI_ROUTE: v.string(),\n\n // other\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\n OTHER_NO_LOGO: v.boolean(),\n OTHER_HARD_RESET_PAGE: v.boolean(),\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\n\n // debugger\n DEBUG_ENABLE: v.boolean(),\n DEBUG_HEADLESS: v.boolean(),\n DEBUG_DEVTOOLS: v.boolean(),\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\n DEBUG_DUMPIO: v.boolean(),\n DEBUG_SLOW_MO: v.nonNegativeNum(),\n DEBUG_DEBUGGING_PORT: v.positiveNum()\n});\n\nexport const envs = Config.partial().parse(process.env);\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { appendFile, existsSync, mkdirSync } from 'fs';\n\n// The available colors\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\n\n// The default logging config\nlet logging = {\n // Flags for logging status\n toConsole: true,\n toFile: false,\n pathCreated: false,\n // Log levels\n levelsDesc: [\n {\n title: 'error',\n color: colors[0]\n },\n {\n title: 'warning',\n color: colors[1]\n },\n {\n title: 'notice',\n color: colors[2]\n },\n {\n title: 'verbose',\n color: colors[3]\n },\n {\n title: 'benchmark',\n color: colors[4]\n }\n ],\n // Log listeners\n listeners: []\n};\n\n/**\n * Logs the provided texts to a file, if file logging is enabled. It creates\n * the necessary directory structure if not already created and appends the\n * content, including an optional prefix, to the specified log file.\n *\n * @param {string[]} texts - An array of texts to be logged.\n * @param {string} prefix - An optional prefix to be added to each log entry.\n */\nconst logToFile = (texts, prefix) => {\n if (!logging.pathCreated) {\n // Create if does not exist\n !existsSync(logging.dest) && mkdirSync(logging.dest);\n\n // We now assume the path is available, e.g. it's the responsibility\n // of the user to create the path with the correct access rights.\n logging.pathCreated = true;\n }\n\n // Add the content to a file\n appendFile(\n `${logging.dest}${logging.file}`,\n [prefix].concat(texts).join(' ') + '\\n',\n (error) => {\n if (error) {\n console.log(`[logger] Unable to write to log file: ${error}`);\n logging.toFile = false;\n }\n }\n );\n};\n\n/**\n * Logs a message. Accepts a variable amount of arguments. Arguments after\n * `level` will be passed directly to console.log, and/or will be joined\n * and appended to the log file.\n *\n * @param {any} args - An array of arguments where the first is the log level\n * and the rest are strings to build a message with.\n */\nexport const log = (...args) => {\n const [newLevel, ...texts] = args;\n\n // Current logging options\n const { levelsDesc, level } = logging;\n\n // Check if log level is within a correct range or is a benchmark log\n if (\n newLevel !== 5 &&\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\n ) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\n );\n }\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Logs an error message with its stack trace. Optionally, a custom message\n * can be provided.\n *\n * @param {number} level - The log level.\n * @param {Error} error - The error object.\n * @param {string} customMessage - An optional custom message to be logged along\n * with the error.\n */\nexport const logWithStack = (newLevel, error, customMessage) => {\n // Get the main message\n const mainMessage = customMessage || error.message;\n\n // Current logging options\n const { level, levelsDesc } = logging;\n\n // Check if log level is within a correct range\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // If the customMessage exists, we want to display the whole stack message\n const stackMessage =\n error.message !== error.stackMessage || error.stackMessage === undefined\n ? error.stack\n : error.stack.split('\\n').slice(1).join('\\n');\n\n // Combine custom message or error message with error stack message\n const texts = [mainMessage, '\\n', stackMessage];\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\n mainMessage[colors[newLevel - 1]],\n '\\n',\n stackMessage\n ])\n );\n }\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Sets the log level to the specified value. Log levels are (0 = no logging,\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\n *\n * @param {number} newLevel - The new log level to be set.\n */\nexport const setLogLevel = (newLevel) => {\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\n logging.level = newLevel;\n }\n};\n\n/**\n * Enables file logging with the specified destination and log file.\n *\n * @param {string} logDest - The destination path for log files.\n * @param {string} logFile - The log file name.\n */\nexport const enableFileLogging = (logDest, logFile) => {\n // Update logging options\n logging = {\n ...logging,\n dest: logDest || logging.dest,\n file: logFile || logging.file,\n toFile: true\n };\n\n if (logging.dest.length === 0) {\n return log(1, '[logger] File logging initialization: no path supplied.');\n }\n\n if (!logging.dest.endsWith('/')) {\n logging.dest += '/';\n }\n};\n\n/**\n * Initializes logging with the specified logging configuration.\n *\n * @param {Object} loggingOptions - The logging configuration object.\n */\nexport const initLogging = (loggingOptions) => {\n // Set all the logging options on our logging module object\n for (const [key, value] of Object.entries(loggingOptions)) {\n logging[key] = value;\n }\n\n // Set the log level\n setLogLevel(loggingOptions && parseInt(loggingOptions.level));\n\n // Set the log file path and name\n if (loggingOptions && loggingOptions.dest && loggingOptions.toFile) {\n enableFileLogging(\n loggingOptions.dest,\n loggingOptions.file || 'highcharts-export-server.log'\n );\n }\n};\n\n/**\n * Adds a listener function to the logging system.\n *\n * @param {function} fn - The listener function to be added.\n */\nexport const listen = (fn) => {\n logging.listeners.push(fn);\n};\n\nexport default {\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n initLogging,\n listen\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { defaultConfig } from '../lib/schemas/config.js';\nimport { log, logWithStack } from './logger.js';\n\nconst MAX_BACKOFF_ATTEMPTS = 6;\n\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\n\n/**\n * Clears and standardizes text by replacing multiple consecutive whitespace\n * characters with a single space and trimming any leading or trailing\n * whitespace.\n *\n * @param {string} text - The input text to be cleared.\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\n * multiple consecutive whitespace characters.\n * @param {string} [replacer=' '] - The string used to replace multiple\n * consecutive whitespace characters.\n *\n * @returns {string} - The cleared and standardized text.\n */\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\n text.replaceAll(rule, replacer).trim();\n\n/**\n * Implements an exponential backoff strategy for retrying a function until\n * a certain number of attempts are reached.\n *\n * @param {Function} fn - The function to be retried.\n * @param {number} [attempt=0] - The current attempt number.\n * @param {...any} args - Arguments to be passed to the function.\n *\n * @returns {Promise} - A promise that resolves to the result of the function\n * if successful.\n *\n * @throws {Error} - Throws an error if the maximum number of attempts\n * is reached.\n */\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\n try {\n // Try to call the function\n return await fn(...args);\n } catch (error) {\n // Calculate delay in ms\n const delayInMs = 2 ** attempt * 1000;\n\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\n throw error;\n }\n\n // Wait given amount of time\n await new Promise((response) => setTimeout(response, delayInMs));\n log(\n 3,\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\n );\n\n // Try again\n return expBackoff(fn, attempt, ...args);\n }\n};\n\n/**\n * Fixes the export type based on MIME types and file extensions.\n *\n * @param {string} type - The original export type.\n * @param {string} outfile - The file path or name.\n *\n * @returns {string} - The corrected export type.\n */\nexport const fixType = (type, outfile) => {\n // MIME types\n const mimeTypes = {\n 'image/png': 'png',\n 'image/jpeg': 'jpeg',\n 'application/pdf': 'pdf',\n 'image/svg+xml': 'svg'\n };\n\n // Formats\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\n\n // Check if type and outfile's extensions are the same\n if (outfile) {\n const outType = outfile.split('.').pop();\n\n if (outType === 'jpg') {\n type = 'jpeg';\n } else if (formats.includes(outType) && type !== outType) {\n type = outType;\n }\n }\n\n // Return a correct type\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\n};\n\n/**\n * Handles and validates resources for export.\n *\n * @param {Object|string} resources - The resources to be handled. Can be either\n * a JSON object, stringified JSON or a path to a JSON file.\n * @param {boolean} allowFileResources - Whether to allow loading resources from\n * files.\n *\n * @returns {Object|undefined} - The handled resources or undefined if no valid\n * resources are found.\n */\nexport const handleResources = (resources = false, allowFileResources) => {\n const allowedProps = ['js', 'css', 'files'];\n\n let handledResources = resources;\n let correctResources = false;\n\n // Try to load resources from a file\n if (allowFileResources && resources.endsWith('.json')) {\n try {\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\n } catch (error) {\n return logWithStack(2, error, `[cli] No resources found.`);\n }\n } else {\n // Try to get JSON\n handledResources = isCorrectJSON(resources);\n\n // Get rid of the files section\n if (handledResources && !allowFileResources) {\n delete handledResources.files;\n }\n }\n\n // Filter from unnecessary properties\n for (const propName in handledResources) {\n if (!allowedProps.includes(propName)) {\n delete handledResources[propName];\n } else if (!correctResources) {\n correctResources = true;\n }\n }\n\n // Check if at least one of allowed properties is present\n if (!correctResources) {\n return log(3, `[cli] No resources found.`);\n }\n\n // Handle files section\n if (handledResources.files) {\n handledResources.files = handledResources.files.map((item) => item.trim());\n if (!handledResources.files || handledResources.files.length <= 0) {\n delete handledResources.files;\n }\n }\n\n // Return resources\n return handledResources;\n};\n\n/**\n * Validates and parses JSON data. Checks if provided data is or can\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\n *\n * @param {Object|string} data - The JSON data to be validated and parsed.\n * @param {boolean} toString - Whether to return a stringified representation\n * of the parsed JSON.\n *\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\n * or false if validation fails.\n */\nexport function isCorrectJSON(data, toString) {\n try {\n // Get the string representation if not already before parsing\n const parsedData = JSON.parse(\n typeof data !== 'string' ? JSON.stringify(data) : data\n );\n\n // Return a stringified representation of a JSON if required\n if (typeof parsedData !== 'string' && toString) {\n return JSON.stringify(parsedData);\n }\n\n // Return a JSON\n return parsedData;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if the given item is an object.\n *\n * @param {any} item - The item to be checked.\n *\n * @returns {boolean} - True if the item is an object, false otherwise.\n */\nexport const isObject = (item) =>\n typeof item === 'object' && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if the given object is empty.\n *\n * @param {Object} item - The object to be checked.\n *\n * @returns {boolean} - True if the object is empty, false otherwise.\n */\nexport const isObjectEmpty = (item) =>\n typeof item === 'object' &&\n !Array.isArray(item) &&\n item !== null &&\n Object.keys(item).length === 0;\n\n/**\n * Checks if a private IP range URL is found in the given string.\n *\n * @param {string} item - The string to be checked for a private IP range URL.\n *\n * @returns {boolean} - True if a private IP range URL is found, false\n * otherwise.\n */\nexport const isPrivateRangeUrlFound = (item) => {\n const regexPatterns = [\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\n ];\n\n return regexPatterns.some((pattern) => pattern.test(item));\n};\n\n/**\n * Creates a deep copy of the given object or array.\n *\n * @param {Object|Array} obj - The object or array to be deeply copied.\n *\n * @returns {Object|Array} - The deep copy of the provided object or array.\n */\nexport const deepCopy = (obj) => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n const copy = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n copy[key] = deepCopy(obj[key]);\n }\n }\n\n return copy;\n};\n\n/**\n * Converts the provided options object to a JSON-formatted string with the\n * option to preserve functions.\n *\n * @param {Object} options - The options object to be converted to a string.\n * @param {boolean} allowFunctions - If set to true, functions are preserved\n * in the output.\n *\n * @returns {string} - The JSON-formatted string representing the options.\n */\nexport const optionsStringify = (options, allowFunctions) => {\n const replacerCallback = (name, value) => {\n if (typeof value === 'string') {\n value = value.trim();\n\n // If allowFunctions is set to true, preserve functions\n if (\n (value.startsWith('function(') || value.startsWith('function (')) &&\n value.endsWith('}')\n ) {\n value = allowFunctions\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : undefined;\n }\n }\n\n return typeof value === 'function'\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : value;\n };\n\n // Stringify options and if required, replace special functions marks\n return JSON.stringify(options, replacerCallback).replaceAll(\n /\"EXP_FUN|EXP_FUN\"/g,\n ''\n );\n};\n\n/**\n * Prints the Highcharts Export Server logo and version information.\n *\n * @param {boolean} noLogo - If true, only prints version information without\n * the logo.\n */\nexport const printLogo = (noLogo) => {\n // Get package version either from env or from package.json\n const packageVersion = JSON.parse(\n readFileSync(join(__dirname, 'package.json'))\n ).version;\n\n // Print text only\n if (noLogo) {\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\n return;\n }\n\n // Print the logo\n console.log(\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\n `v${packageVersion}\\n`.bold\n );\n};\n\n/**\n * Prints the usage information for CLI arguments. If required, it can list\n * properties recursively\n */\nexport function printUsage() {\n const pad = 48;\n const readme = 'https://github.com/highcharts/node-export-server#readme';\n\n // Display readme information\n console.log(\n '\\nUsage of CLI arguments:'.bold,\n '\\n------',\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\n );\n\n const cycleCategories = (options) => {\n for (const [name, option] of Object.entries(options)) {\n // If category has more levels, go further\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\n cycleCategories(option);\n } else {\n let descName = ` --${option.cliName || name} ${\n ('<' + option.type + '>').green\n } `;\n if (descName.length < pad) {\n for (let i = descName.length; i < pad; i++) {\n descName += '.';\n }\n }\n\n // Display correctly aligned messages\n console.log(\n descName,\n option.description,\n `[Default: ${option.value.toString().bold}]`.blue\n );\n }\n }\n };\n\n // Cycle through options of each categories and display the usage info\n Object.keys(defaultConfig).forEach((category) => {\n // Only puppeteer and highcharts categories cannot be configured through CLI\n if (!['puppeteer', 'highcharts'].includes(category)) {\n console.log(`\\n${category.toUpperCase()}`.red);\n cycleCategories(defaultConfig[category]);\n }\n });\n console.log('\\n');\n}\n\n/**\n * Rounds a number to the specified precision.\n *\n * @param {number} value - The number to be rounded.\n * @param {number} precision - The number of decimal places to round to.\n *\n * @returns {number} - The rounded number.\n */\nexport const roundNumber = (value, precision = 1) => {\n const multiplier = Math.pow(10, precision || 0);\n return Math.round(+value * multiplier) / multiplier;\n};\n\n/**\n * Converts a value to a boolean.\n *\n * @param {any} item - The value to be converted to a boolean.\n *\n * @returns {boolean} - The boolean representation of the input value.\n */\nexport const toBoolean = (item) =>\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\n ? false\n : !!item;\n\n/**\n * Wraps custom code to execute it safely.\n *\n * @param {string} customCode - The custom code to be wrapped.\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\n *\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\n * fails.\n */\nexport const wrapAround = (customCode, allowFileResources) => {\n if (customCode && typeof customCode === 'string') {\n customCode = customCode.trim();\n\n if (customCode.endsWith('.js')) {\n return allowFileResources\n ? wrapAround(readFileSync(customCode, 'utf8'))\n : false;\n } else if (\n customCode.startsWith('function()') ||\n customCode.startsWith('function ()') ||\n customCode.startsWith('()=>') ||\n customCode.startsWith('() =>')\n ) {\n return `(${customCode})()`;\n }\n return customCode.replace(/;$/, '');\n }\n};\n\n/**\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\n *\n * @returns {function(): number} - A function to calculate the elapsed time\n * in milliseconds.\n */\nexport const measureTime = () => {\n const start = process.hrtime.bigint();\n return () => Number(process.hrtime.bigint() - start) / 1000000;\n};\n\nexport default {\n __dirname,\n clearText,\n expBackoff,\n fixType,\n handleResources,\n isCorrectJSON,\n isObject,\n isObjectEmpty,\n isPrivateRangeUrlFound,\n optionsStringify,\n printLogo,\n printUsage,\n roundNumber,\n toBoolean,\n wrapAround,\n measureTime\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\n\nimport prompts from 'prompts';\n\nimport {\n absoluteProps,\n defaultConfig,\n nestedArgs,\n promptsConfig\n} from './schemas/config.js';\nimport { envs } from './envs.js';\nimport { log, logWithStack } from './logger.js';\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\n\nlet generalOptions = {};\n\n/**\n * Retrieves and returns the general options for the export process.\n *\n * @returns {Object} The general options object.\n */\nexport const getOptions = () => generalOptions;\n\n/**\n * Initializes and sets the general options for the server instace, keeping\n * the principle of the options load priority. It accepts optional userOptions\n * and args from the CLI.\n *\n * @param {Object} userOptions - User-provided options for customization.\n * @param {Array} args - Command-line arguments for additional configuration\n * (CLI usage).\n *\n * @returns {Object} The updated general options object.\n */\nexport const setOptions = (userOptions, args) => {\n // Only for the CLI usage\n if (args?.length) {\n // Get the additional options from the custom JSON file\n generalOptions = loadConfigFile(args);\n }\n\n // Update the default config with a correct option values\n updateDefaultConfig(defaultConfig, generalOptions);\n\n // Set values for server's options and returns them\n generalOptions = initOptions(defaultConfig);\n\n // Apply user options if there are any\n if (userOptions) {\n // Merge user options\n generalOptions = mergeConfigOptions(\n generalOptions,\n userOptions,\n absoluteProps\n );\n }\n\n // Only for the CLI usage\n if (args?.length) {\n // Pair provided arguments\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\n }\n\n // Return final general options\n return generalOptions;\n};\n\n/**\n * Allows manual configuration based on specified prompts and saves\n * the configuration to a file.\n *\n * @param {string} configFileName - The name of the configuration file.\n *\n * @returns {Promise} A Promise that resolves to true once the manual\n * configuration is completed and saved.\n */\nexport const manualConfig = async (configFileName) => {\n // Prepare a config object\n let configFile = {};\n\n // Check if provided config file exists\n if (existsSync(configFileName)) {\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\n }\n\n // Question about a configuration category\n const onSubmit = async (p, categories) => {\n let questionsCounter = 0;\n let allQuestions = [];\n\n // Create a corresponding property in the manualConfig object\n for (const section of categories) {\n // Mark each option with a section\n promptsConfig[section] = promptsConfig[section].map((option) => ({\n ...option,\n section\n }));\n\n // Collect the questions\n allQuestions = [...allQuestions, ...promptsConfig[section]];\n }\n\n await prompts(allQuestions, {\n onSubmit: async (prompt, answer) => {\n // Get the default module scripts\n if (prompt.name === 'moduleScripts') {\n answer = answer.length\n ? answer.map((module) => prompt.choices[module])\n : prompt.choices;\n\n configFile[prompt.section][prompt.name] = answer;\n } else {\n configFile[prompt.section] = recursiveProps(\n Object.assign({}, configFile[prompt.section] || {}),\n prompt.name.split('.'),\n prompt.choices ? prompt.choices[answer] : answer\n );\n }\n\n if (++questionsCounter === allQuestions.length) {\n try {\n await fsPromises.writeFile(\n configFileName,\n JSON.stringify(configFile, null, 2),\n 'utf8'\n );\n } catch (error) {\n logWithStack(\n 1,\n error,\n `[config] An error occurred while creating the ${configFileName} file.`\n );\n }\n return true;\n }\n }\n });\n\n return true;\n };\n\n // Find the categories\n const choices = Object.keys(promptsConfig).map((choice) => ({\n title: `${choice} options`,\n value: choice\n }));\n\n // Category prompt\n return prompts(\n {\n type: 'multiselect',\n name: 'category',\n message: 'Which category do you want to configure?',\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\n instructions: '',\n choices\n },\n { onSubmit }\n );\n};\n\n/**\n * Maps old-structured (PhantomJS) options to a new configuration format\n * (Puppeteer).\n *\n * @param {Object} oldOptions - Old-structured options to be mapped.\n *\n * @returns {Object} New options structured based on the defined nestedArgs\n * mapping.\n */\nexport const mapToNewConfig = (oldOptions) => {\n const newOptions = {};\n // Cycle through old-structured options\n for (const [key, value] of Object.entries(oldOptions)) {\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\n\n // Populate object in correct properties levels\n propertiesChain.reduce(\n (obj, prop, index) =>\n (obj[prop] =\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\n newOptions\n );\n }\n return newOptions;\n};\n\n/**\n * Merges two sets of configuration options, considering absolute properties.\n *\n * @param {Object} options - Original configuration options.\n * @param {Object} newOptions - New configuration options to be merged.\n * @param {Array} absoluteProps - List of properties that should\n * not be recursively merged.\n *\n * @returns {Object} Merged configuration options.\n */\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\n const mergedOptions = deepCopy(options);\n\n for (const [key, value] of Object.entries(newOptions)) {\n mergedOptions[key] =\n isObject(value) &&\n !absoluteProps.includes(key) &&\n mergedOptions[key] !== undefined\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\n : value !== undefined\n ? value\n : mergedOptions[key];\n }\n\n return mergedOptions;\n};\n\n/**\n * Initializes export settings based on provided exportOptions\n * and generalOptions.\n *\n * @param {Object} exportOptions - Options specific to the export process.\n * @param {Object} generalOptions - General configuration options.\n *\n * @returns {Object} Initialized export settings.\n */\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\n let options = {};\n\n if (exportOptions.svg) {\n options = deepCopy(generalOptions);\n options.export.type = exportOptions.type || exportOptions.export.type;\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\n options.export.outfile =\n exportOptions.outfile || exportOptions.export.outfile;\n options.payload = {\n svg: exportOptions.svg\n };\n } else {\n options = mergeConfigOptions(\n generalOptions,\n exportOptions,\n // Omit going down recursively with the belows\n absoluteProps\n );\n }\n\n options.export.outfile =\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\n return options;\n};\n\n/**\n * Loads additional configuration from a specified file using\n * the --loadConfig option.\n *\n * @param {Array} args - Command-line arguments to check for\n * the --loadConfig option.\n *\n * @returns {Object} Additional configuration loaded from the specified file,\n * or an empty object if not found or invalid.\n */\nfunction loadConfigFile(args) {\n // Check if the --loadConfig option was used\n const configIndex = args.findIndex(\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\n );\n\n // Check if the --loadConfig has a value\n if (configIndex > -1 && args[configIndex + 1]) {\n const fileName = args[configIndex + 1];\n try {\n // Check if an additional config file is a correct JSON file\n if (fileName && fileName.endsWith('.json')) {\n // Load an optional custom JSON config file\n return JSON.parse(readFileSync(fileName));\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[config] Unable to load the configuration from the ${fileName} file.`\n );\n }\n }\n\n // No additional options to return\n return {};\n}\n\n/**\n * Updates the default configuration object with values from a custom object\n * and environment variables.\n *\n * @param {Object} configObj - The default configuration object.\n * @param {Object} customObj - Custom configuration object to override defaults.\n * @param {string} propChain - Property chain for tracking nested properties\n * during recursion.\n */\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\n Object.keys(configObj).forEach((key) => {\n const entry = configObj[key];\n const customValue = customObj && customObj[key];\n\n if (typeof entry.value === 'undefined') {\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\n } else {\n // If a value from a custom JSON exists, it take precedence\n if (customValue !== undefined) {\n entry.value = customValue;\n }\n\n // If a value from an env variable exists, it take precedence\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\n entry.value = envs[entry.envLink];\n }\n }\n });\n}\n\n/**\n * Initializes options object based on provided items, setting values from\n * nested properties recursively.\n *\n * @param {Object} items - Configuration items to be used for initializing\n * options.\n *\n * @returns {Object} Initialized options object.\n */\nfunction initOptions(items) {\n let options = {};\n for (const [name, item] of Object.entries(items)) {\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\n ? item.value\n : initOptions(item);\n }\n return options;\n}\n\n/**\n * Pairs argument values with corresponding options in the configuration,\n * updating the options object.\n *\n * @param {Object} options - Configuration options object to be updated.\n * @param {Array} args - Command-line arguments containing values for specific\n * options.\n * @param {Object} defaultConfig - Default configuration object for reference.\n *\n * @returns {Object} Updated options object.\n */\nfunction pairArgumentValue(options, args, defaultConfig) {\n let showUsage = false;\n for (let i = 0; i < args.length; i++) {\n const option = args[i].replace(/-/g, '');\n\n // Find the right place for property's value\n const propertiesChain = nestedArgs[option]\n ? nestedArgs[option].split('.')\n : [];\n\n // Get the correct type for CLI args which are passed as strings\n let argumentType;\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n argumentType = obj[prop].type;\n }\n return obj[prop];\n }, defaultConfig);\n\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n // Finds an option and set a corresponding value\n if (typeof obj[prop] !== 'undefined') {\n if (args[++i]) {\n if (argumentType === 'boolean') {\n obj[prop] = toBoolean(args[i]);\n } else if (argumentType === 'number') {\n obj[prop] = +args[i];\n } else if (argumentType.indexOf(']') >= 0) {\n obj[prop] = args[i].split(',');\n } else {\n obj[prop] = args[i];\n }\n } else {\n log(\n 2,\n `[config] Missing value for the '${option}' argument. Using the default value.`\n );\n showUsage = true;\n }\n }\n }\n return obj[prop];\n }, options);\n }\n\n // Display the usage for the reference if needed\n if (showUsage) {\n printUsage(defaultConfig);\n }\n\n return options;\n}\n\n/**\n * Recursively updates properties in an object based on nested names and assigns\n * the final value.\n *\n * @param {Object} objectToUpdate - The object to be updated.\n * @param {Array} nestedNames - Array of nested property names.\n * @param {any} value - The final value to be assigned.\n *\n * @returns {Object} Updated object with assigned values.\n */\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\n while (nestedNames.length > 1) {\n const propName = nestedNames.shift();\n\n // Create a property in object if it doesn't exist\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\n objectToUpdate[propName] = {};\n }\n\n // Call function again if there still names to go\n objectToUpdate[propName] = recursiveProps(\n Object.assign({}, objectToUpdate[propName]),\n nestedNames,\n value\n );\n\n return objectToUpdate;\n }\n\n // Assign the final value\n objectToUpdate[nestedNames[0]] = value;\n return objectToUpdate;\n}\n\nexport default {\n getOptions,\n setOptions,\n manualConfig,\n mapToNewConfig,\n mergeConfigOptions,\n initExportSettings\n};\n","/**\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\n */\n\nimport http from 'http';\nimport https from 'https';\n\n/**\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\n *\n * @param {string} url - The URL to determine the protocol.\n *\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\n */\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\n\n/**\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to fetch data from.\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object\n * with added 'text' property or rejecting with an error.\n */\nasync function fetch(url, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n\n protocol\n .get(\n url,\n Object.assign(\n {\n headers: {\n 'User-Agent': 'highcharts/export',\n Referer: 'highcharts/export'\n }\n },\n requestOptions || {}\n ),\n (res) => {\n let data = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n if (!data) {\n reject('Nothing was fetched from the URL.');\n }\n\n res.text = data;\n resolve(res);\n });\n }\n )\n .on('error', (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Sends a POST request to the specified URL with the provided JSON body using\n * either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to send the POST request to.\n * @param {Object} body - The JSON body to include in the POST request\n * (optional, default is an empty object).\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object with\n * added 'text' property or rejecting with an error.\n */\nasync function post(url, body = {}, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n const data = JSON.stringify(body);\n\n // Set default headers and merge with requestOptions\n const options = Object.assign(\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n },\n requestOptions\n );\n\n const req = protocol\n .request(url, options, (res) => {\n let responseData = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n responseData += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n try {\n res.text = responseData;\n resolve(res);\n } catch (error) {\n reject(error);\n }\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n\n // Write the request body and end the request.\n req.write(data);\n req.end();\n });\n}\n\nexport default fetch;\nexport { fetch, post };\n","class ExportError extends Error {\n constructor(message) {\n super();\n this.message = message;\n this.stackMessage = message;\n }\n\n setError(error) {\n this.error = error;\n if (error.name) {\n this.name = error.name;\n }\n if (error.statusCode) {\n this.statusCode = error.statusCode;\n }\n if (error.stack) {\n this.stackMessage = error.message;\n this.stack = error.stack;\n }\n return this;\n }\n}\n\nexport default ExportError;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// The cache manager manages the Highcharts library and its dependencies.\n// The cache itself is stored in .cache, and is checked by the config system\n// before starting the service\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport { HttpsProxyAgent } from 'https-proxy-agent';\n\nimport { getOptions } from './config.js';\nimport { envs } from './envs.js';\nimport { fetch } from './fetch.js';\nimport { log } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\nconst cache = {\n cdnURL: 'https://code.highcharts.com/',\n activeManifest: {},\n sources: '',\n hcVersion: ''\n};\n\n/**\n * Extracts and caches the Highcharts version from the sources string.\n *\n * @returns {string} The extracted Highcharts version.\n */\nexport const extractVersion = (cache) => {\n return cache.sources\n .substring(0, cache.sources.indexOf('*/'))\n .replace('/*', '')\n .replace('*/', '')\n .replace(/\\n/g, '')\n .trim();\n};\n\n/**\n * Extracts the Highcharts module name based on the scriptPath.\n */\nexport const extractModuleName = (scriptPath) => {\n return scriptPath.replace(\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\n ''\n );\n};\n\n/**\n * Saves the provided configuration and fetched modules to the cache manifest\n * file.\n *\n * @param {object} config - Highcharts-related configuration object.\n * @param {object} fetchedModules - An object that contains mapped names of\n * fetched Highcharts modules to use.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\n * the cache manifest.\n */\nexport const saveConfigToManifest = async (config, fetchedModules) => {\n const newManifest = {\n version: config.version,\n modules: fetchedModules || {}\n };\n\n // Update cache object with the current modules\n cache.activeManifest = newManifest;\n\n log(3, '[cache] Writing a new manifest.');\n try {\n writeFileSync(\n join(__dirname, config.cachePath, 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\n error\n );\n }\n};\n\n/**\n * Fetches a single script and updates the fetchedModules accordingly.\n *\n * @param {string} script - A path to script to get.\n * @param {Object} requestOptions - Additional options for the proxy agent\n * to use for a request.\n * @param {Object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\n * thrown. This should be used only for the core scripts.\n *\n * @returns {Promise} A Promise resolving to the text representation\n * of the fetched script.\n *\n * @throws {ExportError} Throws an ExportError if there is a problem with\n * fetching the script.\n */\nexport const fetchAndProcessScript = async (\n script,\n requestOptions,\n fetchedModules,\n shouldThrowError = false\n) => {\n // Get rid of the .js from the custom strings\n if (script.endsWith('.js')) {\n script = script.substring(0, script.length - 3);\n }\n\n log(4, `[cache] Fetching script - ${script}.js`);\n\n // Fetch the script\n const response = await fetch(`${script}.js`, requestOptions);\n\n // If OK, return its text representation\n if (response.statusCode === 200 && typeof response.text == 'string') {\n if (fetchedModules) {\n const moduleName = extractModuleName(script);\n fetchedModules[moduleName] = 1;\n }\n\n return response.text;\n }\n\n if (shouldThrowError) {\n throw new ExportError(\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\n ).setError(response);\n } else {\n log(\n 2,\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\n );\n }\n\n return '';\n};\n\n/**\n * Fetches Highcharts scripts and customScripts from the given CDNs.\n *\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\n * @param {string} customScripts - Array of custom script paths to fetch\n * (full URLs).\n * @param {object} proxyOptions - Options for the proxy agent to use for\n * a request.\n * @param {object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n *\n * @returns {Promise} The fetched scripts content joined.\n */\nexport const fetchScripts = async (\n coreScripts,\n moduleScripts,\n customScripts,\n proxyOptions,\n fetchedModules\n) => {\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = proxyOptions.host;\n const proxyPort = proxyOptions.port;\n\n // Try to create a Proxy Agent\n if (proxyHost && proxyPort) {\n try {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: proxyPort\n });\n } catch (error) {\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\n error\n );\n }\n }\n\n // If exists, add proxy agent to request options\n const requestOptions = proxyAgent\n ? {\n agent: proxyAgent,\n timeout: envs.SERVER_PROXY_TIMEOUT\n }\n : {};\n\n const allFetchPromises = [\n ...coreScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\n ),\n ...moduleScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\n ),\n ...customScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions)\n )\n ];\n\n const fetchedScripts = await Promise.all(allFetchPromises);\n return fetchedScripts.join(';\\n');\n};\n\n/**\n * Updates the local cache with Highcharts scripts and their versions.\n *\n * @param {Object} options - Object containing all options.\n * @param {string} sourcePath - The path to the source file in the cache.\n *\n * @returns {Promise} A Promise resolving to an object representing\n * the fetched modules.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * the local Highcharts cache.\n */\nexport const updateCache = async (\n highchartsOptions,\n proxyOptions,\n sourcePath\n) => {\n const version = highchartsOptions.version;\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\n\n log(\n 3,\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\n );\n\n const fetchedModules = {};\n try {\n cache.sources = await fetchScripts(\n [\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\n ],\n [\n ...highchartsOptions.moduleScripts.map((m) =>\n m === 'map'\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\n : `${cdnURL}${hcVersion}modules/${m}`\n ),\n ...highchartsOptions.indicatorScripts.map(\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\n )\n ],\n highchartsOptions.customScripts,\n proxyOptions,\n fetchedModules\n );\n\n cache.hcVersion = extractVersion(cache);\n\n // Save the fetched modules into caches' source JSON\n writeFileSync(sourcePath, cache.sources);\n return fetchedModules;\n } catch (error) {\n throw new ExportError(\n '[cache] Unable to update the local Highcharts cache.'\n ).setError(error);\n }\n};\n\n/**\n * Updates the Highcharts version in the applied configuration and checks\n * the cache for the new version.\n *\n * @param {string} newVersion - The new Highcharts version to be applied.\n *\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\n * configuration with the new version, or false if no applied configuration\n * exists.\n */\nexport const updateVersion = async (newVersion) => {\n const options = getOptions();\n if (options?.highcharts) {\n options.highcharts.version = newVersion;\n }\n await checkAndUpdateCache(options);\n};\n\n/**\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\n * and loads the sources.\n *\n * @param {Object} options - Object containing all options.\n *\n * @returns {Promise} A Promise that resolves once the cache is checked\n * and updated.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * or reading the cache.\n */\nexport const checkAndUpdateCache = async (options) => {\n const { highcharts, server } = options;\n const cachePath = join(__dirname, highcharts.cachePath);\n\n let fetchedModules;\n // Prepare paths to manifest and sources from the .cache folder\n const manifestPath = join(cachePath, 'manifest.json');\n const sourcePath = join(cachePath, 'sources.js');\n\n // Create the cache destination if it doesn't exist already\n !existsSync(cachePath) && mkdirSync(cachePath);\n\n // Fetch all the scripts either if manifest.json does not exist\n // or if the forceFetch option is enabled\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n let requestUpdate = false;\n\n // Read the manifest JSON\n const manifest = JSON.parse(readFileSync(manifestPath));\n\n // Check if the modules is an array, if so, we rewrite it to a map to make\n // it easier to resolve modules.\n if (manifest.modules && Array.isArray(manifest.modules)) {\n const moduleMap = {};\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\n manifest.modules = moduleMap;\n }\n\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\n const numberOfModules =\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\n\n // Compare the loaded highcharts config with the contents in cache.\n // If there are changes, fetch requested modules and products,\n // and bake them into a giant blob. Save the blob.\n if (manifest.version !== highcharts.version) {\n log(\n 2,\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\n );\n requestUpdate = true;\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\n log(\n 2,\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\n );\n requestUpdate = true;\n } else {\n // Check each module, if anything is missing refetch everything\n requestUpdate = (moduleScripts || []).some((moduleName) => {\n if (!manifest.modules[moduleName]) {\n log(\n 2,\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\n );\n return true;\n }\n });\n }\n\n if (requestUpdate) {\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n log(3, '[cache] Dependency cache is up to date, proceeding.');\n\n // Load the sources\n cache.sources = readFileSync(sourcePath, 'utf8');\n\n // Get current modules map\n fetchedModules = manifest.modules;\n\n cache.hcVersion = extractVersion(cache);\n }\n }\n\n // Finally, save the new manifest, which is basically our current config\n // in a slightly different format\n await saveConfigToManifest(highcharts, fetchedModules);\n};\n\nexport const getCachePath = () =>\n join(__dirname, getOptions().highcharts.cachePath);\n\nexport const getCache = () => cache;\n\nexport const highcharts = () => cache.sources;\n\nexport const version = () => cache.hcVersion;\n\nexport default {\n checkAndUpdateCache,\n getCachePath,\n updateVersion,\n getCache,\n highcharts,\n version\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/* eslint-disable no-undef */\n\n/**\n * Setting the animObject. Called when initing the page.\n */\nexport function setupHighcharts() {\n Highcharts.animObject = function () {\n return { duration: 0 };\n };\n}\n\n/**\n * Creates the actual chart.\n *\n * @param {object} chartOptions - The options for the Highcharts chart.\n * @param {object} options - The export options.\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\n */\nexport async function triggerExport(chartOptions, options, displayErrors) {\n // Display errors flag taken from chart options nad debugger module\n window._displayErrors = displayErrors;\n\n // Get required functions\n const { getOptions, merge, setOptions, wrap } = Highcharts;\n\n // Create a separate object for a potential setOptions usages in order to\n // prevent from polluting other exports that can happen on the same page\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\n\n // By default animation is disabled\n const chart = {\n animation: false\n };\n\n // When straight inject, the size is set through CSS only\n if (options.export.strInj) {\n chart.height = chartOptions.chart.height;\n chart.width = chartOptions.chart.width;\n }\n\n // NOTE: Is this used for anything useful?\n window.isRenderComplete = false;\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\n // Override userOptions with image friendly options\n userOptions = merge(userOptions, {\n exporting: {\n enabled: false\n },\n plotOptions: {\n series: {\n label: {\n enabled: false\n }\n }\n },\n /* Expects tooltip in userOptions when forExport is true.\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\n */\n tooltip: {}\n });\n\n (userOptions.series || []).forEach(function (series) {\n series.animation = false;\n });\n\n // Add flag to know if chart render has been called.\n if (!window.onHighchartsRender) {\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\n window.isRenderComplete = true;\n });\n }\n\n proceed.apply(this, [userOptions, cb]);\n });\n\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\n proceed.apply(this, [chart, options]);\n });\n\n // Get the user options\n const userOptions = options.export.strInj\n ? new Function(`return ${options.export.strInj}`)()\n : chartOptions;\n\n // Trigger custom code\n if (options.customLogic.customCode) {\n new Function('options', options.customLogic.customCode)(userOptions);\n }\n\n // Merge the globalOptions, themeOptions, options from the wrapped\n // setOptions function and user options to create the final options object\n const finalOptions = merge(\n false,\n JSON.parse(options.export.themeOptions),\n userOptions,\n // Placed it here instead in the init because of the size issues\n { chart }\n );\n\n const finalCallback = options.customLogic.callback\n ? new Function(`return ${options.customLogic.callback}`)()\n : undefined;\n\n // Set the global options if exist\n const globalOptions = JSON.parse(options.export.globalOptions);\n if (globalOptions) {\n setOptions(globalOptions);\n }\n\n let constr = options.export.constr || 'chart';\n constr = typeof Highcharts[constr] !== 'undefined' ? constr : 'chart';\n\n Highcharts[constr]('container', finalOptions, finalCallback);\n\n // Get the current global options\n const defaultOptions = getOptions();\n\n // Clear it just in case (e.g. the setOptions was used in the customCode)\n for (const prop in defaultOptions) {\n if (typeof defaultOptions[prop] !== 'function') {\n delete defaultOptions[prop];\n }\n }\n\n // Set the default options back\n setOptions(Highcharts.setOptionsObj);\n\n // Empty the custom global options object\n Highcharts.setOptionsObj = {};\n}\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport path from 'path';\n\nimport puppeteer from 'puppeteer';\n\nimport { getCachePath } from './cache.js';\nimport { getOptions } from './config.js';\nimport { setupHighcharts } from './highcharts.js';\nimport { log, logWithStack } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\n// Get the template for the page\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\n\nlet browser;\n\n/**\n * Retrieves the existing Puppeteer browser instance.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if no valid browser has been\n * created.\n */\nexport function get() {\n if (!browser) {\n throw new ExportError('[browser] No valid browser has been created.');\n }\n return browser;\n}\n\n/**\n * Creates a Puppeteer browser instance with the specified arguments.\n *\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\n * instance are reached, or if no browser instance is found after retries.\n */\nexport async function create(puppeteerArgs) {\n // Get debug and other options\n const { debug, other } = getOptions();\n\n // Get the debug options\n const { enable: enabledDebug, ...debugOptions } = debug;\n\n const launchOptions = {\n headless: other.browserShellMode ? 'shell' : true,\n userDataDir: './tmp/',\n args: puppeteerArgs,\n handleSIGINT: false,\n handleSIGTERM: false,\n handleSIGHUP: false,\n waitForInitialPage: false,\n defaultViewport: null,\n ...(enabledDebug && debugOptions)\n };\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\n );\n browser = await puppeteer.launch(launchOptions);\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Failed to launch a browser instance.'\n );\n\n // Retry to launch browser until reaching max attempts\n if (tryCount < 25) {\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n throw error;\n }\n }\n };\n\n try {\n await open();\n\n // Shell mode inform\n if (launchOptions.headless === 'shell') {\n log(3, `[browser] Launched browser in shell mode.`);\n }\n\n // Debug mode inform\n if (enabledDebug) {\n log(3, `[browser] Launched browser in debug mode.`);\n }\n } catch (error) {\n throw new ExportError(\n '[browser] Maximum retries to open a browser instance reached.'\n ).setError(error);\n }\n\n if (!browser) {\n throw new ExportError('[browser] Cannot find a browser to open.');\n }\n }\n\n // Return a browser promise\n return browser;\n}\n\n/**\n * Closes the Puppeteer browser instance if it is connected.\n *\n * @returns {Promise} A Promise resolving to true after the browser\n * is closed.\n */\nexport async function close() {\n // Close the browser when connnected\n if (browser?.connected) {\n await browser.close();\n }\n log(4, '[browser] Closed the browser.');\n}\n\n/**\n * Creates a new Puppeteer Page within an existing browser instance.\n *\n * If the browser instance is not available, returns false.\n *\n * The function creates a new page, disables caching, sets content using\n * setPageContent(), and returns the created Puppeteer Page.\n *\n * @returns {(boolean|object)} Returns false if the browser instance is not\n * available, or a Puppeteer Page object representing the newly created page.\n */\nexport async function newPage() {\n if (!browser) {\n return false;\n }\n\n // Create a page\n const page = await browser.newPage();\n\n // Disable cache\n await page.setCacheEnabled(false);\n\n // Set the content\n await setPageContent(page);\n\n // Set page events\n setPageEvents(page);\n\n return page;\n}\n\n/**\n * Clears the content of a Puppeteer Page based on the specified mode.\n *\n * @param {Object} page - The Puppeteer Page object to be cleared.\n * @param {boolean} hardReset - A flag indicating the type of clearing\n * to be performed. If true, navigates to 'about:blank' and resets content\n * and scripts. If false, clears the body content by setting a predefined HTML\n * structure.\n *\n * @throws {Error} Logs thrown error if clearing the page content fails.\n */\nexport async function clearPage(page, hardReset = false) {\n try {\n if (page && !page.isClosed()) {\n if (hardReset) {\n // Navigate to about:blank\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\n\n // Set the content and and scripts again\n await setPageContent(page);\n } else {\n // Clear body content\n await page.evaluate(() => {\n document.body.innerHTML =\n '
';\n });\n }\n return true;\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n '[browser] Could not clear the content of the page.'\n );\n }\n\n return false;\n}\n\n/**\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\n * options.\n *\n * @param {Object} page - The Puppeteer Page object to which resources will be\n * added.\n * @param {Object} options - All options and configuration.\n *\n * @returns {Promise>} - Promise resolving to an array of injected\n * resources.\n */\nexport async function addPageResources(page, options) {\n // Injected resources array\n const injectedResources = [];\n\n // Use resources\n const resources = options.customLogic.resources;\n if (resources) {\n const injectedJs = [];\n\n // Load custom JS code\n if (resources.js) {\n injectedJs.push({\n content: resources.js\n });\n }\n\n // Load scripts from all custom files\n if (resources.files) {\n for (const file of resources.files) {\n const isLocal = !file.startsWith('http') ? true : false;\n\n // Add each custom script from resources' files\n injectedJs.push(\n isLocal\n ? {\n content: readFileSync(file, 'utf8')\n }\n : {\n url: file\n }\n );\n }\n }\n\n for (const jsResource of injectedJs) {\n try {\n injectedResources.push(await page.addScriptTag(jsResource));\n } catch (error) {\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\n }\n }\n injectedJs.length = 0;\n\n // Load CSS\n const injectedCss = [];\n if (resources.css) {\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\n if (cssImports) {\n // Handle css section\n for (let cssImportPath of cssImports) {\n if (cssImportPath) {\n cssImportPath = cssImportPath\n .replace('url(', '')\n .replace('@import', '')\n .replace(/\"/g, '')\n .replace(/'/g, '')\n .replace(/;/, '')\n .replace(/\\)/g, '')\n .trim();\n\n // Add each custom css from resources\n if (cssImportPath.startsWith('http')) {\n injectedCss.push({\n url: cssImportPath\n });\n } else if (options.customLogic.allowFileResources) {\n injectedCss.push({\n path: path.join(__dirname, cssImportPath)\n });\n }\n }\n }\n }\n\n // The rest of the CSS section will be content by now\n injectedCss.push({\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\n });\n\n for (const cssResource of injectedCss) {\n try {\n injectedResources.push(await page.addStyleTag(cssResource));\n } catch (error) {\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\n }\n }\n injectedCss.length = 0;\n }\n }\n return injectedResources;\n}\n\n/**\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\n * injected resources and resets CSS and script tags on the page. Additionally,\n * it destroys previously existing charts.\n *\n * @param {Object} page - The Puppeteer Page object from which resources will\n * be cleared.\n * @param {Array} injectedResources - Array of injected resources\n * to be cleared.\n */\nexport async function clearPageResources(page, injectedResources) {\n for (const resource of injectedResources) {\n await resource.dispose();\n }\n\n // Destroy old charts after export is done and reset all CSS and script tags\n await page.evaluate(() => {\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\n // exports\n if (typeof Highcharts !== 'undefined') {\n // eslint-disable-next-line no-undef\n const oldCharts = Highcharts.charts;\n\n // Check in any already existing charts\n if (Array.isArray(oldCharts) && oldCharts.length) {\n // Destroy old charts\n for (const oldChart of oldCharts) {\n oldChart && oldChart.destroy();\n // eslint-disable-next-line no-undef\n Highcharts.charts.shift();\n }\n }\n }\n\n // eslint-disable-next-line no-undef\n const [...scriptsToRemove] = document.getElementsByTagName('script');\n // eslint-disable-next-line no-undef\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\n // eslint-disable-next-line no-undef\n const [...linksToRemove] = document.getElementsByTagName('link');\n\n // Remove tags\n for (const element of [\n ...scriptsToRemove,\n ...stylesToRemove,\n ...linksToRemove\n ]) {\n element.remove();\n }\n });\n}\n\n/**\n * Sets the content for a Puppeteer Page using a predefined template\n * and additional scripts. Also, sets the pageerror in order to catch\n * and display errors from the window context.\n *\n * @param {Object} page - The Puppeteer Page object for which the content\n * is being set.\n */\nasync function setPageContent(page) {\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\n\n // Add all registered Higcharts scripts, quite demanding\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\n\n // Set the initial animObject\n await page.evaluate(setupHighcharts);\n}\n\n/**\n * Set events for a Puppeteer Page.\n *\n * @param {Object} page - The Puppeteer Page object to set events to.\n */\nfunction setPageEvents(page) {\n // Get debug options\n const { debug } = getOptions();\n\n // Set the console listener, if needed\n if (debug.enable && debug.listenToConsole) {\n page.on('console', (message) => {\n console.log(`[debug] ${message.text()}`);\n });\n }\n\n // Set the pageerror listener\n page.on('pageerror', async (error) => {\n // It would seem like this may fire at the same time or shortly before\n // a page is closed.\n if (page.isClosed()) {\n return;\n }\n\n // TODO: Consider adding a switch here that turns on log(0) logging\n // on page errors.\n await page.$eval(\n '#container',\n (element, errorMessage) => {\n // eslint-disable-next-line no-undef\n if (window._displayErrors) {\n element.innerHTML = errorMessage;\n }\n },\n `

Chart input data error:

${error.toString()}`\n );\n });\n}\n\nexport default {\n get,\n create,\n close,\n newPage,\n clearPage,\n addPageResources,\n clearPageResources\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { addPageResources, clearPageResources } from './browser.js';\nimport { getCache } from './cache.js';\nimport { triggerExport } from './highcharts.js';\nimport { log } from './logger.js';\n\nimport svgTemplate from './../templates/svg_export/svg_export.js';\n\nimport ExportError from './errors/ExportError.js';\n\n/**\n * Retrieves the clipping region coordinates of the specified page element with\n * the id 'chart-container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to an object containing\n * x, y, width, and height properties.\n */\nconst getClipRegion = (page) =>\n page.$eval('#chart-container', (element) => {\n const { x, y, width, height } = element.getBoundingClientRect();\n return {\n x,\n y,\n width,\n height: Math.trunc(height > 1 ? height : 500)\n };\n });\n\n/**\n * Creates an image using Puppeteer's page screenshot functionality with\n * specified options.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {string} type - Image type.\n * @param {string} encoding - Image encoding.\n * @param {Object} clip - Clipping region coordinates.\n * @param {number} rasterizationTimeout - Timeout for rasterization\n * in milliseconds.\n *\n * @returns {Promise} Promise resolving to the image buffer or rejecting\n * with an ExportError for timeout.\n */\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\n Promise.race([\n page.screenshot({\n type,\n encoding,\n clip,\n captureBeyondViewport: true,\n fullPage: false,\n optimizeForSpeed: true,\n ...(type !== 'png' ? { quality: 80 } : {}),\n\n // #447, #463 - always render on a transparent page if the expected type\n // format is PNG\n omitBackground: type == 'png'\n }),\n new Promise((_resolve, reject) =>\n setTimeout(\n () => reject(new ExportError('Rasterization timeout')),\n rasterizationTimeout || 1500\n )\n )\n ]);\n\n/**\n * Creates a PDF using Puppeteer's page pdf functionality with specified\n * options.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {number} height - PDF height.\n * @param {number} width - PDF width.\n * @param {string} encoding - PDF encoding.\n *\n * @returns {Promise} Promise resolving to the PDF buffer.\n */\nconst createPDF = async (\n page,\n height,\n width,\n encoding,\n rasterizationTimeout\n) => {\n await page.emulateMediaType('screen');\n\n return page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding,\n timeout: rasterizationTimeout || 1500\n });\n};\n\n/**\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\n * inside an element with the id 'container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to the SVG string.\n */\nconst createSVG = (page) =>\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\n\n/**\n * Sets the specified chart and options as configuration into the triggerExport\n * function within the window context using page.evaluate.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object to be configured.\n * @param {Object} options - Configuration options for the chart.\n *\n * @returns {Promise} Promise resolving after the configuration is set.\n */\nconst setAsConfig = async (page, chart, options, displayErrors) =>\n page.evaluate(triggerExport, chart, options, displayErrors);\n\n/**\n * Exports to a chart from a page using Puppeteer.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object or SVG configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} Promise resolving to\n * the exported data or rejecting with an ExportError.\n */\nexport default async (page, chart, options) => {\n // Injected resources array (additional JS and CSS)\n let injectedResources = [];\n\n try {\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n getCache().activeManifest.modules.debugger;\n\n let isSVG;\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG input handling\n log(4, '[export] Treating as SVG.');\n\n // If input is also SVG, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n await page.setContent(svgTemplate(chart), {\n waitUntil: 'domcontentloaded'\n });\n } else {\n // JSON config handling\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options,\n displayErrors\n );\n } else {\n // Basic configuration export\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n await setAsConfig(page, chart, options, displayErrors);\n }\n }\n\n // Keeps track of all resources added on the page with addXXXTag. etc\n // It's VITAL that all added resources ends up here so we can clear things\n // out when doing a new export in the same page!\n injectedResources = await addPageResources(page, options);\n\n // Get the real chart size and set the zoom accordingly\n const size = isSVG\n ? await page.evaluate((scale) => {\n const svgElement = document.querySelector(\n '#chart-container svg:first-of-type'\n );\n\n // Get the values correctly scaled\n const chartHeight = svgElement.height.baseVal.value * scale;\n const chartWidth = svgElement.width.baseVal.value * scale;\n\n // In case of SVG the zoom must be set directly for body\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n\n return {\n chartHeight,\n chartWidth\n };\n }, parseFloat(exportOptions.scale))\n : await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n\n // No need for such scale manipulation in case of other types of exports\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n\n return {\n chartHeight,\n chartWidth\n };\n });\n\n // Set final height and width for viewport\n const viewportHeight = Math.abs(\n Math.ceil(size.chartHeight || exportOptions.height)\n );\n const viewportWidth = Math.abs(\n Math.ceil(size.chartWidth || exportOptions.width)\n );\n\n // Get the clip region for the page\n const { x, y } = await getClipRegion(page);\n\n // Set the final viewport now that we have the real height\n await page.setViewport({\n height: viewportHeight,\n width: viewportWidth,\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\n });\n\n let data;\n // Rasterization process\n if (exportOptions.type === 'svg') {\n // SVG\n data = await createSVG(page);\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\n // PNG or JPEG\n data = await createImage(\n page,\n exportOptions.type,\n 'base64',\n {\n width: viewportWidth,\n height: viewportHeight,\n x,\n y\n },\n exportOptions.rasterizationTimeout\n );\n } else if (exportOptions.type === 'pdf') {\n // PDF\n data = await createPDF(\n page,\n viewportHeight,\n viewportWidth,\n 'base64',\n exportOptions.rasterizationTimeout\n );\n } else {\n throw new ExportError(\n `[export] Unsupported output format ${exportOptions.type}.`\n );\n }\n\n // Clear previously injected JS and CSS resources\n await clearPageResources(page, injectedResources);\n return data;\n } catch (error) {\n await clearPageResources(page, injectedResources);\n return error;\n }\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cssTemplate from './css.js';\n\nexport default (chart) => `\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${chart}\n
\n \n\n\n`;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { Pool } from 'tarn';\nimport { v4 as uuid } from 'uuid';\n\nimport {\n create as createBrowser,\n close as closeBrowser,\n newPage,\n clearPage\n} from './browser.js';\nimport puppeteerExport from './export.js';\nimport { log, logWithStack } from './logger.js';\nimport { measureTime } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\n// The pool instance\nlet pool = false;\n\n// Pool statistics\nexport const stats = {\n performedExports: 0,\n exportAttempts: 0,\n exportFromSvgAttempts: 0,\n timeSpent: 0,\n droppedExports: 0,\n spentAverage: 0\n};\n\nlet poolConfig = {};\n\nconst factory = {\n /**\n * Creates a new worker page for the export pool.\n *\n * @returns {Object} - An object containing the worker ID, a reference to the\n * browser page, and initial work count.\n *\n * @throws {ExportError} - If there's an error during the creation of the new\n * page.\n */\n create: async () => {\n let page = false;\n\n const id = uuid();\n const startDate = new Date().getTime();\n\n try {\n page = await newPage();\n\n if (!page || page.isClosed()) {\n throw new ExportError('The page is invalid or closed.');\n }\n\n log(\n 3,\n `[pool] Successfully created a worker ${id} - took ${\n new Date().getTime() - startDate\n } ms.`\n );\n } catch (error) {\n throw new ExportError(\n 'Error encountered when creating a new page.'\n ).setError(error);\n }\n\n return {\n id,\n page,\n // Try to distribute the initial work count\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\n };\n },\n\n /**\n * Validates a worker page in the export pool, checking if it has exceeded\n * the work limit.\n *\n * @param {Object} workerHandle - The handle to the worker, containing the\n * worker's ID, a reference to the browser page, and work count.\n *\n * @returns {boolean} - Returns true if the worker is valid and within\n * the work limit; otherwise, returns false.\n */\n validate: async (workerHandle) => {\n // NOTE: In certain cases acquiring throws a TargetCloseError, which may\n // be caused by two things:\n // - The page is closed and attempted to be reused.\n // - Lost contact with the browser\n // What we're seeing in logs is that successive exports typically\n // succeeds, and the server recovers, indicating that it's likely\n // the first case. This is an attempt at allievating the issue by\n // simply not validating the worker if the page is null or closed.\n //\n // The actual result from when this happened, was that a worker would\n // be completely locked, stopping it from being acquired until\n // its work count reached the limit.\n if (!workerHandle.page || workerHandle.page?.isClosed()) {\n return false;\n }\n\n if (\n poolConfig.workLimit &&\n ++workerHandle.workCount > poolConfig.workLimit\n ) {\n log(\n 3,\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\n );\n return false;\n }\n return true;\n },\n\n /**\n * Destroys a worker entry in the export pool, closing its associated page.\n *\n * @param {Object} workerHandle - The handle to the worker, containing\n * the worker's ID and a reference to the browser page.\n */\n destroy: async (workerHandle) => {\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\n\n if (workerHandle.page && !workerHandle.page.isClosed()) {\n await workerHandle.page.close();\n }\n }\n\n // log: (message, level) => log(1, '[tarn] ' + message)\n};\n\n/**\n * Initializes the export pool with the provided configuration, creating\n * a browser instance and setting up worker resources.\n *\n * @param {Object} config - Configuration options for the export pool along\n * with custom puppeteer arguments for the puppeteer.launch function.\n */\nexport const initPool = async (config) => {\n // For the module scope usage\n poolConfig = config && config.pool ? { ...config.pool } : {};\n\n // Create a browser instance with the puppeteer arguments\n await createBrowser(config.puppeteerArgs);\n\n log(\n 3,\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\n );\n\n if (pool) {\n return log(\n 4,\n '[pool] Already initialized, please kill it before creating a new one.'\n );\n }\n\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\n poolConfig.minWorkers = poolConfig.maxWorkers;\n }\n\n try {\n // Create a pool along with a minimal number of resources\n pool = new Pool({\n // Get the create/validate/destroy/log functions\n ...factory,\n min: parseInt(poolConfig.minWorkers),\n max: parseInt(poolConfig.maxWorkers),\n acquireTimeoutMillis: poolConfig.acquireTimeout,\n createTimeoutMillis: poolConfig.createTimeout,\n destroyTimeoutMillis: poolConfig.destroyTimeout,\n idleTimeoutMillis: poolConfig.idleTimeout,\n createRetryIntervalMillis: poolConfig.createRetryInterval,\n reapIntervalMillis: poolConfig.reaperInterval,\n propagateCreateError: false\n });\n\n // Set events\n pool.on('release', async (resource) => {\n // Clear page\n const r = await clearPage(resource.page, false);\n log(\n 4,\n `[pool] Releasing a worker with ID ${resource.id}. Clear page status: ${r}.`\n );\n });\n\n pool.on('destroySuccess', (eventId, resource) => {\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\n resource.page = null;\n });\n\n const initialResources = [];\n // Create an initial number of resources\n for (let i = 0; i < poolConfig.minWorkers; i++) {\n try {\n const resource = await pool.acquire().promise;\n initialResources.push(resource);\n } catch (error) {\n logWithStack(2, error, '[pool] Could not create an initial resource.');\n }\n }\n\n // Release the initial number of resources back to the pool\n initialResources.forEach((resource) => {\n pool.release(resource);\n });\n\n log(\n 3,\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\n );\n } catch (error) {\n throw new ExportError(\n '[pool] Could not create the pool of workers.'\n ).setError(error);\n }\n};\n\n/**\n * Kills all workers in the pool, destroys the pool, and closes the browser\n * instance.\n *\n * @returns {Promise} A promise that resolves after the workers are\n * killed, the pool is destroyed, and the browser is closed.\n */\nexport async function killPool() {\n log(3, '[pool] Killing pool with all workers and closing browser.');\n\n // If still alive, destroy the pool of pages before closing a browser\n if (pool) {\n // Free up not released workers\n for (const worker of pool.used) {\n pool.release(worker.resource);\n }\n\n // Destroy the pool if it is still available\n if (!pool.destroyed) {\n await pool.destroy();\n log(4, '[browser] Destroyed the pool of resources.');\n }\n }\n\n // Close the browser instance\n await closeBrowser();\n}\n\n/**\n * Processes the export work using a worker from the pool. Acquires a worker\n * handle from the pool, performs the export using puppeteer, and releases\n * the worker handle back to the pool.\n *\n * @param {string} chart - The chart data or configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} A promise that resolves with the export resultand\n * options.\n *\n * @throws {ExportError} If an error occurs during the export process.\n */\nexport const postWork = async (chart, options) => {\n let workerHandle;\n\n try {\n log(4, '[pool] Work received, starting to process.');\n\n ++stats.exportAttempts;\n if (poolConfig.benchmarking) {\n getPoolInfo();\n }\n\n if (!pool) {\n throw new ExportError('Work received, but pool has not been started.');\n }\n\n // Acquire the worker along with the id of resource and work count\n const acquireCounter = measureTime();\n try {\n log(4, '[pool] Acquiring a worker handle.');\n workerHandle = await pool.acquire().promise;\n\n // Check the page acquire time\n if (options.server.benchmarking) {\n log(\n 5,\n options.payload?.requestId\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\n : '[benchmark]',\n `Acquired a worker handle: ${acquireCounter()}ms.`\n );\n }\n } catch (error) {\n throw new ExportError(\n (options.payload?.requestId\n ? `For request with ID ${options.payload?.requestId} - `\n : '') +\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\n ).setError(error);\n }\n log(4, '[pool] Acquired a worker handle.');\n\n if (!workerHandle.page) {\n throw new ExportError(\n 'Resolved worker page is invalid: the pool setup is wonky.'\n );\n }\n\n // Save the start time\n let workStart = new Date().getTime();\n\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\n\n // Perform an export on a puppeteer level\n const exportCounter = measureTime();\n const result = await puppeteerExport(workerHandle.page, chart, options);\n\n // Check if it's an error\n if (result instanceof Error) {\n // NOTE: If there's a rasterization timeout, we want need to flush the page.\n // This is because the page may be in a state where it's waiting for\n // the screenshot to finish even though the timeout has occured.\n // Which of course causes a lot of issues with the event system,\n // and page consistency.\n //\n // NOTE: Only page.screenshot will throw this, timeouts for PDF's are\n // handled by the page.pdf function itself.\n //\n // ...yes, this is ugly.\n if (result.message === 'Rasterization timeout') {\n workerHandle.workCount = poolConfig.workLimit + 1;\n workerHandle.page = null;\n }\n\n if (\n result.name === 'TimeoutError' ||\n result.message === 'Rasterization timeout'\n ) {\n throw new ExportError(\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\n ).setError(result);\n } else {\n throw new ExportError(\n (options.payload?.requestId\n ? `For request with ID ${options.payload?.requestId} - `\n : '') + `Error encountered during export: ${exportCounter()}ms.`\n ).setError(result);\n }\n }\n\n // Check the Puppeteer export time\n if (options.server.benchmarking) {\n log(\n 5,\n options.payload?.requestId\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\n : '[benchmark]',\n `Exported a chart sucessfully: ${exportCounter()}ms.`\n );\n }\n\n // Release the resource back to the pool\n pool.release(workerHandle);\n\n // Used for statistics in averageTime and processedWorkCount, which\n // in turn is used by the /health route.\n const workEnd = new Date().getTime();\n const exportTime = workEnd - workStart;\n stats.timeSpent += exportTime;\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\n\n log(4, `[pool] Work completed in ${exportTime} ms.`);\n\n // Otherwise return the result\n return {\n result,\n options\n };\n } catch (error) {\n ++stats.droppedExports;\n\n if (workerHandle) {\n pool.release(workerHandle);\n }\n\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\n error\n );\n }\n};\n\n/**\n * Retrieves the current pool instance.\n *\n * @returns {Object|null} The current pool instance if initialized, or null\n * if the pool has not been created.\n */\nexport const getPool = () => pool;\n\n/**\n * Retrieves pool information in JSON format, including minimum and maximum\n * workers, available workers, workers in use, and pending acquire requests.\n *\n * @returns {Object} Pool information in JSON format.\n */\nexport const getPoolInfoJSON = () => ({\n min: pool.min,\n max: pool.max,\n all: pool.numFree() + pool.numUsed(),\n available: pool.numFree(),\n used: pool.numUsed(),\n pending: pool.numPendingAcquires()\n});\n\n/**\n * Logs information about the current state of the pool, including the minimum\n * and maximum workers, available workers, workers in use, and pending acquire\n * requests.\n */\nexport function getPoolInfo() {\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\n\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\n log(5, `[pool] The number of all created resources: ${all}.`);\n log(5, `[pool] The number of available resources: ${available}.`);\n log(5, `[pool] The number of acquired resources: ${used}.`);\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\n}\n\nexport default {\n initPool,\n killPool,\n postWork,\n getPool,\n getPoolInfo,\n getPoolInfoJSON,\n getStats: () => stats\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync, writeFileSync } from 'fs';\n\nimport { getOptions, initExportSettings } from './config.js';\nimport { log, logWithStack } from './logger.js';\nimport { killPool, postWork, stats } from './pool.js';\nimport {\n fixType,\n handleResources,\n isCorrectJSON,\n optionsStringify,\n roundNumber,\n toBoolean,\n wrapAround\n} from './utils.js';\nimport { sanitize } from './sanitize.js';\nimport ExportError from './errors/ExportError.js';\n\nlet allowCodeExecution = false;\n\n/**\n * Starts an export process. The `settings` contains final options gathered\n * from all possible sources (config, env, cli, json). The `endCallback` is\n * called when the export is completed, with an error object as the first\n * argument and the second containing the base64 respresentation of a chart.\n *\n * @param {Object} settings - The settings object containing export\n * configuration.\n * @param {function} endCallback - The callback function to be invoked upon\n * finalizing work or upon error occurance of the exporting process.\n *\n * @returns {void} This function does not return a value directly; instead,\n * it communicates results via the endCallback.\n */\nexport const startExport = async (settings, endCallback) => {\n // Starting exporting process message\n log(4, '[chart] Starting the exporting process.');\n\n // Initialize options\n const options = initExportSettings(settings, getOptions());\n\n // Get the export options\n const exportOptions = options.export;\n\n // If SVG is an input (argument can be sent only by the request)\n if (options.payload?.svg && options.payload.svg !== '') {\n try {\n log(4, '[chart] Attempting to export from a SVG input.');\n\n const result = exportAsString(\n sanitize(options.payload.svg), // #209\n options,\n endCallback\n );\n\n ++stats.exportFromSvgAttempts;\n return result;\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading SVG input.').setError(error)\n );\n }\n }\n\n // Export using options from the file\n if (exportOptions.infile && exportOptions.infile.length) {\n // Try to read the file to get the string representation\n try {\n log(4, '[chart] Attempting to export from an input file.');\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\n return exportAsString(options.export.instr.trim(), options, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading input file.').setError(error)\n );\n }\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n try {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading raw input.').setError(error)\n );\n }\n }\n\n // No input specified, pass an error message to the callback\n return endCallback(\n new ExportError(\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\n )\n );\n};\n\n/**\n * Starts a batch export process for multiple charts based on the information\n * in the batch option. The batch is a string in the following format:\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\n *\n * @param {Object} options - The options object containing configuration for\n * a batch export.\n *\n * @returns {Promise} A Promise that resolves once the batch export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * any of the batch export process.\n */\nexport const batchExport = async (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (error, info) => {\n // Throw an error\n if (error) {\n throw error;\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n info.options.export.type !== 'svg'\n ? Buffer.from(info.result, 'base64')\n : info.result\n );\n }\n )\n );\n }\n }\n\n try {\n // Await all exports are done\n await Promise.all(batchFunctions);\n\n // Kill pool and close browser after finishing batch export\n await killPool();\n } catch (error) {\n throw new ExportError(\n '[chart] Error encountered during batch export.'\n ).setError(error);\n }\n};\n\n/**\n * Starts a single export process based on the specified options.\n *\n * @param {Object} options - The options object containing configuration for\n * a single export.\n *\n * @returns {Promise} A Promise that resolves once the single export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * the single export process.\n */\nexport const singleExport = async (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n await startExport(options, async (error, info) => {\n // Exit process when error\n if (error) {\n throw error;\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\n );\n\n // Kill pool and close browser after finishing single export\n await killPool();\n });\n};\n\n/**\n * Determines the size and scale for chart export based on the provided options.\n *\n * @param {Object} options - The options object containing configuration for\n * chart export.\n *\n * @returns {Object} An object containing the calculated height, width,\n * and scale for the chart export.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n const size = {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n\n // Get rid of potential px and %\n for (let [param, value] of Object.entries(size)) {\n size[param] =\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\n }\n return size;\n};\n\n/**\n * Function for finalizing options before export.\n *\n * @param {Object} options - The options object containing configuration for\n * the export process.\n * @param {Object} chartJson - The JSON representation of the chart.\n * @param {Function} endCallback - The callback function to be called upon\n * completion or error.\n * @param {string} svg - The SVG representation of the chart.\n *\n * @returns {Promise} A Promise that resolves once the export process\n * is completed.\n */\nconst doExport = async (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customLogic: customLogicOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customLogicOptions.allowCodeExecution === 'boolean'\n ? customLogicOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customLogicOptions) {\n customLogicOptions = options.customLogic = {};\n } else if (allowCodeExecutionScoped) {\n if (typeof options.customLogic.resources === 'string') {\n // Process resources\n options.customLogic.resources = handleResources(\n options.customLogic.resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } else if (!options.customLogic.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customLogic.resources = handleResources(\n resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[chart] Unable to load the default resources.json file.`\n );\n }\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customLogicOptions) {\n if (\n customLogicOptions.callback ||\n customLogicOptions.resources ||\n customLogicOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return endCallback(\n new ExportError(\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\n )\n );\n }\n\n // Reset all additional custom code\n customLogicOptions.callback = false;\n customLogicOptions.resources = false;\n customLogicOptions.customCode = false;\n }\n\n // Clean properties to keep it lean and mean\n if (chartJson) {\n chartJson.chart = chartJson.chart || {};\n chartJson.exporting = chartJson.exporting || {};\n chartJson.exporting.enabled = false;\n }\n\n exportOptions.constr = exportOptions.constr || 'chart';\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\n if (exportOptions.type === 'svg') {\n exportOptions.width = false;\n }\n\n // Prepare global and theme options\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\n try {\n if (exportOptions && exportOptions[optionsName]) {\n if (\n typeof exportOptions[optionsName] === 'string' &&\n exportOptions[optionsName].endsWith('.json')\n ) {\n exportOptions[optionsName] = isCorrectJSON(\n readFileSync(exportOptions[optionsName], 'utf8'),\n true\n );\n } else {\n exportOptions[optionsName] = isCorrectJSON(\n exportOptions[optionsName],\n true\n );\n }\n }\n } catch (error) {\n exportOptions[optionsName] = {};\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\n }\n });\n\n // Prepare the customCode\n if (customLogicOptions.allowCodeExecution) {\n try {\n customLogicOptions.customCode = wrapAround(\n customLogicOptions.customCode,\n customLogicOptions.allowFileResources\n );\n } catch (error) {\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\n }\n }\n\n // Get the callback\n if (\n customLogicOptions &&\n customLogicOptions.callback &&\n customLogicOptions.callback?.indexOf('{') < 0\n ) {\n // The allowFileResources is always set to false for HTTP requests to avoid\n // injecting arbitrary files from the fs\n if (customLogicOptions.allowFileResources) {\n try {\n customLogicOptions.callback = readFileSync(\n customLogicOptions.callback,\n 'utf8'\n );\n } catch (error) {\n customLogicOptions.callback = false;\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\n }\n } else {\n customLogicOptions.callback = false;\n }\n }\n\n // Size search\n options.export = {\n ...options.export,\n ...findChartSize(options)\n };\n\n // Post the work to the pool\n try {\n const result = await postWork(\n exportOptions.strInj || chartJson || svg,\n options\n );\n return endCallback(false, result);\n } catch (error) {\n return endCallback(error);\n }\n};\n\n/**\n * Performs a direct inject of options before export. The function attempts\n * to stringify the provided options and removes unnecessary characters,\n * ensuring a clean and formatted input. The resulting string is saved as\n * a \"stright inject\" string in the export options. It then invokes the\n * doExport function with the updated options.\n *\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\n * a server (see the --allowCodeExecution option).\n *\n * @param {Object} options - The export options containing the input\n * to be injected.\n * @param {function} endCallback - The callback function to be invoked\n * at the end of the process.\n *\n * @returns {Promise} A Promise that resolves with the result of the export\n * operation or rejects with an error if any issues occur during the process.\n */\nconst doStraightInject = (options, endCallback) => {\n try {\n let strInj;\n let instr = options.export.instr || options.export.options;\n\n if (typeof instr !== 'string') {\n // Try to stringify options\n strInj = instr = optionsStringify(\n instr,\n options.customLogic?.allowCodeExecution\n );\n }\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\n\n // Get rid of the ;\n if (strInj[strInj.length - 1] === ';') {\n strInj = strInj.substring(0, strInj.length - 1);\n }\n\n // Save as stright inject string\n options.export.strInj = strInj;\n return doExport(options, false, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError(\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\n ).setError(error)\n );\n }\n};\n\n/**\n * Exports a string based on the provided options and invokes an end callback.\n *\n * @param {string} stringToExport - The string content to be exported.\n * @param {Object} options - Export options, including customLogic with\n * allowCodeExecution flag.\n * @param {Function} endCallback - Callback function to be invoked at the end\n * of the export process.\n *\n * @returns {any} Result of the export process or an error if encountered.\n */\nconst exportAsString = (stringToExport, options, endCallback) => {\n const { allowCodeExecution } = options.customLogic;\n\n // Check if it is SVG\n if (\n stringToExport.indexOf('= 0 ||\n stringToExport.indexOf('= 0\n ) {\n log(4, '[chart] Parsing input as SVG.');\n return doExport(options, false, endCallback, stringToExport);\n }\n\n try {\n // Try to parse to JSON and call the doExport function\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\n\n // If a correct JSON, do the export\n return doExport(options, chartJSON, endCallback);\n } catch (error) {\n // Not a valid JSON\n if (toBoolean(allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n } else {\n // Do not allow straight injection without the allowCodeExecution flag\n return endCallback(\n new ExportError(\n '[chart] Only JSON 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 flag.'\n ).setError(error)\n );\n }\n }\n};\n\n/**\n * Retrieves and returns the current status of code execution permission.\n *\n * @returns {any} The value of allowCodeExecution.\n */\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\n/**\n * Sets the code execution permission based on the provided boolean value.\n *\n * @param {any} value - The value to be converted and assigned\n * to allowCodeExecution.\n */\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/**\n * @overview Used to sanitize the strings coming from the exporting module\n * to prevent XSS attacks (with the DOMPurify library).\n **/\n\nimport { JSDOM } from 'jsdom';\nimport DOMPurify from 'dompurify';\n\n/**\n * Sanitizes a given HTML string by removing tags and any content within them.\n *\n * @param {string} input The HTML string to be sanitized.\n * @returns {string} The sanitized HTML string.\n */\nexport function sanitize(input) {\n const window = new JSDOM('').window;\n const purify = DOMPurify(window);\n return purify.sanitize(input, {\n ADD_TAGS: ['foreignObject'],\n // Dissalow all xlinks in incoming SVG\n FORBID_ATTR: ['xlink:href']\n });\n}\n\nexport default sanitize;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { log } from './logger.js';\n\n// Array that contains ids of all ongoing intervals\nconst intervalIds = [];\n\n/**\n * Adds id of a setInterval to the intervalIds array.\n *\n * @param {NodeJS.Timeout} id - Id of an interval.\n */\nexport const addInterval = (id) => {\n intervalIds.push(id);\n};\n\n/**\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\n */\nexport const clearAllIntervals = () => {\n log(4, `[server] Clearing all registered intervals.`);\n for (const id of intervalIds) {\n clearInterval(id);\n }\n};\n\nexport default {\n addInterval,\n clearAllIntervals\n};\n","import { envs } from '../envs.js';\nimport { logWithStack } from '../logger.js';\n\n/**\n * Middleware for logging errors with stack trace and handling error response.\n *\n * @param {Error} error - The error object.\n * @param {Express.Request} req - The Express request object.\n * @param {Express.Response} res - The Express response object.\n * @param {Function} next - The next middleware function.\n */\nconst logErrorMiddleware = (error, req, res, next) => {\n // Display the error with stack in a correct format\n logWithStack(1, error);\n\n // Delete the stack for the environment other than the development\n if (envs.OTHER_NODE_ENV !== 'development') {\n delete error.stack;\n }\n\n // Call the returnErrorMiddleware\n next(error);\n};\n\n/**\n * Middleware for returning error response.\n *\n * @param {Error} error - The error object.\n * @param {Express.Request} req - The Express request object.\n * @param {Express.Response} res - The Express response object.\n * @param {Function} next - The next middleware function.\n */\nconst returnErrorMiddleware = (error, req, res, next) => {\n // Gather all requied information for the response\n const { statusCode: stCode, status, message, stack } = error;\n const statusCode = stCode || status || 400;\n\n // Set and return response\n res.status(statusCode).json({ statusCode, message, stack });\n};\n\nexport default (app) => {\n // Add log error middleware\n app.use(logErrorMiddleware);\n\n // Add set status and return error middleware\n app.use(returnErrorMiddleware);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport rateLimit from 'express-rate-limit';\n\nimport { log } from '../logger.js';\n\n/**\n * Middleware for enabling rate limiting on the specified Express app.\n *\n * @param {Express} app - The Express app instance.\n * @param {Object} limitConfig - Configuration options for rate limiting.\n */\nexport default (app, limitConfig) => {\n const msg =\n 'Too many requests, you have been rate limited. Please try again later.';\n\n // Options for the rate limiter\n const rateOptions = {\n max: limitConfig.maxRequests || 30,\n window: limitConfig.window || 1,\n delay: limitConfig.delay || 0,\n trustProxy: limitConfig.trustProxy || false,\n skipKey: limitConfig.skipKey || false,\n skipToken: limitConfig.skipToken || false\n };\n\n // Set if behind a proxy\n if (rateOptions.trustProxy) {\n app.enable('trust proxy');\n }\n\n // Create a limiter\n const limiter = rateLimit({\n windowMs: rateOptions.window * 60 * 1000,\n // Limit each IP to 100 requests per windowMs\n max: rateOptions.max,\n // Disable delaying, full speed until the max limit is reached\n delayMs: rateOptions.delay,\n handler: (request, response) => {\n response.format({\n json: () => {\n response.status(429).send({ message: msg });\n },\n default: () => {\n response.status(429).send(msg);\n }\n });\n },\n skip: (request) => {\n // Allow bypassing the limiter if a valid key/token has been sent\n if (\n rateOptions.skipKey !== false &&\n rateOptions.skipToken !== false &&\n request.query.key === rateOptions.skipKey &&\n request.query.access_token === rateOptions.skipToken\n ) {\n log(4, '[rate limiting] Skipping rate limiter.');\n return true;\n }\n return false;\n }\n });\n\n // Use a limiter as a middleware\n app.use(limiter);\n\n log(\n 3,\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\n );\n};\n","import ExportError from './ExportError.js';\n\nclass HttpError extends ExportError {\n constructor(message, status) {\n super(message);\n this.status = this.statusCode = status;\n }\n\n setStatus(status) {\n this.status = status;\n return this;\n }\n}\n\nexport default HttpError;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { updateVersion, version } from '../../cache.js';\nimport { envs } from '../../envs.js';\n\nimport HttpError from '../../errors/HttpError.js';\n\n/**\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\n * the Highcharts version on the server.\n *\n * TODO: Add auth token and connect to API\n */\nexport default (app) =>\n !app\n ? false\n : app.post(\n '/version/change/:newVersion',\n async (request, response, next) => {\n try {\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\n\n // Check the existence of the token\n if (!adminToken || !adminToken.length) {\n throw new HttpError(\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\n 401\n );\n }\n\n // Check if the hc-auth header contain a correct token\n const token = request.get('hc-auth');\n if (!token || token !== adminToken) {\n throw new HttpError(\n 'Invalid or missing token: Set the token in the hc-auth header.',\n 401\n );\n }\n\n // Compare versions\n const newVersion = request.params.newVersion;\n if (newVersion) {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n await updateVersion(newVersion);\n } catch (error) {\n throw new HttpError(\n `Version change: ${error.message}`,\n error.statusCode\n ).setError(error);\n }\n\n // Success\n response.status(200).send({\n statusCode: 200,\n version: version(),\n message: `Successfully updated Highcharts to version: ${newVersion}.`\n });\n } else {\n // No version specified\n throw new HttpError('No new version supplied.', 400);\n }\n } catch (error) {\n next(error);\n }\n }\n );\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\n\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\nimport { getOptions, mergeConfigOptions } from '../../config.js';\nimport { log } from '../../logger.js';\nimport {\n fixType,\n isCorrectJSON,\n isObjectEmpty,\n isPrivateRangeUrlFound,\n optionsStringify,\n measureTime\n} from '../../utils.js';\n\nimport HttpError from '../../errors/HttpError.js';\n\n// Reversed MIME types\nconst reversedMime = {\n png: 'image/png',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n pdf: 'application/pdf',\n svg: 'image/svg+xml'\n};\n\n// The requests counter\nlet requestsCounter = 0;\n\n// The array of callbacks to call before a request\nconst beforeRequest = [];\n\n// The array of callbacks to call after a request\nconst afterRequest = [];\n\n/**\n * Invokes an array of callback functions with specified parameters, allowing\n * customization of request handling.\n *\n * @param {Function[]} callbacks - An array of callback functions\n * to be executed.\n * @param {Express.Request} request - The Express request object.\n * @param {Express.Response} response - The Express response object.\n * @param {Object} data - An object containing parameters like id, uniqueId,\n * type, and body.\n *\n * @returns {boolean} - Returns a boolean indicating the overall result\n * of the callback invocations.\n */\nconst doCallbacks = (callbacks, request, response, data) => {\n let result = true;\n const { id, uniqueId, type, body } = data;\n\n callbacks.some((callback) => {\n if (callback) {\n let callResponse = callback(request, response, id, uniqueId, type, body);\n\n if (callResponse !== undefined && callResponse !== true) {\n result = callResponse;\n }\n\n return true;\n }\n });\n\n return result;\n};\n\n/**\n * Handles the export requests from the client.\n *\n * @param {Express.Request} request - The Express request object.\n * @param {Express.Response} response - The Express response object.\n * @param {Function} next - The next middleware function.\n *\n * @returns {Promise} - A promise that resolves once the export process\n * is complete.\n */\nconst exportHandler = async (request, response, next) => {\n try {\n // Start counting time\n const stopCounter = measureTime();\n\n // Create a unique ID for a request\n const uniqueId = uuid().replace(/-/g, '');\n\n // Get the current server's general options\n const defaultOptions = getOptions();\n\n const body = request.body;\n const id = ++requestsCounter;\n\n let type = fixType(body.type);\n\n // Throw 'Bad Request' if there's no body\n if (!body || isObjectEmpty(body)) {\n throw new HttpError(\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\n 400\n );\n }\n\n // All of the below can be used\n let instr = isCorrectJSON(body.infile || body.options || body.data);\n\n // Throw 'Bad Request' if there's no JSON or SVG to export\n if (!instr && !body.svg) {\n log(\n 2,\n `The request with ID ${uniqueId} from ${\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\n } was incorrect:\n Content-Type: ${request.headers['content-type']}. \n Chart constructor: ${body.constr}.\n Dimensions: ${body.width}x${body.height} @ ${body.scale} scale.\n Type: ${type}.\n Is SVG set? ${typeof body.svg !== 'undefined'}.\n B64? ${typeof body.b64 !== 'undefined'}.\n No download? ${typeof body.noDownload !== 'undefined'}.\n\n Payload received: ${JSON.stringify(body.infile || body.options || body.data || body.svg)}\n\n `\n );\n\n throw new HttpError(\n \"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.\",\n 400\n );\n }\n\n let callResponse = false;\n\n // Call the before request functions\n callResponse = doCallbacks(beforeRequest, request, response, {\n id,\n uniqueId,\n type,\n body\n });\n\n // Block the request if one of a callbacks failed\n if (callResponse !== true) {\n return response.send(callResponse);\n }\n\n let connectionAborted = false;\n\n // In case the connection is closed, force to abort further actions\n request.socket.on('close', (hadErrors) => {\n if (hadErrors) {\n connectionAborted = true;\n }\n });\n\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\n\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\n\n // Gather and organize options from the payload\n const requestOptions = {\n export: {\n instr,\n type,\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\n height: body.height,\n width: body.width,\n scale: body.scale || defaultOptions.export.scale,\n globalOptions: isCorrectJSON(body.globalOptions, true),\n themeOptions: isCorrectJSON(body.themeOptions, true)\n },\n customLogic: {\n allowCodeExecution: getAllowCodeExecution(),\n allowFileResources: false,\n resources: isCorrectJSON(body.resources, true),\n callback: body.callback,\n customCode: body.customCode\n }\n };\n\n if (instr) {\n // Stringify JSON with options\n requestOptions.export.instr = optionsStringify(\n instr,\n requestOptions.customLogic.allowCodeExecution\n );\n }\n\n // Merge the request options into default ones\n const options = mergeConfigOptions(defaultOptions, requestOptions);\n\n // Save the JSON if exists\n options.export.options = instr;\n\n // Lastly, add the server specific arguments into options as payload\n options.payload = {\n svg: body.svg || false,\n b64: body.b64 || false,\n noDownload: body.noDownload || false,\n requestId: uniqueId\n };\n\n // Test xlink:href elements from payload's SVG\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\n throw new HttpError(\n '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.',\n 400\n );\n }\n\n // Start the export process\n await startExport(options, (error, info) => {\n // Remove the close event from the socket\n request.socket.removeAllListeners('close');\n\n // After the whole exporting process\n if (defaultOptions.server.benchmarking) {\n log(\n 5,\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\n );\n }\n\n // If the connection was closed, do nothing\n if (connectionAborted) {\n return log(\n 3,\n `[export] The client closed the connection before the chart finished processing.`\n );\n }\n\n // If error, log it and send it to the error middleware\n if (error) {\n throw error;\n }\n\n // If data is missing, log the message and send it to the error middleware\n if (!info || !info.result) {\n throw new HttpError(\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\n 400\n );\n }\n\n // Get the type from options\n type = info.options.export.type;\n\n // The after request callbacks\n doCallbacks(afterRequest, request, response, { id, body: info.result });\n\n if (info.result) {\n // If only base64 is required, return it\n if (body.b64) {\n // SVG Exception for the Highcharts 11.3.0 version\n if (type === 'pdf' || type == 'svg') {\n return response.send(\n Buffer.from(info.result, 'utf8').toString('base64')\n );\n }\n\n return response.send(info.result);\n }\n\n // Set correct content type\n response.header('Content-Type', reversedMime[type] || 'image/png');\n\n // Decide whether to download or not chart file\n if (!body.noDownload) {\n response.attachment(\n `${request.params.filename || request.body.filename || 'chart'}.${\n type || 'png'\n }`\n );\n }\n\n // If SVG, return plain content\n return type === 'svg'\n ? response.send(info.result)\n : response.send(Buffer.from(info.result, 'base64'));\n }\n });\n } catch (error) {\n next(error);\n }\n};\n\nexport default (app) => {\n /**\n * Adds the POST / a route for handling POST requests at the root endpoint.\n */\n app.post('/', exportHandler);\n\n /**\n * Adds the POST /:filename a route for handling POST requests with\n * a specified filename parameter.\n */\n app.post('/:filename', exportHandler);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { join as pather } from 'path';\nimport { log } from '../../logger.js';\n\nimport { version } from '../../cache.js';\nimport { addInterval } from '../../intervals.js';\nimport pool from '../../pool.js';\nimport { __dirname } from '../../utils.js';\n\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\n\nconst serverStartTime = new Date();\n\nconst successRates = [];\nconst recordInterval = 60 * 1000; // record every minute\nconst windowSize = 30; // 30 minutes\n\n/**\n * Calculates moving average indicator based on the data from the successRates\n * array.\n *\n * @returns {number} - A moving average for success ratio of the server exports.\n */\nfunction calculateMovingAverage() {\n const sum = successRates.reduce((a, b) => a + b, 0);\n return sum / successRates.length;\n}\n\n/**\n * Starts the interval responsible for calculating current success rate ratio\n * and gathers\n *\n * @returns {NodeJS.Timeout} id - Id of an interval.\n */\nexport const startSuccessRate = () =>\n setInterval(() => {\n const stats = pool.getStats();\n const successRatio =\n stats.exportAttempts === 0\n ? 1\n : (stats.performedExports / stats.exportAttempts) * 100;\n\n successRates.push(successRatio);\n if (successRates.length > windowSize) {\n successRates.shift();\n }\n }, recordInterval);\n\n/**\n * Adds the /health and /success-moving-average routes\n * which output basic stats for the server.\n */\nexport default function addHealthRoutes(app) {\n if (!app) {\n return false;\n }\n\n // Start processing success rate ratio interval and save its id to the array\n // for the graceful clearing on shutdown with injected addInterval funtion\n addInterval(startSuccessRate());\n\n app.get('/health', (_, res) => {\n const stats = pool.getStats();\n const period = successRates.length;\n const movingAverage = calculateMovingAverage();\n\n log(4, '[health.js] GET /health [200] - returning server health.');\n\n res.send({\n status: 'OK',\n bootTime: serverStartTime,\n uptime:\n Math.floor(\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\n ) + ' minutes',\n version: pkgFile.version,\n highchartsVersion: version(),\n averageProcessingTime: stats.spentAverage,\n performedExports: stats.performedExports,\n failedExports: stats.droppedExports,\n exportAttempts: stats.exportAttempts,\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\n // eslint-disable-next-line import/no-named-as-default-member\n pool: pool.getPoolInfoJSON(),\n\n // Moving average\n period,\n movingAverage,\n message:\n isNaN(movingAverage) || !successRates.length\n ? 'Too early to report. No exports made yet. Please check back soon.'\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\n\n // SVG/JSON attempts\n svgExportAttempts: stats.exportFromSvgAttempts,\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\n });\n });\n}\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { promises as fsPromises } from 'fs';\nimport { posix } from 'path';\n\nimport cors from 'cors';\nimport express from 'express';\nimport http from 'http';\nimport https from 'https';\nimport multer from 'multer';\n\nimport errorHandler from './error.js';\nimport rateLimit from './rate_limit.js';\nimport { log, logWithStack } from '../logger.js';\nimport { __dirname } from '../utils.js';\n\nimport vSwitchRoute from './routes/change_hc_version.js';\nimport exportRoutes from './routes/export.js';\nimport healthRoute from './routes/health.js';\nimport uiRoute from './routes/ui.js';\n\nimport ExportError from '../errors/ExportError.js';\n\n// Array of an active servers\nconst activeServers = new Map();\n\n// Create express app\nconst app = express();\n\n// Disable the X-Powered-By header\napp.disable('x-powered-by');\n\n// Enable CORS support\napp.use(cors());\n\n// Getting a lot of RangeNotSatisfiableError exception.\n// Even though this is a deprecated options, let's try to set it to false.\napp.use((_req, res, next) => {\n res.set('Accept-Ranges', 'none');\n next();\n});\n\n/**\n * Attach error handlers to the server.\n *\n * @param {http.Server} server - The HTTP/HTTPS server instance.\n */\nconst attachServerErrorHandlers = (server) => {\n server.on('clientError', (error, socket) => {\n logWithStack(\n 1,\n error,\n `[server] Client error: ${error.message}, destroying socket.`\n );\n socket.destroy();\n });\n\n server.on('error', (error) => {\n logWithStack(1, error, `[server] Server error: ${error.message}`);\n });\n\n server.on('connection', (socket) => {\n socket.on('error', (error) => {\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\n });\n });\n};\n\n/**\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\n * object contains all server related properties (see the `server` section\n * in the `lib/schemas/config.js` file for a reference).\n *\n * @param {Object} serverConfig - The server configuration object.\n *\n * @throws {ExportError} - Throws an error if the server cannot be configured\n * and started.\n */\nexport const startServer = async (serverConfig) => {\n try {\n // TODO: Read from config/env\n // NOTE:\n // Too big limits lead to timeouts in the export process when the\n // rasterization timeout is set too low.\n const uploadLimitMiB = serverConfig.maxUploadSize || 3;\n const uploadLimitBytes = uploadLimitMiB * 1024 * 1024;\n\n // Enable parsing of form data (files) with Multer package\n const storage = multer.memoryStorage();\n const upload = multer({\n storage,\n limits: {\n fieldSize: uploadLimitBytes\n }\n });\n\n // Enable body parser\n app.use(express.json({ limit: uploadLimitBytes }));\n app.use(express.urlencoded({ extended: true, limit: uploadLimitBytes }));\n\n // Use only non-file multipart form fields\n app.use(upload.none());\n\n // Stop if not enabled\n if (!serverConfig.enable) {\n return false;\n }\n\n // Listen HTTP server\n if (!serverConfig.ssl.force) {\n // Main server instance (HTTP)\n const httpServer = http.createServer(app);\n\n // Attach error handlers and listen to the server\n attachServerErrorHandlers(httpServer);\n\n // Listen\n httpServer.listen(serverConfig.port, serverConfig.host);\n\n // Save the reference to HTTP server\n activeServers.set(serverConfig.port, httpServer);\n\n log(\n 3,\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\n );\n }\n\n // Listen HTTPS server\n if (serverConfig.ssl.enable) {\n // Set up an SSL server also\n let key, cert;\n\n try {\n // Get the SSL key\n key = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.key'),\n 'utf8'\n );\n\n // Get the SSL certificate\n cert = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\n 'utf8'\n );\n } catch (error) {\n log(\n 2,\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\n );\n }\n\n if (key && cert) {\n // Main server instance (HTTPS)\n const httpsServer = https.createServer({ key, cert }, app);\n\n // Attach error handlers and listen to the server\n attachServerErrorHandlers(httpsServer);\n\n // Listen\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\n\n // Save the reference to HTTPS server\n activeServers.set(serverConfig.ssl.port, httpsServer);\n\n log(\n 3,\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\n );\n }\n }\n\n // Enable the rate limiter if config says so\n if (\n serverConfig.rateLimiting &&\n serverConfig.rateLimiting.enable &&\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\n ) {\n rateLimit(app, serverConfig.rateLimiting);\n }\n\n // Set up static folder's route\n app.use(express.static(posix.join(__dirname, 'public')));\n\n // Set up routes\n healthRoute(app);\n exportRoutes(app);\n uiRoute(app);\n vSwitchRoute(app);\n\n // Set up centralized error handler\n errorHandler(app);\n } catch (error) {\n throw new ExportError(\n '[server] Could not configure and start the server.'\n ).setError(error);\n }\n};\n\n/**\n * Closes all servers associated with Express app instance.\n */\nexport const closeServers = () => {\n log(4, `[server] Closing all servers.`);\n for (const [port, server] of activeServers) {\n server.close(() => {\n activeServers.delete(port);\n log(4, `[server] Closed server on port: ${port}.`);\n });\n }\n};\n\n/**\n * Get all servers associated with Express app instance.\n *\n * @returns {Array} - Servers associated with Express app instance.\n */\nexport const getServers = () => activeServers;\n\n/**\n * Enable rate limiting for the server.\n *\n * @param {Object} limitConfig - Configuration object for rate limiting.\n */\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\n\n/**\n * Get the Express instance.\n *\n * @returns {Object} - The Express instance.\n */\nexport const getExpress = () => express;\n\n/**\n * Get the Express app instance.\n *\n * @returns {Object} - The Express app instance.\n */\nexport const getApp = () => app;\n\n/**\n * Apply middleware(s) to a specific path.\n *\n * @param {string} path - The path to which the middleware(s) should be applied.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const use = (path, ...middlewares) => {\n app.use(path, ...middlewares);\n};\n\n/**\n * Set up a route with GET method and apply middleware(s).\n *\n * @param {string} path - The route path.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const get = (path, ...middlewares) => {\n app.get(path, ...middlewares);\n};\n\n/**\n * Set up a route with POST method and apply middleware(s).\n *\n * @param {string} path - The route path.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const post = (path, ...middlewares) => {\n app.post(path, ...middlewares);\n};\n\nexport default {\n startServer,\n closeServers,\n getServers,\n enableRateLimiting,\n getExpress,\n getApp,\n use,\n get,\n post\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { join } from 'path';\n\nimport { __dirname } from '../../utils.js';\n\n/**\n * Adds the GET / route for a UI when enabled on the export server.\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/', (_request, response) => {\n response.sendFile(join(__dirname, 'public', 'index.html'), {\n acceptRanges: false\n });\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { clearAllIntervals } from './intervals.js';\nimport { killPool } from './pool.js';\nimport { closeServers } from './server/server.js';\n\n/**\n * Clean up function to trigger before ending process for the graceful shutdown.\n *\n * @param {number} exitCode - An exit code for the process.exit() function.\n */\nexport const shutdownCleanUp = async (exitCode) => {\n // Await freeing all resources\n await Promise.allSettled([\n // Clear all ongoing intervals\n clearAllIntervals(),\n\n // Get available server instances (HTTP/HTTPS) and close them\n closeServers(),\n\n // Close pool along with its workers and the browser instance, if exists\n killPool()\n ]);\n\n // Exit process with a correct code\n process.exit(exitCode);\n};\n\nexport default {\n shutdownCleanUp\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport 'colors';\n\nimport { checkAndUpdateCache } from './cache.js';\nimport {\n batchExport,\n setAllowCodeExecution,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\nimport {\n initLogging,\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging\n} from './logger.js';\nimport { initPool, killPool } from './pool.js';\nimport { shutdownCleanUp } from './resource_release.js';\nimport server, { startServer } from './server/server.js';\nimport { printLogo, printUsage } from './utils.js';\n\n/**\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\n * 'uncaughtException' events.\n */\nconst attachProcessExitListeners = () => {\n log(3, '[process] Attaching exit listeners to the process.');\n\n // Handler for the 'exit'\n process.on('exit', (code) => {\n log(4, `Process exited with code ${code}.`);\n });\n\n // Handler for the 'SIGINT'\n process.on('SIGINT', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGTERM'\n process.on('SIGTERM', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGHUP'\n process.on('SIGHUP', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'uncaughtException'\n process.on('uncaughtException', async (error, name) => {\n logWithStack(1, error, `The ${name} error.`);\n await shutdownCleanUp(1);\n });\n};\n\n/**\n * Initializes the export process. Tasks such as configuring logging, checking\n * cache and sources, and initializing the pool of resources happen during\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\n *\n * @param {Object} options - All export options.\n *\n * @returns {Promise} Promise resolving to the updated export options.\n */\nconst initExport = async (options) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customLogic && options.customLogic.allowCodeExecution\n );\n\n // Init the logging\n initLogging(options.logging);\n\n // Attach process' exit listeners\n if (options.other.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n // Check if cache needs to be updated\n await checkAndUpdateCache(options);\n\n // Init the pool\n await initPool({\n pool: options.pool || {\n minWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer.args || []\n });\n\n // Return updated options\n return options;\n};\n\nexport default {\n // Server\n server,\n startServer,\n\n // Exporting\n initExport,\n singleExport,\n batchExport,\n startExport,\n\n // Pool\n initPool,\n killPool,\n\n // Other\n setOptions,\n shutdownCleanUp,\n\n // Logs\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n\n // Utils\n mapToNewConfig,\n manualConfig,\n printLogo,\n printUsage\n};\n"],"names":["scriptsNames","core","modules","indicators","custom","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","maxUploadSize","cliName","enable","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","toConsole","toFile","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","pathCreated","levelsDesc","title","color","listeners","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","key","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","option","entries","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","headers","Referer","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","Function","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","isClosed","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","abs","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","r","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","closeBrowser","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","FORBID_ATTR","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","vSwitchRoute","post","adminToken","token","newVersion","params","updateVersion","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","connection","remoteAddress","b64","noDownload","connectionAborted","socket","hadErrors","toLowerCase","substr","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","_req","set","attachServerErrorHandlers","startServer","serverConfig","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","_request","sendFile","acceptRanges","uiRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","loggingOptions","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"0lBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,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,YAEFC,WAAY,CAAC,kBACbC,OAAQ,CACN,wEACA,mGAMSC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOR,EAAaC,KACpBQ,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOR,EAAaE,QACpBO,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOR,EAAaG,WACpBM,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAOR,EAAaI,OACpBK,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,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"} +{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Possible names for Highcharts scripts\nexport const scriptsNames = {\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n modules: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'parallel-coordinates',\n 'accessibility',\n // 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'data-tools',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'tiledwebmap',\n 'timeline',\n 'treemap',\n 'treegraph',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'geoheatmap',\n 'pyramid3d',\n 'networkgraph',\n 'overlapping-datalabels',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'series-on-point',\n 'solid-gauge',\n 'sonification',\n // 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi',\n 'flowmap',\n 'export-data',\n 'navigator',\n 'textpath'\n ],\n indicators: ['indicators-all'],\n custom: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\n ]\n};\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [\n '--allow-running-insecure-content',\n '--ash-no-nudges',\n '--autoplay-policy=user-gesture-required',\n '--block-new-web-contents',\n '--disable-accelerated-2d-canvas',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-checker-imaging',\n '--disable-client-side-phishing-detection',\n '--disable-component-extensions-with-background-pages',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-logging',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-search-engine-choice-screen',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-site-isolation-trials',\n '--disable-speech-api',\n '--disable-sync',\n '--enable-unsafe-webgpu',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-startup-window',\n '--no-zygote',\n '--password-store=basic',\n '--process-per-tab',\n '--use-mock-keychain'\n ],\n type: 'string[]',\n description: 'Arguments array to send to Puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n type: 'string',\n envLink: 'HIGHCHARTS_VERSION',\n description: 'The Highcharts version to be used.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n type: 'string',\n envLink: 'HIGHCHARTS_CDN_URL',\n description: 'The CDN URL for Highcharts scripts to be used.'\n },\n coreScripts: {\n value: scriptsNames.core,\n type: 'string[]',\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n description: 'The core Highcharts scripts to fetch.'\n },\n moduleScripts: {\n value: scriptsNames.modules,\n type: 'string[]',\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\n description: 'The modules of Highcharts to fetch.'\n },\n indicatorScripts: {\n value: scriptsNames.indicators,\n type: 'string[]',\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\n description: 'The indicators of Highcharts to fetch.'\n },\n customScripts: {\n value: scriptsNames.custom,\n type: 'string[]',\n description: 'Additional custom scripts or dependencies to fetch.'\n },\n forceFetch: {\n value: false,\n type: 'boolean',\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n description:\n 'The flag to determine whether to refetch all scripts after each server rerun.'\n },\n cachePath: {\n value: '.cache',\n type: 'string',\n envLink: 'HIGHCHARTS_CACHE_PATH',\n description:\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\n },\n type: {\n value: 'png',\n type: 'string',\n envLink: 'EXPORT_TYPE',\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\n },\n constr: {\n value: 'chart',\n type: 'string',\n envLink: 'EXPORT_CONSTR',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\n },\n defaultHeight: {\n value: 400,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n description:\n 'the default height of the exported chart. Used when no value is set.'\n },\n defaultWidth: {\n value: 600,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_WIDTH',\n description:\n 'The default width of the exported chart. Used when no value is set.'\n },\n defaultScale: {\n value: 1,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_SCALE',\n description:\n 'The default scale of the exported chart. Used when no value is set.'\n },\n height: {\n value: false,\n type: 'number',\n description:\n 'The height of the exported chart, overriding the option in the chart settings.'\n },\n width: {\n value: false,\n type: 'number',\n description:\n 'The width of the exported chart, overriding the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description:\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\n },\n rasterizationTimeout: {\n value: 1500,\n type: 'number',\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\n description:\n 'The duration in milliseconds to wait for rendering a webpage.'\n }\n },\n customLogic: {\n allowCodeExecution: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\n description:\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\n },\n allowFileResources: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\n description:\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description:\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n legacyName: 'fromFile',\n description: 'A file containing a pre-defined configuration to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Enables setting options through a prompt and saving them in a provided config file.'\n }\n },\n server: {\n maxUploadSize: {\n value: 3,\n type: 'number',\n cliName: 'maxUploadSize',\n envLink: 'SERVER_MAX_UPLOAD_SIZE',\n description:\n 'The maximum upload size, in megabytes, for the server'\n \n },\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_ENABLE',\n cliName: 'enableServer',\n description:\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\n },\n host: {\n value: '0.0.0.0',\n type: 'string',\n envLink: 'SERVER_HOST',\n description:\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\n },\n port: {\n value: 7801,\n type: 'number',\n envLink: 'SERVER_PORT',\n description: 'The server port when enabled.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_BENCHMARKING',\n cliName: 'serverBenchmarking',\n description:\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\n },\n proxy: {\n host: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_HOST',\n cliName: 'proxyHost',\n description: 'The host of the proxy server to use, if it exists.'\n },\n port: {\n value: 8080,\n type: 'number',\n envLink: 'SERVER_PROXY_PORT',\n cliName: 'proxyPort',\n description: 'The port of the proxy server to use, if it exists.'\n },\n timeout: {\n value: 5000,\n type: 'number',\n envLink: 'SERVER_PROXY_TIMEOUT',\n cliName: 'proxyTimeout',\n description: 'The timeout for the proxy server to use, if it exists.'\n }\n },\n rateLimiting: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting for the server.'\n },\n maxRequests: {\n value: 10,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\n legacyName: 'rateLimit',\n description: 'The maximum number of requests allowed in one minute.'\n },\n window: {\n value: 1,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\n description: 'The time window, in minutes, for the rate limiting.'\n },\n delay: {\n value: 0,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_DELAY',\n description:\n 'The delay duration for each successive request before reaching the maximum limit.'\n },\n trustProxy: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\n description: 'Set this to true if the server is behind a load balancer.'\n },\n skipKey: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\n },\n skipToken: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\n }\n },\n ssl: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_ENABLE',\n cliName: 'enableSsl',\n description: 'Enables or disables the SSL protocol.'\n },\n force: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_FORCE',\n cliName: 'sslForce',\n legacyName: 'sslOnly',\n description:\n 'When set to true, the server is forced to serve only over HTTPS.'\n },\n port: {\n value: 443,\n type: 'number',\n envLink: 'SERVER_SSL_PORT',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n value: false,\n type: 'string',\n envLink: 'SERVER_SSL_CERT_PATH',\n legacyName: 'sslPath',\n description: 'The path to the SSL certificate/key file.'\n }\n }\n },\n pool: {\n minWorkers: {\n value: 4,\n type: 'number',\n envLink: 'POOL_MIN_WORKERS',\n description: 'The number of minimum and initial pool workers to spawn.'\n },\n maxWorkers: {\n value: 8,\n type: 'number',\n envLink: 'POOL_MAX_WORKERS',\n legacyName: 'workers',\n description: 'The number of maximum pool workers to spawn.'\n },\n workLimit: {\n value: 40,\n type: 'number',\n envLink: 'POOL_WORK_LIMIT',\n description:\n 'The number of work pieces that can be performed before restarting the worker process.'\n },\n acquireTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_ACQUIRE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for acquiring a resource.'\n },\n createTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_CREATE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for creating a resource.'\n },\n destroyTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_DESTROY_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for destroying a resource.'\n },\n idleTimeout: {\n value: 30000,\n type: 'number',\n envLink: 'POOL_IDLE_TIMEOUT',\n description:\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\n },\n createRetryInterval: {\n value: 200,\n type: 'number',\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\n description:\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\n },\n reaperInterval: {\n value: 1000,\n type: 'number',\n envLink: 'POOL_REAPER_INTERVAL',\n description:\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'POOL_BENCHMARKING',\n cliName: 'poolBenchmarking',\n description:\n 'Indicate whether to show statistics for the pool of resources or not.'\n }\n },\n logging: {\n level: {\n value: 4,\n type: 'number',\n envLink: 'LOGGING_LEVEL',\n cliName: 'logLevel',\n description: 'The logging level to be used.'\n },\n file: {\n value: 'highcharts-export-server.log',\n type: 'string',\n envLink: 'LOGGING_FILE',\n cliName: 'logFile',\n description:\n 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.'\n },\n dest: {\n value: 'log/',\n type: 'string',\n envLink: 'LOGGING_DEST',\n cliName: 'logDest',\n description:\n 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.'\n },\n toConsole: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_CONSOLE',\n cliName: 'logToConsole',\n description: 'Enables or disables showing logs in the console.'\n },\n toFile: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_FILE',\n cliName: 'logToFile',\n description:\n 'Enables or disables creation of the log directory and saving the log into a .log file.'\n }\n },\n ui: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'UI_ENABLE',\n cliName: 'enableUi',\n description:\n 'Enables or disables the user interface (UI) for the export server.'\n },\n route: {\n value: '/',\n type: 'string',\n envLink: 'UI_ROUTE',\n cliName: 'uiRoute',\n description:\n 'The endpoint route to which the user interface (UI) should be attached.'\n }\n },\n other: {\n nodeEnv: {\n value: 'production',\n type: 'string',\n envLink: 'OTHER_NODE_ENV',\n description: 'The type of Node.js environment.'\n },\n listenToProcessExits: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\n description: 'Decides whether or not to attach process.exit handlers.'\n },\n noLogo: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_NO_LOGO',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n },\n hardResetPage: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_HARD_RESET_PAGE',\n description: 'Decides if the page content should be reset entirely.'\n },\n browserShellMode: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_BROWSER_SHELL_MODE',\n description: 'Decides if the browser runs in the shell mode.'\n }\n },\n debug: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_ENABLE',\n cliName: 'enableDebug',\n description: 'Enables or disables debug mode for the underlying browser.'\n },\n headless: {\n value: true,\n type: 'boolean',\n envLink: 'DEBUG_HEADLESS',\n description:\n 'Controls the mode in which the browser is launched when in the debug mode.'\n },\n devtools: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DEVTOOLS',\n description:\n 'Decides whether to enable DevTools when the browser is in a headful state.'\n },\n listenToConsole: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\n description:\n 'Decides whether to enable a listener for console messages sent from the browser.'\n },\n dumpio: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DUMPIO',\n description:\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\n },\n slowMo: {\n value: 0,\n type: 'number',\n envLink: 'DEBUG_SLOW_MO',\n description:\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\n },\n debuggingPort: {\n value: 9222,\n type: 'number',\n envLink: 'DEBUG_DEBUGGING_PORT',\n description: 'Specifies the debugging port.'\n }\n }\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The URL of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'coreScripts',\n message: 'Available core scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.coreScripts.value\n },\n {\n type: 'multiselect',\n name: 'moduleScripts',\n message: 'Available module scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.moduleScripts.value\n },\n {\n type: 'multiselect',\n name: 'indicatorScripts',\n message: 'Available indicator scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.indicatorScripts.value\n },\n {\n type: 'list',\n name: 'customScripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.customScripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Force re-fetch the scripts',\n initial: defaultConfig.highcharts.forceFetch.value\n },\n {\n type: 'text',\n name: 'cachePath',\n message: 'The path to the cache directory',\n initial: defaultConfig.highcharts.cachePath.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default export file type',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n },\n {\n type: 'number',\n name: 'rasterizationTimeout',\n message: 'The rendering webpage timeout in milliseconds',\n initial: defaultConfig.export.rasterizationTimeout.value\n }\n ],\n customLogic: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Enable execution of custom code',\n initial: defaultConfig.customLogic.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Enable file resources',\n initial: defaultConfig.customLogic.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts the server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'Server hostname',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'Server port',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable server benchmarking',\n initial: defaultConfig.server.benchmarking.value\n },\n {\n type: 'text',\n name: 'proxy.host',\n message: 'The host of the proxy server to use',\n initial: defaultConfig.server.proxy.host.value\n },\n {\n type: 'number',\n name: 'proxy.port',\n message: 'The port of the proxy server to use',\n initial: defaultConfig.server.proxy.port.value\n },\n {\n type: 'number',\n name: 'proxy.timeout',\n message: 'The timeout for the proxy server to use',\n initial: defaultConfig.server.proxy.timeout.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'The maximum requests allowed per minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The rate-limiting time window in minutes',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The delay for each successive request before reaching the maximum',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force serving only over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'SSL server port',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'The path to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'minWorkers',\n message: 'The initial number of workers to spawn',\n initial: defaultConfig.pool.minWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The maximum number of workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a Puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'number',\n name: 'createTimeout',\n message: 'The number of milliseconds to wait for creating a resource',\n initial: defaultConfig.pool.createTimeout.value\n },\n {\n type: 'number',\n name: 'destroyTimeout',\n message: 'The number of milliseconds to wait for destroying a resource',\n initial: defaultConfig.pool.destroyTimeout.value\n },\n {\n type: 'number',\n name: 'idleTimeout',\n message: 'The number of milliseconds after an idle resource is destroyed',\n initial: defaultConfig.pool.idleTimeout.value\n },\n {\n type: 'number',\n name: 'createRetryInterval',\n message:\n 'The retry interval in milliseconds after a create process fails',\n initial: defaultConfig.pool.createRetryInterval.value\n },\n {\n type: 'number',\n name: 'reaperInterval',\n message:\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\n initial: defaultConfig.pool.reaperInterval.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable benchmarking for a resource pool',\n initial: defaultConfig.pool.benchmarking.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 5\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A log file name. Set with --toFile and --logDest to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'The path to a log file when the file logging is enabled',\n initial: defaultConfig.logging.dest.value\n },\n {\n type: 'toggle',\n name: 'toConsole',\n message: 'Enable logging to the console',\n initial: defaultConfig.logging.toConsole.value\n },\n {\n type: 'toggle',\n name: 'toFile',\n message: 'Enables logging to a file',\n initial: defaultConfig.logging.toFile.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'text',\n name: 'nodeEnv',\n message: 'The type of Node.js environment',\n initial: defaultConfig.other.nodeEnv.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false to skip attaching process.exit handlers',\n initial: defaultConfig.other.listenToProcessExits.value\n },\n {\n type: 'toggle',\n name: 'noLogo',\n message: 'Skip printing the logo on startup. Replaced by simple text',\n initial: defaultConfig.other.noLogo.value\n },\n {\n type: 'toggle',\n name: 'hardResetPage',\n message: 'Decides if the page content should be reset entirely',\n initial: defaultConfig.other.hardResetPage.value\n },\n {\n type: 'toggle',\n name: 'browserShellMode',\n message: 'Decides if the browser runs in the shell mode',\n initial: defaultConfig.other.browserShellMode.value\n }\n ],\n debug: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enables debug mode for the browser instance',\n initial: defaultConfig.debug.enable.value\n },\n {\n type: 'toggle',\n name: 'headless',\n message: 'The mode setting for the browser',\n initial: defaultConfig.debug.headless.value\n },\n {\n type: 'toggle',\n name: 'devtools',\n message: 'The DevTools for the headful browser',\n initial: defaultConfig.debug.devtools.value\n },\n {\n type: 'toggle',\n name: 'listenToConsole',\n message: 'The event listener for console messages from the browser',\n initial: defaultConfig.debug.listenToConsole.value\n },\n {\n type: 'toggle',\n name: 'dumpio',\n message: 'Redirects the browser stdout and stderr to NodeJS process',\n initial: defaultConfig.debug.dumpio.value\n },\n {\n type: 'number',\n name: 'slowMo',\n message: 'Puppeteer operations slow down in milliseconds',\n initial: defaultConfig.debug.slowMo.value\n },\n {\n type: 'number',\n name: 'debuggingPort',\n message: 'The port number for debugging',\n initial: defaultConfig.debug.debuggingPort.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Recursively creates a chain of nested arguments from an object.\n *\n * @param {Object} obj - The object containing nested arguments.\n * @param {string} propChain - The current chain of nested properties\n * (used internally during recursion).\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n\n // Support for the legacy, PhantomJS properties names\n if (entry.legacyName !== undefined) {\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\n }\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/**\n * @fileoverview\n * This file is responsible for parsing the environment variables with the 'zod'\n * library. The parsed environment variables are then exported to be used\n * in the application as \"envs\". We should not use process.env directly\n * in the application as these would not be parsed properly.\n *\n * The environment variables are parsed and validated only once when\n * the application starts. We should write a custom validator or a transformer\n * for each of the options.\n */\n\nimport dotenv from 'dotenv';\nimport { z } from 'zod';\n\nimport { scriptsNames } from './schemas/config.js';\n\n// Load .env into environment variables\ndotenv.config();\n\n// Object with custom validators and transformers, to avoid repetition\n// in the Config object\nconst v = {\n // Splits string value into elements in an array, trims every element, checks\n // if an array is correct, if it is empty, and if it is, returns undefined\n array: (filterArray) =>\n z\n .string()\n .transform((value) =>\n value\n .split(',')\n .map((value) => value.trim())\n .filter((value) => filterArray.includes(value))\n )\n .transform((value) => (value.length ? value : undefined)),\n\n // Allows only true, false and correctly parse the value to boolean\n // or no value in which case the returned value will be undefined\n boolean: () =>\n z\n .enum(['true', 'false', ''])\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\n\n // Allows passed values or no value in which case the returned value will\n // be undefined\n enum: (values) =>\n z\n .enum([...values, ''])\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Trims the string value and checks if it is empty or contains stringified\n // values such as false, undefined, null, NaN, if it does, returns undefined\n string: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\n value === '',\n (value) => ({\n message: `The string contains forbidden values, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Allows positive numbers or no value in which case the returned value will\n // be undefined\n positiveNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\n (value) => ({\n message: `The value must be numeric and positive, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n\n // Allows non-negative numbers or no value in which case the returned value\n // will be undefined\n nonNegativeNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\n (value) => ({\n message: `The value must be numeric and non-negative, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\n};\n\nexport const Config = z.object({\n // highcharts\n HIGHCHARTS_VERSION: z\n .string()\n .trim()\n .refine(\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\n (value) => ({\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CDN_URL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value.startsWith('https://') ||\n value.startsWith('http://') ||\n value === '',\n (value) => ({\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\n HIGHCHARTS_CACHE_PATH: v.string(),\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\n\n // export\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\n\n // custom\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\n\n // server\n SERVER_ENABLE: v.boolean(),\n SERVER_HOST: v.string(),\n SERVER_PORT: v.positiveNum(),\n SERVER_BENCHMARKING: v.boolean(),\n\n // server proxy\n SERVER_PROXY_HOST: v.string(),\n SERVER_PROXY_PORT: v.positiveNum(),\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\n\n // server rate limiting\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\n\n // server ssl\n SERVER_SSL_ENABLE: v.boolean(),\n SERVER_SSL_FORCE: v.boolean(),\n SERVER_SSL_PORT: v.positiveNum(),\n SERVER_SSL_CERT_PATH: v.string(),\n\n // pool\n POOL_MIN_WORKERS: v.nonNegativeNum(),\n POOL_MAX_WORKERS: v.nonNegativeNum(),\n POOL_WORK_LIMIT: v.positiveNum(),\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\n POOL_BENCHMARKING: v.boolean(),\n\n // logger\n LOGGING_LEVEL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' ||\n (!isNaN(parseFloat(value)) &&\n parseFloat(value) >= 0 &&\n parseFloat(value) <= 5),\n (value) => ({\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n LOGGING_FILE: v.string(),\n LOGGING_DEST: v.string(),\n LOGGING_TO_CONSOLE: v.boolean(),\n LOGGING_TO_FILE: v.boolean(),\n\n // ui\n UI_ENABLE: v.boolean(),\n UI_ROUTE: v.string(),\n\n // other\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\n OTHER_NO_LOGO: v.boolean(),\n OTHER_HARD_RESET_PAGE: v.boolean(),\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\n\n // debugger\n DEBUG_ENABLE: v.boolean(),\n DEBUG_HEADLESS: v.boolean(),\n DEBUG_DEVTOOLS: v.boolean(),\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\n DEBUG_DUMPIO: v.boolean(),\n DEBUG_SLOW_MO: v.nonNegativeNum(),\n DEBUG_DEBUGGING_PORT: v.positiveNum()\n});\n\nexport const envs = Config.partial().parse(process.env);\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { appendFile, existsSync, mkdirSync } from 'fs';\n\n// The available colors\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\n\n// The default logging config\nlet logging = {\n // Flags for logging status\n toConsole: true,\n toFile: false,\n pathCreated: false,\n // Log levels\n levelsDesc: [\n {\n title: 'error',\n color: colors[0]\n },\n {\n title: 'warning',\n color: colors[1]\n },\n {\n title: 'notice',\n color: colors[2]\n },\n {\n title: 'verbose',\n color: colors[3]\n },\n {\n title: 'benchmark',\n color: colors[4]\n }\n ],\n // Log listeners\n listeners: []\n};\n\n/**\n * Logs the provided texts to a file, if file logging is enabled. It creates\n * the necessary directory structure if not already created and appends the\n * content, including an optional prefix, to the specified log file.\n *\n * @param {string[]} texts - An array of texts to be logged.\n * @param {string} prefix - An optional prefix to be added to each log entry.\n */\nconst logToFile = (texts, prefix) => {\n if (!logging.pathCreated) {\n // Create if does not exist\n !existsSync(logging.dest) && mkdirSync(logging.dest);\n\n // We now assume the path is available, e.g. it's the responsibility\n // of the user to create the path with the correct access rights.\n logging.pathCreated = true;\n }\n\n // Add the content to a file\n appendFile(\n `${logging.dest}${logging.file}`,\n [prefix].concat(texts).join(' ') + '\\n',\n (error) => {\n if (error) {\n console.log(`[logger] Unable to write to log file: ${error}`);\n logging.toFile = false;\n }\n }\n );\n};\n\n/**\n * Logs a message. Accepts a variable amount of arguments. Arguments after\n * `level` will be passed directly to console.log, and/or will be joined\n * and appended to the log file.\n *\n * @param {any} args - An array of arguments where the first is the log level\n * and the rest are strings to build a message with.\n */\nexport const log = (...args) => {\n const [newLevel, ...texts] = args;\n\n // Current logging options\n const { levelsDesc, level } = logging;\n\n // Check if log level is within a correct range or is a benchmark log\n if (\n newLevel !== 5 &&\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\n ) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\n );\n }\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Logs an error message with its stack trace. Optionally, a custom message\n * can be provided.\n *\n * @param {number} level - The log level.\n * @param {Error} error - The error object.\n * @param {string} customMessage - An optional custom message to be logged along\n * with the error.\n */\nexport const logWithStack = (newLevel, error, customMessage) => {\n // Get the main message\n const mainMessage = customMessage || error.message;\n\n // Current logging options\n const { level, levelsDesc } = logging;\n\n // Check if log level is within a correct range\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // If the customMessage exists, we want to display the whole stack message\n const stackMessage =\n error.message !== error.stackMessage || error.stackMessage === undefined\n ? error.stack\n : error.stack.split('\\n').slice(1).join('\\n');\n\n // Combine custom message or error message with error stack message\n const texts = [mainMessage, '\\n', stackMessage];\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\n mainMessage[colors[newLevel - 1]],\n '\\n',\n stackMessage\n ])\n );\n }\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Sets the log level to the specified value. Log levels are (0 = no logging,\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\n *\n * @param {number} newLevel - The new log level to be set.\n */\nexport const setLogLevel = (newLevel) => {\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\n logging.level = newLevel;\n }\n};\n\n/**\n * Enables file logging with the specified destination and log file.\n *\n * @param {string} logDest - The destination path for log files.\n * @param {string} logFile - The log file name.\n */\nexport const enableFileLogging = (logDest, logFile) => {\n // Update logging options\n logging = {\n ...logging,\n dest: logDest || logging.dest,\n file: logFile || logging.file,\n toFile: true\n };\n\n if (logging.dest.length === 0) {\n return log(1, '[logger] File logging initialization: no path supplied.');\n }\n\n if (!logging.dest.endsWith('/')) {\n logging.dest += '/';\n }\n};\n\n/**\n * Initializes logging with the specified logging configuration.\n *\n * @param {Object} loggingOptions - The logging configuration object.\n */\nexport const initLogging = (loggingOptions) => {\n // Set all the logging options on our logging module object\n for (const [key, value] of Object.entries(loggingOptions)) {\n logging[key] = value;\n }\n\n // Set the log level\n setLogLevel(loggingOptions && parseInt(loggingOptions.level));\n\n // Set the log file path and name\n if (loggingOptions && loggingOptions.dest && loggingOptions.toFile) {\n enableFileLogging(\n loggingOptions.dest,\n loggingOptions.file || 'highcharts-export-server.log'\n );\n }\n};\n\n/**\n * Adds a listener function to the logging system.\n *\n * @param {function} fn - The listener function to be added.\n */\nexport const listen = (fn) => {\n logging.listeners.push(fn);\n};\n\nexport default {\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n initLogging,\n listen\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { defaultConfig } from '../lib/schemas/config.js';\nimport { log, logWithStack } from './logger.js';\n\nconst MAX_BACKOFF_ATTEMPTS = 6;\n\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\n\n/**\n * Clears and standardizes text by replacing multiple consecutive whitespace\n * characters with a single space and trimming any leading or trailing\n * whitespace.\n *\n * @param {string} text - The input text to be cleared.\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\n * multiple consecutive whitespace characters.\n * @param {string} [replacer=' '] - The string used to replace multiple\n * consecutive whitespace characters.\n *\n * @returns {string} - The cleared and standardized text.\n */\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\n text.replaceAll(rule, replacer).trim();\n\n/**\n * Implements an exponential backoff strategy for retrying a function until\n * a certain number of attempts are reached.\n *\n * @param {Function} fn - The function to be retried.\n * @param {number} [attempt=0] - The current attempt number.\n * @param {...any} args - Arguments to be passed to the function.\n *\n * @returns {Promise} - A promise that resolves to the result of the function\n * if successful.\n *\n * @throws {Error} - Throws an error if the maximum number of attempts\n * is reached.\n */\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\n try {\n // Try to call the function\n return await fn(...args);\n } catch (error) {\n // Calculate delay in ms\n const delayInMs = 2 ** attempt * 1000;\n\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\n throw error;\n }\n\n // Wait given amount of time\n await new Promise((response) => setTimeout(response, delayInMs));\n log(\n 3,\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\n );\n\n // Try again\n return expBackoff(fn, attempt, ...args);\n }\n};\n\n/**\n * Fixes the export type based on MIME types and file extensions.\n *\n * @param {string} type - The original export type.\n * @param {string} outfile - The file path or name.\n *\n * @returns {string} - The corrected export type.\n */\nexport const fixType = (type, outfile) => {\n // MIME types\n const mimeTypes = {\n 'image/png': 'png',\n 'image/jpeg': 'jpeg',\n 'application/pdf': 'pdf',\n 'image/svg+xml': 'svg'\n };\n\n // Formats\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\n\n // Check if type and outfile's extensions are the same\n if (outfile) {\n const outType = outfile.split('.').pop();\n\n if (outType === 'jpg') {\n type = 'jpeg';\n } else if (formats.includes(outType) && type !== outType) {\n type = outType;\n }\n }\n\n // Return a correct type\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\n};\n\n/**\n * Handles and validates resources for export.\n *\n * @param {Object|string} resources - The resources to be handled. Can be either\n * a JSON object, stringified JSON or a path to a JSON file.\n * @param {boolean} allowFileResources - Whether to allow loading resources from\n * files.\n *\n * @returns {Object|undefined} - The handled resources or undefined if no valid\n * resources are found.\n */\nexport const handleResources = (resources = false, allowFileResources) => {\n const allowedProps = ['js', 'css', 'files'];\n\n let handledResources = resources;\n let correctResources = false;\n\n // Try to load resources from a file\n if (allowFileResources && resources.endsWith('.json')) {\n try {\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\n } catch (error) {\n return logWithStack(2, error, `[cli] No resources found.`);\n }\n } else {\n // Try to get JSON\n handledResources = isCorrectJSON(resources);\n\n // Get rid of the files section\n if (handledResources && !allowFileResources) {\n delete handledResources.files;\n }\n }\n\n // Filter from unnecessary properties\n for (const propName in handledResources) {\n if (!allowedProps.includes(propName)) {\n delete handledResources[propName];\n } else if (!correctResources) {\n correctResources = true;\n }\n }\n\n // Check if at least one of allowed properties is present\n if (!correctResources) {\n return log(3, `[cli] No resources found.`);\n }\n\n // Handle files section\n if (handledResources.files) {\n handledResources.files = handledResources.files.map((item) => item.trim());\n if (!handledResources.files || handledResources.files.length <= 0) {\n delete handledResources.files;\n }\n }\n\n // Return resources\n return handledResources;\n};\n\n/**\n * Validates and parses JSON data. Checks if provided data is or can\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\n *\n * @param {Object|string} data - The JSON data to be validated and parsed.\n * @param {boolean} toString - Whether to return a stringified representation\n * of the parsed JSON.\n *\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\n * or false if validation fails.\n */\nexport function isCorrectJSON(data, toString) {\n try {\n // Get the string representation if not already before parsing\n const parsedData = JSON.parse(\n typeof data !== 'string' ? JSON.stringify(data) : data\n );\n\n // Return a stringified representation of a JSON if required\n if (typeof parsedData !== 'string' && toString) {\n return JSON.stringify(parsedData);\n }\n\n // Return a JSON\n return parsedData;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if the given item is an object.\n *\n * @param {any} item - The item to be checked.\n *\n * @returns {boolean} - True if the item is an object, false otherwise.\n */\nexport const isObject = (item) =>\n typeof item === 'object' && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if the given object is empty.\n *\n * @param {Object} item - The object to be checked.\n *\n * @returns {boolean} - True if the object is empty, false otherwise.\n */\nexport const isObjectEmpty = (item) =>\n typeof item === 'object' &&\n !Array.isArray(item) &&\n item !== null &&\n Object.keys(item).length === 0;\n\n/**\n * Checks if a private IP range URL is found in the given string.\n *\n * @param {string} item - The string to be checked for a private IP range URL.\n *\n * @returns {boolean} - True if a private IP range URL is found, false\n * otherwise.\n */\nexport const isPrivateRangeUrlFound = (item) => {\n const regexPatterns = [\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\n ];\n\n return regexPatterns.some((pattern) => pattern.test(item));\n};\n\n/**\n * Creates a deep copy of the given object or array.\n *\n * @param {Object|Array} obj - The object or array to be deeply copied.\n *\n * @returns {Object|Array} - The deep copy of the provided object or array.\n */\nexport const deepCopy = (obj) => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n const copy = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n copy[key] = deepCopy(obj[key]);\n }\n }\n\n return copy;\n};\n\n/**\n * Converts the provided options object to a JSON-formatted string with the\n * option to preserve functions.\n *\n * @param {Object} options - The options object to be converted to a string.\n * @param {boolean} allowFunctions - If set to true, functions are preserved\n * in the output.\n *\n * @returns {string} - The JSON-formatted string representing the options.\n */\nexport const optionsStringify = (options, allowFunctions) => {\n const replacerCallback = (name, value) => {\n if (typeof value === 'string') {\n value = value.trim();\n\n // If allowFunctions is set to true, preserve functions\n if (\n (value.startsWith('function(') || value.startsWith('function (')) &&\n value.endsWith('}')\n ) {\n value = allowFunctions\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : undefined;\n }\n }\n\n return typeof value === 'function'\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : value;\n };\n\n // Stringify options and if required, replace special functions marks\n return JSON.stringify(options, replacerCallback).replaceAll(\n /\"EXP_FUN|EXP_FUN\"/g,\n ''\n );\n};\n\n/**\n * Prints the Highcharts Export Server logo and version information.\n *\n * @param {boolean} noLogo - If true, only prints version information without\n * the logo.\n */\nexport const printLogo = (noLogo) => {\n // Get package version either from env or from package.json\n const packageVersion = JSON.parse(\n readFileSync(join(__dirname, 'package.json'))\n ).version;\n\n // Print text only\n if (noLogo) {\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\n return;\n }\n\n // Print the logo\n console.log(\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\n `v${packageVersion}\\n`.bold\n );\n};\n\n/**\n * Prints the usage information for CLI arguments. If required, it can list\n * properties recursively\n */\nexport function printUsage() {\n const pad = 48;\n const readme = 'https://github.com/highcharts/node-export-server#readme';\n\n // Display readme information\n console.log(\n '\\nUsage of CLI arguments:'.bold,\n '\\n------',\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\n );\n\n const cycleCategories = (options) => {\n for (const [name, option] of Object.entries(options)) {\n // If category has more levels, go further\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\n cycleCategories(option);\n } else {\n let descName = ` --${option.cliName || name} ${\n ('<' + option.type + '>').green\n } `;\n if (descName.length < pad) {\n for (let i = descName.length; i < pad; i++) {\n descName += '.';\n }\n }\n\n // Display correctly aligned messages\n console.log(\n descName,\n option.description,\n `[Default: ${option.value.toString().bold}]`.blue\n );\n }\n }\n };\n\n // Cycle through options of each categories and display the usage info\n Object.keys(defaultConfig).forEach((category) => {\n // Only puppeteer and highcharts categories cannot be configured through CLI\n if (!['puppeteer', 'highcharts'].includes(category)) {\n console.log(`\\n${category.toUpperCase()}`.red);\n cycleCategories(defaultConfig[category]);\n }\n });\n console.log('\\n');\n}\n\n/**\n * Rounds a number to the specified precision.\n *\n * @param {number} value - The number to be rounded.\n * @param {number} precision - The number of decimal places to round to.\n *\n * @returns {number} - The rounded number.\n */\nexport const roundNumber = (value, precision = 1) => {\n const multiplier = Math.pow(10, precision || 0);\n return Math.round(+value * multiplier) / multiplier;\n};\n\n/**\n * Converts a value to a boolean.\n *\n * @param {any} item - The value to be converted to a boolean.\n *\n * @returns {boolean} - The boolean representation of the input value.\n */\nexport const toBoolean = (item) =>\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\n ? false\n : !!item;\n\n/**\n * Wraps custom code to execute it safely.\n *\n * @param {string} customCode - The custom code to be wrapped.\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\n *\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\n * fails.\n */\nexport const wrapAround = (customCode, allowFileResources) => {\n if (customCode && typeof customCode === 'string') {\n customCode = customCode.trim();\n\n if (customCode.endsWith('.js')) {\n return allowFileResources\n ? wrapAround(readFileSync(customCode, 'utf8'))\n : false;\n } else if (\n customCode.startsWith('function()') ||\n customCode.startsWith('function ()') ||\n customCode.startsWith('()=>') ||\n customCode.startsWith('() =>')\n ) {\n return `(${customCode})()`;\n }\n return customCode.replace(/;$/, '');\n }\n};\n\n/**\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\n *\n * @returns {function(): number} - A function to calculate the elapsed time\n * in milliseconds.\n */\nexport const measureTime = () => {\n const start = process.hrtime.bigint();\n return () => Number(process.hrtime.bigint() - start) / 1000000;\n};\n\nexport default {\n __dirname,\n clearText,\n expBackoff,\n fixType,\n handleResources,\n isCorrectJSON,\n isObject,\n isObjectEmpty,\n isPrivateRangeUrlFound,\n optionsStringify,\n printLogo,\n printUsage,\n roundNumber,\n toBoolean,\n wrapAround,\n measureTime\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\n\nimport prompts from 'prompts';\n\nimport {\n absoluteProps,\n defaultConfig,\n nestedArgs,\n promptsConfig\n} from './schemas/config.js';\nimport { envs } from './envs.js';\nimport { log, logWithStack } from './logger.js';\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\n\nlet generalOptions = {};\n\n/**\n * Retrieves and returns the general options for the export process.\n *\n * @returns {Object} The general options object.\n */\nexport const getOptions = () => generalOptions;\n\n/**\n * Initializes and sets the general options for the server instace, keeping\n * the principle of the options load priority. It accepts optional userOptions\n * and args from the CLI.\n *\n * @param {Object} userOptions - User-provided options for customization.\n * @param {Array} args - Command-line arguments for additional configuration\n * (CLI usage).\n *\n * @returns {Object} The updated general options object.\n */\nexport const setOptions = (userOptions, args) => {\n // Only for the CLI usage\n if (args?.length) {\n // Get the additional options from the custom JSON file\n generalOptions = loadConfigFile(args);\n }\n\n // Update the default config with a correct option values\n updateDefaultConfig(defaultConfig, generalOptions);\n\n // Set values for server's options and returns them\n generalOptions = initOptions(defaultConfig);\n\n // Apply user options if there are any\n if (userOptions) {\n // Merge user options\n generalOptions = mergeConfigOptions(\n generalOptions,\n userOptions,\n absoluteProps\n );\n }\n\n // Only for the CLI usage\n if (args?.length) {\n // Pair provided arguments\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\n }\n\n // Return final general options\n return generalOptions;\n};\n\n/**\n * Allows manual configuration based on specified prompts and saves\n * the configuration to a file.\n *\n * @param {string} configFileName - The name of the configuration file.\n *\n * @returns {Promise} A Promise that resolves to true once the manual\n * configuration is completed and saved.\n */\nexport const manualConfig = async (configFileName) => {\n // Prepare a config object\n let configFile = {};\n\n // Check if provided config file exists\n if (existsSync(configFileName)) {\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\n }\n\n // Question about a configuration category\n const onSubmit = async (p, categories) => {\n let questionsCounter = 0;\n let allQuestions = [];\n\n // Create a corresponding property in the manualConfig object\n for (const section of categories) {\n // Mark each option with a section\n promptsConfig[section] = promptsConfig[section].map((option) => ({\n ...option,\n section\n }));\n\n // Collect the questions\n allQuestions = [...allQuestions, ...promptsConfig[section]];\n }\n\n await prompts(allQuestions, {\n onSubmit: async (prompt, answer) => {\n // Get the default module scripts\n if (prompt.name === 'moduleScripts') {\n answer = answer.length\n ? answer.map((module) => prompt.choices[module])\n : prompt.choices;\n\n configFile[prompt.section][prompt.name] = answer;\n } else {\n configFile[prompt.section] = recursiveProps(\n Object.assign({}, configFile[prompt.section] || {}),\n prompt.name.split('.'),\n prompt.choices ? prompt.choices[answer] : answer\n );\n }\n\n if (++questionsCounter === allQuestions.length) {\n try {\n await fsPromises.writeFile(\n configFileName,\n JSON.stringify(configFile, null, 2),\n 'utf8'\n );\n } catch (error) {\n logWithStack(\n 1,\n error,\n `[config] An error occurred while creating the ${configFileName} file.`\n );\n }\n return true;\n }\n }\n });\n\n return true;\n };\n\n // Find the categories\n const choices = Object.keys(promptsConfig).map((choice) => ({\n title: `${choice} options`,\n value: choice\n }));\n\n // Category prompt\n return prompts(\n {\n type: 'multiselect',\n name: 'category',\n message: 'Which category do you want to configure?',\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\n instructions: '',\n choices\n },\n { onSubmit }\n );\n};\n\n/**\n * Maps old-structured (PhantomJS) options to a new configuration format\n * (Puppeteer).\n *\n * @param {Object} oldOptions - Old-structured options to be mapped.\n *\n * @returns {Object} New options structured based on the defined nestedArgs\n * mapping.\n */\nexport const mapToNewConfig = (oldOptions) => {\n const newOptions = {};\n // Cycle through old-structured options\n for (const [key, value] of Object.entries(oldOptions)) {\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\n\n // Populate object in correct properties levels\n propertiesChain.reduce(\n (obj, prop, index) =>\n (obj[prop] =\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\n newOptions\n );\n }\n return newOptions;\n};\n\n/**\n * Merges two sets of configuration options, considering absolute properties.\n *\n * @param {Object} options - Original configuration options.\n * @param {Object} newOptions - New configuration options to be merged.\n * @param {Array} absoluteProps - List of properties that should\n * not be recursively merged.\n *\n * @returns {Object} Merged configuration options.\n */\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\n const mergedOptions = deepCopy(options);\n\n for (const [key, value] of Object.entries(newOptions)) {\n mergedOptions[key] =\n isObject(value) &&\n !absoluteProps.includes(key) &&\n mergedOptions[key] !== undefined\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\n : value !== undefined\n ? value\n : mergedOptions[key];\n }\n\n return mergedOptions;\n};\n\n/**\n * Initializes export settings based on provided exportOptions\n * and generalOptions.\n *\n * @param {Object} exportOptions - Options specific to the export process.\n * @param {Object} generalOptions - General configuration options.\n *\n * @returns {Object} Initialized export settings.\n */\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\n let options = {};\n\n if (exportOptions.svg) {\n options = deepCopy(generalOptions);\n options.export.type = exportOptions.type || exportOptions.export.type;\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\n options.export.outfile =\n exportOptions.outfile || exportOptions.export.outfile;\n options.payload = {\n svg: exportOptions.svg\n };\n } else {\n options = mergeConfigOptions(\n generalOptions,\n exportOptions,\n // Omit going down recursively with the belows\n absoluteProps\n );\n }\n\n options.export.outfile =\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\n return options;\n};\n\n/**\n * Loads additional configuration from a specified file using\n * the --loadConfig option.\n *\n * @param {Array} args - Command-line arguments to check for\n * the --loadConfig option.\n *\n * @returns {Object} Additional configuration loaded from the specified file,\n * or an empty object if not found or invalid.\n */\nfunction loadConfigFile(args) {\n // Check if the --loadConfig option was used\n const configIndex = args.findIndex(\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\n );\n\n // Check if the --loadConfig has a value\n if (configIndex > -1 && args[configIndex + 1]) {\n const fileName = args[configIndex + 1];\n try {\n // Check if an additional config file is a correct JSON file\n if (fileName && fileName.endsWith('.json')) {\n // Load an optional custom JSON config file\n return JSON.parse(readFileSync(fileName));\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[config] Unable to load the configuration from the ${fileName} file.`\n );\n }\n }\n\n // No additional options to return\n return {};\n}\n\n/**\n * Updates the default configuration object with values from a custom object\n * and environment variables.\n *\n * @param {Object} configObj - The default configuration object.\n * @param {Object} customObj - Custom configuration object to override defaults.\n * @param {string} propChain - Property chain for tracking nested properties\n * during recursion.\n */\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\n Object.keys(configObj).forEach((key) => {\n const entry = configObj[key];\n const customValue = customObj && customObj[key];\n\n if (typeof entry.value === 'undefined') {\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\n } else {\n // If a value from a custom JSON exists, it take precedence\n if (customValue !== undefined) {\n entry.value = customValue;\n }\n\n // If a value from an env variable exists, it take precedence\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\n entry.value = envs[entry.envLink];\n }\n }\n });\n}\n\n/**\n * Initializes options object based on provided items, setting values from\n * nested properties recursively.\n *\n * @param {Object} items - Configuration items to be used for initializing\n * options.\n *\n * @returns {Object} Initialized options object.\n */\nfunction initOptions(items) {\n let options = {};\n for (const [name, item] of Object.entries(items)) {\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\n ? item.value\n : initOptions(item);\n }\n return options;\n}\n\n/**\n * Pairs argument values with corresponding options in the configuration,\n * updating the options object.\n *\n * @param {Object} options - Configuration options object to be updated.\n * @param {Array} args - Command-line arguments containing values for specific\n * options.\n * @param {Object} defaultConfig - Default configuration object for reference.\n *\n * @returns {Object} Updated options object.\n */\nfunction pairArgumentValue(options, args, defaultConfig) {\n let showUsage = false;\n for (let i = 0; i < args.length; i++) {\n const option = args[i].replace(/-/g, '');\n\n // Find the right place for property's value\n const propertiesChain = nestedArgs[option]\n ? nestedArgs[option].split('.')\n : [];\n\n // Get the correct type for CLI args which are passed as strings\n let argumentType;\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n argumentType = obj[prop].type;\n }\n return obj[prop];\n }, defaultConfig);\n\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n // Finds an option and set a corresponding value\n if (typeof obj[prop] !== 'undefined') {\n if (args[++i]) {\n if (argumentType === 'boolean') {\n obj[prop] = toBoolean(args[i]);\n } else if (argumentType === 'number') {\n obj[prop] = +args[i];\n } else if (argumentType.indexOf(']') >= 0) {\n obj[prop] = args[i].split(',');\n } else {\n obj[prop] = args[i];\n }\n } else {\n log(\n 2,\n `[config] Missing value for the '${option}' argument. Using the default value.`\n );\n showUsage = true;\n }\n }\n }\n return obj[prop];\n }, options);\n }\n\n // Display the usage for the reference if needed\n if (showUsage) {\n printUsage(defaultConfig);\n }\n\n return options;\n}\n\n/**\n * Recursively updates properties in an object based on nested names and assigns\n * the final value.\n *\n * @param {Object} objectToUpdate - The object to be updated.\n * @param {Array} nestedNames - Array of nested property names.\n * @param {any} value - The final value to be assigned.\n *\n * @returns {Object} Updated object with assigned values.\n */\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\n while (nestedNames.length > 1) {\n const propName = nestedNames.shift();\n\n // Create a property in object if it doesn't exist\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\n objectToUpdate[propName] = {};\n }\n\n // Call function again if there still names to go\n objectToUpdate[propName] = recursiveProps(\n Object.assign({}, objectToUpdate[propName]),\n nestedNames,\n value\n );\n\n return objectToUpdate;\n }\n\n // Assign the final value\n objectToUpdate[nestedNames[0]] = value;\n return objectToUpdate;\n}\n\nexport default {\n getOptions,\n setOptions,\n manualConfig,\n mapToNewConfig,\n mergeConfigOptions,\n initExportSettings\n};\n","/**\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\n */\n\nimport http from 'http';\nimport https from 'https';\n\n/**\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\n *\n * @param {string} url - The URL to determine the protocol.\n *\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\n */\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\n\n/**\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to fetch data from.\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object\n * with added 'text' property or rejecting with an error.\n */\nasync function fetch(url, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n\n protocol\n .get(\n url,\n Object.assign(\n {\n headers: {\n 'User-Agent': 'highcharts/export',\n Referer: 'highcharts/export'\n }\n },\n requestOptions || {}\n ),\n (res) => {\n let data = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n data += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n if (!data) {\n reject('Nothing was fetched from the URL.');\n }\n\n res.text = data;\n resolve(res);\n });\n }\n )\n .on('error', (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Sends a POST request to the specified URL with the provided JSON body using\n * either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to send the POST request to.\n * @param {Object} body - The JSON body to include in the POST request\n * (optional, default is an empty object).\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object with\n * added 'text' property or rejecting with an error.\n */\nasync function post(url, body = {}, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n const data = JSON.stringify(body);\n\n // Set default headers and merge with requestOptions\n const options = Object.assign(\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n },\n requestOptions\n );\n\n const req = protocol\n .request(url, options, (res) => {\n let responseData = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n responseData += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n try {\n res.text = responseData;\n resolve(res);\n } catch (error) {\n reject(error);\n }\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n\n // Write the request body and end the request.\n req.write(data);\n req.end();\n });\n}\n\nexport default fetch;\nexport { fetch, post };\n","class ExportError extends Error {\n constructor(message) {\n super();\n this.message = message;\n this.stackMessage = message;\n }\n\n setError(error) {\n this.error = error;\n if (error.name) {\n this.name = error.name;\n }\n if (error.statusCode) {\n this.statusCode = error.statusCode;\n }\n if (error.stack) {\n this.stackMessage = error.message;\n this.stack = error.stack;\n }\n return this;\n }\n}\n\nexport default ExportError;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// The cache manager manages the Highcharts library and its dependencies.\n// The cache itself is stored in .cache, and is checked by the config system\n// before starting the service\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport { HttpsProxyAgent } from 'https-proxy-agent';\n\nimport { getOptions } from './config.js';\nimport { envs } from './envs.js';\nimport { fetch } from './fetch.js';\nimport { log } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\nconst cache = {\n cdnURL: 'https://code.highcharts.com/',\n activeManifest: {},\n sources: '',\n hcVersion: ''\n};\n\n/**\n * Extracts and caches the Highcharts version from the sources string.\n *\n * @returns {string} The extracted Highcharts version.\n */\nexport const extractVersion = (cache) => {\n return cache.sources\n .substring(0, cache.sources.indexOf('*/'))\n .replace('/*', '')\n .replace('*/', '')\n .replace(/\\n/g, '')\n .trim();\n};\n\n/**\n * Extracts the Highcharts module name based on the scriptPath.\n */\nexport const extractModuleName = (scriptPath) => {\n return scriptPath.replace(\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\n ''\n );\n};\n\n/**\n * Saves the provided configuration and fetched modules to the cache manifest\n * file.\n *\n * @param {object} config - Highcharts-related configuration object.\n * @param {object} fetchedModules - An object that contains mapped names of\n * fetched Highcharts modules to use.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\n * the cache manifest.\n */\nexport const saveConfigToManifest = async (config, fetchedModules) => {\n const newManifest = {\n version: config.version,\n modules: fetchedModules || {}\n };\n\n // Update cache object with the current modules\n cache.activeManifest = newManifest;\n\n log(3, '[cache] Writing a new manifest.');\n try {\n writeFileSync(\n join(__dirname, config.cachePath, 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\n error\n );\n }\n};\n\n/**\n * Fetches a single script and updates the fetchedModules accordingly.\n *\n * @param {string} script - A path to script to get.\n * @param {Object} requestOptions - Additional options for the proxy agent\n * to use for a request.\n * @param {Object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\n * thrown. This should be used only for the core scripts.\n *\n * @returns {Promise} A Promise resolving to the text representation\n * of the fetched script.\n *\n * @throws {ExportError} Throws an ExportError if there is a problem with\n * fetching the script.\n */\nexport const fetchAndProcessScript = async (\n script,\n requestOptions,\n fetchedModules,\n shouldThrowError = false\n) => {\n // Get rid of the .js from the custom strings\n if (script.endsWith('.js')) {\n script = script.substring(0, script.length - 3);\n }\n\n log(4, `[cache] Fetching script - ${script}.js`);\n\n // Fetch the script\n const response = await fetch(`${script}.js`, requestOptions);\n\n // If OK, return its text representation\n if (response.statusCode === 200 && typeof response.text == 'string') {\n if (fetchedModules) {\n const moduleName = extractModuleName(script);\n fetchedModules[moduleName] = 1;\n }\n\n return response.text;\n }\n\n if (shouldThrowError) {\n throw new ExportError(\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\n ).setError(response);\n } else {\n log(\n 2,\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\n );\n }\n\n return '';\n};\n\n/**\n * Fetches Highcharts scripts and customScripts from the given CDNs.\n *\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\n * @param {string} customScripts - Array of custom script paths to fetch\n * (full URLs).\n * @param {object} proxyOptions - Options for the proxy agent to use for\n * a request.\n * @param {object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n *\n * @returns {Promise} The fetched scripts content joined.\n */\nexport const fetchScripts = async (\n coreScripts,\n moduleScripts,\n customScripts,\n proxyOptions,\n fetchedModules\n) => {\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = proxyOptions.host;\n const proxyPort = proxyOptions.port;\n\n // Try to create a Proxy Agent\n if (proxyHost && proxyPort) {\n try {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: proxyPort\n });\n } catch (error) {\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\n error\n );\n }\n }\n\n // If exists, add proxy agent to request options\n const requestOptions = proxyAgent\n ? {\n agent: proxyAgent,\n timeout: envs.SERVER_PROXY_TIMEOUT\n }\n : {};\n\n const allFetchPromises = [\n ...coreScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\n ),\n ...moduleScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\n ),\n ...customScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions)\n )\n ];\n\n const fetchedScripts = await Promise.all(allFetchPromises);\n return fetchedScripts.join(';\\n');\n};\n\n/**\n * Updates the local cache with Highcharts scripts and their versions.\n *\n * @param {Object} options - Object containing all options.\n * @param {string} sourcePath - The path to the source file in the cache.\n *\n * @returns {Promise} A Promise resolving to an object representing\n * the fetched modules.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * the local Highcharts cache.\n */\nexport const updateCache = async (\n highchartsOptions,\n proxyOptions,\n sourcePath\n) => {\n const version = highchartsOptions.version;\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\n\n log(\n 3,\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\n );\n\n const fetchedModules = {};\n try {\n cache.sources = await fetchScripts(\n [\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\n ],\n [\n ...highchartsOptions.moduleScripts.map((m) =>\n m === 'map'\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\n : `${cdnURL}${hcVersion}modules/${m}`\n ),\n ...highchartsOptions.indicatorScripts.map(\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\n )\n ],\n highchartsOptions.customScripts,\n proxyOptions,\n fetchedModules\n );\n\n cache.hcVersion = extractVersion(cache);\n\n // Save the fetched modules into caches' source JSON\n writeFileSync(sourcePath, cache.sources);\n return fetchedModules;\n } catch (error) {\n throw new ExportError(\n '[cache] Unable to update the local Highcharts cache.'\n ).setError(error);\n }\n};\n\n/**\n * Updates the Highcharts version in the applied configuration and checks\n * the cache for the new version.\n *\n * @param {string} newVersion - The new Highcharts version to be applied.\n *\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\n * configuration with the new version, or false if no applied configuration\n * exists.\n */\nexport const updateVersion = async (newVersion) => {\n const options = getOptions();\n if (options?.highcharts) {\n options.highcharts.version = newVersion;\n }\n await checkAndUpdateCache(options);\n};\n\n/**\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\n * and loads the sources.\n *\n * @param {Object} options - Object containing all options.\n *\n * @returns {Promise} A Promise that resolves once the cache is checked\n * and updated.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * or reading the cache.\n */\nexport const checkAndUpdateCache = async (options) => {\n const { highcharts, server } = options;\n const cachePath = join(__dirname, highcharts.cachePath);\n\n let fetchedModules;\n // Prepare paths to manifest and sources from the .cache folder\n const manifestPath = join(cachePath, 'manifest.json');\n const sourcePath = join(cachePath, 'sources.js');\n\n // Create the cache destination if it doesn't exist already\n !existsSync(cachePath) && mkdirSync(cachePath);\n\n // Fetch all the scripts either if manifest.json does not exist\n // or if the forceFetch option is enabled\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n let requestUpdate = false;\n\n // Read the manifest JSON\n const manifest = JSON.parse(readFileSync(manifestPath));\n\n // Check if the modules is an array, if so, we rewrite it to a map to make\n // it easier to resolve modules.\n if (manifest.modules && Array.isArray(manifest.modules)) {\n const moduleMap = {};\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\n manifest.modules = moduleMap;\n }\n\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\n const numberOfModules =\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\n\n // Compare the loaded highcharts config with the contents in cache.\n // If there are changes, fetch requested modules and products,\n // and bake them into a giant blob. Save the blob.\n if (manifest.version !== highcharts.version) {\n log(\n 2,\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\n );\n requestUpdate = true;\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\n log(\n 2,\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\n );\n requestUpdate = true;\n } else {\n // Check each module, if anything is missing refetch everything\n requestUpdate = (moduleScripts || []).some((moduleName) => {\n if (!manifest.modules[moduleName]) {\n log(\n 2,\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\n );\n return true;\n }\n });\n }\n\n if (requestUpdate) {\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n log(3, '[cache] Dependency cache is up to date, proceeding.');\n\n // Load the sources\n cache.sources = readFileSync(sourcePath, 'utf8');\n\n // Get current modules map\n fetchedModules = manifest.modules;\n\n cache.hcVersion = extractVersion(cache);\n }\n }\n\n // Finally, save the new manifest, which is basically our current config\n // in a slightly different format\n await saveConfigToManifest(highcharts, fetchedModules);\n};\n\nexport const getCachePath = () =>\n join(__dirname, getOptions().highcharts.cachePath);\n\nexport const getCache = () => cache;\n\nexport const highcharts = () => cache.sources;\n\nexport const version = () => cache.hcVersion;\n\nexport default {\n checkAndUpdateCache,\n getCachePath,\n updateVersion,\n getCache,\n highcharts,\n version\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/* eslint-disable no-undef */\n\n/**\n * Setting the animObject. Called when initing the page.\n */\nexport function setupHighcharts() {\n Highcharts.animObject = function () {\n return { duration: 0 };\n };\n}\n\n/**\n * Creates the actual chart.\n *\n * @param {object} chartOptions - The options for the Highcharts chart.\n * @param {object} options - The export options.\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\n */\nexport async function triggerExport(chartOptions, options, displayErrors) {\n // Display errors flag taken from chart options nad debugger module\n window._displayErrors = displayErrors;\n\n // Get required functions\n const { getOptions, merge, setOptions, wrap } = Highcharts;\n\n // Create a separate object for a potential setOptions usages in order to\n // prevent from polluting other exports that can happen on the same page\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\n\n // By default animation is disabled\n const chart = {\n animation: false\n };\n\n // When straight inject, the size is set through CSS only\n if (options.export.strInj) {\n chart.height = chartOptions.chart.height;\n chart.width = chartOptions.chart.width;\n }\n\n // NOTE: Is this used for anything useful?\n window.isRenderComplete = false;\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\n // Override userOptions with image friendly options\n userOptions = merge(userOptions, {\n exporting: {\n enabled: false\n },\n plotOptions: {\n series: {\n label: {\n enabled: false\n }\n }\n },\n /* Expects tooltip in userOptions when forExport is true.\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\n */\n tooltip: {}\n });\n\n (userOptions.series || []).forEach(function (series) {\n series.animation = false;\n });\n\n // Add flag to know if chart render has been called.\n if (!window.onHighchartsRender) {\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\n window.isRenderComplete = true;\n });\n }\n\n proceed.apply(this, [userOptions, cb]);\n });\n\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\n proceed.apply(this, [chart, options]);\n });\n\n // Get the user options\n const userOptions = options.export.strInj\n ? new Function(`return ${options.export.strInj}`)()\n : chartOptions;\n\n // Trigger custom code\n if (options.customLogic.customCode) {\n new Function('options', options.customLogic.customCode)(userOptions);\n }\n\n // Merge the globalOptions, themeOptions, options from the wrapped\n // setOptions function and user options to create the final options object\n const finalOptions = merge(\n false,\n JSON.parse(options.export.themeOptions),\n userOptions,\n // Placed it here instead in the init because of the size issues\n { chart }\n );\n\n const finalCallback = options.customLogic.callback\n ? new Function(`return ${options.customLogic.callback}`)()\n : undefined;\n\n // Set the global options if exist\n const globalOptions = JSON.parse(options.export.globalOptions);\n if (globalOptions) {\n setOptions(globalOptions);\n }\n\n let constr = options.export.constr || 'chart';\n constr = typeof Highcharts[constr] !== 'undefined' ? constr : 'chart';\n\n Highcharts[constr]('container', finalOptions, finalCallback);\n\n // Get the current global options\n const defaultOptions = getOptions();\n\n // Clear it just in case (e.g. the setOptions was used in the customCode)\n for (const prop in defaultOptions) {\n if (typeof defaultOptions[prop] !== 'function') {\n delete defaultOptions[prop];\n }\n }\n\n // Set the default options back\n setOptions(Highcharts.setOptionsObj);\n\n // Empty the custom global options object\n Highcharts.setOptionsObj = {};\n}\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport path from 'path';\n\nimport puppeteer from 'puppeteer';\n\nimport { getCachePath } from './cache.js';\nimport { getOptions } from './config.js';\nimport { setupHighcharts } from './highcharts.js';\nimport { log, logWithStack } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\n// Get the template for the page\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\n\nlet browser;\n\n/**\n * Retrieves the existing Puppeteer browser instance.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if no valid browser has been\n * created.\n */\nexport function get() {\n if (!browser) {\n throw new ExportError('[browser] No valid browser has been created.');\n }\n return browser;\n}\n\n/**\n * Creates a Puppeteer browser instance with the specified arguments.\n *\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\n * instance are reached, or if no browser instance is found after retries.\n */\nexport async function create(puppeteerArgs) {\n // Get debug and other options\n const { debug, other } = getOptions();\n\n // Get the debug options\n const { enable: enabledDebug, ...debugOptions } = debug;\n\n const launchOptions = {\n headless: other.browserShellMode ? 'shell' : true,\n userDataDir: './tmp/',\n args: puppeteerArgs,\n handleSIGINT: false,\n handleSIGTERM: false,\n handleSIGHUP: false,\n waitForInitialPage: false,\n defaultViewport: null,\n ...(enabledDebug && debugOptions)\n };\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\n );\n browser = await puppeteer.launch(launchOptions);\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Failed to launch a browser instance.'\n );\n\n // Retry to launch browser until reaching max attempts\n if (tryCount < 25) {\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n throw error;\n }\n }\n };\n\n try {\n await open();\n\n // Shell mode inform\n if (launchOptions.headless === 'shell') {\n log(3, `[browser] Launched browser in shell mode.`);\n }\n\n // Debug mode inform\n if (enabledDebug) {\n log(3, `[browser] Launched browser in debug mode.`);\n }\n } catch (error) {\n throw new ExportError(\n '[browser] Maximum retries to open a browser instance reached.'\n ).setError(error);\n }\n\n if (!browser) {\n throw new ExportError('[browser] Cannot find a browser to open.');\n }\n }\n\n // Return a browser promise\n return browser;\n}\n\n/**\n * Closes the Puppeteer browser instance if it is connected.\n *\n * @returns {Promise} A Promise resolving to true after the browser\n * is closed.\n */\nexport async function close() {\n // Close the browser when connnected\n if (browser?.connected) {\n await browser.close();\n }\n log(4, '[browser] Closed the browser.');\n}\n\n/**\n * Creates a new Puppeteer Page within an existing browser instance.\n *\n * If the browser instance is not available, returns false.\n *\n * The function creates a new page, disables caching, sets content using\n * setPageContent(), and returns the created Puppeteer Page.\n *\n * @returns {(boolean|object)} Returns false if the browser instance is not\n * available, or a Puppeteer Page object representing the newly created page.\n */\nexport async function newPage() {\n if (!browser) {\n return false;\n }\n\n // Create a page\n const page = await browser.newPage();\n\n // Disable cache\n await page.setCacheEnabled(false);\n\n // Set the content\n await setPageContent(page);\n\n // Set page events\n setPageEvents(page);\n\n return page;\n}\n\n/**\n * Clears the content of a Puppeteer Page based on the specified mode.\n *\n * @param {Object} page - The Puppeteer Page object to be cleared.\n * @param {boolean} hardReset - A flag indicating the type of clearing\n * to be performed. If true, navigates to 'about:blank' and resets content\n * and scripts. If false, clears the body content by setting a predefined HTML\n * structure.\n *\n * @throws {Error} Logs thrown error if clearing the page content fails.\n */\nexport async function clearPage(page, hardReset = false) {\n try {\n if (page && !page.isClosed()) {\n if (hardReset) {\n // Navigate to about:blank\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\n\n // Set the content and and scripts again\n await setPageContent(page);\n } else {\n // Clear body content\n await page.evaluate(() => {\n document.body.innerHTML =\n '
';\n });\n }\n return true;\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n '[browser] Could not clear the content of the page.'\n );\n }\n\n return false;\n}\n\n/**\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\n * options.\n *\n * @param {Object} page - The Puppeteer Page object to which resources will be\n * added.\n * @param {Object} options - All options and configuration.\n *\n * @returns {Promise>} - Promise resolving to an array of injected\n * resources.\n */\nexport async function addPageResources(page, options) {\n // Injected resources array\n const injectedResources = [];\n\n // Use resources\n const resources = options.customLogic.resources;\n if (resources) {\n const injectedJs = [];\n\n // Load custom JS code\n if (resources.js) {\n injectedJs.push({\n content: resources.js\n });\n }\n\n // Load scripts from all custom files\n if (resources.files) {\n for (const file of resources.files) {\n const isLocal = !file.startsWith('http') ? true : false;\n\n // Add each custom script from resources' files\n injectedJs.push(\n isLocal\n ? {\n content: readFileSync(file, 'utf8')\n }\n : {\n url: file\n }\n );\n }\n }\n\n for (const jsResource of injectedJs) {\n try {\n injectedResources.push(await page.addScriptTag(jsResource));\n } catch (error) {\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\n }\n }\n injectedJs.length = 0;\n\n // Load CSS\n const injectedCss = [];\n if (resources.css) {\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\n if (cssImports) {\n // Handle css section\n for (let cssImportPath of cssImports) {\n if (cssImportPath) {\n cssImportPath = cssImportPath\n .replace('url(', '')\n .replace('@import', '')\n .replace(/\"/g, '')\n .replace(/'/g, '')\n .replace(/;/, '')\n .replace(/\\)/g, '')\n .trim();\n\n // Add each custom css from resources\n if (cssImportPath.startsWith('http')) {\n injectedCss.push({\n url: cssImportPath\n });\n } else if (options.customLogic.allowFileResources) {\n injectedCss.push({\n path: path.join(__dirname, cssImportPath)\n });\n }\n }\n }\n }\n\n // The rest of the CSS section will be content by now\n injectedCss.push({\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\n });\n\n for (const cssResource of injectedCss) {\n try {\n injectedResources.push(await page.addStyleTag(cssResource));\n } catch (error) {\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\n }\n }\n injectedCss.length = 0;\n }\n }\n return injectedResources;\n}\n\n/**\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\n * injected resources and resets CSS and script tags on the page. Additionally,\n * it destroys previously existing charts.\n *\n * @param {Object} page - The Puppeteer Page object from which resources will\n * be cleared.\n * @param {Array} injectedResources - Array of injected resources\n * to be cleared.\n */\nexport async function clearPageResources(page, injectedResources) {\n try {\n for (const resource of injectedResources) {\n await resource.dispose();\n }\n\n // Destroy old charts after export is done and reset all CSS and script tags\n await page.evaluate(() => {\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\n // exports\n if (typeof Highcharts !== 'undefined') {\n // eslint-disable-next-line no-undef\n const oldCharts = Highcharts.charts;\n\n // Check in any already existing charts\n if (Array.isArray(oldCharts) && oldCharts.length) {\n // Destroy old charts\n for (const oldChart of oldCharts) {\n oldChart && oldChart.destroy();\n // eslint-disable-next-line no-undef\n Highcharts.charts.shift();\n }\n }\n }\n\n // eslint-disable-next-line no-undef\n const [...scriptsToRemove] = document.getElementsByTagName('script');\n // eslint-disable-next-line no-undef\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\n // eslint-disable-next-line no-undef\n const [...linksToRemove] = document.getElementsByTagName('link');\n\n // Remove tags\n for (const element of [\n ...scriptsToRemove,\n ...stylesToRemove,\n ...linksToRemove\n ]) {\n element.remove();\n }\n });\n } catch (error) {\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\n }\n}\n\n/**\n * Sets the content for a Puppeteer Page using a predefined template\n * and additional scripts. Also, sets the pageerror in order to catch\n * and display errors from the window context.\n *\n * @param {Object} page - The Puppeteer Page object for which the content\n * is being set.\n */\nasync function setPageContent(page) {\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\n\n // Add all registered Higcharts scripts, quite demanding\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\n\n // Set the initial animObject\n await page.evaluate(setupHighcharts);\n}\n\n/**\n * Set events for a Puppeteer Page.\n *\n * @param {Object} page - The Puppeteer Page object to set events to.\n */\nfunction setPageEvents(page) {\n // Get debug options\n const { debug } = getOptions();\n\n // Set the console listener, if needed\n if (debug.enable && debug.listenToConsole) {\n page.on('console', (message) => {\n console.log(`[debug] ${message.text()}`);\n });\n }\n\n // Set the pageerror listener\n page.on('pageerror', async (error) => {\n // It would seem like this may fire at the same time or shortly before\n // a page is closed.\n if (page.isClosed()) {\n return;\n }\n\n // TODO: Consider adding a switch here that turns on log(0) logging\n // on page errors.\n await page.$eval(\n '#container',\n (element, errorMessage) => {\n // eslint-disable-next-line no-undef\n if (window._displayErrors) {\n element.innerHTML = errorMessage;\n }\n },\n `

Chart input data error:

${error.toString()}`\n );\n });\n}\n\nexport default {\n get,\n create,\n close,\n newPage,\n clearPage,\n addPageResources,\n clearPageResources\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { addPageResources, clearPageResources } from './browser.js';\nimport { getCache } from './cache.js';\nimport { triggerExport } from './highcharts.js';\nimport { log } from './logger.js';\n\nimport svgTemplate from './../templates/svg_export/svg_export.js';\n\nimport ExportError from './errors/ExportError.js';\n\n/**\n * Retrieves the clipping region coordinates of the specified page element with\n * the id 'chart-container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to an object containing\n * x, y, width, and height properties.\n */\nconst getClipRegion = (page) =>\n page.$eval('#chart-container', (element) => {\n const { x, y, width, height } = element.getBoundingClientRect();\n return {\n x,\n y,\n width,\n height: Math.trunc(height > 1 ? height : 500)\n };\n });\n\n/**\n * Creates an image using Puppeteer's page screenshot functionality with\n * specified options.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {string} type - Image type.\n * @param {string} encoding - Image encoding.\n * @param {Object} clip - Clipping region coordinates.\n * @param {number} rasterizationTimeout - Timeout for rasterization\n * in milliseconds.\n *\n * @returns {Promise} Promise resolving to the image buffer or rejecting\n * with an ExportError for timeout.\n */\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\n Promise.race([\n page.screenshot({\n type,\n encoding,\n clip,\n captureBeyondViewport: true,\n fullPage: false,\n optimizeForSpeed: true,\n ...(type !== 'png' ? { quality: 80 } : {}),\n\n // #447, #463 - always render on a transparent page if the expected type\n // format is PNG\n omitBackground: type == 'png'\n }),\n new Promise((_resolve, reject) =>\n setTimeout(\n () => reject(new ExportError('Rasterization timeout')),\n rasterizationTimeout || 1500\n )\n )\n ]);\n\n/**\n * Creates a PDF using Puppeteer's page pdf functionality with specified\n * options.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {number} height - PDF height.\n * @param {number} width - PDF width.\n * @param {string} encoding - PDF encoding.\n *\n * @returns {Promise} Promise resolving to the PDF buffer.\n */\nconst createPDF = async (\n page,\n height,\n width,\n encoding,\n rasterizationTimeout\n) => {\n await page.emulateMediaType('screen');\n\n return page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding,\n timeout: rasterizationTimeout || 1500\n });\n};\n\n/**\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\n * inside an element with the id 'container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to the SVG string.\n */\nconst createSVG = (page) =>\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\n\n/**\n * Sets the specified chart and options as configuration into the triggerExport\n * function within the window context using page.evaluate.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object to be configured.\n * @param {Object} options - Configuration options for the chart.\n *\n * @returns {Promise} Promise resolving after the configuration is set.\n */\nconst setAsConfig = async (page, chart, options, displayErrors) => {\n // Get rid of the redunant string data\n options.export.instr = null;\n options.export.infile = null;\n\n // Get the size of the export input\n const totalSize = Buffer.byteLength(\n options.export?.strInj ? options.export?.strInj : JSON.stringify(chart),\n 'utf-8'\n );\n\n // Log the size in MB\n log(\n 3,\n `[export] The current total size of data passed to a page is around ${(\n totalSize /\n (1024 * 1024)\n ).toFixed(2)} MB`\n );\n\n // Check the size of data passed to the page\n if (totalSize >= 100 * 1024 * 1024) {\n throw new ExportError(`[export] The data passed to a page exceeded 100MB.`);\n }\n\n // Trigger the Highcharts chart creation\n return page.evaluate(triggerExport, chart, options, displayErrors);\n};\n\n/**\n * Exports to a chart from a page using Puppeteer.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object or SVG configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} Promise resolving to\n * the exported data or rejecting with an ExportError.\n */\nexport default async (page, chart, options) => {\n // Injected resources array (additional JS and CSS)\n let injectedResources = [];\n\n try {\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n getCache().activeManifest.modules.debugger;\n\n let isSVG;\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG input handling\n log(4, '[export] Treating as SVG.');\n\n // If input is also SVG, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n await page.setContent(svgTemplate(chart), {\n waitUntil: 'domcontentloaded'\n });\n } else {\n // JSON config handling\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options,\n displayErrors\n );\n } else {\n // Basic configuration export\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n await setAsConfig(page, chart, options, displayErrors);\n }\n }\n\n // Keeps track of all resources added on the page with addXXXTag. etc\n // It's VITAL that all added resources ends up here so we can clear things\n // out when doing a new export in the same page!\n injectedResources = await addPageResources(page, options);\n\n // Get the real chart size and set the zoom accordingly\n const size = isSVG\n ? await page.evaluate((scale) => {\n const svgElement = document.querySelector(\n '#chart-container svg:first-of-type'\n );\n\n // Get the values correctly scaled\n const chartHeight = svgElement.height.baseVal.value * scale;\n const chartWidth = svgElement.width.baseVal.value * scale;\n\n // In case of SVG the zoom must be set directly for body\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n\n return {\n chartHeight,\n chartWidth\n };\n }, parseFloat(exportOptions.scale))\n : await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n\n // No need for such scale manipulation in case of other types of exports\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n\n return {\n chartHeight,\n chartWidth\n };\n });\n\n // Set final height and width for viewport\n const viewportHeight = Math.abs(\n Math.ceil(size.chartHeight || exportOptions.height)\n );\n const viewportWidth = Math.abs(\n Math.ceil(size.chartWidth || exportOptions.width)\n );\n\n // Get the clip region for the page\n const { x, y } = await getClipRegion(page);\n\n // Set the final viewport now that we have the real height\n await page.setViewport({\n height: viewportHeight,\n width: viewportWidth,\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\n });\n\n let data;\n // Rasterization process\n if (exportOptions.type === 'svg') {\n // SVG\n data = await createSVG(page);\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\n // PNG or JPEG\n data = await createImage(\n page,\n exportOptions.type,\n 'base64',\n {\n width: viewportWidth,\n height: viewportHeight,\n x,\n y\n },\n exportOptions.rasterizationTimeout\n );\n } else if (exportOptions.type === 'pdf') {\n // PDF\n data = await createPDF(\n page,\n viewportHeight,\n viewportWidth,\n 'base64',\n exportOptions.rasterizationTimeout\n );\n } else {\n throw new ExportError(\n `[export] Unsupported output format ${exportOptions.type}.`\n );\n }\n\n // Clear previously injected JS and CSS resources\n await clearPageResources(page, injectedResources);\n return data;\n } catch (error) {\n await clearPageResources(page, injectedResources);\n return error;\n }\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport cssTemplate from './css.js';\n\nexport default (chart) => `\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${chart}\n
\n \n\n\n`;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { Pool } from 'tarn';\nimport { v4 as uuid } from 'uuid';\n\nimport {\n create as createBrowser,\n close as closeBrowser,\n newPage,\n clearPage\n} from './browser.js';\nimport puppeteerExport from './export.js';\nimport { log, logWithStack } from './logger.js';\nimport { measureTime } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\n// The pool instance\nlet pool = false;\n\n// Pool statistics\nexport const stats = {\n performedExports: 0,\n exportAttempts: 0,\n exportFromSvgAttempts: 0,\n timeSpent: 0,\n droppedExports: 0,\n spentAverage: 0\n};\n\nlet poolConfig = {};\n\nconst factory = {\n /**\n * Creates a new worker page for the export pool.\n *\n * @returns {Object} - An object containing the worker ID, a reference to the\n * browser page, and initial work count.\n *\n * @throws {ExportError} - If there's an error during the creation of the new\n * page.\n */\n create: async () => {\n let page = false;\n\n const id = uuid();\n const startDate = new Date().getTime();\n\n try {\n page = await newPage();\n\n if (!page || page.isClosed()) {\n throw new ExportError('The page is invalid or closed.');\n }\n\n log(\n 3,\n `[pool] Successfully created a worker ${id} - took ${\n new Date().getTime() - startDate\n } ms.`\n );\n } catch (error) {\n throw new ExportError(\n 'Error encountered when creating a new page.'\n ).setError(error);\n }\n\n return {\n id,\n page,\n // Try to distribute the initial work count\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\n };\n },\n\n /**\n * Validates a worker page in the export pool, checking if it has exceeded\n * the work limit.\n *\n * @param {Object} workerHandle - The handle to the worker, containing the\n * worker's ID, a reference to the browser page, and work count.\n *\n * @returns {boolean} - Returns true if the worker is valid and within\n * the work limit; otherwise, returns false.\n */\n validate: async (workerHandle) => {\n // NOTE: In certain cases acquiring throws a TargetCloseError, which may\n // be caused by two things:\n // - The page is closed and attempted to be reused.\n // - Lost contact with the browser\n // What we're seeing in logs is that successive exports typically\n // succeeds, and the server recovers, indicating that it's likely\n // the first case. This is an attempt at allievating the issue by\n // simply not validating the worker if the page is null or closed.\n //\n // The actual result from when this happened, was that a worker would\n // be completely locked, stopping it from being acquired until\n // its work count reached the limit.\n if (!workerHandle.page || workerHandle.page?.isClosed()) {\n return false;\n }\n\n if (\n poolConfig.workLimit &&\n ++workerHandle.workCount > poolConfig.workLimit\n ) {\n log(\n 3,\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\n );\n return false;\n }\n return true;\n },\n\n /**\n * Destroys a worker entry in the export pool, closing its associated page.\n *\n * @param {Object} workerHandle - The handle to the worker, containing\n * the worker's ID and a reference to the browser page.\n */\n destroy: async (workerHandle) => {\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\n\n if (workerHandle.page && !workerHandle.page.isClosed()) {\n await workerHandle.page.close();\n }\n }\n\n // log: (message, level) => log(1, '[tarn] ' + message)\n};\n\n/**\n * Initializes the export pool with the provided configuration, creating\n * a browser instance and setting up worker resources.\n *\n * @param {Object} config - Configuration options for the export pool along\n * with custom puppeteer arguments for the puppeteer.launch function.\n */\nexport const initPool = async (config) => {\n // For the module scope usage\n poolConfig = config && config.pool ? { ...config.pool } : {};\n\n // Create a browser instance with the puppeteer arguments\n await createBrowser(config.puppeteerArgs);\n\n log(\n 3,\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\n );\n\n if (pool) {\n return log(\n 4,\n '[pool] Already initialized, please kill it before creating a new one.'\n );\n }\n\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\n poolConfig.minWorkers = poolConfig.maxWorkers;\n }\n\n try {\n // Create a pool along with a minimal number of resources\n pool = new Pool({\n // Get the create/validate/destroy/log functions\n ...factory,\n min: parseInt(poolConfig.minWorkers),\n max: parseInt(poolConfig.maxWorkers),\n acquireTimeoutMillis: poolConfig.acquireTimeout,\n createTimeoutMillis: poolConfig.createTimeout,\n destroyTimeoutMillis: poolConfig.destroyTimeout,\n idleTimeoutMillis: poolConfig.idleTimeout,\n createRetryIntervalMillis: poolConfig.createRetryInterval,\n reapIntervalMillis: poolConfig.reaperInterval,\n propagateCreateError: false\n });\n\n // Set events\n pool.on('release', async (resource) => {\n // Clear page\n const r = await clearPage(resource.page, false);\n log(\n 4,\n `[pool] Releasing a worker with ID ${resource.id}. Clear page status: ${r}.`\n );\n });\n\n pool.on('destroySuccess', (eventId, resource) => {\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\n resource.page = null;\n });\n\n const initialResources = [];\n // Create an initial number of resources\n for (let i = 0; i < poolConfig.minWorkers; i++) {\n try {\n const resource = await pool.acquire().promise;\n initialResources.push(resource);\n } catch (error) {\n logWithStack(2, error, '[pool] Could not create an initial resource.');\n }\n }\n\n // Release the initial number of resources back to the pool\n initialResources.forEach((resource) => {\n pool.release(resource);\n });\n\n log(\n 3,\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\n );\n } catch (error) {\n throw new ExportError(\n '[pool] Could not create the pool of workers.'\n ).setError(error);\n }\n};\n\n/**\n * Kills all workers in the pool, destroys the pool, and closes the browser\n * instance.\n *\n * @returns {Promise} A promise that resolves after the workers are\n * killed, the pool is destroyed, and the browser is closed.\n */\nexport async function killPool() {\n log(3, '[pool] Killing pool with all workers and closing browser.');\n\n // If still alive, destroy the pool of pages before closing a browser\n if (pool) {\n // Free up not released workers\n for (const worker of pool.used) {\n pool.release(worker.resource);\n }\n\n // Destroy the pool if it is still available\n if (!pool.destroyed) {\n await pool.destroy();\n log(4, '[browser] Destroyed the pool of resources.');\n }\n }\n\n // Close the browser instance\n await closeBrowser();\n}\n\n/**\n * Processes the export work using a worker from the pool. Acquires a worker\n * handle from the pool, performs the export using puppeteer, and releases\n * the worker handle back to the pool.\n *\n * @param {string} chart - The chart data or configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} A promise that resolves with the export resultand\n * options.\n *\n * @throws {ExportError} If an error occurs during the export process.\n */\nexport const postWork = async (chart, options) => {\n let workerHandle;\n\n try {\n log(4, '[pool] Work received, starting to process.');\n\n ++stats.exportAttempts;\n if (poolConfig.benchmarking) {\n getPoolInfo();\n }\n\n if (!pool) {\n throw new ExportError('Work received, but pool has not been started.');\n }\n\n // Acquire the worker along with the id of resource and work count\n const acquireCounter = measureTime();\n try {\n log(4, '[pool] Acquiring a worker handle.');\n workerHandle = await pool.acquire().promise;\n\n // Check the page acquire time\n if (options.server.benchmarking) {\n log(\n 5,\n options.payload?.requestId\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\n : '[benchmark]',\n `Acquired a worker handle: ${acquireCounter()}ms.`\n );\n }\n } catch (error) {\n throw new ExportError(\n (options.payload?.requestId\n ? `For request with ID ${options.payload?.requestId} - `\n : '') +\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\n ).setError(error);\n }\n log(4, '[pool] Acquired a worker handle.');\n\n if (!workerHandle.page) {\n throw new ExportError(\n 'Resolved worker page is invalid: the pool setup is wonky.'\n );\n }\n\n // Save the start time\n let workStart = new Date().getTime();\n\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\n\n // Perform an export on a puppeteer level\n const exportCounter = measureTime();\n const result = await puppeteerExport(workerHandle.page, chart, options);\n\n // Check if it's an error\n if (result instanceof Error) {\n // NOTE: If there's a rasterization timeout, we want need to flush the page.\n // This is because the page may be in a state where it's waiting for\n // the screenshot to finish even though the timeout has occured.\n // Which of course causes a lot of issues with the event system,\n // and page consistency.\n //\n // NOTE: Only page.screenshot will throw this, timeouts for PDF's are\n // handled by the page.pdf function itself.\n //\n // ...yes, this is ugly.\n if (result.message === 'Rasterization timeout') {\n workerHandle.workCount = poolConfig.workLimit + 1;\n workerHandle.page = null;\n }\n\n if (\n result.name === 'TimeoutError' ||\n result.message === 'Rasterization timeout'\n ) {\n throw new ExportError(\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\n ).setError(result);\n } else {\n throw new ExportError(\n (options.payload?.requestId\n ? `For request with ID ${options.payload?.requestId} - `\n : '') + `Error encountered during export: ${exportCounter()}ms.`\n ).setError(result);\n }\n }\n\n // Check the Puppeteer export time\n if (options.server.benchmarking) {\n log(\n 5,\n options.payload?.requestId\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\n : '[benchmark]',\n `Exported a chart sucessfully: ${exportCounter()}ms.`\n );\n }\n\n // Release the resource back to the pool\n pool.release(workerHandle);\n\n // Used for statistics in averageTime and processedWorkCount, which\n // in turn is used by the /health route.\n const workEnd = new Date().getTime();\n const exportTime = workEnd - workStart;\n stats.timeSpent += exportTime;\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\n\n log(4, `[pool] Work completed in ${exportTime} ms.`);\n\n // Otherwise return the result\n return {\n result,\n options\n };\n } catch (error) {\n ++stats.droppedExports;\n\n if (workerHandle) {\n pool.release(workerHandle);\n }\n\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\n error\n );\n }\n};\n\n/**\n * Retrieves the current pool instance.\n *\n * @returns {Object|null} The current pool instance if initialized, or null\n * if the pool has not been created.\n */\nexport const getPool = () => pool;\n\n/**\n * Retrieves pool information in JSON format, including minimum and maximum\n * workers, available workers, workers in use, and pending acquire requests.\n *\n * @returns {Object} Pool information in JSON format.\n */\nexport const getPoolInfoJSON = () => ({\n min: pool.min,\n max: pool.max,\n all: pool.numFree() + pool.numUsed(),\n available: pool.numFree(),\n used: pool.numUsed(),\n pending: pool.numPendingAcquires()\n});\n\n/**\n * Logs information about the current state of the pool, including the minimum\n * and maximum workers, available workers, workers in use, and pending acquire\n * requests.\n */\nexport function getPoolInfo() {\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\n\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\n log(5, `[pool] The number of all created resources: ${all}.`);\n log(5, `[pool] The number of available resources: ${available}.`);\n log(5, `[pool] The number of acquired resources: ${used}.`);\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\n}\n\nexport default {\n initPool,\n killPool,\n postWork,\n getPool,\n getPoolInfo,\n getPoolInfoJSON,\n getStats: () => stats\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync, writeFileSync } from 'fs';\n\nimport { getOptions, initExportSettings } from './config.js';\nimport { log, logWithStack } from './logger.js';\nimport { killPool, postWork, stats } from './pool.js';\nimport {\n fixType,\n handleResources,\n isCorrectJSON,\n optionsStringify,\n roundNumber,\n toBoolean,\n wrapAround\n} from './utils.js';\nimport { sanitize } from './sanitize.js';\nimport ExportError from './errors/ExportError.js';\n\nlet allowCodeExecution = false;\n\n/**\n * Starts an export process. The `settings` contains final options gathered\n * from all possible sources (config, env, cli, json). The `endCallback` is\n * called when the export is completed, with an error object as the first\n * argument and the second containing the base64 respresentation of a chart.\n *\n * @param {Object} settings - The settings object containing export\n * configuration.\n * @param {function} endCallback - The callback function to be invoked upon\n * finalizing work or upon error occurance of the exporting process.\n *\n * @returns {void} This function does not return a value directly; instead,\n * it communicates results via the endCallback.\n */\nexport const startExport = async (settings, endCallback) => {\n // Starting exporting process message\n log(4, '[chart] Starting the exporting process.');\n\n // Initialize options\n const options = initExportSettings(settings, getOptions());\n\n // Get the export options\n const exportOptions = options.export;\n\n // If SVG is an input (argument can be sent only by the request)\n if (options.payload?.svg && options.payload.svg !== '') {\n try {\n log(4, '[chart] Attempting to export from a SVG input.');\n\n const result = exportAsString(\n sanitize(options.payload.svg), // #209\n options,\n endCallback\n );\n\n ++stats.exportFromSvgAttempts;\n return result;\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading SVG input.').setError(error)\n );\n }\n }\n\n // Export using options from the file\n if (exportOptions.infile && exportOptions.infile.length) {\n // Try to read the file to get the string representation\n try {\n log(4, '[chart] Attempting to export from an input file.');\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\n return exportAsString(options.export.instr.trim(), options, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading input file.').setError(error)\n );\n }\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n try {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading raw input.').setError(error)\n );\n }\n }\n\n // No input specified, pass an error message to the callback\n return endCallback(\n new ExportError(\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\n )\n );\n};\n\n/**\n * Starts a batch export process for multiple charts based on the information\n * in the batch option. The batch is a string in the following format:\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\n *\n * @param {Object} options - The options object containing configuration for\n * a batch export.\n *\n * @returns {Promise} A Promise that resolves once the batch export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * any of the batch export process.\n */\nexport const batchExport = async (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (error, info) => {\n // Throw an error\n if (error) {\n throw error;\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n info.options.export.type !== 'svg'\n ? Buffer.from(info.result, 'base64')\n : info.result\n );\n }\n )\n );\n }\n }\n\n try {\n // Await all exports are done\n await Promise.all(batchFunctions);\n\n // Kill pool and close browser after finishing batch export\n await killPool();\n } catch (error) {\n throw new ExportError(\n '[chart] Error encountered during batch export.'\n ).setError(error);\n }\n};\n\n/**\n * Starts a single export process based on the specified options.\n *\n * @param {Object} options - The options object containing configuration for\n * a single export.\n *\n * @returns {Promise} A Promise that resolves once the single export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * the single export process.\n */\nexport const singleExport = async (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n await startExport(options, async (error, info) => {\n // Exit process when error\n if (error) {\n throw error;\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\n );\n\n // Kill pool and close browser after finishing single export\n await killPool();\n });\n};\n\n/**\n * Determines the size and scale for chart export based on the provided options.\n *\n * @param {Object} options - The options object containing configuration for\n * chart export.\n *\n * @returns {Object} An object containing the calculated height, width,\n * and scale for the chart export.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n const size = {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n\n // Get rid of potential px and %\n for (let [param, value] of Object.entries(size)) {\n size[param] =\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\n }\n return size;\n};\n\n/**\n * Function for finalizing options before export.\n *\n * @param {Object} options - The options object containing configuration for\n * the export process.\n * @param {Object} chartJson - The JSON representation of the chart.\n * @param {Function} endCallback - The callback function to be called upon\n * completion or error.\n * @param {string} svg - The SVG representation of the chart.\n *\n * @returns {Promise} A Promise that resolves once the export process\n * is completed.\n */\nconst doExport = async (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customLogic: customLogicOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customLogicOptions.allowCodeExecution === 'boolean'\n ? customLogicOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customLogicOptions) {\n customLogicOptions = options.customLogic = {};\n } else if (allowCodeExecutionScoped) {\n if (typeof options.customLogic.resources === 'string') {\n // Process resources\n options.customLogic.resources = handleResources(\n options.customLogic.resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } else if (!options.customLogic.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customLogic.resources = handleResources(\n resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[chart] Unable to load the default resources.json file.`\n );\n }\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customLogicOptions) {\n if (\n customLogicOptions.callback ||\n customLogicOptions.resources ||\n customLogicOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return endCallback(\n new ExportError(\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\n )\n );\n }\n\n // Reset all additional custom code\n customLogicOptions.callback = false;\n customLogicOptions.resources = false;\n customLogicOptions.customCode = false;\n }\n\n // Clean properties to keep it lean and mean\n if (chartJson) {\n chartJson.chart = chartJson.chart || {};\n chartJson.exporting = chartJson.exporting || {};\n chartJson.exporting.enabled = false;\n }\n\n exportOptions.constr = exportOptions.constr || 'chart';\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\n if (exportOptions.type === 'svg') {\n exportOptions.width = false;\n }\n\n // Prepare global and theme options\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\n try {\n if (exportOptions && exportOptions[optionsName]) {\n if (\n typeof exportOptions[optionsName] === 'string' &&\n exportOptions[optionsName].endsWith('.json')\n ) {\n exportOptions[optionsName] = isCorrectJSON(\n readFileSync(exportOptions[optionsName], 'utf8'),\n true\n );\n } else {\n exportOptions[optionsName] = isCorrectJSON(\n exportOptions[optionsName],\n true\n );\n }\n }\n } catch (error) {\n exportOptions[optionsName] = {};\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\n }\n });\n\n // Prepare the customCode\n if (customLogicOptions.allowCodeExecution) {\n try {\n customLogicOptions.customCode = wrapAround(\n customLogicOptions.customCode,\n customLogicOptions.allowFileResources\n );\n } catch (error) {\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\n }\n }\n\n // Get the callback\n if (\n customLogicOptions &&\n customLogicOptions.callback &&\n customLogicOptions.callback?.indexOf('{') < 0\n ) {\n // The allowFileResources is always set to false for HTTP requests to avoid\n // injecting arbitrary files from the fs\n if (customLogicOptions.allowFileResources) {\n try {\n customLogicOptions.callback = readFileSync(\n customLogicOptions.callback,\n 'utf8'\n );\n } catch (error) {\n customLogicOptions.callback = false;\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\n }\n } else {\n customLogicOptions.callback = false;\n }\n }\n\n // Size search\n options.export = {\n ...options.export,\n ...findChartSize(options)\n };\n\n // Post the work to the pool\n try {\n const result = await postWork(\n exportOptions.strInj || chartJson || svg,\n options\n );\n return endCallback(false, result);\n } catch (error) {\n return endCallback(error);\n }\n};\n\n/**\n * Performs a direct inject of options before export. The function attempts\n * to stringify the provided options and removes unnecessary characters,\n * ensuring a clean and formatted input. The resulting string is saved as\n * a \"stright inject\" string in the export options. It then invokes the\n * doExport function with the updated options.\n *\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\n * a server (see the --allowCodeExecution option).\n *\n * @param {Object} options - The export options containing the input\n * to be injected.\n * @param {function} endCallback - The callback function to be invoked\n * at the end of the process.\n *\n * @returns {Promise} A Promise that resolves with the result of the export\n * operation or rejects with an error if any issues occur during the process.\n */\nconst doStraightInject = (options, endCallback) => {\n try {\n let strInj;\n let instr = options.export.instr || options.export.options;\n\n if (typeof instr !== 'string') {\n // Try to stringify options\n strInj = instr = optionsStringify(\n instr,\n options.customLogic?.allowCodeExecution\n );\n }\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\n\n // Get rid of the ;\n if (strInj[strInj.length - 1] === ';') {\n strInj = strInj.substring(0, strInj.length - 1);\n }\n\n // Save as stright inject string\n options.export.strInj = strInj;\n return doExport(options, false, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError(\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\n ).setError(error)\n );\n }\n};\n\n/**\n * Exports a string based on the provided options and invokes an end callback.\n *\n * @param {string} stringToExport - The string content to be exported.\n * @param {Object} options - Export options, including customLogic with\n * allowCodeExecution flag.\n * @param {Function} endCallback - Callback function to be invoked at the end\n * of the export process.\n *\n * @returns {any} Result of the export process or an error if encountered.\n */\nconst exportAsString = (stringToExport, options, endCallback) => {\n const { allowCodeExecution } = options.customLogic;\n\n // Check if it is SVG\n if (\n stringToExport.indexOf('= 0 ||\n stringToExport.indexOf('= 0\n ) {\n log(4, '[chart] Parsing input as SVG.');\n return doExport(options, false, endCallback, stringToExport);\n }\n\n try {\n // Try to parse to JSON and call the doExport function\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\n\n // If a correct JSON, do the export\n return doExport(options, chartJSON, endCallback);\n } catch (error) {\n // Not a valid JSON\n if (toBoolean(allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n } else {\n // Do not allow straight injection without the allowCodeExecution flag\n return endCallback(\n new ExportError(\n '[chart] Only JSON 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 flag.'\n ).setError(error)\n );\n }\n }\n};\n\n/**\n * Retrieves and returns the current status of code execution permission.\n *\n * @returns {any} The value of allowCodeExecution.\n */\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\n/**\n * Sets the code execution permission based on the provided boolean value.\n *\n * @param {any} value - The value to be converted and assigned\n * to allowCodeExecution.\n */\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/**\n * @overview Used to sanitize the strings coming from the exporting module\n * to prevent XSS attacks (with the DOMPurify library).\n **/\n\nimport { JSDOM } from 'jsdom';\nimport DOMPurify from 'dompurify';\n\n/**\n * Sanitizes a given HTML string by removing tags and any content within them.\n *\n * @param {string} input The HTML string to be sanitized.\n * @returns {string} The sanitized HTML string.\n */\nexport function sanitize(input) {\n const window = new JSDOM('').window;\n const purify = DOMPurify(window);\n return purify.sanitize(input, {\n ADD_TAGS: ['foreignObject'],\n // Dissalow all xlinks in incoming SVG\n FORBID_ATTR: ['xlink:href']\n });\n}\n\nexport default sanitize;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { log } from './logger.js';\n\n// Array that contains ids of all ongoing intervals\nconst intervalIds = [];\n\n/**\n * Adds id of a setInterval to the intervalIds array.\n *\n * @param {NodeJS.Timeout} id - Id of an interval.\n */\nexport const addInterval = (id) => {\n intervalIds.push(id);\n};\n\n/**\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\n */\nexport const clearAllIntervals = () => {\n log(4, `[server] Clearing all registered intervals.`);\n for (const id of intervalIds) {\n clearInterval(id);\n }\n};\n\nexport default {\n addInterval,\n clearAllIntervals\n};\n","import { envs } from '../envs.js';\nimport { logWithStack } from '../logger.js';\n\n/**\n * Middleware for logging errors with stack trace and handling error response.\n *\n * @param {Error} error - The error object.\n * @param {Express.Request} req - The Express request object.\n * @param {Express.Response} res - The Express response object.\n * @param {Function} next - The next middleware function.\n */\nconst logErrorMiddleware = (error, req, res, next) => {\n // Display the error with stack in a correct format\n logWithStack(1, error);\n\n // Delete the stack for the environment other than the development\n if (envs.OTHER_NODE_ENV !== 'development') {\n delete error.stack;\n }\n\n // Call the returnErrorMiddleware\n next(error);\n};\n\n/**\n * Middleware for returning error response.\n *\n * @param {Error} error - The error object.\n * @param {Express.Request} req - The Express request object.\n * @param {Express.Response} res - The Express response object.\n * @param {Function} next - The next middleware function.\n */\nconst returnErrorMiddleware = (error, req, res, next) => {\n // Gather all requied information for the response\n const { statusCode: stCode, status, message, stack } = error;\n const statusCode = stCode || status || 400;\n\n // Set and return response\n res.status(statusCode).json({ statusCode, message, stack });\n};\n\nexport default (app) => {\n // Add log error middleware\n app.use(logErrorMiddleware);\n\n // Add set status and return error middleware\n app.use(returnErrorMiddleware);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport rateLimit from 'express-rate-limit';\n\nimport { log } from '../logger.js';\n\n/**\n * Middleware for enabling rate limiting on the specified Express app.\n *\n * @param {Express} app - The Express app instance.\n * @param {Object} limitConfig - Configuration options for rate limiting.\n */\nexport default (app, limitConfig) => {\n const msg =\n 'Too many requests, you have been rate limited. Please try again later.';\n\n // Options for the rate limiter\n const rateOptions = {\n max: limitConfig.maxRequests || 30,\n window: limitConfig.window || 1,\n delay: limitConfig.delay || 0,\n trustProxy: limitConfig.trustProxy || false,\n skipKey: limitConfig.skipKey || false,\n skipToken: limitConfig.skipToken || false\n };\n\n // Set if behind a proxy\n if (rateOptions.trustProxy) {\n app.enable('trust proxy');\n }\n\n // Create a limiter\n const limiter = rateLimit({\n windowMs: rateOptions.window * 60 * 1000,\n // Limit each IP to 100 requests per windowMs\n max: rateOptions.max,\n // Disable delaying, full speed until the max limit is reached\n delayMs: rateOptions.delay,\n handler: (request, response) => {\n response.format({\n json: () => {\n response.status(429).send({ message: msg });\n },\n default: () => {\n response.status(429).send(msg);\n }\n });\n },\n skip: (request) => {\n // Allow bypassing the limiter if a valid key/token has been sent\n if (\n rateOptions.skipKey !== false &&\n rateOptions.skipToken !== false &&\n request.query.key === rateOptions.skipKey &&\n request.query.access_token === rateOptions.skipToken\n ) {\n log(4, '[rate limiting] Skipping rate limiter.');\n return true;\n }\n return false;\n }\n });\n\n // Use a limiter as a middleware\n app.use(limiter);\n\n log(\n 3,\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\n );\n};\n","import ExportError from './ExportError.js';\n\nclass HttpError extends ExportError {\n constructor(message, status) {\n super(message);\n this.status = this.statusCode = status;\n }\n\n setStatus(status) {\n this.status = status;\n return this;\n }\n}\n\nexport default HttpError;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { updateVersion, version } from '../../cache.js';\nimport { envs } from '../../envs.js';\n\nimport HttpError from '../../errors/HttpError.js';\n\n/**\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\n * the Highcharts version on the server.\n *\n * TODO: Add auth token and connect to API\n */\nexport default (app) =>\n !app\n ? false\n : app.post(\n '/version/change/:newVersion',\n async (request, response, next) => {\n try {\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\n\n // Check the existence of the token\n if (!adminToken || !adminToken.length) {\n throw new HttpError(\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\n 401\n );\n }\n\n // Check if the hc-auth header contain a correct token\n const token = request.get('hc-auth');\n if (!token || token !== adminToken) {\n throw new HttpError(\n 'Invalid or missing token: Set the token in the hc-auth header.',\n 401\n );\n }\n\n // Compare versions\n const newVersion = request.params.newVersion;\n if (newVersion) {\n try {\n // eslint-disable-next-line import/no-named-as-default-member\n await updateVersion(newVersion);\n } catch (error) {\n throw new HttpError(\n `Version change: ${error.message}`,\n error.statusCode\n ).setError(error);\n }\n\n // Success\n response.status(200).send({\n statusCode: 200,\n version: version(),\n message: `Successfully updated Highcharts to version: ${newVersion}.`\n });\n } else {\n // No version specified\n throw new HttpError('No new version supplied.', 400);\n }\n } catch (error) {\n next(error);\n }\n }\n );\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { v4 as uuid } from 'uuid';\n\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\nimport { getOptions, mergeConfigOptions } from '../../config.js';\nimport { log } from '../../logger.js';\nimport {\n fixType,\n isCorrectJSON,\n isObjectEmpty,\n isPrivateRangeUrlFound,\n optionsStringify,\n measureTime\n} from '../../utils.js';\n\nimport HttpError from '../../errors/HttpError.js';\n\n// Reversed MIME types\nconst reversedMime = {\n png: 'image/png',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n pdf: 'application/pdf',\n svg: 'image/svg+xml'\n};\n\n// The requests counter\nlet requestsCounter = 0;\n\n// The array of callbacks to call before a request\nconst beforeRequest = [];\n\n// The array of callbacks to call after a request\nconst afterRequest = [];\n\n/**\n * Invokes an array of callback functions with specified parameters, allowing\n * customization of request handling.\n *\n * @param {Function[]} callbacks - An array of callback functions\n * to be executed.\n * @param {Express.Request} request - The Express request object.\n * @param {Express.Response} response - The Express response object.\n * @param {Object} data - An object containing parameters like id, uniqueId,\n * type, and body.\n *\n * @returns {boolean} - Returns a boolean indicating the overall result\n * of the callback invocations.\n */\nconst doCallbacks = (callbacks, request, response, data) => {\n let result = true;\n const { id, uniqueId, type, body } = data;\n\n callbacks.some((callback) => {\n if (callback) {\n let callResponse = callback(request, response, id, uniqueId, type, body);\n\n if (callResponse !== undefined && callResponse !== true) {\n result = callResponse;\n }\n\n return true;\n }\n });\n\n return result;\n};\n\n/**\n * Handles the export requests from the client.\n *\n * @param {Express.Request} request - The Express request object.\n * @param {Express.Response} response - The Express response object.\n * @param {Function} next - The next middleware function.\n *\n * @returns {Promise} - A promise that resolves once the export process\n * is complete.\n */\nconst exportHandler = async (request, response, next) => {\n try {\n // Start counting time\n const stopCounter = measureTime();\n\n // Create a unique ID for a request\n const uniqueId = uuid().replace(/-/g, '');\n\n // Get the current server's general options\n const defaultOptions = getOptions();\n\n const body = request.body;\n const id = ++requestsCounter;\n\n let type = fixType(body.type);\n\n // Throw 'Bad Request' if there's no body\n if (!body || isObjectEmpty(body)) {\n throw new HttpError(\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\n 400\n );\n }\n\n // All of the below can be used\n let instr = isCorrectJSON(body.infile || body.options || body.data);\n\n // Throw 'Bad Request' if there's no JSON or SVG to export\n if (!instr && !body.svg) {\n log(\n 2,\n `The request with ID ${uniqueId} from ${\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\n } was incorrect:\n Content-Type: ${request.headers['content-type']}. \n Chart constructor: ${body.constr}.\n Dimensions: ${body.width}x${body.height} @ ${body.scale} scale.\n Type: ${type}.\n Is SVG set? ${typeof body.svg !== 'undefined'}.\n B64? ${typeof body.b64 !== 'undefined'}.\n No download? ${typeof body.noDownload !== 'undefined'}.\n\n Payload received: ${JSON.stringify(body.infile || body.options || body.data || body.svg)}\n\n `\n );\n\n throw new HttpError(\n \"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.\",\n 400\n );\n }\n\n let callResponse = false;\n\n // Call the before request functions\n callResponse = doCallbacks(beforeRequest, request, response, {\n id,\n uniqueId,\n type,\n body\n });\n\n // Block the request if one of a callbacks failed\n if (callResponse !== true) {\n return response.send(callResponse);\n }\n\n let connectionAborted = false;\n\n // In case the connection is closed, force to abort further actions\n request.socket.on('close', (hadErrors) => {\n if (hadErrors) {\n connectionAborted = true;\n }\n });\n\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\n\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\n\n // Gather and organize options from the payload\n const requestOptions = {\n export: {\n instr,\n type,\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\n height: body.height,\n width: body.width,\n scale: body.scale || defaultOptions.export.scale,\n globalOptions: isCorrectJSON(body.globalOptions, true),\n themeOptions: isCorrectJSON(body.themeOptions, true)\n },\n customLogic: {\n allowCodeExecution: getAllowCodeExecution(),\n allowFileResources: false,\n resources: isCorrectJSON(body.resources, true),\n callback: body.callback,\n customCode: body.customCode\n }\n };\n\n if (instr) {\n // Stringify JSON with options\n requestOptions.export.instr = optionsStringify(\n instr,\n requestOptions.customLogic.allowCodeExecution\n );\n }\n\n // Merge the request options into default ones\n const options = mergeConfigOptions(defaultOptions, requestOptions);\n\n // Save the JSON if exists\n options.export.options = instr;\n\n // Lastly, add the server specific arguments into options as payload\n options.payload = {\n svg: body.svg || false,\n b64: body.b64 || false,\n noDownload: body.noDownload || false,\n requestId: uniqueId\n };\n\n // Test xlink:href elements from payload's SVG\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\n throw new HttpError(\n '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.',\n 400\n );\n }\n\n // Start the export process\n await startExport(options, (error, info) => {\n // Remove the close event from the socket\n request.socket.removeAllListeners('close');\n\n // After the whole exporting process\n if (defaultOptions.server.benchmarking) {\n log(\n 5,\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\n );\n }\n\n // If the connection was closed, do nothing\n if (connectionAborted) {\n return log(\n 3,\n `[export] The client closed the connection before the chart finished processing.`\n );\n }\n\n // If error, log it and send it to the error middleware\n if (error) {\n throw error;\n }\n\n // If data is missing, log the message and send it to the error middleware\n if (!info || !info.result) {\n throw new HttpError(\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\n 400\n );\n }\n\n // Get the type from options\n type = info.options.export.type;\n\n // The after request callbacks\n doCallbacks(afterRequest, request, response, { id, body: info.result });\n\n if (info.result) {\n // If only base64 is required, return it\n if (body.b64) {\n // SVG Exception for the Highcharts 11.3.0 version\n if (type === 'pdf' || type == 'svg') {\n return response.send(\n Buffer.from(info.result, 'utf8').toString('base64')\n );\n }\n\n return response.send(info.result);\n }\n\n // Set correct content type\n response.header('Content-Type', reversedMime[type] || 'image/png');\n\n // Decide whether to download or not chart file\n if (!body.noDownload) {\n response.attachment(\n `${request.params.filename || request.body.filename || 'chart'}.${\n type || 'png'\n }`\n );\n }\n\n // If SVG, return plain content\n return type === 'svg'\n ? response.send(info.result)\n : response.send(Buffer.from(info.result, 'base64'));\n }\n });\n } catch (error) {\n next(error);\n }\n};\n\nexport default (app) => {\n /**\n * Adds the POST / a route for handling POST requests at the root endpoint.\n */\n app.post('/', exportHandler);\n\n /**\n * Adds the POST /:filename a route for handling POST requests with\n * a specified filename parameter.\n */\n app.post('/:filename', exportHandler);\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { join as pather } from 'path';\nimport { log } from '../../logger.js';\n\nimport { version } from '../../cache.js';\nimport { addInterval } from '../../intervals.js';\nimport pool from '../../pool.js';\nimport { __dirname } from '../../utils.js';\n\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\n\nconst serverStartTime = new Date();\n\nconst successRates = [];\nconst recordInterval = 60 * 1000; // record every minute\nconst windowSize = 30; // 30 minutes\n\n/**\n * Calculates moving average indicator based on the data from the successRates\n * array.\n *\n * @returns {number} - A moving average for success ratio of the server exports.\n */\nfunction calculateMovingAverage() {\n const sum = successRates.reduce((a, b) => a + b, 0);\n return sum / successRates.length;\n}\n\n/**\n * Starts the interval responsible for calculating current success rate ratio\n * and gathers\n *\n * @returns {NodeJS.Timeout} id - Id of an interval.\n */\nexport const startSuccessRate = () =>\n setInterval(() => {\n const stats = pool.getStats();\n const successRatio =\n stats.exportAttempts === 0\n ? 1\n : (stats.performedExports / stats.exportAttempts) * 100;\n\n successRates.push(successRatio);\n if (successRates.length > windowSize) {\n successRates.shift();\n }\n }, recordInterval);\n\n/**\n * Adds the /health and /success-moving-average routes\n * which output basic stats for the server.\n */\nexport default function addHealthRoutes(app) {\n if (!app) {\n return false;\n }\n\n // Start processing success rate ratio interval and save its id to the array\n // for the graceful clearing on shutdown with injected addInterval funtion\n addInterval(startSuccessRate());\n\n app.get('/health', (_, res) => {\n const stats = pool.getStats();\n const period = successRates.length;\n const movingAverage = calculateMovingAverage();\n\n log(4, '[health.js] GET /health [200] - returning server health.');\n\n res.send({\n status: 'OK',\n bootTime: serverStartTime,\n uptime:\n Math.floor(\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\n ) + ' minutes',\n version: pkgFile.version,\n highchartsVersion: version(),\n averageProcessingTime: stats.spentAverage,\n performedExports: stats.performedExports,\n failedExports: stats.droppedExports,\n exportAttempts: stats.exportAttempts,\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\n // eslint-disable-next-line import/no-named-as-default-member\n pool: pool.getPoolInfoJSON(),\n\n // Moving average\n period,\n movingAverage,\n message:\n isNaN(movingAverage) || !successRates.length\n ? 'Too early to report. No exports made yet. Please check back soon.'\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\n\n // SVG/JSON attempts\n svgExportAttempts: stats.exportFromSvgAttempts,\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\n });\n });\n}\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { promises as fsPromises } from 'fs';\nimport { posix } from 'path';\n\nimport cors from 'cors';\nimport express from 'express';\nimport http from 'http';\nimport https from 'https';\nimport multer from 'multer';\n\nimport errorHandler from './error.js';\nimport rateLimit from './rate_limit.js';\nimport { log, logWithStack } from '../logger.js';\nimport { __dirname } from '../utils.js';\n\nimport vSwitchRoute from './routes/change_hc_version.js';\nimport exportRoutes from './routes/export.js';\nimport healthRoute from './routes/health.js';\nimport uiRoute from './routes/ui.js';\n\nimport ExportError from '../errors/ExportError.js';\n\n// Array of an active servers\nconst activeServers = new Map();\n\n// Create express app\nconst app = express();\n\n// Disable the X-Powered-By header\napp.disable('x-powered-by');\n\n// Enable CORS support\napp.use(cors());\n\n// Getting a lot of RangeNotSatisfiableError exception.\n// Even though this is a deprecated options, let's try to set it to false.\napp.use((_req, res, next) => {\n res.set('Accept-Ranges', 'none');\n next();\n});\n\n/**\n * Attach error handlers to the server.\n *\n * @param {http.Server} server - The HTTP/HTTPS server instance.\n */\nconst attachServerErrorHandlers = (server) => {\n server.on('clientError', (error, socket) => {\n logWithStack(\n 1,\n error,\n `[server] Client error: ${error.message}, destroying socket.`\n );\n socket.destroy();\n });\n\n server.on('error', (error) => {\n logWithStack(1, error, `[server] Server error: ${error.message}`);\n });\n\n server.on('connection', (socket) => {\n socket.on('error', (error) => {\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\n });\n });\n};\n\n/**\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\n * object contains all server related properties (see the `server` section\n * in the `lib/schemas/config.js` file for a reference).\n *\n * @param {Object} serverConfig - The server configuration object.\n *\n * @throws {ExportError} - Throws an error if the server cannot be configured\n * and started.\n */\nexport const startServer = async (serverConfig) => {\n try {\n // TODO: Read from config/env\n // NOTE:\n // Too big limits lead to timeouts in the export process when the\n // rasterization timeout is set too low.\n const uploadLimitMiB = serverConfig.maxUploadSize || 3;\n const uploadLimitBytes = uploadLimitMiB * 1024 * 1024;\n\n // Enable parsing of form data (files) with Multer package\n const storage = multer.memoryStorage();\n const upload = multer({\n storage,\n limits: {\n fieldSize: uploadLimitBytes\n }\n });\n\n // Enable body parser\n app.use(express.json({ limit: uploadLimitBytes }));\n app.use(express.urlencoded({ extended: true, limit: uploadLimitBytes }));\n\n // Use only non-file multipart form fields\n app.use(upload.none());\n\n // Stop if not enabled\n if (!serverConfig.enable) {\n return false;\n }\n\n // Listen HTTP server\n if (!serverConfig.ssl.force) {\n // Main server instance (HTTP)\n const httpServer = http.createServer(app);\n\n // Attach error handlers and listen to the server\n attachServerErrorHandlers(httpServer);\n\n // Listen\n httpServer.listen(serverConfig.port, serverConfig.host);\n\n // Save the reference to HTTP server\n activeServers.set(serverConfig.port, httpServer);\n\n log(\n 3,\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\n );\n }\n\n // Listen HTTPS server\n if (serverConfig.ssl.enable) {\n // Set up an SSL server also\n let key, cert;\n\n try {\n // Get the SSL key\n key = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.key'),\n 'utf8'\n );\n\n // Get the SSL certificate\n cert = await fsPromises.readFile(\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\n 'utf8'\n );\n } catch (error) {\n log(\n 2,\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\n );\n }\n\n if (key && cert) {\n // Main server instance (HTTPS)\n const httpsServer = https.createServer({ key, cert }, app);\n\n // Attach error handlers and listen to the server\n attachServerErrorHandlers(httpsServer);\n\n // Listen\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\n\n // Save the reference to HTTPS server\n activeServers.set(serverConfig.ssl.port, httpsServer);\n\n log(\n 3,\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\n );\n }\n }\n\n // Enable the rate limiter if config says so\n if (\n serverConfig.rateLimiting &&\n serverConfig.rateLimiting.enable &&\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\n ) {\n rateLimit(app, serverConfig.rateLimiting);\n }\n\n // Set up static folder's route\n app.use(express.static(posix.join(__dirname, 'public')));\n\n // Set up routes\n healthRoute(app);\n exportRoutes(app);\n uiRoute(app);\n vSwitchRoute(app);\n\n // Set up centralized error handler\n errorHandler(app);\n } catch (error) {\n throw new ExportError(\n '[server] Could not configure and start the server.'\n ).setError(error);\n }\n};\n\n/**\n * Closes all servers associated with Express app instance.\n */\nexport const closeServers = () => {\n log(4, `[server] Closing all servers.`);\n for (const [port, server] of activeServers) {\n server.close(() => {\n activeServers.delete(port);\n log(4, `[server] Closed server on port: ${port}.`);\n });\n }\n};\n\n/**\n * Get all servers associated with Express app instance.\n *\n * @returns {Array} - Servers associated with Express app instance.\n */\nexport const getServers = () => activeServers;\n\n/**\n * Enable rate limiting for the server.\n *\n * @param {Object} limitConfig - Configuration object for rate limiting.\n */\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\n\n/**\n * Get the Express instance.\n *\n * @returns {Object} - The Express instance.\n */\nexport const getExpress = () => express;\n\n/**\n * Get the Express app instance.\n *\n * @returns {Object} - The Express app instance.\n */\nexport const getApp = () => app;\n\n/**\n * Apply middleware(s) to a specific path.\n *\n * @param {string} path - The path to which the middleware(s) should be applied.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const use = (path, ...middlewares) => {\n app.use(path, ...middlewares);\n};\n\n/**\n * Set up a route with GET method and apply middleware(s).\n *\n * @param {string} path - The route path.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const get = (path, ...middlewares) => {\n app.get(path, ...middlewares);\n};\n\n/**\n * Set up a route with POST method and apply middleware(s).\n *\n * @param {string} path - The route path.\n * @param {...Function} middlewares - The middleware functions to be applied.\n */\nexport const post = (path, ...middlewares) => {\n app.post(path, ...middlewares);\n};\n\nexport default {\n startServer,\n closeServers,\n getServers,\n enableRateLimiting,\n getExpress,\n getApp,\n use,\n get,\n post\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { join } from 'path';\n\nimport { __dirname } from '../../utils.js';\n\n/**\n * Adds the GET / route for a UI when enabled on the export server.\n */\nexport default (app) =>\n !app\n ? false\n : app.get('/', (_request, response) => {\n response.sendFile(join(__dirname, 'public', 'index.html'), {\n acceptRanges: false\n });\n });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { clearAllIntervals } from './intervals.js';\nimport { killPool } from './pool.js';\nimport { closeServers } from './server/server.js';\n\n/**\n * Clean up function to trigger before ending process for the graceful shutdown.\n *\n * @param {number} exitCode - An exit code for the process.exit() function.\n */\nexport const shutdownCleanUp = async (exitCode) => {\n // Await freeing all resources\n await Promise.allSettled([\n // Clear all ongoing intervals\n clearAllIntervals(),\n\n // Get available server instances (HTTP/HTTPS) and close them\n closeServers(),\n\n // Close pool along with its workers and the browser instance, if exists\n killPool()\n ]);\n\n // Exit process with a correct code\n process.exit(exitCode);\n};\n\nexport default {\n shutdownCleanUp\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport 'colors';\n\nimport { checkAndUpdateCache } from './cache.js';\nimport {\n batchExport,\n setAllowCodeExecution,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\nimport {\n initLogging,\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging\n} from './logger.js';\nimport { initPool, killPool } from './pool.js';\nimport { shutdownCleanUp } from './resource_release.js';\nimport server, { startServer } from './server/server.js';\nimport { printLogo, printUsage } from './utils.js';\n\n/**\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\n * 'uncaughtException' events.\n */\nconst attachProcessExitListeners = () => {\n log(3, '[process] Attaching exit listeners to the process.');\n\n // Handler for the 'exit'\n process.on('exit', (code) => {\n log(4, `Process exited with code ${code}.`);\n });\n\n // Handler for the 'SIGINT'\n process.on('SIGINT', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGTERM'\n process.on('SIGTERM', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGHUP'\n process.on('SIGHUP', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'uncaughtException'\n process.on('uncaughtException', async (error, name) => {\n logWithStack(1, error, `The ${name} error.`);\n await shutdownCleanUp(1);\n });\n};\n\n/**\n * Initializes the export process. Tasks such as configuring logging, checking\n * cache and sources, and initializing the pool of resources happen during\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\n *\n * @param {Object} options - All export options.\n *\n * @returns {Promise} Promise resolving to the updated export options.\n */\nconst initExport = async (options) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customLogic && options.customLogic.allowCodeExecution\n );\n\n // Init the logging\n initLogging(options.logging);\n\n // Attach process' exit listeners\n if (options.other.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n // Check if cache needs to be updated\n await checkAndUpdateCache(options);\n\n // Init the pool\n await initPool({\n pool: options.pool || {\n minWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer.args || []\n });\n\n // Return updated options\n return options;\n};\n\nexport default {\n // Server\n server,\n startServer,\n\n // Exporting\n initExport,\n singleExport,\n batchExport,\n startExport,\n\n // Pool\n initPool,\n killPool,\n\n // Other\n setOptions,\n shutdownCleanUp,\n\n // Logs\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n\n // Utils\n mapToNewConfig,\n manualConfig,\n printLogo,\n printUsage\n};\n"],"names":["scriptsNames","core","modules","indicators","custom","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","maxUploadSize","cliName","enable","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","toConsole","toFile","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","pathCreated","levelsDesc","title","color","listeners","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","key","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","option","entries","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","headers","Referer","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","Function","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","isClosed","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","totalSize","Buffer","byteLength","toFixed","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","abs","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","setTimeout","createImage","emulateMediaType","pdf","createPDF","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","create","id","uuid","startDate","getTime","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","r","hardReset","goto","clearPage","eventId","initialResources","acquire","promise","release","killPool","worker","used","destroyed","connected","closeBrowser","postWork","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","numFree","numUsed","available","pending","numPendingAcquires","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","FORBID_ATTR","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","intervalIds","clearAllIntervals","clearInterval","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","status","json","rateLimit","app","limitConfig","msg","rateOptions","limiter","windowMs","delayMs","handler","request","format","send","default","skip","query","access_token","use","HttpError","setStatus","vSwitchRoute","post","adminToken","token","newVersion","params","updateVersion","reversedMime","png","jpeg","gif","requestsCounter","beforeRequest","afterRequest","doCallbacks","callbacks","uniqueId","callResponse","exportHandler","stopCounter","connection","remoteAddress","b64","noDownload","connectionAborted","socket","hadErrors","toLowerCase","substr","pattern","isPrivateRangeUrlFound","info","removeAllListeners","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","_req","set","attachServerErrorHandlers","startServer","serverConfig","uploadLimitBytes","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","httpServer","createServer","listen","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","_request","sendFile","acceptRanges","uiRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","loggingOptions","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"0lBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,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,YAEFC,WAAY,CAAC,kBACbC,OAAQ,CACN,wEACA,mGAMSC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOR,EAAaC,KACpBQ,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOR,EAAaE,QACpBO,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOR,EAAaG,WACpBM,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAOR,EAAaI,OACpBK,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,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"} diff --git a/lib/browser.js b/lib/browser.js index 8b5756fc..d4db9396 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -331,45 +331,49 @@ export async function addPageResources(page, options) { * to be cleared. */ export async function clearPageResources(page, injectedResources) { - for (const resource of injectedResources) { - await resource.dispose(); - } + try { + for (const resource of injectedResources) { + await resource.dispose(); + } - // Destroy old charts after export is done and reset all CSS and script tags - await page.evaluate(() => { - // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG - // exports - if (typeof Highcharts !== 'undefined') { - // eslint-disable-next-line no-undef - const oldCharts = Highcharts.charts; - - // Check in any already existing charts - if (Array.isArray(oldCharts) && oldCharts.length) { - // Destroy old charts - for (const oldChart of oldCharts) { - oldChart && oldChart.destroy(); - // eslint-disable-next-line no-undef - Highcharts.charts.shift(); + // Destroy old charts after export is done and reset all CSS and script tags + await page.evaluate(() => { + // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG + // exports + if (typeof Highcharts !== 'undefined') { + // eslint-disable-next-line no-undef + const oldCharts = Highcharts.charts; + + // Check in any already existing charts + if (Array.isArray(oldCharts) && oldCharts.length) { + // Destroy old charts + for (const oldChart of oldCharts) { + oldChart && oldChart.destroy(); + // eslint-disable-next-line no-undef + Highcharts.charts.shift(); + } } } - } - // eslint-disable-next-line no-undef - const [...scriptsToRemove] = document.getElementsByTagName('script'); - // eslint-disable-next-line no-undef - const [, ...stylesToRemove] = document.getElementsByTagName('style'); - // eslint-disable-next-line no-undef - const [...linksToRemove] = document.getElementsByTagName('link'); - - // Remove tags - for (const element of [ - ...scriptsToRemove, - ...stylesToRemove, - ...linksToRemove - ]) { - element.remove(); - } - }); + // eslint-disable-next-line no-undef + const [...scriptsToRemove] = document.getElementsByTagName('script'); + // eslint-disable-next-line no-undef + const [, ...stylesToRemove] = document.getElementsByTagName('style'); + // eslint-disable-next-line no-undef + const [...linksToRemove] = document.getElementsByTagName('link'); + + // Remove tags + for (const element of [ + ...scriptsToRemove, + ...stylesToRemove, + ...linksToRemove + ]) { + element.remove(); + } + }); + } catch (error) { + logWithStack(2, error, `[browser] Could not clear page's resources.`); + } } /** diff --git a/lib/export.js b/lib/export.js index da615658..d19a82b9 100644 --- a/lib/export.js +++ b/lib/export.js @@ -128,8 +128,34 @@ const createSVG = (page) => * * @returns {Promise} Promise resolving after the configuration is set. */ -const setAsConfig = async (page, chart, options, displayErrors) => - page.evaluate(triggerExport, chart, options, displayErrors); +const setAsConfig = async (page, chart, options, displayErrors) => { + // Get rid of the redunant string data + options.export.instr = null; + options.export.infile = null; + + // Get the size of the export input + const totalSize = Buffer.byteLength( + options.export?.strInj ? options.export?.strInj : JSON.stringify(chart), + 'utf-8' + ); + + // Log the size in MB + log( + 3, + `[export] The current total size of data passed to a page is around ${( + totalSize / + (1024 * 1024) + ).toFixed(2)} MB` + ); + + // Check the size of data passed to the page + if (totalSize >= 100 * 1024 * 1024) { + throw new ExportError(`[export] The data passed to a page exceeded 100MB.`); + } + + // Trigger the Highcharts chart creation + return page.evaluate(triggerExport, chart, options, displayErrors); +}; /** * Exports to a chart from a page using Puppeteer.