diff --git a/README.md b/README.md
index 66852028..27c6921a 100644
--- a/README.md
+++ b/README.md
@@ -6,6 +6,16 @@ Convert Highcharts.JS charts into static image files.
## Upgrade Notes
+## v4.x.x to v5.x.x
+
+There are two breaking changes in v5.x.x:
+ - `xlink:href` is now dissallowed in incoming SVG. This has adverse effects on exports with e.g. background images or other external resources, and is being done to prevent potential security issues. To allow this attribute, set `OTHER_ALLOW_XLINK_HREF` to `true`.
+ - There is now an active upload limit which defaults to 3MB (can be configured with `SERVER_MAX_UPLOAD_SIZE`/`--maxUploadSize`/`maxUploadSize`)
+
+For other changes and fixes, please see the [changelog](CHANGELOG.md).
+
+## v3.x.x to v4.x.x
+
In most cases, v4 should serve as a drop-in replacement for v2 and v3. However, due to changes in the browser backend, various tweaks related to process handling (e.g., worker counts, and so on) may now have different effects than before.
Significant changes have been made to the API for using the server as a Node.js module. While a compatibility layer has been created to address this, it is recommended to transition to the new API described below. It is worth noting that the compatibility layer may be deprecated at some point in the future.
@@ -384,6 +394,7 @@ These variables are set in your environment and take precedence over options fro
- `OTHER_NO_LOGO`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`).
- `OTHER_HARD_RESET_PAGE`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`).
- `OTHER_BROWSER_SHELL_MODE`: Decides whether to enable older but much more performant _shell_ mode for the browser (defaults to `true`).
+- `OTHER_ALLOW_XLINK`: If set to true, allow `xlink:href` in incoming SVG (defaults to `false`).
### Debugging Config
- `DEBUG_ENABLE`: Enables or disables debug mode for the underlying browser (defaults to `false`).
diff --git a/dist/index.cjs b/dist/index.cjs
index b3e41917..3617a540 100644
--- a/dist/index.cjs
+++ b/dist/index.cjs
@@ -1,2 +1,2 @@
-"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),s=require("zod"),n=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."},tempDir:{value:"./tmp/",type:"string",envLink:"PUPPETEER_TEMP_DIR",description:"The directory for Puppeteer to store temporary files."}},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",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in MB, 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."},username:{value:!1,type:"string",envLink:"SERVER_PROXY_USERNAME",cliName:"proxyUsername",description:"The username for the proxy server, if it exists."},password:{value:!1,type:"string",envLink:"SERVER_PROXY_PASSWORD",cliName:"proxyPassword",description:"The password for the proxy server, 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=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),L=()=>s.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=()=>s.z.string().trim().refine((e=>/^(\.\/|\.\.\/|\/|[a-zA-Z]:\\|[a-zA-Z]:\/)?((?:[\w-]+)[\\/]?)+$/.test(e)),{},{message:"The string is an invalid path directory string."}),I=()=>s.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)),C=()=>s.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)),N=s.z.object({PUPPETEER_TEMP_DIR:k(),HIGHCHARTS_VERSION:s.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:s.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:_(),HIGHCHARTS_CACHE_PATH:L(),HIGHCHARTS_ADMIN_TOKEN:L(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:I(),EXPORT_DEFAULT_WIDTH:I(),EXPORT_DEFAULT_SCALE:I(),EXPORT_RASTERIZATION_TIMEOUT:C(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:L(),SERVER_PORT:I(),SERVER_MAX_UPLOAD_SIZE:I(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:L(),SERVER_PROXY_PORT:I(),SERVER_PROXY_USERNAME:L(),SERVER_PROXY_PASSWORD:L(),SERVER_PROXY_TIMEOUT:C(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:C(),SERVER_RATE_LIMITING_WINDOW:C(),SERVER_RATE_LIMITING_DELAY:C(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:L(),SERVER_RATE_LIMITING_SKIP_TOKEN:L(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:I(),SERVER_SSL_CERT_PATH:L(),POOL_MIN_WORKERS:C(),POOL_MAX_WORKERS:C(),POOL_WORK_LIMIT:I(),POOL_ACQUIRE_TIMEOUT:C(),POOL_CREATE_TIMEOUT:C(),POOL_DESTROY_TIMEOUT:C(),POOL_IDLE_TIMEOUT:C(),POOL_CREATE_RETRY_INTERVAL:C(),POOL_REAPER_INTERVAL:C(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:s.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:L(),LOGGING_DEST:L(),LOGGING_TO_CONSOLE:_(),LOGGING_TO_FILE:_(),UI_ENABLE:_(),UI_ROUTE:L(),OTHER_NODE_ENV:O(["development","production","test"]),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:C(),DEBUG_DEBUGGING_PORT:I()}).partial().parse(process.env),A=["red","yellow","blue","gray","green"];let P={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:A[0]},{title:"warning",color:A[1]},{title:"notice",color:A[2]},{title:"verbose",color:A[3]},{title:"benchmark",color:A[4]}],listeners:[]};const H=(t,r)=>{P.pathCreated||(!e.existsSync(P.dest)&&e.mkdirSync(P.dest),P.pathCreated=!0),e.appendFile(`${P.dest}${P.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),P.toFile=!1)}))},$=(...e)=>{const[t,...r]=e,{levelsDesc:o,level:i}=P;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;P.listeners.forEach((e=>{e(s,r.join(" "))})),P.toConsole&&console.log.apply(void 0,[s.toString()[P.levelsDesc[t-1].color]].concat(r)),P.toFile&&H(r,s)},D=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=P;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=[o,"\n",a];P.toConsole&&console.log.apply(void 0,[n.toString()[P.levelsDesc[e-1].color]].concat([o[A[e-1]],"\n",a])),P.listeners.forEach((e=>{e(n,l.join(" "))})),P.toFile&&H(l,n)},U=e=>{e>=0&&e<=P.levelsDesc.length&&(P.level=e)},G=(e,t)=>{if(P={...P,dest:e||P.dest,file:t||P.file,toFile:!0},0===P.dest.length)return $(1,"[logger] File logging initialization: no path supplied.");P.dest.endsWith("/")||(P.dest+="/")},F=n.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)),j=(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"},M=(t=!1,r)=>{const o=["js","css","files"];let i=t,s=!1;if(r&&t.endsWith(".json"))try{i=V(e.readFileSync(t,"utf8"))}catch(e){return D(2,e,"[cli] No resources found.")}else i=V(t),i&&!r&&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):$(3,"[cli] No resources found.")};function V(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 W=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]=W(e[r]));return t},q=(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 B(){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 z=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,X=(t,r)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!r&&X(e.readFileSync(t,"utf8")):t.startsWith("function()")||t.startsWith("function ()")||t.startsWith("()=>")||t.startsWith("() =>")?`(${t})()`:t.replace(/;$/,"")},K=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let J={};const Y=()=>J,Z=(e,t,r=[])=>{const o=W(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:Z(o[e],s,r);var i;return o};function Q(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?Q(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in N&&void 0!==N[i.envLink]&&(i.value=N[i.envLink]))}))}function ee(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ee(o);return t}function te(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=te(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function re(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 oe 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 ie={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=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)),$(4,`[cache] Fetching script - ${e}.js`);const i=await re(`${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 oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return $(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ae=async(t,o,i)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ie.cdnURL;$(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ie.sources=await(async(e,t,o,i,s)=>{let n;const{host:a,port:l,username:c,password:p}=i;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l,...c&&p?{username:c,password:p}:{}})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const h=n?{agent:n,timeout:N.SERVER_PROXY_TIMEOUT}:{},u=[...e.map((e=>ne(`${e}`,h,s,!0))),...t.map((e=>ne(`${e}`,h,s))),...o.map((e=>ne(`${e}`,h)))];return(await Promise.all(u)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,o,l),ie.hcVersion=se(ie),e.writeFileSync(i,ie.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},le=async r=>{const{highcharts:o,server:i}=r,s=t.join(F,o.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||o.forceFetch)$(3,"[cache] Fetching and caching Highcharts dependencies."),n=await ae(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:s,moduleScripts:c,indicatorScripts:p}=o,h=s.length+c.length+p.length;r.version!==o.version?($(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==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 $(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await ae(o,i.proxy,l):($(3,"[cache] Dependency cache is up to date, proceeding."),ie.sources=e.readFileSync(l,"utf8"),n=r.modules,ie.hcVersion=se(ie))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ie.activeManifest=i,$(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(o,n)},ce=()=>t.join(F,Y().highcharts.cachePath),pe=()=>ie.hcVersion;function he(){Highcharts.animObject=function(){return{duration:0}}}async function ue(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=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,n(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])})),n(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&&s(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];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const de=e.readFileSync(F+"/templates/template.html","utf8");let ge;async function me(){if(!ge)return!1;const e=await ge.newPage();return await e.setCacheEnabled(!1),await ve(e),function(e){const{debug:t}=Y();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 fe(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){D(2,e,"[browser] Could not clear page's resources.")}}async function ve(e){await e.setContent(de,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ce()}/sources.js`}),await e.evaluate(he)}const ye=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($(3,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new oe("[export] The data passed to a page exceeded 100MB.");return e.evaluate(ue,t,r,o)};var be=async(r,o,i)=>{let s=[];try{$(4,"[export] Determining export path.");const n=i.export,a=n?.options?.chart?.displayErrors&&ie.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if($(4,"[export] Treating as SVG."),"svg"===n.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 $(4,"[export] Treating as config."),n.strInj?await ye(r,{chart:{height:n.height,width:n.width}},i,a):(o.chart.height=n.height,o.chart.width=n.width,await ye(r,o,i,a));s=await async function(r,o){const i=[],s=o.customLogic.resources;if(s){const n=[];if(s.js&&n.push({content:s.js}),s.files)for(const t of s.files){const r=!t.startsWith("http");n.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of n)try{i.push(await r.addScriptTag(e))}catch(e){D(2,e,"[export] The JS resource cannot be loaded.")}n.length=0;const a=[];if(s.css){let e=s.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(F,r)}));a.push({content:s.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){D(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(n.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||n.height)),h=Math.abs(Math.ceil(c.chartWidth||n.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(n.scale)}),"svg"===n.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(n.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 oe("Rasterization timeout"))),i||1500)))]))(r,n.type,"base64",{width:h,height:p,x:u,y:d},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new oe(`[export] Unsupported output format ${n.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",n.rasterizationTimeout)}return await fe(r,s),g}catch(e){return await fe(r,s),e}};let we=!1;const Ee={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Te={};const Se={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await me(),!e||e.isClosed())throw new oe("The page is invalid or closed.");$(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Te.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Te.workLimit&&++e.workCount>Te.workLimit)||($(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Te.workLimit}).`),!1)),destroy:async e=>{$(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},xe=async e=>{if(Te=e&&e.pool?{...e.pool}:{},await async function(e){const{puppeteer:t,debug:r,other:o}=Y(),{enable:i,...s}=r,n={headless:!o.browserShellMode||"shell",userDataDir:t.tempDir||"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...i&&s};if(!ge){let e=0;const t=async()=>{try{$(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ge=await h.launch(n)}catch(r){if(D(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;$(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&&$(3,"[browser] Launched browser in shell mode."),i&&$(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ge)throw new oe("[browser] Cannot find a browser to open.")}return ge}(e.puppeteerArgs),$(3,`[pool] Initializing pool with workers: min ${Te.minWorkers}, max ${Te.maxWorkers}.`),we)return $(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Te.minWorkers)>parseInt(Te.maxWorkers)&&(Te.minWorkers=Te.maxWorkers);try{we=new c.Pool({...Se,min:parseInt(Te.minWorkers),max:parseInt(Te.maxWorkers),acquireTimeoutMillis:Te.acquireTimeout,createTimeoutMillis:Te.createTimeout,destroyTimeoutMillis:Te.destroyTimeout,idleTimeoutMillis:Te.idleTimeout,createRetryIntervalMillis:Te.createRetryInterval,reapIntervalMillis:Te.reaperInterval,propagateCreateError:!1}),we.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 ve(e)):await e.evaluate((()=>{document.body.innerHTML=''})),!0}catch(e){D(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);$(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),we.on("destroySuccess",((e,t)=>{$(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{we.release(e)})),$(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function Re(){if($(3,"[pool] Killing pool with all workers and closing browser."),we){for(const e of we.used)we.release(e.resource);we.destroyed||(await we.destroy(),$(4,"[browser] Destroyed the pool of resources."))}await async function(){ge?.connected&&await ge.close(),$(4,"[browser] Closed the browser.")}()}const _e=async(e,t)=>{let r;try{if($(4,"[pool] Work received, starting to process."),++Ee.exportAttempts,Te.benchmarking&&Le(),!we)throw new oe("Work received, but pool has not been started.");const o=K();try{$(4,"[pool] Acquiring a worker handle."),r=await we.acquire().promise,t.server.benchmarking&&$(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if($(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();$(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=K(),n=await be(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.workCount=Te.workLimit+1,r.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new oe("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&$(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),we.release(r);const a=(new Date).getTime()-i;return Ee.timeSpent+=a,Ee.spentAverage=Ee.timeSpent/++Ee.performedExports,$(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ee.droppedExports,r&&we.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Oe=()=>({min:we.min,max:we.max,all:we.numFree()+we.numUsed(),available:we.numFree(),used:we.numUsed(),pending:we.numPendingAcquires()});function Le(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Oe();$(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),$(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),$(5,`[pool] The number of all created resources: ${r}.`),$(5,`[pool] The number of available resources: ${o}.`),$(5,`[pool] The number of acquired resources: ${i}.`),$(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var ke=Oe,Ie=()=>Ee;let Ce=!1;const Ne=async(t,r)=>{$(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=W(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=Z(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Y()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{$(4,"[chart] Attempting to export from a SVG input.");const e=$e(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++Ee.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return $(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),$e(o.export.instr.trim(),o,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return $(4,"[chart] Attempting to export from a raw input."),i.instr=i.instr||i.options,z(o.customLogic?.allowCodeExecution)?He(o,r):"string"==typeof i.instr?$e(i.instr.trim(),o,r):Pe(o,i.instr||i.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ae=e=>{const{chart:t,exporting:r}=e.export?.options||V(e.export?.instr),o=V(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 s={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(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Pe=async(t,r,o,i)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ce;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=M(t.customLogic.resources,z(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=M(r,z(t.customLogic.allowFileResources))}catch(e){$(2,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=j(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=V(e.readFileSync(s[t],"utf8"),!0):s[t]=V(s[t],!0))}catch(e){s[t]={},D(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=X(n.customCode,n.allowFileResources)}catch(e){D(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,D(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...Ae(t)};try{return o(!1,await _e(s.strInj||r||i,t))}catch(e){return o(e)}},He=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=q(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,Pe(e,!1,t)}catch(r){return t(new oe(`[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))}},$e=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return $(4,"[chart] Parsing input as SVG."),Pe(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Pe(t,o,r)}catch(e){return z(o)?He(t,r):r(new oe("[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))}},De=[],Ue=()=>{$(4,"[server] Clearing all registered intervals.");for(const e of De)clearInterval(e)},Ge=(e,t,r,o)=>{D(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,o(e)},Fe=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||400;r.status(l).json({statusCode:l,message:n,stack:a})};var je=(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&&($(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),$(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Me extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Ve=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Me("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 Me("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Me("No new version supplied.",400);try{await(async e=>{const t=Y();t?.highcharts&&(t.highcharts.version=e),await le(t)})(i)}catch(e){throw new Me(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:pe(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const We={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let qe=0;const Be=[],ze=[],Xe=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Ke=async(e,t,r)=>{try{const r=K(),i=p.v4().replace(/-/g,""),s=Y(),n=e.body,a=++qe;let l=j(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Me("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=V(n.infile||n.options||n.data);if(!c&&!n.svg)throw $(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 Me("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=Xe(Be,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(e=>{e&&(u=!0)})),$(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={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:V(n.globalOptions,!0),themeOptions:V(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ce,allowFileResources:!1,resources:V(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=q(c,d.customLogic.allowCodeExecution));const g=Z(s,d);if(g.export.options=c,g.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))))(g.payload.svg))throw new Me("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 Ne(g,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&$(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),u)return $(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Me(`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,Xe(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",We[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){r(e)}var o};const Je=JSON.parse(e.readFileSync(t.join(F,"package.json"))),Ye=new Date,Ze=[];function Qe(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Ie(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ze.push(t),Ze.length>30&&Ze.shift()}),6e4),De.push(t),e.get("/health",((e,t)=>{const r=Ie(),o=Ze.length,i=Ze.reduce(((e,t)=>e+t),0)/Ze.length;$(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Ye,uptime:Math.floor(((new Date).getTime()-Ye.getTime())/1e3/60)+" minutes",version:Je.version,highchartsVersion:pe(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:ke(),period:o,movingAverage:i,message:isNaN(i)||!Ze.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 et=new Map,tt=m();tt.disable("x-powered-by"),tt.use(g()),tt.use(((e,t,r)=>{t.set("Accept-Ranges","none"),r()}));const rt=e=>{e.on("clientError",((e,t)=>{D(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{D(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{D(1,e,`[server] Socket error: ${e.message}`)}))}))},ot=async r=>{try{const o=1024*(r.maxUploadSize||3)*1024,i=f.memoryStorage(),s=f({storage:i,limits:{fieldSize:o}});if(tt.use(m.json({limit:o})),tt.use(m.urlencoded({extended:!0,limit:o})),tt.use(s.none()),!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(tt);rt(e),e.listen(r.port,r.host),et.set(r.port,e),$(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){$(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},tt);rt(e),e.listen(r.ssl.port,r.host),et.set(r.ssl.port,e),$(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&je(tt,r.rateLimiting),tt.use(m.static(t.posix.join(F,"public"))),Qe(tt),(e=>{e.post("/",Ke),e.post("/:filename",Ke)})(tt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"),{acceptRanges:!1})}))})(tt),Ve(tt),(e=>{e.use(Ge),e.use(Fe)})(tt)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},it=()=>{$(4,"[server] Closing all servers.");for(const[e,t]of et)t.close((()=>{et.delete(e),$(4,`[server] Closed server on port: ${e}.`)}))};var st={startServer:ot,closeServers:it,getServers:()=>et,enableRateLimiting:e=>je(tt,e),getExpress:()=>m,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};const nt=async e=>{await Promise.allSettled([Ue(),it(),Re()]),process.exit(e)};var at={server:st,startServer:ot,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ce=z(t),(e=>{for(const[t,r]of Object.entries(e))P[t]=r;U(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&($(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{$(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGTERM",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGHUP",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("uncaughtException",(async(e,t)=>{D(1,e,`The ${t} error.`),await nt(1)}))),await le(e),await xe({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 Ne(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 Re()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ne({...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 Re()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:Ne,initPool:xe,killPool:Re,setOptions:(t,r)=>(r?.length&&(J=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){D(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Q(w,J),J=ee(w),t&&(J=Z(J,t,T)),r?.length&&(J=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=z(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:($(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&B();return e}(J,r,w)),J),shutdownCleanUp:nt,log:$,logWithStack:D,setLogLevel:U,enableFileLogging:G,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,s)=>{let n=0,a=[];for(const e of s)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]=te(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){D(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:B};module.exports=at;
-//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdwYXJhbGxlbC1jb29yZGluYXRlcycsXHJcbiAgICAnYWNjZXNzaWJpbGl0eScsXHJcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxyXG4gICAgJ2Jvb3N0LWNhbnZhcycsXHJcbiAgICAnYm9vc3QnLFxyXG4gICAgJ2RhdGEnLFxyXG4gICAgJ2RhdGEtdG9vbHMnLFxyXG4gICAgJ2RyYWdnYWJsZS1wb2ludHMnLFxyXG4gICAgJ3N0YXRpYy1zY2FsZScsXHJcbiAgICAnYnJva2VuLWF4aXMnLFxyXG4gICAgJ2hlYXRtYXAnLFxyXG4gICAgJ3RpbGVtYXAnLFxyXG4gICAgJ3RpbGVkd2VibWFwJyxcclxuICAgICd0aW1lbGluZScsXHJcbiAgICAndHJlZW1hcCcsXHJcbiAgICAndHJlZWdyYXBoJyxcclxuICAgICdpdGVtLXNlcmllcycsXHJcbiAgICAnZHJpbGxkb3duJyxcclxuICAgICdoaXN0b2dyYW0tYmVsbGN1cnZlJyxcclxuICAgICdidWxsZXQnLFxyXG4gICAgJ2Z1bm5lbCcsXHJcbiAgICAnZnVubmVsM2QnLFxyXG4gICAgJ2dlb2hlYXRtYXAnLFxyXG4gICAgJ3B5cmFtaWQzZCcsXHJcbiAgICAnbmV0d29ya2dyYXBoJyxcclxuICAgICdvdmVybGFwcGluZy1kYXRhbGFiZWxzJyxcclxuICAgICdwYXJldG8nLFxyXG4gICAgJ3BhdHRlcm4tZmlsbCcsXHJcbiAgICAncGljdG9yaWFsJyxcclxuICAgICdwcmljZS1pbmRpY2F0b3InLFxyXG4gICAgJ3NhbmtleScsXHJcbiAgICAnYXJjLWRpYWdyYW0nLFxyXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxyXG4gICAgJ3Nlcmllcy1sYWJlbCcsXHJcbiAgICAnc2VyaWVzLW9uLXBvaW50JyxcclxuICAgICdzb2xpZC1nYXVnZScsXHJcbiAgICAnc29uaWZpY2F0aW9uJyxcclxuICAgIC8vICdzdG9jay10b29scycsXHJcbiAgICAnc3RyZWFtZ3JhcGgnLFxyXG4gICAgJ3N1bmJ1cnN0JyxcclxuICAgICd2YXJpYWJsZS1waWUnLFxyXG4gICAgJ3Zhcml3aWRlJyxcclxuICAgICd2ZWN0b3InLFxyXG4gICAgJ3Zlbm4nLFxyXG4gICAgJ3dpbmRiYXJiJyxcclxuICAgICd3b3JkY2xvdWQnLFxyXG4gICAgJ3hyYW5nZScsXHJcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcclxuICAgICdkcmFnLXBhbmVzJyxcclxuICAgICdkZWJ1Z2dlcicsXHJcbiAgICAnZHVtYmJlbGwnLFxyXG4gICAgJ2xvbGxpcG9wJyxcclxuICAgICdjeWxpbmRlcicsXHJcbiAgICAnb3JnYW5pemF0aW9uJyxcclxuICAgICdkb3RwbG90JyxcclxuICAgICdtYXJrZXItY2x1c3RlcnMnLFxyXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcclxuICAgICdoZWlraW5hc2hpJyxcclxuICAgICdmbG93bWFwJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAnbmF2aWdhdG9yJyxcclxuICAgICd0ZXh0cGF0aCdcclxuICBdLFxyXG4gIGluZGljYXRvcnM6IFsnaW5kaWNhdG9ycy1hbGwnXSxcclxuICBjdXN0b206IFtcclxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxyXG4gICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuNDUvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgXVxyXG59O1xyXG5cclxuLy8gVGhpcyBpcyB0aGUgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCBhbGwgb3B0aW9ucyBhbmQgdGhlaXIgZGVmYXVsdCB2YWx1ZXMsXHJcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcclxuZXhwb3J0IGNvbnN0IGRlZmF1bHRDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiB7XHJcbiAgICBhcmdzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJy0tYWxsb3ctcnVubmluZy1pbnNlY3VyZS1jb250ZW50JyxcclxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcclxuICAgICAgICAnLS1hdXRvcGxheS1wb2xpY3k9dXNlci1nZXN0dXJlLXJlcXVpcmVkJyxcclxuICAgICAgICAnLS1ibG9jay1uZXctd2ViLWNvbnRlbnRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLW5ldHdvcmtpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC10aW1lci10aHJvdHRsaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1icmVha3BhZCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jaGVja2VyLWltYWdpbmcnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC1leHRlbnNpb25zLXdpdGgtYmFja2dyb3VuZC1wYWdlcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtdXBkYXRlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZXYtc2htLXVzYWdlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWRvbWFpbi1yZWxpYWJpbGl0eScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWZlYXR1cmVzPUNhbGN1bGF0ZU5hdGl2ZVdpbk9jY2x1c2lvbixJbnRlcmVzdEZlZWRDb250ZW50U3VnZ2VzdGlvbnMsV2ViT1RQJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWhhbmctbW9uaXRvcicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1sb2dnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW5vdGlmaWNhdGlvbnMnLFxyXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXBvcHVwLWJsb2NraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByaW50LXByZXZpZXcnLFxyXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1yZW5kZXJlci1iYWNrZ3JvdW5kaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNlYXJjaC1lbmdpbmUtY2hvaWNlLXNjcmVlbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNldHVpZC1zYW5kYm94JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXNpdGUtaXNvbGF0aW9uLXRyaWFscycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcclxuICAgICAgICAnLS1kaXNhYmxlLXN5bmMnLFxyXG4gICAgICAgICctLWVuYWJsZS11bnNhZmUtd2ViZ3B1JyxcclxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcclxuICAgICAgICAnLS1oaWRlLXNjcm9sbGJhcnMnLFxyXG4gICAgICAgICctLW1ldHJpY3MtcmVjb3JkaW5nLW9ubHknLFxyXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxyXG4gICAgICAgICctLW5vLWRlZmF1bHQtYnJvd3Nlci1jaGVjaycsXHJcbiAgICAgICAgJy0tbm8tZmlyc3QtcnVuJyxcclxuICAgICAgICAnLS1uby1waW5ncycsXHJcbiAgICAgICAgJy0tbm8tc2FuZGJveCcsXHJcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxyXG4gICAgICAgICctLW5vLXp5Z290ZScsXHJcbiAgICAgICAgJy0tcGFzc3dvcmQtc3RvcmU9YmFzaWMnLFxyXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXHJcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcclxuICAgIH0sXHJcbiAgICB0ZW1wRGlyOiB7XHJcbiAgICAgIHZhbHVlOiAnLi90bXAvJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfVEVNUF9ESVInLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBkaXJlY3RvcnkgZm9yIFB1cHBldGVlciB0byBzdG9yZSB0ZW1wb3JhcnkgZmlsZXMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgaGlnaGNoYXJ0czoge1xyXG4gICAgdmVyc2lvbjoge1xyXG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19WRVJTSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNkblVSTDoge1xyXG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0ROX1VSTCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcclxuICAgIH0sXHJcbiAgICBjb3JlU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NPUkVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBtb2R1bGVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGluZGljYXRvclNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBZGRpdGlvbmFsIGN1c3RvbSBzY3JpcHRzIG9yIGRlcGVuZGVuY2llcyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgZm9yY2VGZXRjaDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfRk9SQ0VfRkVUQ0gnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXHJcbiAgICB9LFxyXG4gICAgY2FjaGVQYXRoOiB7XHJcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0NBQ0hFX1BBVEgnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeS4gSXQgaXMgdXNlZCB0byBzdG9yZSB0aGUgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b20gc2NyaXB0cy4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBleHBvcnQ6IHtcclxuICAgIGluZmlsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXHJcbiAgICB9LFxyXG4gICAgaW5zdHI6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXHJcbiAgICB9LFxyXG4gICAgb3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FuIGFsaWFzIGZvciB0aGUgLS1pbnN0ciBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG91dGZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBvdXRwdXQgZmlsZW5hbWUgYWxvbmcgd2l0aCBhIHR5cGUgKGpwZWcsIHBuZywgcGRmLCBvciBzdmcpLiBUaGlzIHdpbGwgaWdub3JlIHRoZSAtLXR5cGUgZmxhZy4nXHJcbiAgICB9LFxyXG4gICAgdHlwZToge1xyXG4gICAgICB2YWx1ZTogJ3BuZycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1RZUEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBmaWxlIGV4cG9ydCBmb3JtYXQuIEl0IGNhbiBiZSBqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnLidcclxuICAgIH0sXHJcbiAgICBjb25zdHI6IHtcclxuICAgICAgdmFsdWU6ICdjaGFydCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0NPTlNUUicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0SGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiA0MDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX0RFRkFVTFRfSEVJR0hUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ3RoZSBkZWZhdWx0IGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRXaWR0aDoge1xyXG4gICAgICB2YWx1ZTogNjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdFNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiAxLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1NDQUxFJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXHJcbiAgICB9LFxyXG4gICAgaGVpZ2h0OiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXHJcbiAgICB9LFxyXG4gICAgd2lkdGg6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHNjYWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXHJcbiAgICB9LFxyXG4gICAgZ2xvYmFsT3B0aW9uczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcclxuICAgIH0sXHJcbiAgICB0aGVtZU9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgYmF0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xyXG4gICAgfSxcclxuICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiAxNTAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uIGluIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciByZW5kZXJpbmcgYSB3ZWJwYWdlLidcclxuICAgIH1cclxuICB9LFxyXG4gIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICBhbGxvd0NvZGVFeGVjdXRpb246IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgd2hldGhlciB0aGUgZXhlY3V0aW9uIG9mIGFyYml0cmFyeSBjb2RlIGlzIGFsbG93ZWQgZHVyaW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nXHJcbiAgICB9LFxyXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBhYmlsaXR5IHRvIGluamVjdCByZXNvdXJjZXMgZnJvbSB0aGUgZmlsZXN5c3RlbS4gVGhpcyBzZXR0aW5nIGhhcyBubyBlZmZlY3Qgd2hlbiBydW5uaW5nIGFzIGEgc2VydmVyLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21Db2RlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDdXN0b20gY29kZSB0byBleGVjdXRlIGJlZm9yZSBjaGFydCBpbml0aWFsaXphdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24sIGNvZGUgd3JhcHBlZCB3aXRoaW4gYSBmdW5jdGlvbiwgb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICBjYWxsYmFjazoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSmF2YVNjcmlwdCBjb2RlIHRvIHJ1biBkdXJpbmcgY29uc3RydWN0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xyXG4gICAgfSxcclxuICAgIHJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQWRkaXRpb25hbCByZXNvdXJjZSBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04sIHdoaWNoIG1heSBjb250YWluIGZpbGVzLCBqcywgYW5kIGNzcyBzZWN0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgbG9hZENvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnZnJvbUZpbGUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0EgZmlsZSBjb250YWluaW5nIGEgcHJlLWRlZmluZWQgY29uZmlndXJhdGlvbiB0byB1c2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZUNvbmZpZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBzZXR0aW5nIG9wdGlvbnMgdGhyb3VnaCBhIHByb21wdCBhbmQgc2F2aW5nIHRoZW0gaW4gYSBwcm92aWRlZCBjb25maWcgZmlsZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBzZXJ2ZXI6IHtcclxuICAgIG1heFVwbG9hZFNpemU6IHtcclxuICAgICAgdmFsdWU6IDMsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX01BWF9VUExPQURfU0laRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gdXBsb2FkIHNpemUsIGluIE1CLCBmb3IgdGhlIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgZW5hYmxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVTZXJ2ZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXHJcbiAgICB9LFxyXG4gICAgaG9zdDoge1xyXG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBob3N0bmFtZSBvZiB0aGUgc2VydmVyLiBBZGRpdGlvbmFsbHksIGl0IHN0YXJ0cyBhIHNlcnZlciBvbiB0aGUgcHJvdmlkZWQgaG9zdG5hbWUuJ1xyXG4gICAgfSxcclxuICAgIHBvcnQ6IHtcclxuICAgICAgdmFsdWU6IDc4MDEsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBzZXJ2ZXIgcG9ydCB3aGVuIGVuYWJsZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxyXG4gICAgICBjbGlOYW1lOiAnc2VydmVyQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcclxuICAgIH0sXHJcbiAgICBwcm94eToge1xyXG4gICAgICBob3N0OiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5SG9zdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA4MDgwLFxyXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfSxcclxuICAgICAgdXNlcm5hbWU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9VU0VSTkFNRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VXNlcm5hbWUnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHVzZXJuYW1lIGZvciB0aGUgcHJveHkgc2VydmVyLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwYXNzd29yZDoge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BBU1NXT1JEJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQYXNzd29yZCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGFzc3dvcmQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIsIGlmIGl0IGV4aXN0cy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRpbWVvdXQ6IHtcclxuICAgICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1RJTUVPVVQnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgcmF0ZUxpbWl0aW5nOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBtYXhSZXF1ZXN0czoge1xyXG4gICAgICAgIHZhbHVlOiAxMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIG51bWJlciBvZiByZXF1ZXN0cyBhbGxvd2VkIGluIG9uZSBtaW51dGUuJ1xyXG4gICAgICB9LFxyXG4gICAgICB3aW5kb3c6IHtcclxuICAgICAgICB2YWx1ZTogMSxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lIHdpbmRvdywgaW4gbWludXRlcywgZm9yIHRoZSByYXRlIGxpbWl0aW5nLidcclxuICAgICAgfSxcclxuICAgICAgZGVsYXk6IHtcclxuICAgICAgICB2YWx1ZTogMCxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcclxuICAgICAgfSxcclxuICAgICAgdHJ1c3RQcm94eToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcclxuICAgICAgfSxcclxuICAgICAgc2tpcEtleToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVknLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBUb2tlbjoge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIGFuZCBzaG91bGQgYmUgcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudC4nXHJcbiAgICAgIH1cclxuICAgIH0sXHJcbiAgICBzc2w6IHtcclxuICAgICAgZW5hYmxlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgU1NMIHByb3RvY29sLidcclxuICAgICAgfSxcclxuICAgICAgZm9yY2U6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsRm9yY2UnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIGlzIGZvcmNlZCB0byBzZXJ2ZSBvbmx5IG92ZXIgSFRUUFMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDQ0MyxcclxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAnc3NsUG9ydCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xyXG4gICAgICB9LFxyXG4gICAgICBjZXJ0UGF0aDoge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9DRVJUX1BBVEgnLFxyXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSxcclxuICBwb29sOiB7XHJcbiAgICBtaW5Xb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWluaW11bSBhbmQgaW5pdGlhbCBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xyXG4gICAgfSxcclxuICAgIG1heFdvcmtlcnM6IHtcclxuICAgICAgdmFsdWU6IDgsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXHJcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1heGltdW0gcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICB3b3JrTGltaXQ6IHtcclxuICAgICAgdmFsdWU6IDQwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbnVtYmVyIG9mIHdvcmsgcGllY2VzIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyB0aGUgd29ya2VyIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFjcXVpcmVUaW1lb3V0OiB7XHJcbiAgICAgIHZhbHVlOiA1MDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQUNRVUlSRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBkZXN0cm95VGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlLidcclxuICAgIH0sXHJcbiAgICBpZGxlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMzAwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9JRExFX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAyMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgYmVmb3JlIHJldHJ5aW5nIHRoZSBjcmVhdGUgcHJvY2VzcyBpbiBjYXNlIG9mIGEgZmFpbHVyZS4nXHJcbiAgICB9LFxyXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcclxuICAgICAgdmFsdWU6IDEwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveSBpcyB0cmlnZ2VyZWQuJ1xyXG4gICAgfSxcclxuICAgIGJlbmNobWFya2luZzoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQkVOQ0hNQVJLSU5HJyxcclxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGUgd2hldGhlciB0byBzaG93IHN0YXRpc3RpY3MgZm9yIHRoZSBwb29sIG9mIHJlc291cmNlcyBvciBub3QuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgbG9nZ2luZzoge1xyXG4gICAgbGV2ZWw6IHtcclxuICAgICAgdmFsdWU6IDQsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGxvZ2dpbmcgbGV2ZWwgdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgZmlsZToge1xyXG4gICAgICB2YWx1ZTogJ2hpZ2hjaGFydHMtZXhwb3J0LXNlcnZlci5sb2cnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dGaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBuYW1lIG9mIGEgbG9nIGZpbGUuIFRoZSBgbG9nVG9GaWxlYCBhbmQgYGxvZ0Rlc3RgIG9wdGlvbnMgYWxzbyBuZWVkIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nLidcclxuICAgIH0sXHJcbiAgICBkZXN0OiB7XHJcbiAgICAgIHZhbHVlOiAnbG9nLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHBhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBUaGUgYGxvZ1RvRmlsZWAgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xyXG4gICAgfSxcclxuICAgIHRvQ29uc29sZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19DT05TT0xFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBzaG93aW5nIGxvZ3MgaW4gdGhlIGNvbnNvbGUuJ1xyXG4gICAgfSxcclxuICAgIHRvRmlsZToge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcclxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGNyZWF0aW9uIG9mIHRoZSBsb2cgZGlyZWN0b3J5IGFuZCBzYXZpbmcgdGhlIGxvZyBpbnRvIGEgLmxvZyBmaWxlLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlLidcclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBtb2RlIGluIHdoaWNoIHRoZSBicm93c2VyIGlzIGxhdW5jaGVkIHdoZW4gaW4gdGhlIGRlYnVnIG1vZGUuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBEZXZUb29scyB3aGVuIHRoZSBicm93c2VyIGlzIGluIGEgaGVhZGZ1bCBzdGF0ZS4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBhIGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIHNlbnQgZnJvbSB0aGUgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBicm93c2VyIHByb2Nlc3Mgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyLidcclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTbG93cyBkb3duIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3BlY2lmaWVzIHRoZSBkZWJ1Z2dpbmcgcG9ydC4nXHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xyXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxyXG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcclxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxyXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxyXG4vLyAqIEluaXRpYWwgdmFsdWVcclxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2FyZ3MnLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfVxyXG4gIF0sXHJcbiAgaGlnaGNoYXJ0czogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdpbmRpY2F0b3JTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5pbmRpY2F0b3JTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmN1c3RvbVNjcmlwdHMudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZXhwb3J0OiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAndHlwZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb25zdHInLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcclxuICAgICAgbWluOiAwLjEsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgY3VzdG9tTG9naWM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgc2VydmVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2hvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgbG9nZ2luZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2xldmVsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxyXG4gICAgICByb3VuZDogMCxcclxuICAgICAgbWluOiAwLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2ZpbGUnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIC0tdG9GaWxlIGFuZCAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGEgbG9nIGZpbGUgd2hlbiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICd0b0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcudG9Db25zb2xlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3RvRmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIGxvZ2dpbmcgdG8gYSBmaWxlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLnRvRmlsZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYnJvd3NlclNoZWxsTW9kZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBicm93c2VyIHJ1bnMgaW4gdGhlIHNoZWxsIG1vZGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmJyb3dzZXJTaGVsbE1vZGUudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIENoZWNrcyBpZiB0aGUgc3RyaW5nIGlzIGEgdmFsaWQgcGF0aCBkaXJlY3RvcnkgKHBhdGggZm9ybWF0KVxyXG4gIHBhdGg6ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PiB7XHJcbiAgICAgICAgICAvLyBTaW1wbGlmaWVkIHJlZ2V4IHRvIG1hdGNoIGJvdGggYWJzb2x1dGUgYW5kIHJlbGF0aXZlIHBhdGhzXHJcbiAgICAgICAgICByZXR1cm4gL14oXFwuXFwvfFxcLlxcLlxcL3xcXC98W2EtekEtWl06XFxcXHxbYS16QS1aXTpcXC8pPygoPzpbXFx3LV0rKVtcXFxcL10/KSskLy50ZXN0KFxyXG4gICAgICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIHt9LFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIG1lc3NhZ2U6ICdUaGUgc3RyaW5nIGlzIGFuIGludmFsaWQgcGF0aCBkaXJlY3Rvcnkgc3RyaW5nLidcclxuICAgICAgICB9XHJcbiAgICAgICksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gcHVwcGV0ZWVyXHJcbiAgUFVQUEVURUVSX1RFTVBfRElSOiB2LnBhdGgoKSxcclxuXHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9NQVhfVVBMT0FEX1NJWkU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUFJPWFlfVVNFUk5BTUU6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BST1hZX1BBU1NXT1JEOiB2LnN0cmluZygpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdi5ib29sZWFuKCksXHJcbiAgTE9HR0lOR19UT19GSUxFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xyXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcclxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXHJcbiAqL1xyXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xyXG4gIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xyXG4gICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xyXG5cclxuICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XHJcbiAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XHJcbiAgfVxyXG5cclxuICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgYXBwZW5kRmlsZShcclxuICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxyXG4gICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgIChlcnJvcikgPT4ge1xyXG4gICAgICBpZiAoZXJyb3IpIHtcclxuICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbHNEZXNjLCBsZXZlbCB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcclxuICAgIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xyXG4gICAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nT3B0aW9ucyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmdPcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IGFsbCB0aGUgbG9nZ2luZyBvcHRpb25zIG9uIG91ciBsb2dnaW5nIG1vZHVsZSBvYmplY3RcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhsb2dnaW5nT3B0aW9ucykpIHtcclxuICAgIGxvZ2dpbmdba2V5XSA9IHZhbHVlO1xyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcclxuICBzZXRMb2dMZXZlbChsb2dnaW5nT3B0aW9ucyAmJiBwYXJzZUludChsb2dnaW5nT3B0aW9ucy5sZXZlbCkpO1xyXG5cclxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcclxuICBpZiAobG9nZ2luZ09wdGlvbnMgJiYgbG9nZ2luZ09wdGlvbnMuZGVzdCAmJiBsb2dnaW5nT3B0aW9ucy50b0ZpbGUpIHtcclxuICAgIGVuYWJsZUZpbGVMb2dnaW5nKFxyXG4gICAgICBsb2dnaW5nT3B0aW9ucy5kZXN0LFxyXG4gICAgICBsb2dnaW5nT3B0aW9ucy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuICBpbml0TG9nZ2luZyxcclxuICBsaXN0ZW5cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XHJcblxyXG5pbXBvcnQgeyBkZWZhdWx0Q29uZmlnIH0gZnJvbSAnLi4vbGliL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5jb25zdCBNQVhfQkFDS09GRl9BVFRFTVBUUyA9IDY7XHJcblxyXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxyXG4gKiBjaGFyYWN0ZXJzIHdpdGggYSBzaW5nbGUgc3BhY2UgYW5kIHRyaW1taW5nIGFueSBsZWFkaW5nIG9yIHRyYWlsaW5nXHJcbiAqIHdoaXRlc3BhY2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIGlucHV0IHRleHQgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXHJcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cclxuICogQHBhcmFtIHtzdHJpbmd9IFtyZXBsYWNlcj0nICddIC0gVGhlIHN0cmluZyB1c2VkIHRvIHJlcGxhY2UgbXVsdGlwbGVcclxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjbGVhcmVkIGFuZCBzdGFuZGFyZGl6ZWQgdGV4dC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxyXG4gIHRleHQucmVwbGFjZUFsbChydWxlLCByZXBsYWNlcikudHJpbSgpO1xyXG5cclxuLyoqXHJcbiAqIEltcGxlbWVudHMgYW4gZXhwb25lbnRpYWwgYmFja29mZiBzdHJhdGVneSBmb3IgcmV0cnlpbmcgYSBmdW5jdGlvbiB1bnRpbFxyXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiAtIFRoZSBmdW5jdGlvbiB0byBiZSByZXRyaWVkLlxyXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cclxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cclxuICogaWYgc3VjY2Vzc2Z1bC5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xyXG4gKiBpcyByZWFjaGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBjYWxsIHRoZSBmdW5jdGlvblxyXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBDYWxjdWxhdGUgZGVsYXkgaW4gbXNcclxuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XHJcblxyXG4gICAgLy8gSWYgdGhlIGF0dGVtcHQgZXhjZWVkcyB0aGUgbWF4aW11bSBhdHRlbXB0cyBvZiByZWFwZWF0LCB0aHJvdyBhbiBlcnJvclxyXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXHJcbiAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIGRlbGF5SW5NcykpO1xyXG4gICAgbG9nKFxyXG4gICAgICAzLFxyXG4gICAgICBgW3Bvb2xdIFdhaXRlZCAke2RlbGF5SW5Nc31tcyB1bnRpbCBuZXh0IGNhbGwgZm9yIHRoZSByZXNvdXJjZSBpZDogJHthcmdzWzBdfS5gXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFRyeSBhZ2FpblxyXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGaXhlcyB0aGUgZXhwb3J0IHR5cGUgYmFzZWQgb24gTUlNRSB0eXBlcyBhbmQgZmlsZSBleHRlbnNpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cclxuICogQHBhcmFtIHtzdHJpbmd9IG91dGZpbGUgLSBUaGUgZmlsZSBwYXRoIG9yIG5hbWUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcclxuICAvLyBNSU1FIHR5cGVzXHJcbiAgY29uc3QgbWltZVR5cGVzID0ge1xyXG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxyXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXHJcbiAgICAnYXBwbGljYXRpb24vcGRmJzogJ3BkZicsXHJcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXHJcbiAgfTtcclxuXHJcbiAgLy8gRm9ybWF0c1xyXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXHJcbiAgaWYgKG91dGZpbGUpIHtcclxuICAgIGNvbnN0IG91dFR5cGUgPSBvdXRmaWxlLnNwbGl0KCcuJykucG9wKCk7XHJcblxyXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XHJcbiAgICAgIHR5cGUgPSAnanBlZyc7XHJcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xyXG4gICAgICB0eXBlID0gb3V0VHlwZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGNvcnJlY3QgdHlwZVxyXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXHJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIFdoZXRoZXIgdG8gYWxsb3cgbG9hZGluZyByZXNvdXJjZXMgZnJvbVxyXG4gKiBmaWxlcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdHx1bmRlZmluZWR9IC0gVGhlIGhhbmRsZWQgcmVzb3VyY2VzIG9yIHVuZGVmaW5lZCBpZiBubyB2YWxpZFxyXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGhhbmRsZVJlc291cmNlcyA9IChyZXNvdXJjZXMgPSBmYWxzZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XHJcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcclxuXHJcbiAgbGV0IGhhbmRsZWRSZXNvdXJjZXMgPSByZXNvdXJjZXM7XHJcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcclxuXHJcbiAgLy8gVHJ5IHRvIGxvYWQgcmVzb3VyY2VzIGZyb20gYSBmaWxlXHJcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlYWRGaWxlU3luYyhyZXNvdXJjZXMsICd1dGY4JykpO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcclxuICAgIH1cclxuICB9IGVsc2Uge1xyXG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZXNvdXJjZXMpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cclxuICAgIGlmIChoYW5kbGVkUmVzb3VyY2VzICYmICFhbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXHJcbiAgZm9yIChjb25zdCBwcm9wTmFtZSBpbiBoYW5kbGVkUmVzb3VyY2VzKSB7XHJcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcclxuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xyXG4gICAgfSBlbHNlIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxyXG4gIGlmICghY29ycmVjdFJlc291cmNlcykge1xyXG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cclxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xyXG4gICAgaGFuZGxlZFJlc291cmNlcy5maWxlcyA9IGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMubWFwKChpdGVtKSA9PiBpdGVtLnRyaW0oKSk7XHJcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiByZXNvdXJjZXNcclxuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxyXG4gKiBiZSBhIGNvcnJlY3QgSlNPTi4gSWYgYSBwcmltaXRpdmUgaXMgcHJvdmlkZWQsIGl0IGlzIHN0cmluZ2lmaWVkIGFuZCByZXR1cm5lZC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cclxuICogQHBhcmFtIHtib29sZWFufSB0b1N0cmluZyAtIFdoZXRoZXIgdG8gcmV0dXJuIGEgc3RyaW5naWZpZWQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHN0cmluZ3xib29sZWFufSAtIFRoZSBwYXJzZWQgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04sXHJcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gaXNDb3JyZWN0SlNPTihkYXRhLCB0b1N0cmluZykge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xyXG4gICAgY29uc3QgcGFyc2VkRGF0YSA9IEpTT04ucGFyc2UoXHJcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcclxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcclxuICAgICAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KHBhcnNlZERhdGEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJldHVybiBhIEpTT05cclxuICAgIHJldHVybiBwYXJzZWREYXRhO1xyXG4gIH0gY2F0Y2gge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgaXRlbSBpcyBhbiBvYmplY3QsIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJiAhQXJyYXkuaXNBcnJheShpdGVtKSAmJiBpdGVtICE9PSBudWxsO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gb2JqZWN0IGlzIGVtcHR5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNPYmplY3RFbXB0eSA9IChpdGVtKSA9PlxyXG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxyXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXHJcbiAgaXRlbSAhPT0gbnVsbCAmJlxyXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcclxuXHJcbi8qKlxyXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaXRlbSAtIFRoZSBzdHJpbmcgdG8gYmUgY2hlY2tlZCBmb3IgYSBwcml2YXRlIElQIHJhbmdlIFVSTC5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxyXG4gKiBvdGhlcndpc2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XHJcbiAgY29uc3QgcmVnZXhQYXR0ZXJucyA9IFtcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMjdcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcclxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xyXG4gIF07XHJcblxyXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIGRlZXAgY29weSBvZiB0aGUgZ2l2ZW4gb2JqZWN0IG9yIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBkZWVwQ29weSA9IChvYmopID0+IHtcclxuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XHJcbiAgICByZXR1cm4gb2JqO1xyXG4gIH1cclxuXHJcbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XHJcblxyXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xyXG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcclxuICAgICAgY29weVtrZXldID0gZGVlcENvcHkob2JqW2tleV0pO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgcmV0dXJuIGNvcHk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXHJcbiAqIG9wdGlvbiB0byBwcmVzZXJ2ZSBmdW5jdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cclxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0Z1bmN0aW9ucyAtIElmIHNldCB0byB0cnVlLCBmdW5jdGlvbnMgYXJlIHByZXNlcnZlZFxyXG4gKiBpbiB0aGUgb3V0cHV0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgcmVwcmVzZW50aW5nIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcclxuICBjb25zdCByZXBsYWNlckNhbGxiYWNrID0gKG5hbWUsIHZhbHVlKSA9PiB7XHJcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xyXG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcclxuXHJcbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcclxuICAgICAgaWYgKFxyXG4gICAgICAgICh2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbignKSB8fCB2YWx1ZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoJykpICYmXHJcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxyXG4gICAgICApIHtcclxuICAgICAgICB2YWx1ZSA9IGFsbG93RnVuY3Rpb25zXHJcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxyXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nXHJcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgIDogdmFsdWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXHJcbiAgcmV0dXJuIEpTT04uc3RyaW5naWZ5KG9wdGlvbnMsIHJlcGxhY2VyQ2FsbGJhY2spLnJlcGxhY2VBbGwoXHJcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxyXG4gICAgJydcclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gbm9Mb2dvIC0gSWYgdHJ1ZSwgb25seSBwcmludHMgdmVyc2lvbiBpbmZvcm1hdGlvbiB3aXRob3V0XHJcbiAqIHRoZSBsb2dvLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHByaW50TG9nbyA9IChub0xvZ28pID0+IHtcclxuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxyXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcclxuICAgIHJlYWRGaWxlU3luYyhqb2luKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKVxyXG4gICkudmVyc2lvbjtcclxuXHJcbiAgLy8gUHJpbnQgdGV4dCBvbmx5XHJcbiAgaWYgKG5vTG9nbykge1xyXG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIFByaW50IHRoZSBsb2dvXHJcbiAgY29uc29sZS5sb2coXHJcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxyXG4gICAgYHYke3BhY2thZ2VWZXJzaW9ufVxcbmAuYm9sZFxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XHJcbiAqIHByb3BlcnRpZXMgcmVjdXJzaXZlbHlcclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xyXG4gIGNvbnN0IHBhZCA9IDQ4O1xyXG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcclxuXHJcbiAgLy8gRGlzcGxheSByZWFkbWUgaW5mb3JtYXRpb25cclxuICBjb25zb2xlLmxvZyhcclxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcclxuICAgICdcXG4tLS0tLS0nLFxyXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XHJcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XHJcbiAgICAgIC8vIElmIGNhdGVnb3J5IGhhcyBtb3JlIGxldmVscywgZ28gZnVydGhlclxyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XHJcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XHJcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXHJcbiAgICAgICAgfSBgO1xyXG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcclxuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xyXG4gICAgICAgICAgICBkZXNjTmFtZSArPSAnLic7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXHJcbiAgICAgICAgY29uc29sZS5sb2coXHJcbiAgICAgICAgICBkZXNjTmFtZSxcclxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcclxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfTtcclxuXHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xyXG4gIE9iamVjdC5rZXlzKGRlZmF1bHRDb25maWcpLmZvckVhY2goKGNhdGVnb3J5KSA9PiB7XHJcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcclxuICAgICAgY29uc29sZS5sb2coYFxcbiR7Y2F0ZWdvcnkudG9VcHBlckNhc2UoKX1gLnJlZCk7XHJcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbiAgY29uc29sZS5sb2coJ1xcbicpO1xyXG59XHJcblxyXG4vKipcclxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cclxuICovXHJcbmV4cG9ydCBjb25zdCByb3VuZE51bWJlciA9ICh2YWx1ZSwgcHJlY2lzaW9uID0gMSkgPT4ge1xyXG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xyXG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyBhIHZhbHVlIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvQm9vbGVhbiA9IChpdGVtKSA9PlxyXG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcclxuICAgID8gZmFsc2VcclxuICAgIDogISFpdGVtO1xyXG5cclxuLyoqXHJcbiAqIFdyYXBzIGN1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgaXQgc2FmZWx5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RmlsZVJlc291cmNlcyAtIEZsYWcgdG8gYWxsb3cgbG9hZGluZyBjb2RlIGZyb20gYSBmaWxlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcclxuICogZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBpZiAoY3VzdG9tQ29kZSAmJiB0eXBlb2YgY3VzdG9tQ29kZSA9PT0gJ3N0cmluZycpIHtcclxuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcclxuXHJcbiAgICBpZiAoY3VzdG9tQ29kZS5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcclxuICAgICAgICA6IGZhbHNlO1xyXG4gICAgfSBlbHNlIGlmIChcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbiAoKScpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XHJcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxyXG4gICAgKSB7XHJcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIGN1c3RvbUNvZGUucmVwbGFjZSgvOyQvLCAnJyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XHJcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcclxuICByZXR1cm4gKCkgPT4gTnVtYmVyKHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpIC0gc3RhcnQpIC8gMTAwMDAwMDtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBfX2Rpcm5hbWUsXHJcbiAgY2xlYXJUZXh0LFxyXG4gIGV4cEJhY2tvZmYsXHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdCxcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBwcmludExvZ28sXHJcbiAgcHJpbnRVc2FnZSxcclxuICByb3VuZE51bWJlcixcclxuICB0b0Jvb2xlYW4sXHJcbiAgd3JhcEFyb3VuZCxcclxuICBtZWFzdXJlVGltZVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xyXG5cclxuaW1wb3J0IHtcclxuICBhYnNvbHV0ZVByb3BzLFxyXG4gIGRlZmF1bHRDb25maWcsXHJcbiAgbmVzdGVkQXJncyxcclxuICBwcm9tcHRzQ29uZmlnXHJcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcclxuICogdGhlIHByaW5jaXBsZSBvZiB0aGUgb3B0aW9ucyBsb2FkIHByaW9yaXR5LiBJdCBhY2NlcHRzIG9wdGlvbmFsIHVzZXJPcHRpb25zXHJcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHVzZXJPcHRpb25zIC0gVXNlci1wcm92aWRlZCBvcHRpb25zIGZvciBjdXN0b21pemF0aW9uLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXHJcbiAqIChDTEkgdXNhZ2UpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHNldE9wdGlvbnMgPSAodXNlck9wdGlvbnMsIGFyZ3MpID0+IHtcclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gR2V0IHRoZSBhZGRpdGlvbmFsIG9wdGlvbnMgZnJvbSB0aGUgY3VzdG9tIEpTT04gZmlsZVxyXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcclxuICB9XHJcblxyXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xyXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cclxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xyXG5cclxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxyXG4gIGlmICh1c2VyT3B0aW9ucykge1xyXG4gICAgLy8gTWVyZ2UgdXNlciBvcHRpb25zXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIHVzZXJPcHRpb25zLFxyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxyXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcclxuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcclxuICByZXR1cm4gZ2VuZXJhbE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xyXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0cnVlIG9uY2UgdGhlIG1hbnVhbFxyXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFudWFsQ29uZmlnID0gYXN5bmMgKGNvbmZpZ0ZpbGVOYW1lKSA9PiB7XHJcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcclxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xyXG5cclxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcclxuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcclxuICAgIGNvbmZpZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhjb25maWdGaWxlTmFtZSwgJ3V0ZjgnKSk7XHJcbiAgfVxyXG5cclxuICAvLyBRdWVzdGlvbiBhYm91dCBhIGNvbmZpZ3VyYXRpb24gY2F0ZWdvcnlcclxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XHJcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XHJcbiAgICBsZXQgYWxsUXVlc3Rpb25zID0gW107XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxyXG4gICAgZm9yIChjb25zdCBzZWN0aW9uIG9mIGNhdGVnb3JpZXMpIHtcclxuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxyXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcclxuICAgICAgICAuLi5vcHRpb24sXHJcbiAgICAgICAgc2VjdGlvblxyXG4gICAgICB9KSk7XHJcblxyXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcclxuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XHJcbiAgICB9XHJcblxyXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcclxuICAgICAgb25TdWJtaXQ6IGFzeW5jIChwcm9tcHQsIGFuc3dlcikgPT4ge1xyXG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xyXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XHJcbiAgICAgICAgICBhbnN3ZXIgPSBhbnN3ZXIubGVuZ3RoXHJcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxyXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xyXG5cclxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxyXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxyXG4gICAgICAgICAgICBwcm9tcHQuY2hvaWNlcyA/IHByb21wdC5jaG9pY2VzW2Fuc3dlcl0gOiBhbnN3ZXJcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICBhd2FpdCBmc1Byb21pc2VzLndyaXRlRmlsZShcclxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcclxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcclxuICAgICAgICAgICAgICAndXRmOCdcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgICAgICAxLFxyXG4gICAgICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBBbiBlcnJvciBvY2N1cnJlZCB3aGlsZSBjcmVhdGluZyB0aGUgJHtjb25maWdGaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICAgICAgICk7XHJcbiAgICAgICAgICB9XHJcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG5cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH07XHJcblxyXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcclxuICBjb25zdCBjaG9pY2VzID0gT2JqZWN0LmtleXMocHJvbXB0c0NvbmZpZykubWFwKChjaG9pY2UpID0+ICh7XHJcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcclxuICAgIHZhbHVlOiBjaG9pY2VcclxuICB9KSk7XHJcblxyXG4gIC8vIENhdGVnb3J5IHByb21wdFxyXG4gIHJldHVybiBwcm9tcHRzKFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY2F0ZWdvcnknLFxyXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXHJcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICcnLFxyXG4gICAgICBjaG9pY2VzXHJcbiAgICB9LFxyXG4gICAgeyBvblN1Ym1pdCB9XHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcclxuICogKFB1cHBldGVlcikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xyXG4gKiBtYXBwaW5nLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcclxuICBjb25zdCBuZXdPcHRpb25zID0ge307XHJcbiAgLy8gQ3ljbGUgdGhyb3VnaCBvbGQtc3RydWN0dXJlZCBvcHRpb25zXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XHJcblxyXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXHJcbiAgICAgIChvYmosIHByb3AsIGluZGV4KSA9PlxyXG4gICAgICAgIChvYmpbcHJvcF0gPVxyXG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxyXG4gICAgICBuZXdPcHRpb25zXHJcbiAgICApO1xyXG4gIH1cclxuICByZXR1cm4gbmV3T3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9yaWdpbmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxyXG4gKiBub3QgYmUgcmVjdXJzaXZlbHkgbWVyZ2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcclxuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XHJcblxyXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XHJcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxyXG4gICAgICBpc09iamVjdCh2YWx1ZSkgJiZcclxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxyXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxyXG4gICAgICAgID8gbWVyZ2VDb25maWdPcHRpb25zKG1lcmdlZE9wdGlvbnNba2V5XSwgdmFsdWUsIGFic29sdXRlUHJvcHMpXHJcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgICA/IHZhbHVlXHJcbiAgICAgICAgICA6IG1lcmdlZE9wdGlvbnNba2V5XTtcclxuICB9XHJcblxyXG4gIHJldHVybiBtZXJnZWRPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXHJcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0RXhwb3J0U2V0dGluZ3MgPSAoZXhwb3J0T3B0aW9ucywgZ2VuZXJhbE9wdGlvbnMgPSB7fSkgPT4ge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcblxyXG4gIGlmIChleHBvcnRPcHRpb25zLnN2Zykge1xyXG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0LnNjYWxlID0gZXhwb3J0T3B0aW9ucy5zY2FsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5zY2FsZTtcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcclxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcclxuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xyXG4gICAgfTtcclxuICB9IGVsc2Uge1xyXG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcclxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMsXHJcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcclxuICAgICAgYWJzb2x1dGVQcm9wc1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcclxuICByZXR1cm4gb3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBMb2FkcyBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gZnJvbSBhIHNwZWNpZmllZCBmaWxlIHVzaW5nXHJcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyB0byBjaGVjayBmb3JcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBsb2FkZWQgZnJvbSB0aGUgc3BlY2lmaWVkIGZpbGUsXHJcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cclxuICovXHJcbmZ1bmN0aW9uIGxvYWRDb25maWdGaWxlKGFyZ3MpIHtcclxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxyXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXHJcbiAgICAoYXJnKSA9PiBhcmcucmVwbGFjZSgvLS9nLCAnJykgPT09ICdsb2FkQ29uZmlnJ1xyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgaGFzIGEgdmFsdWVcclxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcclxuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xyXG4gICAgdHJ5IHtcclxuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXHJcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgICAgIC8vIExvYWQgYW4gb3B0aW9uYWwgY3VzdG9tIEpTT04gY29uZmlnIGZpbGVcclxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gYWRkaXRpb25hbCBvcHRpb25zIHRvIHJldHVyblxyXG4gIHJldHVybiB7fTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcclxuICogYW5kIGVudmlyb25tZW50IHZhcmlhYmxlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY3VzdG9tT2JqIC0gQ3VzdG9tIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHRvIG92ZXJyaWRlIGRlZmF1bHRzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqIGR1cmluZyByZWN1cnNpb24uXHJcbiAqL1xyXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XHJcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcclxuICAgIGNvbnN0IGVudHJ5ID0gY29uZmlnT2JqW2tleV07XHJcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcclxuXHJcbiAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhIGN1c3RvbSBKU09OIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxyXG4gICAgICBpZiAoZW50cnkuZW52TGluayBpbiBlbnZzICYmIGVudnNbZW50cnkuZW52TGlua10gIT09IHVuZGVmaW5lZCkge1xyXG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cclxuICogbmVzdGVkIHByb3BlcnRpZXMgcmVjdXJzaXZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXHJcbiAqIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcclxuICBsZXQgb3B0aW9ucyA9IHt9O1xyXG4gIGZvciAoY29uc3QgW25hbWUsIGl0ZW1dIG9mIE9iamVjdC5lbnRyaWVzKGl0ZW1zKSkge1xyXG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxyXG4gICAgICA/IGl0ZW0udmFsdWVcclxuICAgICAgOiBpbml0T3B0aW9ucyhpdGVtKTtcclxuICB9XHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQYWlycyBhcmd1bWVudCB2YWx1ZXMgd2l0aCBjb3JyZXNwb25kaW5nIG9wdGlvbnMgaW4gdGhlIGNvbmZpZ3VyYXRpb24sXHJcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xyXG4gKiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGVmYXVsdENvbmZpZyAtIERlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJlZmVyZW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cclxuICovXHJcbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcclxuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XHJcbiAgZm9yIChsZXQgaSA9IDA7IGkgPCBhcmdzLmxlbmd0aDsgaSsrKSB7XHJcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xyXG5cclxuICAgIC8vIEZpbmQgdGhlIHJpZ2h0IHBsYWNlIGZvciBwcm9wZXJ0eSdzIHZhbHVlXHJcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cclxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxyXG4gICAgICA6IFtdO1xyXG5cclxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcclxuICAgIGxldCBhcmd1bWVudFR5cGU7XHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICBhcmd1bWVudFR5cGUgPSBvYmpbcHJvcF0udHlwZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xyXG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XHJcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgICBpZiAoYXJnc1srK2ldKSB7XHJcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUgPT09ICdudW1iZXInKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXS5zcGxpdCgnLCcpO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgIGxvZyhcclxuICAgICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgc2hvd1VzYWdlID0gdHJ1ZTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcclxuICAgIH0sIG9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXHJcbiAgaWYgKHNob3dVc2FnZSkge1xyXG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBvcHRpb25zO1xyXG59XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcclxuICogdGhlIGZpbmFsIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXHJcbiAqIEBwYXJhbSB7QXJyYXl9IG5lc3RlZE5hbWVzIC0gQXJyYXkgb2YgbmVzdGVkIHByb3BlcnR5IG5hbWVzLlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb2JqZWN0IHdpdGggYXNzaWduZWQgdmFsdWVzLlxyXG4gKi9cclxuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xyXG4gIHdoaWxlIChuZXN0ZWROYW1lcy5sZW5ndGggPiAxKSB7XHJcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XHJcblxyXG4gICAgLy8gQ3JlYXRlIGEgcHJvcGVydHkgaW4gb2JqZWN0IGlmIGl0IGRvZXNuJ3QgZXhpc3RcclxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcclxuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xyXG4gICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0gcmVjdXJzaXZlUHJvcHMoXHJcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXHJcbiAgICAgIG5lc3RlZE5hbWVzLFxyXG4gICAgICB2YWx1ZVxyXG4gICAgKTtcclxuXHJcbiAgICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbiAgfVxyXG5cclxuICAvLyBBc3NpZ24gdGhlIGZpbmFsIHZhbHVlXHJcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XHJcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0T3B0aW9ucyxcclxuICBzZXRPcHRpb25zLFxyXG4gIG1hbnVhbENvbmZpZyxcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXHJcbiAgaW5pdEV4cG9ydFNldHRpbmdzXHJcbn07XHJcbiIsIi8qKlxyXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxyXG4gKi9cclxuXHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHVybnMgdGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBVUkwuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXHJcbiAqL1xyXG5jb25zdCBnZXRQcm90b2NvbCA9ICh1cmwpID0+ICh1cmwuc3RhcnRzV2l0aCgnaHR0cHMnKSA/IGh0dHBzIDogaHR0cCk7XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcclxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcclxuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xyXG5cclxuICAgIHByb3RvY29sXHJcbiAgICAgIC5nZXQoXHJcbiAgICAgICAgdXJsLFxyXG4gICAgICAgIE9iamVjdC5hc3NpZ24oXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdoaWdoY2hhcnRzL2V4cG9ydCcsXHJcbiAgICAgICAgICAgICAgUmVmZXJlcjogJ2hpZ2hjaGFydHMvZXhwb3J0J1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgcmVxdWVzdE9wdGlvbnMgfHwge31cclxuICAgICAgICApLFxyXG4gICAgICAgIChyZXMpID0+IHtcclxuICAgICAgICAgIGxldCBkYXRhID0gJyc7XHJcblxyXG4gICAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICAgIGRhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcbiAgICAgIClcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG4gIH0pO1xyXG59XHJcblxyXG4vKipcclxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXHJcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcclxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcclxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxyXG4gKi9cclxuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XHJcblxyXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xyXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXHJcbiAgICAgIHtcclxuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcclxuICAgICAgICBoZWFkZXJzOiB7XHJcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxyXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIHJlcXVlc3RPcHRpb25zXHJcbiAgICApO1xyXG5cclxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXHJcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xyXG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XHJcbiAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcclxuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9KTtcclxuICAgICAgfSlcclxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgICAgIHJlamVjdChlcnJvcik7XHJcbiAgICAgIH0pO1xyXG5cclxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cclxuICAgIHJlcS53cml0ZShkYXRhKTtcclxuICAgIHJlcS5lbmQoKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XHJcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XHJcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UpIHtcclxuICAgIHN1cGVyKCk7XHJcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gICAgdGhpcy5zdGFja01lc3NhZ2UgPSBtZXNzYWdlO1xyXG4gIH1cclxuXHJcbiAgc2V0RXJyb3IoZXJyb3IpIHtcclxuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcclxuICAgIGlmIChlcnJvci5uYW1lKSB7XHJcbiAgICAgIHRoaXMubmFtZSA9IGVycm9yLm5hbWU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xyXG4gICAgICB0aGlzLnN0YXR1c0NvZGUgPSBlcnJvci5zdGF0dXNDb2RlO1xyXG4gICAgfVxyXG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XHJcbiAgICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gZXJyb3IubWVzc2FnZTtcclxuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXHJcbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cclxuLy8gYmVmb3JlIHN0YXJ0aW5nIHRoZSBzZXJ2aWNlXHJcblxyXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5cclxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGZldGNoIH0gZnJvbSAnLi9mZXRjaC5qcyc7XHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY29uc3QgY2FjaGUgPSB7XHJcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxyXG4gIHNvdXJjZXM6ICcnLFxyXG4gIGhjVmVyc2lvbjogJydcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RWZXJzaW9uID0gKGNhY2hlKSA9PiB7XHJcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcclxuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxyXG4gICAgLnJlcGxhY2UoJy8qJywgJycpXHJcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcclxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXHJcbiAgICAudHJpbSgpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGV4dHJhY3RNb2R1bGVOYW1lID0gKHNjcmlwdFBhdGgpID0+IHtcclxuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxyXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcclxuICogZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHRoYXQgY29udGFpbnMgbWFwcGVkIG5hbWVzIG9mXHJcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgd2hpbGUgd3JpdGluZ1xyXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2F2ZUNvbmZpZ1RvTWFuaWZlc3QgPSBhc3luYyAoY29uZmlnLCBmZXRjaGVkTW9kdWxlcykgPT4ge1xyXG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xyXG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXHJcbiAgICBtb2R1bGVzOiBmZXRjaGVkTW9kdWxlcyB8fCB7fVxyXG4gIH07XHJcblxyXG4gIC8vIFVwZGF0ZSBjYWNoZSBvYmplY3Qgd2l0aCB0aGUgY3VycmVudCBtb2R1bGVzXHJcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcclxuXHJcbiAgbG9nKDMsICdbY2FjaGVdIFdyaXRpbmcgYSBuZXcgbWFuaWZlc3QuJyk7XHJcbiAgdHJ5IHtcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIGpvaW4oX19kaXJuYW1lLCBjb25maWcuY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpLFxyXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXHJcbiAgICAgICd1dGY4J1xyXG4gICAgKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XHJcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcclxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cclxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXHJcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxyXG4gIHNjcmlwdCxcclxuICByZXF1ZXN0T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlcyxcclxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcclxuKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXHJcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcclxuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xyXG4gIH1cclxuXHJcbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xyXG5cclxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XHJcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xyXG5cclxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xyXG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XHJcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xyXG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XHJcbiAgfVxyXG5cclxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcclxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xyXG4gIH0gZWxzZSB7XHJcbiAgICBsb2coXHJcbiAgICAgIDIsXHJcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiAnJztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxyXG4gKiAoZnVsbCBVUkxzKS5cclxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXHJcbiAqIGEgcmVxdWVzdC5cclxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXHJcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxyXG4gIGNvcmVTY3JpcHRzLFxyXG4gIG1vZHVsZVNjcmlwdHMsXHJcbiAgY3VzdG9tU2NyaXB0cyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgZmV0Y2hlZE1vZHVsZXNcclxuKSA9PiB7XHJcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xyXG4gIGxldCBwcm94eUFnZW50O1xyXG4gIGNvbnN0IHsgaG9zdCwgcG9ydCwgdXNlcm5hbWUsIHBhc3N3b3JkIH0gPSBwcm94eU9wdGlvbnM7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChob3N0ICYmIHBvcnQpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcclxuICAgICAgICBob3N0LFxyXG4gICAgICAgIHBvcnQsXHJcbiAgICAgICAgLi4uKHVzZXJuYW1lICYmIHBhc3N3b3JkID8geyB1c2VybmFtZSwgcGFzc3dvcmQgfSA6IHt9KVxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xyXG5cclxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xyXG5cclxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZSxcclxuICBoaWdoY2hhcnRzLFxyXG4gIHZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cclxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXHJcbiAgY29uc3QgY2hhcnQgPSB7XHJcbiAgICBhbmltYXRpb246IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XHJcbiAgaWYgKG9wdGlvbnMuZXhwb3J0LnN0ckluaikge1xyXG4gICAgY2hhcnQuaGVpZ2h0ID0gY2hhcnRPcHRpb25zLmNoYXJ0LmhlaWdodDtcclxuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xyXG4gIH1cclxuXHJcbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XHJcbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcclxuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcclxuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xyXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xyXG4gICAgICBleHBvcnRpbmc6IHtcclxuICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICB9LFxyXG4gICAgICBwbG90T3B0aW9uczoge1xyXG4gICAgICAgIHNlcmllczoge1xyXG4gICAgICAgICAgbGFiZWw6IHtcclxuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxyXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcclxuICAgICAgICAqL1xyXG4gICAgICB0b29sdGlwOiB7fVxyXG4gICAgfSk7XHJcblxyXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XHJcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cclxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xyXG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xyXG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XHJcbiAgfSk7XHJcblxyXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xyXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcclxuICB9KTtcclxuXHJcbiAgLy8gR2V0IHRoZSB1c2VyIG9wdGlvbnNcclxuICBjb25zdCB1c2VyT3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0LnN0cklualxyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuZXhwb3J0LnN0ckluan1gKSgpXHJcbiAgICA6IGNoYXJ0T3B0aW9ucztcclxuXHJcbiAgLy8gVHJpZ2dlciBjdXN0b20gY29kZVxyXG4gIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpIHtcclxuICAgIG5ldyBGdW5jdGlvbignb3B0aW9ucycsIG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkodXNlck9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgLy8gTWVyZ2UgdGhlIGdsb2JhbE9wdGlvbnMsIHRoZW1lT3B0aW9ucywgb3B0aW9ucyBmcm9tIHRoZSB3cmFwcGVkXHJcbiAgLy8gc2V0T3B0aW9ucyBmdW5jdGlvbiBhbmQgdXNlciBvcHRpb25zIHRvIGNyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3RcclxuICBjb25zdCBmaW5hbE9wdGlvbnMgPSBtZXJnZShcclxuICAgIGZhbHNlLFxyXG4gICAgSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnMpLFxyXG4gICAgdXNlck9wdGlvbnMsXHJcbiAgICAvLyBQbGFjZWQgaXQgaGVyZSBpbnN0ZWFkIGluIHRoZSBpbml0IGJlY2F1c2Ugb2YgdGhlIHNpemUgaXNzdWVzXHJcbiAgICB7IGNoYXJ0IH1cclxuICApO1xyXG5cclxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xyXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2t9YCkoKVxyXG4gICAgOiB1bmRlZmluZWQ7XHJcblxyXG4gIC8vIFNldCB0aGUgZ2xvYmFsIG9wdGlvbnMgaWYgZXhpc3RcclxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zKTtcclxuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xyXG4gICAgc2V0T3B0aW9ucyhnbG9iYWxPcHRpb25zKTtcclxuICB9XHJcblxyXG4gIGxldCBjb25zdHIgPSBvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBjb25zdHIgPSB0eXBlb2YgSGlnaGNoYXJ0c1tjb25zdHJdICE9PSAndW5kZWZpbmVkJyA/IGNvbnN0ciA6ICdjaGFydCc7XHJcblxyXG4gIEhpZ2hjaGFydHNbY29uc3RyXSgnY29udGFpbmVyJywgZmluYWxPcHRpb25zLCBmaW5hbENhbGxiYWNrKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBjdXJyZW50IGdsb2JhbCBvcHRpb25zXHJcbiAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gIC8vIENsZWFyIGl0IGp1c3QgaW4gY2FzZSAoZS5nLiB0aGUgc2V0T3B0aW9ucyB3YXMgdXNlZCBpbiB0aGUgY3VzdG9tQ29kZSlcclxuICBmb3IgKGNvbnN0IHByb3AgaW4gZGVmYXVsdE9wdGlvbnMpIHtcclxuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcclxuICAgICAgZGVsZXRlIGRlZmF1bHRPcHRpb25zW3Byb3BdO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2V0IHRoZSBkZWZhdWx0IG9wdGlvbnMgYmFja1xyXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcclxuXHJcbiAgLy8gRW1wdHkgdGhlIGN1c3RvbSBnbG9iYWwgb3B0aW9ucyBvYmplY3RcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHBhdGggZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgcHVwcGV0ZWVyIGZyb20gJ3B1cHBldGVlcic7XHJcblxyXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgc2V0dXBIaWdoY2hhcnRzIH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIEdldCB0aGUgdGVtcGxhdGUgZm9yIHRoZSBwYWdlXHJcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLCAndXRmOCcpO1xyXG5cclxubGV0IGJyb3dzZXI7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBleGlzdGluZyBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxyXG4gKiBjcmVhdGVkLlxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIGdldCgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcclxuICB9XHJcbiAgcmV0dXJuIGJyb3dzZXI7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cclxuICpcclxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBtYXggcmV0cmllcyB0byBvcGVuIGEgYnJvd3NlclxyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZShwdXBwZXRlZXJBcmdzKSB7XHJcbiAgLy8gR2V0IGRlYnVnIGFuZCBvdGhlciBvcHRpb25zXHJcbiAgY29uc3QgeyBwdXBwZXRlZXI6IHB1cHBldGVlck9wdGlvbnMsIGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiBwdXBwZXRlZXJPcHRpb25zLnRlbXBEaXIgfHwgJy4vdG1wLycsXHJcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxyXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcclxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHSFVQOiBmYWxzZSxcclxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXHJcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXHJcbiAgICAuLi4oZW5hYmxlZERlYnVnICYmIGRlYnVnT3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyXHJcbiAgaWYgKCFicm93c2VyKSB7XHJcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xyXG5cclxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxyXG4gICAgICAgICk7XHJcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgMSxcclxuICAgICAgICAgIGVycm9yLFxyXG4gICAgICAgICAgJ1ticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZS4nXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXHJcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcclxuICAgICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIFJldHJ5IHRvIG9wZW4gYSBicm93c2VyICgke3RyeUNvdW50fSBvdXQgb2YgMjUpLmApO1xyXG4gICAgICAgICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCA0MDAwKSk7XHJcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfTtcclxuXHJcbiAgICB0cnkge1xyXG4gICAgICBhd2FpdCBvcGVuKCk7XHJcblxyXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAobGF1bmNoT3B0aW9ucy5oZWFkbGVzcyA9PT0gJ3NoZWxsJykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cclxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xyXG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gZGVidWcgbW9kZS5gKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoIWJyb3dzZXIpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gQ2Fubm90IGZpbmQgYSBicm93c2VyIHRvIG9wZW4uJyk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXHJcbiAqIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZSgpIHtcclxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5uZWN0ZWRcclxuICBpZiAoYnJvd3Nlcj8uY29ubmVjdGVkKSB7XHJcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XHJcbiAgfVxyXG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIElmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdCBhdmFpbGFibGUsIHJldHVybnMgZmFsc2UuXHJcbiAqXHJcbiAqIFRoZSBmdW5jdGlvbiBjcmVhdGVzIGEgbmV3IHBhZ2UsIGRpc2FibGVzIGNhY2hpbmcsIHNldHMgY29udGVudCB1c2luZ1xyXG4gKiBzZXRQYWdlQ29udGVudCgpLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHJldHVybnMgeyhib29sZWFufG9iamVjdCl9IFJldHVybnMgZmFsc2UgaWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90XHJcbiAqIGF2YWlsYWJsZSwgb3IgYSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBuZXdseSBjcmVhdGVkIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gbmV3UGFnZSgpIHtcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIHJldHVybiBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIHBhZ2VcclxuICBjb25zdCBwYWdlID0gYXdhaXQgYnJvd3Nlci5uZXdQYWdlKCk7XHJcblxyXG4gIC8vIERpc2FibGUgY2FjaGVcclxuICBhd2FpdCBwYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XHJcblxyXG4gIC8vIFNldCB0aGUgY29udGVudFxyXG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBhZ2UpO1xyXG5cclxuICAvLyBTZXQgcGFnZSBldmVudHNcclxuICBzZXRQYWdlRXZlbnRzKHBhZ2UpO1xyXG5cclxuICByZXR1cm4gcGFnZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENsZWFycyB0aGUgY29udGVudCBvZiBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgbW9kZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gaGFyZFJlc2V0IC0gQSBmbGFnIGluZGljYXRpbmcgdGhlIHR5cGUgb2YgY2xlYXJpbmdcclxuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcclxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXHJcbiAqIHN0cnVjdHVyZS5cclxuICpcclxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XHJcbiAgdHJ5IHtcclxuICAgIGlmIChwYWdlICYmICFwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXHJcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAyLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIHJldHVybiBmYWxzZTtcclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcclxuICogYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXHJcbiAqIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcclxuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxyXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIHRyeSB7XHJcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XHJcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXHJcbiAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIGUsZywgd2hlbiBkb2luZyBTVkdcclxuICAgICAgLy8gZXhwb3J0c1xyXG4gICAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XHJcblxyXG4gICAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG9sZENoYXJ0cykgJiYgb2xkQ2hhcnRzLmxlbmd0aCkge1xyXG4gICAgICAgICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzXHJcbiAgICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xyXG4gICAgICAgICAgICBvbGRDaGFydCAmJiBvbGRDaGFydC5kZXN0cm95KCk7XHJcbiAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgIGNvbnN0IFsuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcclxuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcclxuICAgICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXHJcbiAgICAgICAgLi4ubGlua3NUb1JlbW92ZVxyXG4gICAgICBdKSB7XHJcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgcGFnZSdzIHJlc291cmNlcy5gKTtcclxuICB9XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXHJcbiAqL1xyXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAvLyBJdCB3b3VsZCBzZWVtIGxpa2UgdGhpcyBtYXkgZmlyZSBhdCB0aGUgc2FtZSB0aW1lIG9yIHNob3J0bHkgYmVmb3JlXHJcbiAgICAvLyBhIHBhZ2UgaXMgY2xvc2VkLlxyXG4gICAgaWYgKHBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICByZXR1cm47XHJcbiAgICB9XHJcblxyXG4gICAgLy8gVE9ETzogQ29uc2lkZXIgYWRkaW5nIGEgc3dpdGNoIGhlcmUgdGhhdCB0dXJucyBvbiBsb2coMCkgbG9nZ2luZ1xyXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXHJcbiAgICBhd2FpdCBwYWdlLiRldmFsKFxyXG4gICAgICAnI2NvbnRhaW5lcicsXHJcbiAgICAgIChlbGVtZW50LCBlcnJvck1lc3NhZ2UpID0+IHtcclxuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XHJcbiAgICAgICAgICBlbGVtZW50LmlubmVySFRNTCA9IGVycm9yTWVzc2FnZTtcclxuICAgICAgICB9XHJcbiAgICAgIH0sXHJcbiAgICAgIGA8aDE+Q2hhcnQgaW5wdXQgZGF0YSBlcnJvcjogPC9oMT4ke2Vycm9yLnRvU3RyaW5nKCl9YFxyXG4gICAgKTtcclxuICB9KTtcclxufVxyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGdldCxcclxuICBjcmVhdGUsXHJcbiAgY2xvc2UsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2UsXHJcbiAgYWRkUGFnZVJlc291cmNlcyxcclxuICBjbGVhclBhZ2VSZXNvdXJjZXNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgeyBnZXRDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzIG9mIHRoZSBzcGVjaWZpZWQgcGFnZSBlbGVtZW50IHdpdGhcclxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcclxuICogeCwgeSwgd2lkdGgsIGFuZCBoZWlnaHQgcHJvcGVydGllcy5cclxuICovXHJcbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY2hhcnQtY29udGFpbmVyJywgKGVsZW1lbnQpID0+IHtcclxuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHgsXHJcbiAgICAgIHksXHJcbiAgICAgIHdpZHRoLFxyXG4gICAgICBoZWlnaHQ6IE1hdGgudHJ1bmMoaGVpZ2h0ID4gMSA/IGhlaWdodCA6IDUwMClcclxuICAgIH07XHJcbiAgfSk7XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXHJcbiAqIHNwZWNpZmllZCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBJbWFnZSB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cclxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSByYXN0ZXJpemF0aW9uVGltZW91dCAtIFRpbWVvdXQgZm9yIHJhc3Rlcml6YXRpb25cclxuICogaW4gbWlsbGlzZWNvbmRzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgaW1hZ2UgYnVmZmVyIG9yIHJlamVjdGluZ1xyXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxyXG4gKi9cclxuY29uc3QgY3JlYXRlSW1hZ2UgPSAocGFnZSwgdHlwZSwgZW5jb2RpbmcsIGNsaXAsIHJhc3Rlcml6YXRpb25UaW1lb3V0KSA9PlxyXG4gIFByb21pc2UucmFjZShbXHJcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xyXG4gICAgICB0eXBlLFxyXG4gICAgICBlbmNvZGluZyxcclxuICAgICAgY2xpcCxcclxuICAgICAgY2FwdHVyZUJleW9uZFZpZXdwb3J0OiB0cnVlLFxyXG4gICAgICBmdWxsUGFnZTogZmFsc2UsXHJcbiAgICAgIG9wdGltaXplRm9yU3BlZWQ6IHRydWUsXHJcbiAgICAgIC4uLih0eXBlICE9PSAncG5nJyA/IHsgcXVhbGl0eTogODAgfSA6IHt9KSxcclxuXHJcbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxyXG4gICAgICAvLyBmb3JtYXQgaXMgUE5HXHJcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXHJcbiAgICB9KSxcclxuICAgIG5ldyBQcm9taXNlKChfcmVzb2x2ZSwgcmVqZWN0KSA9PlxyXG4gICAgICBzZXRUaW1lb3V0KFxyXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcclxuICAgICAgICByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXHJcbiAgICAgIClcclxuICAgIClcclxuICBdKTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgUERGIHVzaW5nIFB1cHBldGVlcidzIHBhZ2UgcGRmIGZ1bmN0aW9uYWxpdHkgd2l0aCBzcGVjaWZpZWRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBQREYgaGVpZ2h0LlxyXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIFBERiBlbmNvZGluZy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVQREYgPSBhc3luYyAoXHJcbiAgcGFnZSxcclxuICBoZWlnaHQsXHJcbiAgd2lkdGgsXHJcbiAgZW5jb2RpbmcsXHJcbiAgcmFzdGVyaXphdGlvblRpbWVvdXRcclxuKSA9PiB7XHJcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcclxuXHJcbiAgcmV0dXJuIHBhZ2UucGRmKHtcclxuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xyXG4gICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgd2lkdGgsXHJcbiAgICBlbmNvZGluZyxcclxuICAgIHRpbWVvdXQ6IHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XHJcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFNWRyBzdHJpbmcuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cclxuICBwYWdlLiRldmFsKCcjY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJywgKGVsZW1lbnQpID0+IGVsZW1lbnQub3V0ZXJIVE1MKTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBzcGVjaWZpZWQgY2hhcnQgYW5kIG9wdGlvbnMgYXMgY29uZmlndXJhdGlvbiBpbnRvIHRoZSB0cmlnZ2VyRXhwb3J0XHJcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cclxuICovXHJcbmNvbnN0IHNldEFzQ29uZmlnID0gYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSA9PiB7XHJcbiAgLy8gR2V0IHJpZCBvZiB0aGUgcmVkdW5hbnQgc3RyaW5nIGRhdGFcclxuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG51bGw7XHJcbiAgb3B0aW9ucy5leHBvcnQuaW5maWxlID0gbnVsbDtcclxuXHJcbiAgLy8gR2V0IHRoZSBzaXplIG9mIHRoZSBleHBvcnQgaW5wdXRcclxuICBjb25zdCB0b3RhbFNpemUgPSBCdWZmZXIuYnl0ZUxlbmd0aChcclxuICAgIG9wdGlvbnMuZXhwb3J0Py5zdHJJbmogPyBvcHRpb25zLmV4cG9ydD8uc3RySW5qIDogSlNPTi5zdHJpbmdpZnkoY2hhcnQpLFxyXG4gICAgJ3V0Zi04J1xyXG4gICk7XHJcblxyXG4gIC8vIExvZyB0aGUgc2l6ZSBpbiBNQlxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW2V4cG9ydF0gVGhlIGN1cnJlbnQgdG90YWwgc2l6ZSBvZiBkYXRhIHBhc3NlZCB0byBhIHBhZ2UgaXMgYXJvdW5kICR7KFxyXG4gICAgICB0b3RhbFNpemUgL1xyXG4gICAgICAoMTAyNCAqIDEwMjQpXHJcbiAgICApLnRvRml4ZWQoMil9IE1CYFxyXG4gICk7XHJcblxyXG4gIC8vIENoZWNrIHRoZSBzaXplIG9mIGRhdGEgcGFzc2VkIHRvIHRoZSBwYWdlXHJcbiAgaWYgKHRvdGFsU2l6ZSA+PSAxMDAgKiAxMDI0ICogMTAyNCkge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbZXhwb3J0XSBUaGUgZGF0YSBwYXNzZWQgdG8gYSBwYWdlIGV4Y2VlZGVkIDEwME1CLmApO1xyXG4gIH1cclxuXHJcbiAgLy8gVHJpZ2dlciB0aGUgSGlnaGNoYXJ0cyBjaGFydCBjcmVhdGlvblxyXG4gIHJldHVybiBwYWdlLmV2YWx1YXRlKHRyaWdnZXJFeHBvcnQsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBFeHBvcnRzIHRvIGEgY2hhcnQgZnJvbSBhIHBhZ2UgdXNpbmcgUHVwcGV0ZWVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCBvciBTVkcgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nIHwgQnVmZmVyIHwgRXhwb3J0RXJyb3I+fSBQcm9taXNlIHJlc29sdmluZyB0b1xyXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucykgPT4ge1xyXG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxyXG4gIGxldCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcclxuXHJcbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gRGVjaWRlIHdoZXRoZXIgZGlzcGxheSBlcnJvciBvciBkZWJidWdlciB3cmFwcGVyIGFyb3VuZCBpdFxyXG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXHJcbiAgICAgIGdldENhY2hlKCkuYWN0aXZlTWFuaWZlc3QubW9kdWxlcy5kZWJ1Z2dlcjtcclxuXHJcbiAgICBsZXQgaXNTVkc7XHJcbiAgICBpZiAoXHJcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcclxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcclxuICAgICkge1xyXG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XHJcblxyXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcclxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgICByZXR1cm4gY2hhcnQ7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlzU1ZHID0gdHJ1ZTtcclxuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xyXG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXHJcbiAgICAgIH0pO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcclxuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBjb25maWcuJyk7XHJcblxyXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnN0ckluaikge1xyXG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxyXG4gICAgICAgICAgcGFnZSxcclxuICAgICAgICAgIHtcclxuICAgICAgICAgICAgY2hhcnQ6IHtcclxuICAgICAgICAgICAgICBoZWlnaHQ6IGV4cG9ydE9wdGlvbnMuaGVpZ2h0LFxyXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBjaGFydC5jaGFydC5oZWlnaHQgPSBleHBvcnRPcHRpb25zLmhlaWdodDtcclxuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XHJcblxyXG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKHBhZ2UsIGNoYXJ0LCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xyXG4gICAgLy8gSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcclxuICAgIC8vIG91dCB3aGVuIGRvaW5nIGEgbmV3IGV4cG9ydCBpbiB0aGUgc2FtZSBwYWdlIVxyXG4gICAgaW5qZWN0ZWRSZXNvdXJjZXMgPSBhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgcmVhbCBjaGFydCBzaXplIGFuZCBzZXQgdGhlIHpvb20gYWNjb3JkaW5nbHlcclxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xyXG4gICAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XHJcbiAgICAgICAgICBjb25zdCBzdmdFbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcclxuICAgICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnXHJcbiAgICAgICAgICApO1xyXG5cclxuICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWVzIGNvcnJlY3RseSBzY2FsZWRcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0SGVpZ2h0ID0gc3ZnRWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG4gICAgICAgICAgY29uc3QgY2hhcnRXaWR0aCA9IHN2Z0VsZW1lbnQud2lkdGguYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XHJcbiAgICAgICAgICAvLyBTZXQgdGhlIHpvb20gYXMgc2NhbGVcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XHJcblxyXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUubWFyZ2luID0gJzBweCc7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSwgcGFyc2VGbG9hdChleHBvcnRPcHRpb25zLnNjYWxlKSlcclxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgICAgY29uc3QgeyBjaGFydEhlaWdodCwgY2hhcnRXaWR0aCB9ID0gd2luZG93LkhpZ2hjaGFydHMuY2hhcnRzWzBdO1xyXG5cclxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xyXG4gICAgICAgICAgLy8gUmVzZXQgdGhlIHpvb20gZm9yIG90aGVyIGV4cG9ydHMgdGhhbiB0byBTVkdzXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XHJcblxyXG4gICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXHJcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcclxuICAgICAgICAgIH07XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XHJcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguYWJzKFxyXG4gICAgICBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodClcclxuICAgICk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5hYnMoXHJcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aClcclxuICAgICk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjbGlwIHJlZ2lvbiBmb3IgdGhlIHBhZ2VcclxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcclxuXHJcbiAgICAvLyBTZXQgdGhlIGZpbmFsIHZpZXdwb3J0IG5vdyB0aGF0IHdlIGhhdmUgdGhlIHJlYWwgaGVpZ2h0XHJcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcclxuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgd2lkdGg6IHZpZXdwb3J0V2lkdGgsXHJcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXHJcbiAgICB9KTtcclxuXHJcbiAgICBsZXQgZGF0YTtcclxuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xyXG4gICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgICAgLy8gU1ZHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XHJcbiAgICB9IGVsc2UgaWYgKFsncG5nJywgJ2pwZWcnXS5pbmNsdWRlcyhleHBvcnRPcHRpb25zLnR5cGUpKSB7XHJcbiAgICAgIC8vIFBORyBvciBKUEVHXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcclxuICAgICAgICBwYWdlLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICB7XHJcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgICB4LFxyXG4gICAgICAgICAgeVxyXG4gICAgICAgIH0sXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XHJcbiAgICAgIC8vIFBERlxyXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgdmlld3BvcnRIZWlnaHQsXHJcbiAgICAgICAgdmlld3BvcnRXaWR0aCxcclxuICAgICAgICAnYmFzZTY0JyxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDbGVhciBwcmV2aW91c2x5IGluamVjdGVkIEpTIGFuZCBDU1MgcmVzb3VyY2VzXHJcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGRhdGE7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZXJyb3I7XHJcbiAgfVxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoY2hhcnQpID0+IGBcclxuPCFET0NUWVBFIGh0bWw+XHJcbjxodG1sIGxhbmc9J2VuLVVTJz5cclxuICA8aGVhZD5cclxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XHJcbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxyXG4gIDwvaGVhZD5cclxuICA8c3R5bGU+XHJcbiAgICAke2Nzc1RlbXBsYXRlKCl9XHJcbiAgPC9zdHlsZT5cclxuICA8Ym9keT5cclxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cclxuICAgICAgJHtjaGFydH1cclxuICAgIDwvZGl2PlxyXG4gIDwvYm9keT5cclxuPC9odG1sPlxyXG5cclxuYDtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XHJcbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcclxuXHJcbmltcG9ydCB7XHJcbiAgY3JlYXRlIGFzIGNyZWF0ZUJyb3dzZXIsXHJcbiAgY2xvc2UgYXMgY2xvc2VCcm93c2VyLFxyXG4gIG5ld1BhZ2UsXHJcbiAgY2xlYXJQYWdlXHJcbn0gZnJvbSAnLi9icm93c2VyLmpzJztcclxuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbi8vIFRoZSBwb29sIGluc3RhbmNlXHJcbmxldCBwb29sID0gZmFsc2U7XHJcblxyXG4vLyBQb29sIHN0YXRpc3RpY3NcclxuZXhwb3J0IGNvbnN0IHN0YXRzID0ge1xyXG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXHJcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXHJcbiAgZXhwb3J0RnJvbVN2Z0F0dGVtcHRzOiAwLFxyXG4gIHRpbWVTcGVudDogMCxcclxuICBkcm9wcGVkRXhwb3J0czogMCxcclxuICBzcGVudEF2ZXJhZ2U6IDBcclxufTtcclxuXHJcbmxldCBwb29sQ29uZmlnID0ge307XHJcblxyXG5jb25zdCBmYWN0b3J5ID0ge1xyXG4gIC8qKlxyXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtPYmplY3R9IC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdvcmtlciBJRCwgYSByZWZlcmVuY2UgdG8gdGhlXHJcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gSWYgdGhlcmUncyBhbiBlcnJvciBkdXJpbmcgdGhlIGNyZWF0aW9uIG9mIHRoZSBuZXdcclxuICAgKiBwYWdlLlxyXG4gICAqL1xyXG4gIGNyZWF0ZTogYXN5bmMgKCkgPT4ge1xyXG4gICAgbGV0IHBhZ2UgPSBmYWxzZTtcclxuXHJcbiAgICBjb25zdCBpZCA9IHV1aWQoKTtcclxuICAgIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIHBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XHJcblxyXG4gICAgICBpZiAoIXBhZ2UgfHwgcGFnZS5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdUaGUgcGFnZSBpcyBpbnZhbGlkIG9yIGNsb3NlZC4nKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBTdWNjZXNzZnVsbHkgY3JlYXRlZCBhIHdvcmtlciAke2lkfSAtIHRvb2sgJHtcclxuICAgICAgICAgIG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc3RhcnREYXRlXHJcbiAgICAgICAgfSBtcy5gXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ0Vycm9yIGVuY291bnRlcmVkIHdoZW4gY3JlYXRpbmcgYSBuZXcgcGFnZS4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB7XHJcbiAgICAgIGlkLFxyXG4gICAgICBwYWdlLFxyXG4gICAgICAvLyBUcnkgdG8gZGlzdHJpYnV0ZSB0aGUgaW5pdGlhbCB3b3JrIGNvdW50XHJcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXHJcbiAgICB9O1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIFZhbGlkYXRlcyBhIHdvcmtlciBwYWdlIGluIHRoZSBleHBvcnQgcG9vbCwgY2hlY2tpbmcgaWYgaXQgaGFzIGV4Y2VlZGVkXHJcbiAgICogdGhlIHdvcmsgbGltaXQuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nIHRoZVxyXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cclxuICAgKlxyXG4gICAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgdHJ1ZSBpZiB0aGUgd29ya2VyIGlzIHZhbGlkIGFuZCB3aXRoaW5cclxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxyXG4gICAqL1xyXG4gIHZhbGlkYXRlOiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICAvLyBOT1RFOiBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcclxuICAgIC8vICAgICAgIGJlIGNhdXNlZCBieSB0d28gdGhpbmdzOlxyXG4gICAgLy8gICAgICAgICAtIFRoZSBwYWdlIGlzIGNsb3NlZCBhbmQgYXR0ZW1wdGVkIHRvIGJlIHJldXNlZC5cclxuICAgIC8vICAgICAgICAgLSBMb3N0IGNvbnRhY3Qgd2l0aCB0aGUgYnJvd3NlclxyXG4gICAgLy8gICAgICAgV2hhdCB3ZSdyZSBzZWVpbmcgaW4gbG9ncyBpcyB0aGF0IHN1Y2Nlc3NpdmUgZXhwb3J0cyB0eXBpY2FsbHlcclxuICAgIC8vICAgICAgIHN1Y2NlZWRzLCBhbmQgdGhlIHNlcnZlciByZWNvdmVycywgaW5kaWNhdGluZyB0aGF0IGl0J3MgbGlrZWx5XHJcbiAgICAvLyAgICAgICB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxyXG4gICAgLy8gICAgICAgc2ltcGx5IG5vdCB2YWxpZGF0aW5nIHRoZSB3b3JrZXIgaWYgdGhlIHBhZ2UgaXMgbnVsbCBvciBjbG9zZWQuXHJcbiAgICAvL1xyXG4gICAgLy8gICAgICAgVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXHJcbiAgICAvLyAgICAgICBiZSBjb21wbGV0ZWx5IGxvY2tlZCwgc3RvcHBpbmcgaXQgZnJvbSBiZWluZyBhY3F1aXJlZCB1bnRpbFxyXG4gICAgLy8gICAgICAgaXRzIHdvcmsgY291bnQgcmVhY2hlZCB0aGUgbGltaXQuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlIHx8IHdvcmtlckhhbmRsZS5wYWdlPy5pc0Nsb3NlZCgpKSB7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAoXHJcbiAgICAgIHBvb2xDb25maWcud29ya0xpbWl0ICYmXHJcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XHJcbiAgICApIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDMsXHJcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXHJcbiAgICAgICk7XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICAgIHJldHVybiB0cnVlO1xyXG4gIH0sXHJcblxyXG4gIC8qKlxyXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxyXG4gICAqXHJcbiAgICogQHBhcmFtIHtPYmplY3R9IHdvcmtlckhhbmRsZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xyXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cclxuICAgKi9cclxuICBkZXN0cm95OiBhc3luYyAod29ya2VySGFuZGxlKSA9PiB7XHJcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUucGFnZSAmJiAhd29ya2VySGFuZGxlLnBhZ2UuaXNDbG9zZWQoKSkge1xyXG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gbG9nOiAobWVzc2FnZSwgbGV2ZWwpID0+IGxvZygxLCAnW3Rhcm5dICcgKyAgbWVzc2FnZSlcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcclxuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xyXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcclxuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxyXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXHJcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XHJcblxyXG4gIGxvZyhcclxuICAgIDMsXHJcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXHJcbiAgKTtcclxuXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIHJldHVybiBsb2coXHJcbiAgICAgIDQsXHJcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XHJcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBwb29sID0gbmV3IFBvb2woe1xyXG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcclxuICAgICAgLi4uZmFjdG9yeSxcclxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxyXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXHJcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXHJcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxyXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcclxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxyXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXHJcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gU2V0IGV2ZW50c1xyXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xyXG4gICAgICAvLyBDbGVhciBwYWdlXHJcbiAgICAgIGNvbnN0IHIgPSBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UucGFnZSwgZmFsc2UpO1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgNCxcclxuICAgICAgICBgW3Bvb2xdIFJlbGVhc2luZyBhIHdvcmtlciB3aXRoIElEICR7cmVzb3VyY2UuaWR9LiBDbGVhciBwYWdlIHN0YXR1czogJHtyfS5gXHJcbiAgICAgICk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgICAgcmVzb3VyY2UucGFnZSA9IG51bGw7XHJcbiAgICB9KTtcclxuXHJcbiAgICBjb25zdCBpbml0aWFsUmVzb3VyY2VzID0gW107XHJcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXHJcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXHJcbiAgICBpbml0aWFsUmVzb3VyY2VzLmZvckVhY2goKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gVGhlIHBvb2wgaXMgcmVhZHkke2luaXRpYWxSZXNvdXJjZXMubGVuZ3RoID8gYCB3aXRoICR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGh9IGluaXRpYWwgcmVzb3VyY2VzIHdhaXRpbmcuYCA6ICcuJ31gXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcclxuICogaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcclxuICoga2lsbGVkLCB0aGUgcG9vbCBpcyBkZXN0cm95ZWQsIGFuZCB0aGUgYnJvd3NlciBpcyBjbG9zZWQuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XHJcbiAgbG9nKDMsICdbcG9vbF0gS2lsbGluZyBwb29sIHdpdGggYWxsIHdvcmtlcnMgYW5kIGNsb3NpbmcgYnJvd3Nlci4nKTtcclxuXHJcbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXHJcbiAgaWYgKHBvb2wpIHtcclxuICAgIC8vIEZyZWUgdXAgbm90IHJlbGVhc2VkIHdvcmtlcnNcclxuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xyXG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VyLnJlc291cmNlKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxyXG4gICAgaWYgKCFwb29sLmRlc3Ryb3llZCkge1xyXG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcclxuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIGluc3RhbmNlXHJcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXHJcbiAqIGhhbmRsZSBmcm9tIHRoZSBwb29sLCBwZXJmb3JtcyB0aGUgZXhwb3J0IHVzaW5nIHB1cHBldGVlciwgYW5kIHJlbGVhc2VzXHJcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjaGFydCAtIFRoZSBjaGFydCBkYXRhIG9yIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIGV4cG9ydCByZXN1bHRhbmRcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IElmIGFuIGVycm9yIG9jY3VycyBkdXJpbmcgdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XHJcbiAgbGV0IHdvcmtlckhhbmRsZTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW3Bvb2xdIFdvcmsgcmVjZWl2ZWQsIHN0YXJ0aW5nIHRvIHByb2Nlc3MuJyk7XHJcblxyXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcclxuICAgIGlmIChwb29sQ29uZmlnLmJlbmNobWFya2luZykge1xyXG4gICAgICBnZXRQb29sSW5mbygpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghcG9vbCkge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1dvcmsgcmVjZWl2ZWQsIGJ1dCBwb29sIGhhcyBub3QgYmVlbiBzdGFydGVkLicpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIEFjcXVpcmUgdGhlIHdvcmtlciBhbG9uZyB3aXRoIHRoZSBpZCBvZiByZXNvdXJjZSBhbmQgd29yayBjb3VudFxyXG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyaW5nIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcclxuXHJcbiAgICAgIC8vIENoZWNrIHRoZSBwYWdlIGFjcXVpcmUgdGltZVxyXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXHJcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArXHJcbiAgICAgICAgICBgRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBhY3F1aXJpbmcgYW4gYXZhaWxhYmxlIGVudHJ5OiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcclxuICAgIH1cclxuICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmVkIGEgd29ya2VyIGhhbmRsZS4nKTtcclxuXHJcbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnUmVzb2x2ZWQgd29ya2VyIHBhZ2UgaXMgaW52YWxpZDogdGhlIHBvb2wgc2V0dXAgaXMgd29ua3kuJ1xyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcclxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgLy8gUGVyZm9ybSBhbiBleHBvcnQgb24gYSBwdXBwZXRlZXIgbGV2ZWxcclxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XHJcblxyXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxyXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XHJcbiAgICAgIC8vIE5PVEU6IElmIHRoZXJlJ3MgYSByYXN0ZXJpemF0aW9uIHRpbWVvdXQsIHdlIHdhbnQgbmVlZCB0byBmbHVzaCB0aGUgcGFnZS5cclxuICAgICAgLy8gICAgICAgVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcclxuICAgICAgLy8gICAgICAgdGhlIHNjcmVlbnNob3QgdG8gZmluaXNoIGV2ZW4gdGhvdWdoIHRoZSB0aW1lb3V0IGhhcyBvY2N1cmVkLlxyXG4gICAgICAvLyAgICAgICBXaGljaCBvZiBjb3Vyc2UgY2F1c2VzIGEgbG90IG9mIGlzc3VlcyB3aXRoIHRoZSBldmVudCBzeXN0ZW0sXHJcbiAgICAgIC8vICAgICAgIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxyXG4gICAgICAvL1xyXG4gICAgICAvLyBOT1RFOiBPbmx5IHBhZ2Uuc2NyZWVuc2hvdCB3aWxsIHRocm93IHRoaXMsIHRpbWVvdXRzIGZvciBQREYncyBhcmVcclxuICAgICAgLy8gICAgICAgaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxyXG4gICAgICAvL1xyXG4gICAgICAvLyAgICAgICAuLi55ZXMsIHRoaXMgaXMgdWdseS5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBwb29sQ29uZmlnLndvcmtMaW1pdCArIDE7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBudWxsO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmVzdWx0Lm5hbWUgPT09ICdUaW1lb3V0RXJyb3InIHx8XHJcbiAgICAgICAgcmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnXHJcbiAgICAgICkge1xyXG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQ6IHlvdXIgY2hhcnQgbWF5IGJlIHRvbyBjb21wbGV4IG9yIGxhcmdlLCBhbmQgZmFpbGVkIHRvIHJlbmRlciB3aXRoaW4gdGhlIGFsbG90dGVkIHRpbWUuJ1xyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgICAgOiAnJykgKyBgRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGV4cG9ydDogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcclxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDUsXHJcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxyXG4gICAgICAgICAgOiAnW2JlbmNobWFya10nLFxyXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgcmVzb3VyY2UgYmFjayB0byB0aGUgcG9vbFxyXG4gICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcblxyXG4gICAgLy8gVXNlZCBmb3Igc3RhdGlzdGljcyBpbiBhdmVyYWdlVGltZSBhbmQgcHJvY2Vzc2VkV29ya0NvdW50LCB3aGljaFxyXG4gICAgLy8gaW4gdHVybiBpcyB1c2VkIGJ5IHRoZSAvaGVhbHRoIHJvdXRlLlxyXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG4gICAgY29uc3QgZXhwb3J0VGltZSA9IHdvcmtFbmQgLSB3b3JrU3RhcnQ7XHJcbiAgICBzdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcclxuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcclxuXHJcbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9IG1zLmApO1xyXG5cclxuICAgIC8vIE90aGVyd2lzZSByZXR1cm4gdGhlIHJlc3VsdFxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgcmVzdWx0LFxyXG4gICAgICBvcHRpb25zXHJcbiAgICB9O1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICArK3N0YXRzLmRyb3BwZWRFeHBvcnRzO1xyXG5cclxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XHJcbiAgICB9XHJcblxyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbcG9vbF0gSW4gcG9vbC5wb3N0V29yazogJHtlcnJvci5tZXNzYWdlfWApLnNldEVycm9yKFxyXG4gICAgICBlcnJvclxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8bnVsbH0gVGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZSBpZiBpbml0aWFsaXplZCwgb3IgbnVsbFxyXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sID0gKCkgPT4gcG9vbDtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgcG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdCwgaW5jbHVkaW5nIG1pbmltdW0gYW5kIG1heGltdW1cclxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBQb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XHJcbiAgbWluOiBwb29sLm1pbixcclxuICBtYXg6IHBvb2wubWF4LFxyXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcclxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxyXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxyXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcclxufSk7XHJcblxyXG4vKipcclxuICogTG9ncyBpbmZvcm1hdGlvbiBhYm91dCB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgcG9vbCwgaW5jbHVkaW5nIHRoZSBtaW5pbXVtXHJcbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxyXG4gKiByZXF1ZXN0cy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcclxuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XHJcblxyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCBjcmVhdGVkIHJlc291cmNlczogJHthbGx9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYXZhaWxhYmxlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgYWNxdWlyZWQ6ICR7cGVuZGluZ30uYCk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuICBwb3N0V29yayxcclxuICBnZXRQb29sLFxyXG4gIGdldFBvb2xJbmZvLFxyXG4gIGdldFBvb2xJbmZvSlNPTixcclxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCwgcG9zdFdvcmssIHN0YXRzIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgcm91bmROdW1iZXIsXHJcbiAgdG9Cb29sZWFuLFxyXG4gIHdyYXBBcm91bmRcclxufSBmcm9tICcuL3V0aWxzLmpzJztcclxuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcclxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcclxuXHJcbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcclxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXHJcbiAqIGNhbGxlZCB3aGVuIHRoZSBleHBvcnQgaXMgY29tcGxldGVkLCB3aXRoIGFuIGVycm9yIG9iamVjdCBhcyB0aGUgZmlyc3RcclxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gc2V0dGluZ3MgLSBUaGUgc2V0dGluZ3Mgb2JqZWN0IGNvbnRhaW5pbmcgZXhwb3J0XHJcbiAqIGNvbmZpZ3VyYXRpb24uXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxyXG4gKiBmaW5hbGl6aW5nIHdvcmsgb3IgdXBvbiBlcnJvciBvY2N1cmFuY2Ugb2YgdGhlIGV4cG9ydGluZyBwcm9jZXNzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcclxuICogaXQgY29tbXVuaWNhdGVzIHJlc3VsdHMgdmlhIHRoZSBlbmRDYWxsYmFjay5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcclxuICAvLyBTdGFydGluZyBleHBvcnRpbmcgcHJvY2VzcyBtZXNzYWdlXHJcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSW5pdGlhbGl6ZSBvcHRpb25zXHJcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcclxuXHJcbiAgLy8gR2V0IHRoZSBleHBvcnQgb3B0aW9uc1xyXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcclxuXHJcbiAgLy8gSWYgU1ZHIGlzIGFuIGlucHV0IChhcmd1bWVudCBjYW4gYmUgc2VudCBvbmx5IGJ5IHRoZSByZXF1ZXN0KVxyXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSBTVkcgaW5wdXQuJyk7XHJcblxyXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcclxuICAgICAgICBzYW5pdGl6ZShvcHRpb25zLnBheWxvYWQuc3ZnKSwgLy8gIzIwOVxyXG4gICAgICAgIG9wdGlvbnMsXHJcbiAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgKTtcclxuXHJcbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xyXG4gICAgICByZXR1cm4gcmVzdWx0O1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcignW2NoYXJ0XSBFcnJvciBsb2FkaW5nIFNWRyBpbnB1dC4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcclxuICBpZiAoZXhwb3J0T3B0aW9ucy5pbmZpbGUgJiYgZXhwb3J0T3B0aW9ucy5pbmZpbGUubGVuZ3RoKSB7XHJcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxyXG4gICAgdHJ5IHtcclxuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYW4gaW5wdXQgZmlsZS4nKTtcclxuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XHJcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cclxuICBpZiAoXHJcbiAgICAoZXhwb3J0T3B0aW9ucy5pbnN0ciAmJiBleHBvcnRPcHRpb25zLmluc3RyICE9PSAnJykgfHxcclxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcclxuICApIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xyXG5cclxuICAgICAgLy8gVXNlIHdoaWNoZXZlciBvbmUgaXMgYXZhaWxhYmxlXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgPSBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucztcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZygyLCBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxyXG4gIC8vIG9mIGNhbGxiYWNrLCByZXNvdXJjZXMsIGFuZCBjdXN0b20gY29kZS4gQWRkaXRpb25hbGx5LCB0aGUgd29ya2VyIHdpbGxcclxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxyXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXHJcbiAgaWYgKCFhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgJiYgY3VzdG9tTG9naWNPcHRpb25zKSB7XHJcbiAgICBpZiAoXHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXHJcbiAgICApIHtcclxuICAgICAgLy8gU2VuZCBiYWNrIGEgZnJpZW5kbHkgbWVzc2FnZSBzYXlpbmcgdGhhdCB0aGUgZXhwb3J0ZXIgZG9lcyBub3Qgc3VwcG9ydFxyXG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cclxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXHJcbiAgICAgICAgKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlc2V0IGFsbCBhZGRpdGlvbmFsIGN1c3RvbSBjb2RlXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBDbGVhbiBwcm9wZXJ0aWVzIHRvIGtlZXAgaXQgbGVhbiBhbmQgbWVhblxyXG4gIGlmIChjaGFydEpzb24pIHtcclxuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcclxuICAgIGNoYXJ0SnNvbi5leHBvcnRpbmcgPSBjaGFydEpzb24uZXhwb3J0aW5nIHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XHJcbiAgfVxyXG5cclxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XHJcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcclxuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXHJcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XHJcbiAgICB0cnkge1xyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xyXG4gICAgICAgIGlmIChcclxuICAgICAgICAgIHR5cGVvZiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9PT0gJ3N0cmluZycgJiZcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXHJcbiAgICAgICAgKSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSxcclxuICAgICAgICAgICAgdHJ1ZVxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0ge307XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxyXG4gIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUsXHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xyXG4gICAgICApO1xyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXHJcbiAgaWYgKFxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjaz8uaW5kZXhPZigneycpIDwgMFxyXG4gICkge1xyXG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXHJcbiAgICAvLyBpbmplY3RpbmcgYXJiaXRyYXJ5IGZpbGVzIGZyb20gdGhlIGZzXHJcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IHJlYWRGaWxlU3luYyhcclxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XHJcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2NhbGxiYWNrJyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFNpemUgc2VhcmNoXHJcbiAgb3B0aW9ucy5leHBvcnQgPSB7XHJcbiAgICAuLi5vcHRpb25zLmV4cG9ydCxcclxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcclxuICB9O1xyXG5cclxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXHJcbiAgdHJ5IHtcclxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHBvc3RXb3JrKFxyXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxyXG4gICAgICBvcHRpb25zXHJcbiAgICApO1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcclxuICogdG8gc3RyaW5naWZ5IHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCByZW1vdmVzIHVubmVjZXNzYXJ5IGNoYXJhY3RlcnMsXHJcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcclxuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxyXG4gKiBkb0V4cG9ydCBmdW5jdGlvbiB3aXRoIHRoZSB1cGRhdGVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcclxuICogYSBzZXJ2ZXIgKHNlZSB0aGUgIC0tYWxsb3dDb2RlRXhlY3V0aW9uIG9wdGlvbikuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XHJcbiAqIHRvIGJlIGluamVjdGVkLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXHJcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxyXG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxyXG4gKi9cclxuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICBsZXQgc3RySW5qO1xyXG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcclxuXHJcbiAgICBpZiAodHlwZW9mIGluc3RyICE9PSAnc3RyaW5nJykge1xyXG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcclxuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcclxuXHJcbiAgICAvLyBHZXQgcmlkIG9mIHRoZSA7XHJcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XHJcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXHJcbiAgICBvcHRpb25zLmV4cG9ydC5zdHJJbmogPSBzdHJJbmo7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4cG9ydHMgYSBzdHJpbmcgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIGludm9rZXMgYW4gZW5kIGNhbGxiYWNrLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMsIGluY2x1ZGluZyBjdXN0b21Mb2dpYyB3aXRoXHJcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxyXG4gKiBvZiB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcclxuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXHJcbiAgaWYgKFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPHN2ZycpID49IDAgfHxcclxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxyXG4gICkge1xyXG4gICAgbG9nKDQsICdbY2hhcnRdIFBhcnNpbmcgaW5wdXQgYXMgU1ZHLicpO1xyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xyXG4gIH1cclxuXHJcbiAgdHJ5IHtcclxuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxyXG4gICAgY29uc3QgY2hhcnRKU09OID0gSlNPTi5wYXJzZShzdHJpbmdUb0V4cG9ydC5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnICcpKTtcclxuXHJcbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxyXG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGNoYXJ0SlNPTiwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXHJcbiAgICBpZiAodG9Cb29sZWFuKGFsbG93Q29kZUV4ZWN1dGlvbikpIHtcclxuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gRG8gbm90IGFsbG93IHN0cmFpZ2h0IGluamVjdGlvbiB3aXRob3V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZ1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgJ1tjaGFydF0gT25seSBKU09OIGNvbmZpZ3VyYXRpb25zIGFuZCBTVkcgYXJlIGFsbG93ZWQgZm9yIHRoaXMgc2VydmVyLiBJZiB0aGlzIGlzIHlvdXIgc2VydmVyLCBKYXZhU2NyaXB0IGN1c3RvbSBjb2RlIGNhbiBiZSBlbmFibGVkIGJ5IHN0YXJ0aW5nIHRoZSBzZXJ2ZXIgd2l0aCB0aGUgLS1hbGxvd0NvZGVFeGVjdXRpb24gZmxhZy4nXHJcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxyXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XHJcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzdGFydEV4cG9ydCxcclxuICBmaW5kQ2hhcnRTaXplXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLyoqXHJcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXHJcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cclxuICoqL1xyXG5cclxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XHJcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcclxuXHJcbi8qKlxyXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxyXG4gKiBUaGlzIGZ1bmN0aW9uIHVzZXMgYSByZWd1bGFyIGV4cHJlc3Npb24gdG8gZmluZCBhbmQgcmVtb3ZlIGFsbFxyXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGlucHV0IFRoZSBIVE1MIHN0cmluZyB0byBiZSBzYW5pdGl6ZWQuXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXQpIHtcclxuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcclxuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcclxuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7XHJcbiAgICBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10sXHJcbiAgICAvLyBEaXNhbGxvdyBhbGwgeGxpbmtzIGluIGluY29taW5nIFNWR1xyXG4gICAgRk9SQklEX0FUVFI6IFsneGxpbms6aHJlZiddXHJcbiAgfSk7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbi8vIEFycmF5IHRoYXQgY29udGFpbnMgaWRzIG9mIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcclxuICBpbnRlcnZhbElkcy5wdXNoKGlkKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgY2xlYXJBbGxJbnRlcnZhbHMgPSAoKSA9PiB7XHJcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XHJcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xyXG4gICAgY2xlYXJJbnRlcnZhbChpZCk7XHJcbiAgfVxyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGFkZEludGVydmFsLFxyXG4gIGNsZWFyQWxsSW50ZXJ2YWxzXHJcbn07XHJcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBsb2dnaW5nIGVycm9ycyB3aXRoIHN0YWNrIHRyYWNlIGFuZCBoYW5kbGluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcclxuICBsb2dXaXRoU3RhY2soMSwgZXJyb3IpO1xyXG5cclxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcclxuICBpZiAoZW52cy5PVEhFUl9OT0RFX0VOViAhPT0gJ2RldmVsb3BtZW50Jykge1xyXG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXHJcbiAgbmV4dChlcnJvcik7XHJcbn07XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgcmV0dXJuaW5nIGVycm9yIHJlc3BvbnNlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKi9cclxuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xyXG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXHJcbiAgY29uc3QgeyBzdGF0dXNDb2RlOiBzdENvZGUsIHN0YXR1cywgbWVzc2FnZSwgc3RhY2sgfSA9IGVycm9yO1xyXG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDQwMDtcclxuXHJcbiAgLy8gU2V0IGFuZCByZXR1cm4gcmVzcG9uc2VcclxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxvZ0Vycm9yTWlkZGxld2FyZSk7XHJcblxyXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxyXG4gIGFwcC51c2UocmV0dXJuRXJyb3JNaWRkbGV3YXJlKTtcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIGVuYWJsaW5nIHJhdGUgbGltaXRpbmcgb24gdGhlIHNwZWNpZmllZCBFeHByZXNzIGFwcC5cclxuICpcclxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XHJcbiAgY29uc3QgbXNnID1cclxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcclxuXHJcbiAgLy8gT3B0aW9ucyBmb3IgdGhlIHJhdGUgbGltaXRlclxyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xyXG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcclxuICAgIHdpbmRvdzogbGltaXRDb25maWcud2luZG93IHx8IDEsXHJcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcclxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXHJcbiAgICBza2lwS2V5OiBsaW1pdENvbmZpZy5za2lwS2V5IHx8IGZhbHNlLFxyXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcclxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xyXG4gICAgYXBwLmVuYWJsZSgndHJ1c3QgcHJveHknKTtcclxuICB9XHJcblxyXG4gIC8vIENyZWF0ZSBhIGxpbWl0ZXJcclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcclxuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXHJcbiAgICAvLyBMaW1pdCBlYWNoIElQIHRvIDEwMCByZXF1ZXN0cyBwZXIgd2luZG93TXNcclxuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxyXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcclxuICAgIGRlbGF5TXM6IHJhdGVPcHRpb25zLmRlbGF5LFxyXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XHJcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XHJcbiAgICAgICAganNvbjogKCkgPT4ge1xyXG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcclxuICAgICAgICB9LFxyXG4gICAgICAgIGRlZmF1bHQ6ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcclxuICAgICAgICB9XHJcbiAgICAgIH0pO1xyXG4gICAgfSxcclxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XHJcbiAgICAgIC8vIEFsbG93IGJ5cGFzc2luZyB0aGUgbGltaXRlciBpZiBhIHZhbGlkIGtleS90b2tlbiBoYXMgYmVlbiBzZW50XHJcbiAgICAgIGlmIChcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxyXG4gICAgICAgIHJhdGVPcHRpb25zLnNraXBUb2tlbiAhPT0gZmFsc2UgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxyXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cclxuICAgICAgKSB7XHJcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xyXG4gICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBmYWxzZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKGxpbWl0ZXIpO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcclxuICApO1xyXG59O1xyXG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jbGFzcyBIdHRwRXJyb3IgZXh0ZW5kcyBFeHBvcnRFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XHJcbiAgICBzdXBlcihtZXNzYWdlKTtcclxuICAgIHRoaXMuc3RhdHVzID0gdGhpcy5zdGF0dXNDb2RlID0gc3RhdHVzO1xyXG4gIH1cclxuXHJcbiAgc2V0U3RhdHVzKHN0YXR1cykge1xyXG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEh0dHBFcnJvcjtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB1cGRhdGVWZXJzaW9uLCB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLyoqXHJcbiAqIEFkZHMgdGhlIFBPU1QgL2NoYW5nZV9oY192ZXJzaW9uLzpuZXdWZXJzaW9uIHJvdXRlIHRoYXQgY2FuIGJlIHV0aWxpemVkIHRvIG1vZGlmeVxyXG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIFRPRE86IEFkZCBhdXRoIHRva2VuIGFuZCBjb25uZWN0IHRvIEFQSVxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cclxuICAhYXBwXHJcbiAgICA/IGZhbHNlXHJcbiAgICA6IGFwcC5wb3N0KFxyXG4gICAgICAgICcvdmVyc2lvbi9jaGFuZ2UvOm5ld1ZlcnNpb24nLFxyXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xyXG4gICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgY29uc3QgYWRtaW5Ub2tlbiA9IGVudnMuSElHSENIQVJUU19BRE1JTl9UT0tFTjtcclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXHJcbiAgICAgICAgICAgIGlmICghYWRtaW5Ub2tlbiB8fCAhYWRtaW5Ub2tlbi5sZW5ndGgpIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXHJcbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcclxuICAgICAgICAgICAgaWYgKCF0b2tlbiB8fCB0b2tlbiAhPT0gYWRtaW5Ub2tlbikge1xyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxyXG4gICAgICAgICAgICAgICAgNDAxXHJcbiAgICAgICAgICAgICAgKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xyXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcclxuICAgICAgICAgICAgaWYgKG5ld1ZlcnNpb24pIHtcclxuICAgICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICAgICAgICAgICAgYXdhaXQgdXBkYXRlVmVyc2lvbihuZXdWZXJzaW9uKTtcclxuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICAgYFZlcnNpb24gY2hhbmdlOiAke2Vycm9yLm1lc3NhZ2V9YCxcclxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxyXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXHJcbiAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDIwMCkuc2VuZCh7XHJcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXHJcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiB2ZXJzaW9uKCksXHJcbiAgICAgICAgICAgICAgICBtZXNzYWdlOiBgU3VjY2Vzc2Z1bGx5IHVwZGF0ZWQgSGlnaGNoYXJ0cyB0byB2ZXJzaW9uOiAke25ld1ZlcnNpb259LmBcclxuICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAvLyBObyB2ZXJzaW9uIHNwZWNpZmllZFxyXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgKTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XHJcblxyXG5pbXBvcnQgeyBnZXRBbGxvd0NvZGVFeGVjdXRpb24sIHN0YXJ0RXhwb3J0IH0gZnJvbSAnLi4vLi4vY2hhcnQuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQge1xyXG4gIGZpeFR5cGUsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBpc09iamVjdEVtcHR5LFxyXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXHJcbiAgb3B0aW9uc1N0cmluZ2lmeSxcclxuICBtZWFzdXJlVGltZVxyXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XHJcblxyXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXHJcbmNvbnN0IHJldmVyc2VkTWltZSA9IHtcclxuICBwbmc6ICdpbWFnZS9wbmcnLFxyXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcclxuICBnaWY6ICdpbWFnZS9naWYnLFxyXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXHJcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcclxufTtcclxuXHJcbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXHJcbmxldCByZXF1ZXN0c0NvdW50ZXIgPSAwO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcclxuY29uc3QgYmVmb3JlUmVxdWVzdCA9IFtdO1xyXG5cclxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxyXG5jb25zdCBhZnRlclJlcXVlc3QgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBJbnZva2VzIGFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9ucyB3aXRoIHNwZWNpZmllZCBwYXJhbWV0ZXJzLCBhbGxvd2luZ1xyXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb25bXX0gY2FsbGJhY2tzIC0gQW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zXHJcbiAqIHRvIGJlIGV4ZWN1dGVkLlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXHJcbiAqIHR5cGUsIGFuZCBib2R5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxyXG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXHJcbiAqL1xyXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XHJcbiAgbGV0IHJlc3VsdCA9IHRydWU7XHJcbiAgY29uc3QgeyBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkgfSA9IGRhdGE7XHJcblxyXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xyXG4gICAgaWYgKGNhbGxiYWNrKSB7XHJcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcclxuXHJcbiAgICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHVuZGVmaW5lZCAmJiBjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICByZXR1cm4gcmVzdWx0O1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgdGhlIGV4cG9ydCByZXF1ZXN0cyBmcm9tIHRoZSBjbGllbnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZS5cclxuICovXHJcbmNvbnN0IGV4cG9ydEhhbmRsZXIgPSBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxyXG4gICAgY29uc3Qgc3RvcENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xyXG5cclxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XHJcbiAgICBjb25zdCB1bmlxdWVJZCA9IHV1aWQoKS5yZXBsYWNlKC8tL2csICcnKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXHJcbiAgICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xyXG4gICAgY29uc3QgaWQgPSArK3JlcXVlc3RzQ291bnRlcjtcclxuXHJcbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxyXG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBbGwgb2YgdGhlIGJlbG93IGNhbiBiZSB1c2VkXHJcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xyXG5cclxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBKU09OIG9yIFNWRyB0byBleHBvcnRcclxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcclxuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcclxuICAgICAgICB9IHdhcyBpbmNvcnJlY3Q6XHJcbiAgQ29udGVudC1UeXBlOiAke3JlcXVlc3QuaGVhZGVyc1snY29udGVudC10eXBlJ119LiBcclxuICBDaGFydCBjb25zdHJ1Y3RvcjogJHtib2R5LmNvbnN0cn0uXHJcbiAgRGltZW5zaW9uczogJHtib2R5LndpZHRofXgke2JvZHkuaGVpZ2h0fSBAICR7Ym9keS5zY2FsZX0gc2NhbGUuXHJcbiAgVHlwZTogJHt0eXBlfS5cclxuICBJcyBTVkcgc2V0PyAke3R5cGVvZiBib2R5LnN2ZyAhPT0gJ3VuZGVmaW5lZCd9LlxyXG4gIEI2ND8gJHt0eXBlb2YgYm9keS5iNjQgIT09ICd1bmRlZmluZWQnfS5cclxuICBObyBkb3dubG9hZD8gJHt0eXBlb2YgYm9keS5ub0Rvd25sb2FkICE9PSAndW5kZWZpbmVkJ30uXHJcblxyXG4gIFBheWxvYWQgcmVjZWl2ZWQ6ICR7SlNPTi5zdHJpbmdpZnkoYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSB8fCBib2R5LnN2Zyl9XHJcblxyXG4gIGBcclxuICAgICAgKTtcclxuXHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjYWxsUmVzcG9uc2UgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcclxuICAgIGNhbGxSZXNwb25zZSA9IGRvQ2FsbGJhY2tzKGJlZm9yZVJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7XHJcbiAgICAgIGlkLFxyXG4gICAgICB1bmlxdWVJZCxcclxuICAgICAgdHlwZSxcclxuICAgICAgYm9keVxyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxyXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xyXG4gICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChjYWxsUmVzcG9uc2UpO1xyXG4gICAgfVxyXG5cclxuICAgIGxldCBjb25uZWN0aW9uQWJvcnRlZCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcclxuICAgIHJlcXVlc3Quc29ja2V0Lm9uKCdjbG9zZScsIChoYWRFcnJvcnMpID0+IHtcclxuICAgICAgaWYgKGhhZEVycm9ycykge1xyXG4gICAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XHJcblxyXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcclxuXHJcbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxyXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XHJcbiAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHR5cGUsXHJcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxyXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXHJcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXHJcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxyXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcclxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXHJcbiAgICAgIH0sXHJcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XHJcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcclxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxyXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXHJcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXHJcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgaWYgKGluc3RyKSB7XHJcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xyXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxyXG4gICAgICAgIGluc3RyLFxyXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcclxuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xyXG5cclxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXHJcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XHJcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXHJcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXHJcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcclxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxyXG4gICAgfTtcclxuXHJcbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXHJcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXHJcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcclxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xyXG5cclxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXHJcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgNSxcclxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xyXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcclxuICAgICAgICByZXR1cm4gbG9nKFxyXG4gICAgICAgICAgMyxcclxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcclxuICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcclxuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxyXG4gICAgICAgICAgNDAwXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xyXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xyXG5cclxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXHJcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xyXG5cclxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxyXG4gICAgICAgIGlmIChib2R5LmI2NCkge1xyXG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cclxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XHJcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxyXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG5cclxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxyXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcclxuXHJcbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcclxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xyXG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcclxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XHJcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xyXG4gICAgICAgICAgICB9YFxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcclxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcclxuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcclxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcclxuICAgICAgfVxyXG4gICAgfSk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIG5leHQoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xyXG5cclxuICAvKipcclxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXHJcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxyXG4gICAqL1xyXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xyXG5cclxuaW1wb3J0IHsgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xyXG5cclxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xyXG5cclxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcclxuXHJcbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xyXG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxyXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcclxuXHJcbi8qKlxyXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcclxuICogYXJyYXkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXHJcbiAqL1xyXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xyXG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcclxuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxufVxyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXHJcbiAqIGFuZCBnYXRoZXJzXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cclxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XHJcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcclxuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XHJcbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXHJcbiAgICAgICAgPyAxXHJcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcclxuXHJcbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xyXG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XHJcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xyXG4gICAgfVxyXG4gIH0sIHJlY29yZEludGVydmFsKTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcclxuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxyXG4gKi9cclxuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xyXG4gIGlmICghYXBwKSB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG5cclxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XHJcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cclxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xyXG5cclxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xyXG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcclxuXHJcbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XHJcblxyXG4gICAgcmVzLnNlbmQoe1xyXG4gICAgICBzdGF0dXM6ICdPSycsXHJcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXHJcbiAgICAgIHVwdGltZTpcclxuICAgICAgICBNYXRoLmZsb29yKFxyXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcclxuICAgICAgICApICsgJyBtaW51dGVzJyxcclxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxyXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogdmVyc2lvbigpLFxyXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcclxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcclxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXHJcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcclxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxyXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXHJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXHJcblxyXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxyXG4gICAgICBwZXJpb2QsXHJcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcclxuICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xyXG4gICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gR2V0dGluZyBhIGxvdCBvZiBSYW5nZU5vdFNhdGlzZmlhYmxlRXJyb3IgZXhjZXB0aW9uLlxyXG4vLyBFdmVuIHRob3VnaCB0aGlzIGlzIGEgZGVwcmVjYXRlZCBvcHRpb25zLCBsZXQncyB0cnkgdG8gc2V0IGl0IHRvIGZhbHNlLlxyXG5hcHAudXNlKChfcmVxLCByZXMsIG5leHQpID0+IHtcclxuICByZXMuc2V0KCdBY2NlcHQtUmFuZ2VzJywgJ25vbmUnKTtcclxuICBuZXh0KCk7XHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXHJcbiAqL1xyXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xyXG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IsIHNvY2tldCkgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAxLFxyXG4gICAgICBlcnJvcixcclxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxyXG4gICAgKTtcclxuICAgIHNvY2tldC5kZXN0cm95KCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBUT0RPOiBSZWFkIGZyb20gY29uZmlnL2VudlxyXG4gICAgLy8gTk9URTpcclxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW4gdGhlXHJcbiAgICAvLyByYXN0ZXJpemF0aW9uIHRpbWVvdXQgaXMgc2V0IHRvbyBsb3cuXHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdE1pQiA9IHNlcnZlckNvbmZpZy5tYXhVcGxvYWRTaXplIHx8IDM7XHJcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gdXBsb2FkTGltaXRNaUIgKiAxMDI0ICogMTAyNDtcclxuXHJcbiAgICAvLyBFbmFibGUgcGFyc2luZyBvZiBmb3JtIGRhdGEgKGZpbGVzKSB3aXRoIE11bHRlciBwYWNrYWdlXHJcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuICAgIGNvbnN0IHVwbG9hZCA9IG11bHRlcih7XHJcbiAgICAgIHN0b3JhZ2UsXHJcbiAgICAgIGxpbWl0czoge1xyXG4gICAgICAgIGZpZWxkU2l6ZTogdXBsb2FkTGltaXRCeXRlc1xyXG4gICAgICB9XHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBFbmFibGUgYm9keSBwYXJzZXJcclxuICAgIGFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXMgfSkpO1xyXG4gICAgYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXMgfSkpO1xyXG5cclxuICAgIC8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xyXG4gICAgYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcclxuXHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChfcmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcclxuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJyksIHtcclxuICAgICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcclxuICAgICAgICB9KTtcclxuICAgICAgfSk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgY2xlYXJBbGxJbnRlcnZhbHMgfSBmcm9tICcuL2ludGVydmFscy5qcyc7XHJcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgY2xvc2VTZXJ2ZXJzIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBDbGVhbiB1cCBmdW5jdGlvbiB0byB0cmlnZ2VyIGJlZm9yZSBlbmRpbmcgcHJvY2VzcyBmb3IgdGhlIGdyYWNlZnVsIHNodXRkb3duLlxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBwcm9jZXNzLmV4aXQoKSBmdW5jdGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzaHV0ZG93bkNsZWFuVXAgPSBhc3luYyAoZXhpdENvZGUpID0+IHtcclxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcclxuICBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoW1xyXG4gICAgLy8gQ2xlYXIgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXHJcbiAgICBjbGVhckFsbEludGVydmFscygpLFxyXG5cclxuICAgIC8vIEdldCBhdmFpbGFibGUgc2VydmVyIGluc3RhbmNlcyAoSFRUUC9IVFRQUykgYW5kIGNsb3NlIHRoZW1cclxuICAgIGNsb3NlU2VydmVycygpLFxyXG5cclxuICAgIC8vIENsb3NlIHBvb2wgYWxvbmcgd2l0aCBpdHMgd29ya2VycyBhbmQgdGhlIGJyb3dzZXIgaW5zdGFuY2UsIGlmIGV4aXN0c1xyXG4gICAga2lsbFBvb2woKVxyXG4gIF0pO1xyXG5cclxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxyXG4gIHByb2Nlc3MuZXhpdChleGl0Q29kZSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc2h1dGRvd25DbGVhblVwXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0ICdjb2xvcnMnO1xyXG5cclxuaW1wb3J0IHsgY2hlY2tBbmRVcGRhdGVDYWNoZSB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnRcclxufSBmcm9tICcuL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcclxuaW1wb3J0IHtcclxuICBpbml0TG9nZ2luZyxcclxuICBsb2csXHJcbiAgbG9nV2l0aFN0YWNrLFxyXG4gIHNldExvZ0xldmVsLFxyXG4gIGVuYWJsZUZpbGVMb2dnaW5nXHJcbn0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBpbml0UG9vbCwga2lsbFBvb2wgfSBmcm9tICcuL3Bvb2wuanMnO1xyXG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xyXG5pbXBvcnQgc2VydmVyLCB7IHN0YXJ0U2VydmVyIH0gZnJvbSAnLi9zZXJ2ZXIvc2VydmVyLmpzJztcclxuaW1wb3J0IHsgcHJpbnRMb2dvLCBwcmludFVzYWdlIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG4vKipcclxuICogQXR0YWNoZXMgZXhpdCBsaXN0ZW5lcnMgdG8gdGhlIHByb2Nlc3MsIGVuc3VyaW5nIHByb3BlciBjbGVhbnVwIG9mIHJlc291cmNlc1xyXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXHJcbiAqICd1bmNhdWdodEV4Y2VwdGlvbicgZXZlbnRzLlxyXG4gKi9cclxuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XHJcbiAgbG9nKDMsICdbcHJvY2Vzc10gQXR0YWNoaW5nIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLicpO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXHJcbiAgcHJvY2Vzcy5vbignZXhpdCcsIChjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFByb2Nlc3MgZXhpdGVkIHdpdGggY29kZSAke2NvZGV9LmApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0lOVCdcclxuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHVEVSTSdcclxuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR0hVUCdcclxuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBUaGUgJHtuYW1lfSBldmVudCB3aXRoIGNvZGU6ICR7Y29kZX0uYCk7XHJcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAndW5jYXVnaHRFeGNlcHRpb24nXHJcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFRoZSAke25hbWV9IGVycm9yLmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDEpO1xyXG4gIH0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcHJvY2Vzcy4gVGFza3Mgc3VjaCBhcyBjb25maWd1cmluZyBsb2dnaW5nLCBjaGVja2luZ1xyXG4gKiBjYWNoZSBhbmQgc291cmNlcywgYW5kIGluaXRpYWxpemluZyB0aGUgcG9vbCBvZiByZXNvdXJjZXMgaGFwcGVuIGR1cmluZ1xyXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgZXhwb3J0IG9wdGlvbnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkIGV4cG9ydCBvcHRpb25zLlxyXG4gKi9cclxuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgLy8gU2V0IHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gcGVyIGV4cG9ydCBtb2R1bGUgc2NvcGVcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24oXHJcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgKTtcclxuXHJcbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xyXG4gIGluaXRMb2dnaW5nKG9wdGlvbnMubG9nZ2luZyk7XHJcblxyXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xyXG4gIGlmIChvcHRpb25zLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzKSB7XHJcbiAgICBhdHRhY2hQcm9jZXNzRXhpdExpc3RlbmVycygpO1xyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgY2FjaGUgbmVlZHMgdG8gYmUgdXBkYXRlZFxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcblxyXG4gIC8vIEluaXQgdGhlIHBvb2xcclxuICBhd2FpdCBpbml0UG9vbCh7XHJcbiAgICBwb29sOiBvcHRpb25zLnBvb2wgfHwge1xyXG4gICAgICBtaW5Xb3JrZXJzOiAxLFxyXG4gICAgICBtYXhXb3JrZXJzOiAxXHJcbiAgICB9LFxyXG4gICAgcHVwcGV0ZWVyQXJnczogb3B0aW9ucy5wdXBwZXRlZXIuYXJncyB8fCBbXVxyXG4gIH0pO1xyXG5cclxuICAvLyBSZXR1cm4gdXBkYXRlZCBvcHRpb25zXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgLy8gU2VydmVyXHJcbiAgc2VydmVyLFxyXG4gIHN0YXJ0U2VydmVyLFxyXG5cclxuICAvLyBFeHBvcnRpbmdcclxuICBpbml0RXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBiYXRjaEV4cG9ydCxcclxuICBzdGFydEV4cG9ydCxcclxuXHJcbiAgLy8gUG9vbFxyXG4gIGluaXRQb29sLFxyXG4gIGtpbGxQb29sLFxyXG5cclxuICAvLyBPdGhlclxyXG4gIHNldE9wdGlvbnMsXHJcbiAgc2h1dGRvd25DbGVhblVwLFxyXG5cclxuICAvLyBMb2dzXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZyxcclxuXHJcbiAgLy8gVXRpbHNcclxuICBtYXBUb05ld0NvbmZpZyxcclxuICBtYW51YWxDb25maWcsXHJcbiAgcHJpbnRMb2dvLFxyXG4gIHByaW50VXNhZ2VcclxufTtcclxuIl0sIm5hbWVzIjpbInNjcmlwdHNOYW1lcyIsImNvcmUiLCJtb2R1bGVzIiwiaW5kaWNhdG9ycyIsImN1c3RvbSIsImRlZmF1bHRDb25maWciLCJwdXBwZXRlZXIiLCJhcmdzIiwidmFsdWUiLCJ0eXBlIiwiZGVzY3JpcHRpb24iLCJ0ZW1wRGlyIiwiZW52TGluayIsImhpZ2hjaGFydHMiLCJ2ZXJzaW9uIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwibWF4VXBsb2FkU2l6ZSIsImVuYWJsZSIsImNsaU5hbWUiLCJob3N0IiwicG9ydCIsImJlbmNobWFya2luZyIsInByb3h5IiwidXNlcm5hbWUiLCJwYXNzd29yZCIsInRpbWVvdXQiLCJyYXRlTGltaXRpbmciLCJtYXhSZXF1ZXN0cyIsIndpbmRvdyIsImRlbGF5IiwidHJ1c3RQcm94eSIsInNraXBLZXkiLCJza2lwVG9rZW4iLCJzc2wiLCJmb3JjZSIsImNlcnRQYXRoIiwicG9vbCIsIm1pbldvcmtlcnMiLCJtYXhXb3JrZXJzIiwid29ya0xpbWl0IiwiYWNxdWlyZVRpbWVvdXQiLCJjcmVhdGVUaW1lb3V0IiwiZGVzdHJveVRpbWVvdXQiLCJpZGxlVGltZW91dCIsImNyZWF0ZVJldHJ5SW50ZXJ2YWwiLCJyZWFwZXJJbnRlcnZhbCIsImxvZ2dpbmciLCJsZXZlbCIsImZpbGUiLCJkZXN0IiwidG9Db25zb2xlIiwidG9GaWxlIiwidWkiLCJyb3V0ZSIsIm90aGVyIiwibm9kZUVudiIsImxpc3RlblRvUHJvY2Vzc0V4aXRzIiwibm9Mb2dvIiwiaGFyZFJlc2V0UGFnZSIsImJyb3dzZXJTaGVsbE1vZGUiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwidGVzdCIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJQVVBQRVRFRVJfVEVNUF9ESVIiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9NQVhfVVBMT0FEX1NJWkUiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9VU0VSTkFNRSIsIlNFUlZFUl9QUk9YWV9QQVNTV09SRCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInRhZ05hbWUiLCJ0b1VwcGVyQ2FzZSIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwib3B0aW9uIiwiZW50cmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJoZWFkZXJzIiwiUmVmZXJlciIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsImlzQ2xvc2VkIiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJ0b3RhbFNpemUiLCJCdWZmZXIiLCJieXRlTGVuZ3RoIiwidG9GaXhlZCIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsInB1cHBldGVlck9wdGlvbnMiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiY3JlYXRlQnJvd3NlciIsInBhcnNlSW50IiwiUG9vbCIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJyIiwiaGFyZFJlc2V0IiwiZ290byIsImNsZWFyUGFnZSIsImV2ZW50SWQiLCJpbml0aWFsUmVzb3VyY2VzIiwiYWNxdWlyZSIsInByb21pc2UiLCJyZWxlYXNlIiwia2lsbFBvb2wiLCJ3b3JrZXIiLCJ1c2VkIiwiZGVzdHJveWVkIiwiY29ubmVjdGVkIiwiY2xvc2VCcm93c2VyIiwicG9zdFdvcmsiLCJnZXRQb29sSW5mbyIsImFjcXVpcmVDb3VudGVyIiwicGF5bG9hZCIsInJlcXVlc3RJZCIsIndvcmtTdGFydCIsImV4cG9ydENvdW50ZXIiLCJyZXN1bHQiLCJleHBvcnRUaW1lIiwiZ2V0UG9vbEluZm9KU09OIiwibnVtRnJlZSIsIm51bVVzZWQiLCJhdmFpbGFibGUiLCJwZW5kaW5nIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicG9vbCQxIiwic3RhcnRFeHBvcnQiLCJzZXR0aW5ncyIsImVuZENhbGxiYWNrIiwic3ZnIiwiaW5pdEV4cG9ydFNldHRpbmdzIiwiZXhwb3J0QXNTdHJpbmciLCJpbnB1dCIsIkpTRE9NIiwiRE9NUHVyaWZ5Iiwic2FuaXRpemUiLCJBRERfVEFHUyIsIkZPUkJJRF9BVFRSIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInZTd2l0Y2hSb3V0ZSIsInBvc3QiLCJhZG1pblRva2VuIiwidG9rZW4iLCJuZXdWZXJzaW9uIiwicGFyYW1zIiwidXBkYXRlVmVyc2lvbiIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiYjY0Iiwibm9Eb3dubG9hZCIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwiaGFkRXJyb3JzIiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInN2Z0V4cG9ydEF0dGVtcHRzIiwianNvbkV4cG9ydEF0dGVtcHRzIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJkaXNhYmxlIiwiY29ycyIsIl9yZXEiLCJzZXQiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJ1cGxvYWRMaW1pdEJ5dGVzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsImV4cG9ydFJvdXRlcyIsIl9yZXF1ZXN0Iiwic2VuZEZpbGUiLCJhY2NlcHRSYW5nZXMiLCJ1aVJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImVuYWJsZVJhdGVMaW1pdGluZyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiYWxsU2V0dGxlZCIsImV4aXQiLCJpbmRleCIsImluaXRFeHBvcnQiLCJsb2dnaW5nT3B0aW9ucyIsImluaXRMb2dnaW5nIiwiY29kZSIsInNpbmdsZUV4cG9ydCIsImJhdGNoRXhwb3J0IiwiYmF0Y2hGdW5jdGlvbnMiLCJwYWlyIiwiY29uZmlnSW5kZXgiLCJmaW5kSW5kZXgiLCJhcmciLCJmaWxlTmFtZSIsImxvYWRDb25maWdGaWxlIiwic2hvd1VzYWdlIiwicHJvcGVydGllc0NoYWluIiwiYXJndW1lbnRUeXBlIiwicGFpckFyZ3VtZW50VmFsdWUiLCJtYXBUb05ld0NvbmZpZyIsIm9sZE9wdGlvbnMiLCJtYW51YWxDb25maWciLCJjb25maWdGaWxlTmFtZSIsImNvbmZpZ0ZpbGUiLCJjaG9pY2UiLCJwcm9tcHRzIiwib25TdWJtaXQiLCJwIiwiY2F0ZWdvcmllcyIsInF1ZXN0aW9uc0NvdW50ZXIiLCJhbGxRdWVzdGlvbnMiLCJzZWN0aW9uIiwicHJvbXB0IiwiYW5zd2VyIiwibW9kdWxlIiwicHJvbWlzZXMiLCJ3cml0ZUZpbGUiLCJwcmludExvZ28iLCJwYWNrYWdlVmVyc2lvbiJdLCJtYXBwaW5ncyI6IitjQWVPLE1BQU1BLEVBQWUsQ0FDMUJDLEtBQU0sQ0FBQyxhQUFjLGtCQUFtQixpQkFDeENDLFFBQVMsQ0FDUCxRQUNBLE1BQ0EsUUFDQSxZQUNBLHVCQUNBLGdCQUVBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNBLFVBQ0EsVUFDQSxjQUNBLFdBQ0EsVUFDQSxZQUNBLGNBQ0EsWUFDQSxzQkFDQSxTQUNBLFNBQ0EsV0FDQSxhQUNBLFlBQ0EsZUFDQSx5QkFDQSxTQUNBLGVBQ0EsWUFDQSxrQkFDQSxTQUNBLGNBQ0EsbUJBQ0EsZUFDQSxrQkFDQSxjQUNBLGVBRUEsY0FDQSxXQUNBLGVBQ0EsV0FDQSxTQUNBLE9BQ0EsV0FDQSxZQUNBLFNBQ0EscUJBQ0EsYUFDQSxXQUNBLFdBQ0EsV0FDQSxXQUNBLGVBQ0EsVUFDQSxrQkFDQSxvQkFDQSxhQUNBLFVBQ0EsY0FDQSxZQUNBLFlBRUZDLFdBQVksQ0FBQyxrQkFDYkMsT0FBUSxDQUNOLHdFQUNBLG1HQU1TQyxFQUFnQixDQUMzQkMsVUFBVyxDQUNUQyxLQUFNLENBQ0pDLE1BQU8sQ0FDTCxtQ0FDQSxrQkFDQSwwQ0FDQSwyQkFDQSxrQ0FDQSxrQ0FDQSx3Q0FDQSwyQ0FDQSxxQkFDQSw0QkFDQSwyQ0FDQSx1REFDQSw2QkFDQSx5QkFDQSwwQkFDQSwrQkFDQSx1QkFDQSx1RkFDQSx5QkFDQSxvQ0FDQSxvQkFDQSwwQkFDQSw4Q0FDQSwyQkFDQSwwQkFDQSw2QkFDQSxtQ0FDQSx3Q0FDQSxtQ0FDQSwyQkFDQSxrQ0FDQSx1QkFDQSxpQkFDQSx5QkFDQSw4QkFDQSxvQkFDQSwyQkFDQSxlQUNBLDZCQUNBLGlCQUNBLGFBQ0EsZUFDQSxzQkFDQSxjQUNBLHlCQUNBLG9CQUNBLHVCQUVGQyxLQUFNLFdBQ05DLFlBQWEs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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"),s=require("zod"),n=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","--pipe","--no-startup-window","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."},tempDir:{value:"./tmp/",type:"string",envLink:"PUPPETEER_TEMP_DIR",description:"The directory for Puppeteer to store temporary files."}},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",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in MB, 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."},username:{value:!1,type:"string",envLink:"SERVER_PROXY_USERNAME",cliName:"proxyUsername",description:"The username for the proxy server, if it exists."},password:{value:!1,type:"string",envLink:"SERVER_PROXY_PASSWORD",cliName:"proxyPassword",description:"The password for the proxy server, 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=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),_=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),L=()=>s.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=()=>s.z.string().trim().refine((e=>/^(\.\/|\.\.\/|\/|[a-zA-Z]:\\|[a-zA-Z]:\/)?((?:[\w-]+)[\\/]?)+$/.test(e)),{},{message:"The string is an invalid path directory string."}),I=()=>s.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)),C=()=>s.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)),N=s.z.object({PUPPETEER_TEMP_DIR:k(),HIGHCHARTS_VERSION:s.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:s.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:_(),HIGHCHARTS_CACHE_PATH:L(),HIGHCHARTS_ADMIN_TOKEN:L(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:I(),EXPORT_DEFAULT_WIDTH:I(),EXPORT_DEFAULT_SCALE:I(),EXPORT_RASTERIZATION_TIMEOUT:C(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:_(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:_(),SERVER_ENABLE:_(),SERVER_HOST:L(),SERVER_PORT:I(),SERVER_MAX_UPLOAD_SIZE:I(),SERVER_BENCHMARKING:_(),SERVER_PROXY_HOST:L(),SERVER_PROXY_PORT:I(),SERVER_PROXY_USERNAME:L(),SERVER_PROXY_PASSWORD:L(),SERVER_PROXY_TIMEOUT:C(),SERVER_RATE_LIMITING_ENABLE:_(),SERVER_RATE_LIMITING_MAX_REQUESTS:C(),SERVER_RATE_LIMITING_WINDOW:C(),SERVER_RATE_LIMITING_DELAY:C(),SERVER_RATE_LIMITING_TRUST_PROXY:_(),SERVER_RATE_LIMITING_SKIP_KEY:L(),SERVER_RATE_LIMITING_SKIP_TOKEN:L(),SERVER_SSL_ENABLE:_(),SERVER_SSL_FORCE:_(),SERVER_SSL_PORT:I(),SERVER_SSL_CERT_PATH:L(),POOL_MIN_WORKERS:C(),POOL_MAX_WORKERS:C(),POOL_WORK_LIMIT:I(),POOL_ACQUIRE_TIMEOUT:C(),POOL_CREATE_TIMEOUT:C(),POOL_DESTROY_TIMEOUT:C(),POOL_IDLE_TIMEOUT:C(),POOL_CREATE_RETRY_INTERVAL:C(),POOL_REAPER_INTERVAL:C(),POOL_BENCHMARKING:_(),LOGGING_LEVEL:s.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:L(),LOGGING_DEST:L(),LOGGING_TO_CONSOLE:_(),LOGGING_TO_FILE:_(),UI_ENABLE:_(),UI_ROUTE:L(),OTHER_NODE_ENV:O(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:_(),OTHER_NO_LOGO:_(),OTHER_HARD_RESET_PAGE:_(),OTHER_BROWSER_SHELL_MODE:_(),OTHER_ALLOW_XLINK:_(),DEBUG_ENABLE:_(),DEBUG_HEADLESS:_(),DEBUG_DEVTOOLS:_(),DEBUG_LISTEN_TO_CONSOLE:_(),DEBUG_DUMPIO:_(),DEBUG_SLOW_MO:C(),DEBUG_DEBUGGING_PORT:I()}).partial().parse(process.env),A=["red","yellow","blue","gray","green"];let P={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:A[0]},{title:"warning",color:A[1]},{title:"notice",color:A[2]},{title:"verbose",color:A[3]},{title:"benchmark",color:A[4]}],listeners:[]};const H=(t,r)=>{P.pathCreated||(!e.existsSync(P.dest)&&e.mkdirSync(P.dest),P.pathCreated=!0),e.appendFile(`${P.dest}${P.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),P.toFile=!1)}))},$=(...e)=>{const[t,...r]=e,{levelsDesc:o,level:i}=P;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;P.listeners.forEach((e=>{e(s,r.join(" "))})),P.toConsole&&console.log.apply(void 0,[s.toString()[P.levelsDesc[t-1].color]].concat(r)),P.toFile&&H(r,s)},D=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=P;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=[o,"\n",a];P.toConsole&&console.log.apply(void 0,[n.toString()[P.levelsDesc[e-1].color]].concat([o[A[e-1]],"\n",a])),P.listeners.forEach((e=>{e(n,l.join(" "))})),P.toFile&&H(l,n)},U=e=>{e>=0&&e<=P.levelsDesc.length&&(P.level=e)},G=(e,t)=>{if(P={...P,dest:e||P.dest,file:t||P.file,toFile:!0},0===P.dest.length)return $(1,"[logger] File logging initialization: no path supplied.");P.dest.endsWith("/")||(P.dest+="/")},F=n.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)),j=(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"},M=(t=!1,r)=>{const o=["js","css","files"];let i=t,s=!1;if(r&&t.endsWith(".json"))try{i=V(e.readFileSync(t,"utf8"))}catch(e){return D(2,e,"[cli] No resources found.")}else i=V(t),i&&!r&&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):$(3,"[cli] No resources found.")};function V(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 W=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]=W(e[r]));return t},q=(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 B(){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 X=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(/;$/,"")},K=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let J={};const Y=()=>J,Z=(e,t,r=[])=>{const o=W(e);for(const[e,s]of Object.entries(t))o[e]="object"!=typeof(i=s)||Array.isArray(i)||null===i||r.includes(e)||void 0===o[e]?void 0!==s?s:o[e]:Z(o[e],s,r);var i;return o};function Q(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?Q(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in N&&void 0!==N[i.envLink]&&(i.value=N[i.envLink]))}))}function ee(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:ee(o);return t}function te(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=te(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function re(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 oe 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 ie={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},se=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)),$(4,`[cache] Fetching script - ${e}.js`);const i=await re(`${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 oe(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return $(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ae=async(t,o,i)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ie.cdnURL;$(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ie.sources=await(async(e,t,o,i,s)=>{let n;const{host:a,port:l,username:c,password:p}=i;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l,...c&&p?{username:c,password:p}:{}})}catch(e){throw new oe("[cache] Could not create a Proxy Agent.").setError(e)}const h=n?{agent:n,timeout:N.SERVER_PROXY_TIMEOUT}:{},u=[...e.map((e=>ne(`${e}`,h,s,!0))),...t.map((e=>ne(`${e}`,h,s))),...o.map((e=>ne(`${e}`,h)))];return(await Promise.all(u)).join(";\n")})([...t.coreScripts.map((e=>`${a}${n}${e}`))],[...t.moduleScripts.map((e=>"map"===e?`${a}maps/${n}modules/${e}`:`${a}${n}modules/${e}`)),...t.indicatorScripts.map((e=>`${a}stock/${n}indicators/${e}`))],t.customScripts,o,l),ie.hcVersion=se(ie),e.writeFileSync(i,ie.sources),l}catch(e){throw new oe("[cache] Unable to update the local Highcharts cache.").setError(e)}},le=async r=>{const{highcharts:o,server:i}=r,s=t.join(F,o.cachePath);let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s),!e.existsSync(a)||o.forceFetch)$(3,"[cache] Fetching and caching Highcharts dependencies."),n=await ae(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:s,moduleScripts:c,indicatorScripts:p}=o,h=s.length+c.length+p.length;r.version!==o.version?($(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==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 $(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await ae(o,i.proxy,l):($(3,"[cache] Dependency cache is up to date, proceeding."),ie.sources=e.readFileSync(l,"utf8"),n=r.modules,ie.hcVersion=se(ie))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};ie.activeManifest=i,$(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new oe("[cache] Error writing the cache manifest.").setError(e)}})(o,n)},ce=()=>t.join(F,Y().highcharts.cachePath),pe=()=>ie.hcVersion;function he(){Highcharts.animObject=function(){return{duration:0}}}async function ue(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=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,n(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])})),n(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&&s(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];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const de=e.readFileSync(F+"/templates/template.html","utf8");let ge;async function me(){if(!ge)return!1;const e=await ge.newPage();return await e.setCacheEnabled(!1),await ve(e),function(e){const{debug:t}=Y();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 fe(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){D(2,e,"[browser] Could not clear page's resources.")}}async function ve(e){await e.setContent(de,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ce()}/sources.js`}),await e.evaluate(he)}const ye=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($(4,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new oe("[export] The data passed to a page exceeded 100MB.");return e.evaluate(ue,t,r,o)};var be=async(r,o,i)=>{let s=[];try{$(4,"[export] Determining export path.");const n=i.export,a=n?.options?.chart?.displayErrors&&ie.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if($(4,"[export] Treating as SVG."),"svg"===n.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 $(4,"[export] Treating as config."),n.strInj?await ye(r,{chart:{height:n.height,width:n.width}},i,a):(o.chart.height=n.height,o.chart.width=n.width,await ye(r,o,i,a));s=await async function(r,o){const i=[],s=o.customLogic.resources;if(s){const n=[];if(s.js&&n.push({content:s.js}),s.files)for(const t of s.files){const r=!t.startsWith("http");n.push(r?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of n)try{i.push(await r.addScriptTag(e))}catch(e){D(2,e,"[export] The JS resource cannot be loaded.")}n.length=0;const a=[];if(s.css){let e=s.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(F,r)}));a.push({content:s.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await r.addStyleTag(e))}catch(e){D(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(n.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||n.height)),h=Math.abs(Math.ceil(c.chartWidth||n.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(n.scale)}),"svg"===n.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(r);else if(["png","jpeg"].includes(n.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 oe("Rasterization timeout"))),i||1500)))]))(r,n.type,"base64",{width:h,height:p,x:u,y:d},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new oe(`[export] Unsupported output format ${n.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",n.rasterizationTimeout)}return await fe(r,s),g}catch(e){return await fe(r,s),e}};let we=!1;const Ee={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Te={};const Se={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await me(),!e||e.isClosed())throw new oe("The page is invalid or closed.");$(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new oe("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Te.workLimit/2))}},validate:async e=>!(!e.page||e.page?.isClosed())&&(!(Te.workLimit&&++e.workCount>Te.workLimit)||($(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Te.workLimit}).`),!1)),destroy:async e=>{$(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},xe=async e=>{if(Te=e&&e.pool?{...e.pool}:{},await async function(e){const{puppeteer:t,debug:r,other:o}=Y(),{enable:i,...s}=r,n={headless:!o.browserShellMode||"shell",userDataDir:t.tempDir||"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...i&&s};if(!ge){const e=25;let t=0;const r=async()=>{try{$(3,`[browser] Attempting to get a browser instance (try ${++t}).`),ge=await h.launch(n)}catch(o){if(D(2,o,`[browser] Failed to launch a browser instance - retrying (attempt ${t}/${e}).`),!(t<25))throw o;$(3,`[browser] Retry to open a browser (attempt ${t}/${e}).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),"shell"===n.headless&&$(3,"[browser] Launched browser in shell mode."),i&&$(3,"[browser] Launched browser in debug mode.")}catch(e){throw new oe("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!ge)throw new oe("[browser] Cannot find a browser to open.")}return ge}(e.puppeteerArgs),$(3,`[pool] Initializing pool with workers: min ${Te.minWorkers}, max ${Te.maxWorkers}.`),we)return $(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Te.minWorkers)>parseInt(Te.maxWorkers)&&(Te.minWorkers=Te.maxWorkers);try{we=new c.Pool({...Se,min:parseInt(Te.minWorkers),max:parseInt(Te.maxWorkers),acquireTimeoutMillis:Te.acquireTimeout,createTimeoutMillis:Te.createTimeout,destroyTimeoutMillis:Te.destroyTimeout,idleTimeoutMillis:Te.idleTimeout,createRetryIntervalMillis:Te.createRetryInterval,reapIntervalMillis:Te.reaperInterval,propagateCreateError:!1}),we.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 ve(e)):await e.evaluate((()=>{document.body.innerHTML=''})),!0}catch(e){D(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);$(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),we.on("destroySuccess",((e,t)=>{$(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{we.release(e)})),$(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new oe("[pool] Could not create the pool of workers.").setError(e)}};async function Re(){if($(3,"[pool] Killing pool with all workers and closing browser."),we){for(const e of we.used)we.release(e.resource);we.destroyed||(await we.destroy(),$(4,"[browser] Destroyed the pool of resources."))}await async function(){ge?.connected&&await ge.close(),$(4,"[browser] Closed the browser.")}()}const _e=async(e,t)=>{let r;try{if($(4,"[pool] Work received, starting to process."),++Ee.exportAttempts,Te.benchmarking&&Le(),!we)throw new oe("Work received, but pool has not been started.");const o=K();try{$(4,"[pool] Acquiring a worker handle."),r=await we.acquire().promise,t.server.benchmarking&&$(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if($(4,"[pool] Acquired a worker handle."),!r.page)throw new oe("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();$(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=K(),n=await be(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.workCount=Te.workLimit+1,r.page=null),"TimeoutError"===n.name||"Rasterization timeout"===n.message?new oe("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new oe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&$(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),we.release(r);const a=(new Date).getTime()-i;return Ee.timeSpent+=a,Ee.spentAverage=Ee.timeSpent/++Ee.performedExports,$(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Ee.droppedExports,r&&we.release(r),new oe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Oe=()=>({min:we.min,max:we.max,all:we.numFree()+we.numUsed(),available:we.numFree(),used:we.numUsed(),pending:we.numPendingAcquires()});function Le(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Oe();$(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),$(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),$(5,`[pool] The number of all created resources: ${r}.`),$(5,`[pool] The number of available resources: ${o}.`),$(5,`[pool] The number of acquired resources: ${i}.`),$(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var ke=Oe,Ie=()=>Ee;let Ce=!1;const Ne=async(t,r)=>{$(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=W(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=Z(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,Y()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{$(4,"[chart] Attempting to export from a SVG input.");const e=$e(function(e){const t=[];N.OTHER_ALLOW_XLINK||t.push("xlink:href");const r=new u.JSDOM("").window;return d(r).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:t})}(o.payload.svg),o,r);return++Ee.exportFromSvgAttempts,e}catch(e){return r(new oe("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return $(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),$e(o.export.instr.trim(),o,r)}catch(e){return r(new oe("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return $(4,"[chart] Attempting to export from a raw input."),i.instr=i.instr||i.options,X(o.customLogic?.allowCodeExecution)?He(o,r):"string"==typeof i.instr?$e(i.instr.trim(),o,r):Pe(o,i.instr||i.options,r)}catch(e){return r(new oe("[chart] Error loading raw input.").setError(e))}return r(new oe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ae=e=>{const{chart:t,exporting:r}=e.export?.options||V(e.export?.instr),o=V(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 s={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(s))s[e]="string"==typeof t?+t.replace(/px|%/gi,""):t;return s},Pe=async(t,r,o,i)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ce;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=M(t.customLogic.resources,X(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=M(r,X(t.customLogic.allowFileResources))}catch(e){$(2,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new oe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server."));n.callback=!1,n.resources=!1,n.customCode=!1}if(r&&(r.chart=r.chart||{},r.exporting=r.exporting||{},r.exporting.enabled=!1),s.constr=s.constr||"chart",s.type=j(s.type,s.outfile),"svg"===s.type&&(s.width=!1),["globalOptions","themeOptions"].forEach((t=>{try{s&&s[t]&&("string"==typeof s[t]&&s[t].endsWith(".json")?s[t]=V(e.readFileSync(s[t],"utf8"),!0):s[t]=V(s[t],!0))}catch(e){s[t]={},D(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=z(n.customCode,n.allowFileResources)}catch(e){D(2,e,"[chart] The 'customCode' cannot be loaded.")}if(n&&n.callback&&n.callback?.indexOf("{")<0)if(n.allowFileResources)try{n.callback=e.readFileSync(n.callback,"utf8")}catch(e){n.callback=!1,D(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...Ae(t)};try{return o(!1,await _e(s.strInj||r||i,t))}catch(e){return o(e)}},He=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=q(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,Pe(e,!1,t)}catch(r){return t(new oe(`[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))}},$e=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return $(4,"[chart] Parsing input as SVG."),Pe(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Pe(t,o,r)}catch(e){return X(o)?He(t,r):r(new oe("[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))}},De=[],Ue=()=>{$(4,"[server] Clearing all registered intervals.");for(const e of De)clearInterval(e)},Ge=(e,t,r,o)=>{D(1,e),"development"!==N.OTHER_NODE_ENV&&delete e.stack,o(e)},Fe=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||400;r.status(l).json({statusCode:l,message:n,stack:a})};var je=(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&&($(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),$(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class Me extends oe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Ve=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=N.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Me("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 Me("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Me("No new version supplied.",400);try{await(async e=>{const t=Y();t?.highcharts&&(t.highcharts.version=e),await le(t)})(i)}catch(e){throw new Me(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:pe(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const We={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let qe=0;const Be=[],Xe=[],ze=(e,t,r,o)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=o;return e.some((e=>{if(e){let o=e(t,r,s,n,a,l);return void 0!==o&&!0!==o&&(i=o),!0}})),i},Ke=async(e,t,r)=>{try{const r=K(),i=p.v4().replace(/-/g,""),s=Y(),n=e.body,a=++qe;let l=j(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Me("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=V(n.infile||n.options||n.data);if(!c&&!n.svg)throw $(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 Me("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(Be,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(e=>{e&&(u=!0)})),$(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const d={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:V(n.globalOptions,!0),themeOptions:V(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ce,allowFileResources:!1,resources:V(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=q(c,d.customLogic.allowCodeExecution));const g=Z(s,d);if(g.export.options=c,g.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))))(g.payload.svg))throw new Me("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 Ne(g,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&$(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),u)return $(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Me(`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(Xe,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",We[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){r(e)}var o};const Je=JSON.parse(e.readFileSync(t.join(F,"package.json"))),Ye=new Date,Ze=[];function Qe(e){if(!e)return!1;var t;t=setInterval((()=>{const e=Ie(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ze.push(t),Ze.length>30&&Ze.shift()}),6e4),De.push(t),e.get("/health",((e,t)=>{const r=Ie(),o=Ze.length,i=Ze.reduce(((e,t)=>e+t),0)/Ze.length;$(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Ye,uptime:Math.floor(((new Date).getTime()-Ye.getTime())/1e3/60)+" minutes",version:Je.version,highchartsVersion:pe(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:ke(),period:o,movingAverage:i,message:isNaN(i)||!Ze.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 et=new Map,tt=m();tt.disable("x-powered-by"),tt.use(g()),tt.use(((e,t,r)=>{t.set("Accept-Ranges","none"),r()}));const rt=e=>{e.on("clientError",((e,t)=>{D(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{D(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{D(1,e,`[server] Socket error: ${e.message}`)}))}))},ot=async r=>{try{const o=1024*(r.maxUploadSize||3)*1024,i=f.memoryStorage(),s=f({storage:i,limits:{fieldSize:o}});if(tt.use(m.json({limit:o})),tt.use(m.urlencoded({extended:!0,limit:o})),tt.use(s.none()),!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(tt);rt(e),e.listen(r.port,r.host),et.set(r.port,e),$(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){$(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},tt);rt(e),e.listen(r.ssl.port,r.host),et.set(r.ssl.port,e),$(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&je(tt,r.rateLimiting),tt.use(m.static(t.posix.join(F,"public"))),Qe(tt),(e=>{e.post("/",Ke),e.post("/:filename",Ke)})(tt),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"),{acceptRanges:!1})}))})(tt),Ve(tt),(e=>{e.use(Ge),e.use(Fe)})(tt)}catch(e){throw new oe("[server] Could not configure and start the server.").setError(e)}},it=()=>{$(4,"[server] Closing all servers.");for(const[e,t]of et)t.close((()=>{et.delete(e),$(4,`[server] Closed server on port: ${e}.`)}))};var st={startServer:ot,closeServers:it,getServers:()=>et,enableRateLimiting:e=>je(tt,e),getExpress:()=>m,getApp:()=>tt,use:(e,...t)=>{tt.use(e,...t)},get:(e,...t)=>{tt.get(e,...t)},post:(e,...t)=>{tt.post(e,...t)}};const nt=async e=>{await Promise.allSettled([Ue(),it(),Re()]),process.exit(e)};var at={server:st,startServer:ot,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ce=X(t),(e=>{for(const[t,r]of Object.entries(e))P[t]=r;U(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&G(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&($(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{$(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGTERM",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("SIGHUP",(async(e,t)=>{$(4,`The ${e} event with code: ${t}.`),await nt(0)})),process.on("uncaughtException",(async(e,t)=>{D(1,e,`The ${t} error.`),await nt(1)}))),await le(e),await xe({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 Ne(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 Re()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ne({...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 Re()}catch(e){throw new oe("[chart] Error encountered during batch export.").setError(e)}},startExport:Ne,initPool:xe,killPool:Re,setOptions:(t,r)=>(r?.length&&(J=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){D(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Q(w,J),J=ee(w),t&&(J=Z(J,t,T)),r?.length&&(J=function(e,t,r){let o=!1;for(let i=0;i(n.length-1===r&&(a=e[t].type),e[t])),r),n.reduce(((e,r,l)=>(n.length-1===l&&void 0!==e[r]&&(t[++i]?"boolean"===a?e[r]=X(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:($(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&B();return e}(J,r,w)),J),shutdownCleanUp:nt,log:$,logWithStack:D,setLogLevel:U,enableFileLogging:G,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,s)=>{let n=0,a=[];for(const e of s)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]=te(Object.assign({},r[o.section]||{}),o.name.split("."),o.choices?o.choices[i]:i),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(r,null,2),"utf8")}catch(e){D(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:r=>{const o=JSON.parse(e.readFileSync(t.join(F,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(F+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:B};module.exports=at;
+//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBQb3NzaWJsZSBuYW1lcyBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcbiAgbW9kdWxlczogW1xuICAgICdzdG9jaycsXG4gICAgJ21hcCcsXG4gICAgJ2dhbnR0JyxcbiAgICAnZXhwb3J0aW5nJyxcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxuICAgICdhY2Nlc3NpYmlsaXR5JyxcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICdib29zdC1jYW52YXMnLFxuICAgICdib29zdCcsXG4gICAgJ2RhdGEnLFxuICAgICdkYXRhLXRvb2xzJyxcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgJ3N0YXRpYy1zY2FsZScsXG4gICAgJ2Jyb2tlbi1heGlzJyxcbiAgICAnaGVhdG1hcCcsXG4gICAgJ3RpbGVtYXAnLFxuICAgICd0aWxlZHdlYm1hcCcsXG4gICAgJ3RpbWVsaW5lJyxcbiAgICAndHJlZW1hcCcsXG4gICAgJ3RyZWVncmFwaCcsXG4gICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAnZHJpbGxkb3duJyxcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXG4gICAgJ2J1bGxldCcsXG4gICAgJ2Z1bm5lbCcsXG4gICAgJ2Z1bm5lbDNkJyxcbiAgICAnZ2VvaGVhdG1hcCcsXG4gICAgJ3B5cmFtaWQzZCcsXG4gICAgJ25ldHdvcmtncmFwaCcsXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxuICAgICdwYXJldG8nLFxuICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICdwaWN0b3JpYWwnLFxuICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICdzYW5rZXknLFxuICAgICdhcmMtZGlhZ3JhbScsXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICdzZXJpZXMtb24tcG9pbnQnLFxuICAgICdzb2xpZC1nYXVnZScsXG4gICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcbiAgICAnc3RyZWFtZ3JhcGgnLFxuICAgICdzdW5idXJzdCcsXG4gICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgJ3Zhcml3aWRlJyxcbiAgICAndmVjdG9yJyxcbiAgICAndmVubicsXG4gICAgJ3dpbmRiYXJiJyxcbiAgICAnd29yZGNsb3VkJyxcbiAgICAneHJhbmdlJyxcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcbiAgICAnZHJhZy1wYW5lcycsXG4gICAgJ2RlYnVnZ2VyJyxcbiAgICAnZHVtYmJlbGwnLFxuICAgICdsb2xsaXBvcCcsXG4gICAgJ2N5bGluZGVyJyxcbiAgICAnb3JnYW5pemF0aW9uJyxcbiAgICAnZG90cGxvdCcsXG4gICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcbiAgICAnaGVpa2luYXNoaScsXG4gICAgJ2Zsb3dtYXAnLFxuICAgICdleHBvcnQtZGF0YScsXG4gICAgJ25hdmlnYXRvcicsXG4gICAgJ3RleHRwYXRoJ1xuICBdLFxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gIGN1c3RvbTogW1xuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICBdXG59O1xuXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xuICBwdXBwZXRlZXI6IHtcbiAgICBhcmdzOiB7XG4gICAgICB2YWx1ZTogW1xuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxuICAgICAgICAnLS1uby1waW5ncycsXG4gICAgICAgICctLXBpcGUnLFxuICAgICAgICAvLyAnLS1uby1zYW5kYm94JyxcbiAgICAgICAgJy0tbm8tc3RhcnR1cC13aW5kb3cnLFxuICAgICAgICAvLyAnLS1uby16eWdvdGUnLFxuICAgICAgICAnLS1wYXNzd29yZC1zdG9yZT1iYXNpYycsXG4gICAgICAgICctLXByb2Nlc3MtcGVyLXRhYicsXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xuICAgICAgXSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXG4gICAgfSxcbiAgICB0ZW1wRGlyOiB7XG4gICAgICB2YWx1ZTogJy4vdG1wLycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdQVVBQRVRFRVJfVEVNUF9ESVInLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZGlyZWN0b3J5IGZvciBQdXBwZXRlZXIgdG8gc3RvcmUgdGVtcG9yYXJ5IGZpbGVzLidcbiAgICB9XG4gIH0sXG4gIGhpZ2hjaGFydHM6IHtcbiAgICB2ZXJzaW9uOiB7XG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgY2RuVVJMOiB7XG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGNvcmVTY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIG1vZHVsZVNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBjdXN0b21TY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXG4gICAgfSxcbiAgICBjYWNoZVBhdGg6IHtcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvdXRmaWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRTY2FsZToge1xuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXG4gICAgfSxcbiAgICBoZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xuICAgIH0sXG4gICAgc2NhbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXG4gICAgfSxcbiAgICBiYXRjaDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xuICAgIH0sXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAxNTAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Mb2dpYzoge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjcmVhdGVDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjoge1xuICAgIG1heFVwbG9hZFNpemU6IHtcbiAgICAgIHZhbHVlOiAzLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX01BWF9VUExPQURfU0laRScsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtYXhpbXVtIHVwbG9hZCBzaXplLCBpbiBNQiwgZm9yIHRoZSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgZW5hYmxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0VOQUJMRScsXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlU2VydmVyJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBzdGFydHMgb24gdGhlIGxvY2FsIElQIGFkZHJlc3MgMC4wLjAuMC4nXG4gICAgfSxcbiAgICBob3N0OiB7XG4gICAgICB2YWx1ZTogJzAuMC4wLjAnLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaG9zdG5hbWUgb2YgdGhlIHNlcnZlci4gQWRkaXRpb25hbGx5LCBpdCBzdGFydHMgYSBzZXJ2ZXIgb24gdGhlIHByb3ZpZGVkIGhvc3RuYW1lLidcbiAgICB9LFxuICAgIHBvcnQ6IHtcbiAgICAgIHZhbHVlOiA3ODAxLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX1BPUlQnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgc2VydmVyIHBvcnQgd2hlbiBlbmFibGVkLidcbiAgICB9LFxuICAgIGJlbmNobWFya2luZzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9CRU5DSE1BUktJTkcnLFxuICAgICAgY2xpTmFtZTogJ3NlcnZlckJlbmNobWFya2luZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luZGljYXRlcyB3aGV0aGVyIHRvIGRpc3BsYXkgdGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIG9mIHNwZWNpZmljIGFjdGlvbnMgdGhhdCBvY2N1ciBvbiB0aGUgc2VydmVyIHdoaWxlIHNlcnZpbmcgYSByZXF1ZXN0LidcbiAgICB9LFxuICAgIHByb3h5OiB7XG4gICAgICBob3N0OiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfSE9TVCcsXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eUhvc3QnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xuICAgICAgfSxcbiAgICAgIHBvcnQ6IHtcbiAgICAgICAgdmFsdWU6IDgwODAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BPUlQnLFxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH0sXG4gICAgICB1c2VybmFtZToge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1VTRVJOQU1FJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VXNlcm5hbWUnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB1c2VybmFtZSBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH0sXG4gICAgICBwYXNzd29yZDoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX1BBU1NXT1JEJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UGFzc3dvcmQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXNzd29yZCBmb3IgdGhlIHByb3h5IHNlcnZlciwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH0sXG4gICAgICB0aW1lb3V0OiB7XG4gICAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5VGltZW91dCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xuICAgICAgfVxuICAgIH0sXG4gICAgcmF0ZUxpbWl0aW5nOiB7XG4gICAgICBlbmFibGU6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlUmF0ZUxpbWl0aW5nJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuJ1xuICAgICAgfSxcbiAgICAgIG1heFJlcXVlc3RzOiB7XG4gICAgICAgIHZhbHVlOiAxMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMnLFxuICAgICAgICBsZWdhY3lOYW1lOiAncmF0ZUxpbWl0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcbiAgICAgIH0sXG4gICAgICB3aW5kb3c6IHtcbiAgICAgICAgdmFsdWU6IDEsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXG4gICAgICB9LFxuICAgICAgZGVsYXk6IHtcbiAgICAgICAgdmFsdWU6IDAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVknLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnVGhlIGRlbGF5IGR1cmF0aW9uIGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0gbGltaXQuJ1xuICAgICAgfSxcbiAgICAgIHRydXN0UHJveHk6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnU2V0IHRoaXMgdG8gdHJ1ZSBpZiB0aGUgc2VydmVyIGlzIGJlaGluZCBhIGxvYWQgYmFsYW5jZXIuJ1xuICAgICAgfSxcbiAgICAgIHNraXBLZXk6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudC4nXG4gICAgICB9LFxuICAgICAgc2tpcFRva2VuOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xuICAgICAgfVxuICAgIH0sXG4gICAgc3NsOiB7XG4gICAgICBlbmFibGU6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0VOQUJMRScsXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVTc2wnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXG4gICAgICB9LFxuICAgICAgZm9yY2U6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0ZPUkNFJyxcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbE9ubHknLFxuICAgICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcbiAgICAgIH0sXG4gICAgICBwb3J0OiB7XG4gICAgICAgIHZhbHVlOiA0NDMsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9QT1JUJyxcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9uIHdoaWNoIHRvIHJ1biB0aGUgU1NMIHNlcnZlci4nXG4gICAgICB9LFxuICAgICAgY2VydFBhdGg6IHtcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcbiAgICAgICAgbGVnYWN5TmFtZTogJ3NzbFBhdGgnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwYXRoIHRvIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5IGZpbGUuJ1xuICAgICAgfVxuICAgIH1cbiAgfSxcbiAgcG9vbDoge1xuICAgIG1pbldvcmtlcnM6IHtcbiAgICAgIHZhbHVlOiA0LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NSU5fV09SS0VSUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWluaW11bSBhbmQgaW5pdGlhbCBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xuICAgIH0sXG4gICAgbWF4V29ya2Vyczoge1xuICAgICAgdmFsdWU6IDgsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX01BWF9XT1JLRVJTJyxcbiAgICAgIGxlZ2FjeU5hbWU6ICd3b3JrZXJzJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXG4gICAgfSxcbiAgICB3b3JrTGltaXQ6IHtcbiAgICAgIHZhbHVlOiA0MCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfV09SS19MSU1JVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBudW1iZXIgb2Ygd29yayBwaWVjZXMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIHRoZSB3b3JrZXIgcHJvY2Vzcy4nXG4gICAgfSxcbiAgICBhY3F1aXJlVGltZW91dDoge1xuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZS4nXG4gICAgfSxcbiAgICBjcmVhdGVUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogNTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXG4gICAgfSxcbiAgICBkZXN0cm95VGltZW91dDoge1xuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0RFU1RST1lfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgaWRsZVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAzMDAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkLidcbiAgICB9LFxuICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWw6IHtcbiAgICAgIHZhbHVlOiAyMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xuICAgIH0sXG4gICAgcmVhcGVySW50ZXJ2YWw6IHtcbiAgICAgIHZhbHVlOiAxMDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9SRUFQRVJfSU5URVJWQUwnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgYWZ0ZXIgd2hpY2ggdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95IGlzIHRyaWdnZXJlZC4nXG4gICAgfSxcbiAgICBiZW5jaG1hcmtpbmc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXG4gICAgICBjbGlOYW1lOiAncG9vbEJlbmNobWFya2luZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcbiAgICB9XG4gIH0sXG4gIGxvZ2dpbmc6IHtcbiAgICBsZXZlbDoge1xuICAgICAgdmFsdWU6IDQsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0xFVkVMJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dMZXZlbCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgZmlsZToge1xuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfRklMRScsXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBuYW1lIG9mIGEgbG9nIGZpbGUuIFRoZSBgbG9nVG9GaWxlYCBhbmQgYGxvZ0Rlc3RgIG9wdGlvbnMgYWxzbyBuZWVkIHRvIGJlIHNldCB0byBlbmFibGUgZmlsZSBsb2dnaW5nLidcbiAgICB9LFxuICAgIGRlc3Q6IHtcbiAgICAgIHZhbHVlOiAnbG9nLycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0RFU1QnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0Rlc3QnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgcGF0aCB0byBzdG9yZSBsb2cgZmlsZXMuIFRoZSBgbG9nVG9GaWxlYCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXG4gICAgfSxcbiAgICB0b0NvbnNvbGU6IHtcbiAgICAgIHZhbHVlOiB0cnVlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0xPR0dJTkdfVE9fQ09OU09MRScsXG4gICAgICBjbGlOYW1lOiAnbG9nVG9Db25zb2xlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBzaG93aW5nIGxvZ3MgaW4gdGhlIGNvbnNvbGUuJ1xuICAgIH0sXG4gICAgdG9GaWxlOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0ZJTEUnLFxuICAgICAgY2xpTmFtZTogJ2xvZ1RvRmlsZScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgY3JlYXRpb24gb2YgdGhlIGxvZyBkaXJlY3RvcnkgYW5kIHNhdmluZyB0aGUgbG9nIGludG8gYSAubG9nIGZpbGUuJ1xuICAgIH1cbiAgfSxcbiAgdWk6IHtcbiAgICBlbmFibGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVVpJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgcm91dGU6IHtcbiAgICAgIHZhbHVlOiAnLycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdVSV9ST1VURScsXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBlbmRwb2ludCByb3V0ZSB0byB3aGljaCB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBzaG91bGQgYmUgYXR0YWNoZWQuJ1xuICAgIH1cbiAgfSxcbiAgb3RoZXI6IHtcbiAgICBub2RlRW52OiB7XG4gICAgICB2YWx1ZTogJ3Byb2R1Y3Rpb24nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50LidcbiAgICB9LFxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgd2hldGhlciBvciBub3QgdG8gYXR0YWNoIHByb2Nlc3MuZXhpdCBoYW5kbGVycy4nXG4gICAgfSxcbiAgICBub0xvZ286IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBhIHN0YXJ0dXAuIFdpbGwgYmUgcmVwbGFjZWQgYnkgYSBzaW1wbGUgdGV4dC4nXG4gICAgfSxcbiAgICBoYXJkUmVzZXRQYWdlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfSEFSRF9SRVNFVF9QQUdFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgcGFnZSBjb250ZW50IHNob3VsZCBiZSByZXNldCBlbnRpcmVseS4nXG4gICAgfSxcbiAgICBicm93c2VyU2hlbGxNb2RlOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUnLFxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIGlmIHRoZSBicm93c2VyIHJ1bnMgaW4gdGhlIHNoZWxsIG1vZGUuJ1xuICAgIH1cbiAgfSxcbiAgZGVidWc6IHtcbiAgICBlbmFibGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxuICAgICAgY2xpTmFtZTogJ2VuYWJsZURlYnVnJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyLidcbiAgICB9LFxuICAgIGhlYWRsZXNzOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19IRUFETEVTUycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBtb2RlIGluIHdoaWNoIHRoZSBicm93c2VyIGlzIGxhdW5jaGVkIHdoZW4gaW4gdGhlIGRlYnVnIG1vZGUuJ1xuICAgIH0sXG4gICAgZGV2dG9vbHM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0RlY2lkZXMgd2hldGhlciB0byBlbmFibGUgRGV2VG9vbHMgd2hlbiB0aGUgYnJvd3NlciBpcyBpbiBhIGhlYWRmdWwgc3RhdGUuJ1xuICAgIH0sXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIGEgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgc2VudCBmcm9tIHRoZSBicm93c2VyLidcbiAgICB9LFxuICAgIGR1bXBpbzoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0RVTVBJTycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1JlZGlyZWN0cyBicm93c2VyIHByb2Nlc3Mgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyLidcbiAgICB9LFxuICAgIHNsb3dNbzoge1xuICAgICAgdmFsdWU6IDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnU2xvd3MgZG93biBQdXBwZXRlZXIgb3BlcmF0aW9ucyBieSB0aGUgc3BlY2lmaWVkIG51bWJlciBvZiBtaWxsaXNlY29uZHMuJ1xuICAgIH0sXG4gICAgZGVidWdnaW5nUG9ydDoge1xuICAgICAgdmFsdWU6IDkyMjIsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXG4gICAgICBkZXNjcmlwdGlvbjogJ1NwZWNpZmllcyB0aGUgZGVidWdnaW5nIHBvcnQuJ1xuICAgIH1cbiAgfVxufTtcblxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xuLy8gaW5mb3JtYXRpb24gbGlrZTpcbi8vICogVHlwZSBvZiBhIHByb21wdFxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxuLy8gKiBTaG9ydCBkZXNjcmlwdGlvbiBvZiBhIGNob3NlbiBvcHRpb25cbi8vICogSW5pdGlhbCB2YWx1ZVxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XG4gIHB1cHBldGVlcjogW1xuICAgIHtcbiAgICAgIHR5cGU6ICdsaXN0JyxcbiAgICAgIG5hbWU6ICdhcmdzJyxcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxuICAgICAgc2VwYXJhdG9yOiAnLCdcbiAgICB9XG4gIF0sXG4gIGhpZ2hjaGFydHM6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAndmVyc2lvbicsXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnY2RuVVJMJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ2NvcmVTY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY29yZVNjcmlwdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZSBzY3JpcHRzJyxcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdpbmRpY2F0b3JTY3JpcHRzJyxcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgaW5kaWNhdG9yIHNjcmlwdHMnLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5pbmRpY2F0b3JTY3JpcHRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbGlzdCcsXG4gICAgICBuYW1lOiAnY3VzdG9tU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmN1c3RvbVNjcmlwdHMudmFsdWUuam9pbignLCcpLFxuICAgICAgc2VwYXJhdG9yOiAnLCdcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5mb3JjZUZldGNoLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jYWNoZVBhdGgudmFsdWVcbiAgICB9XG4gIF0sXG4gIGV4cG9ydDogW1xuICAgIHtcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxuICAgICAgbmFtZTogJ3R5cGUnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxuICAgICAgaW5pdGlhbDogMCxcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjb25zdHInLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGNvbnN0cnVjdG9yIGZvciBIaWdoY2hhcnRzJyxcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxuICAgICAgaW5pdGlhbDogMCxcbiAgICAgIGNob2ljZXM6IFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J11cbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdEhlaWdodC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFdpZHRoLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0U2NhbGUudmFsdWUsXG4gICAgICBtaW46IDAuMSxcbiAgICAgIG1heDogNVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmFzdGVyaXphdGlvblRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgY3VzdG9tTG9naWM6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBleGVjdXRpb24gb2YgY3VzdG9tIGNvZGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGZpbGUgcmVzb3VyY2VzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXG4gICAgfVxuICBdLFxuICBzZXJ2ZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnaG9zdCcsXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmhvc3QudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3BvcnQnLFxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuYmVuY2htYXJraW5nLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkuaG9zdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkucG9ydC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcud2luZG93LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSBkZWxheSBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxuICAgICAgbWVzc2FnZTogJ1NldCB0byB0cnVlIGlmIGJlaGluZCBhIGxvYWQgYmFsYW5jZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBUb2tlbicsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcFRva2VuLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmZvcmNlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5jZXJ0UGF0aC52YWx1ZVxuICAgIH1cbiAgXSxcbiAgcG9vbDogW1xuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ21pbldvcmtlcnMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdtYXhXb3JrZXJzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnd29ya0xpbWl0JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLndvcmtMaW1pdC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5hY3F1aXJlVGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlVGltZW91dC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuZGVzdHJveVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuaWRsZVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSByZXRyeSBpbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgYWZ0ZXIgYSBjcmVhdGUgcHJvY2VzcyBmYWlscycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYmVuY2htYXJraW5nJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxuICAgIH1cbiAgXSxcbiAgbG9nZ2luZzogW1xuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2xldmVsJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxuICAgICAgcm91bmQ6IDAsXG4gICAgICBtaW46IDAsXG4gICAgICBtYXg6IDVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdmaWxlJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIC0tdG9GaWxlIGFuZCAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZmlsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2Rlc3QnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGEgbG9nIGZpbGUgd2hlbiB0aGUgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3RvQ29uc29sZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGxvZ2dpbmcgdG8gdGhlIGNvbnNvbGUnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLnRvQ29uc29sZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAndG9GaWxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIGxvZ2dpbmcgdG8gYSBmaWxlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy50b0ZpbGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIHVpOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgVUkgZm9yIHRoZSBleHBvcnQgc2VydmVyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncm91dGUnLFxuICAgICAgbWVzc2FnZTogJ0Egcm91dGUgdG8gYXR0YWNoIHRoZSBVSScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXG4gICAgfVxuICBdLFxuICBvdGhlcjogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9kZUVudi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubm9Mb2dvLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIuaGFyZFJlc2V0UGFnZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYnJvd3NlclNoZWxsTW9kZScsXG4gICAgICBtZXNzYWdlOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIuYnJvd3NlclNoZWxsTW9kZS52YWx1ZVxuICAgIH1cbiAgXSxcbiAgZGVidWc6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5lbmFibGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2hlYWRsZXNzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmhlYWRsZXNzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdkZXZ0b29scycsXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGV2dG9vbHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2xpc3RlblRvQ29uc29sZScsXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2R1bXBpbycsXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZHVtcGlvLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdzbG93TW8nLFxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5zbG93TW8udmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlYnVnZ2luZ1BvcnQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGVidWdnaW5nUG9ydC52YWx1ZVxuICAgIH1cbiAgXVxufTtcblxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXG4gICdvcHRpb25zJyxcbiAgJ2dsb2JhbE9wdGlvbnMnLFxuICAndGhlbWVPcHRpb25zJyxcbiAgJ3Jlc291cmNlcycsXG4gICdwYXlsb2FkJ1xuXTtcblxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IGNyZWF0ZXMgYSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzIGZyb20gYW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllc1xuICogKHVzZWQgaW50ZXJuYWxseSBkdXJpbmcgcmVjdXJzaW9uKS5cbiAqL1xuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XG4gIE9iamVjdC5rZXlzKG9iaikuZm9yRWFjaCgoaykgPT4ge1xuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcbiAgICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcblxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xuICAgICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5sZWdhY3lOYW1lXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9KTtcbn07XG5cbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XG4iLCIvKipcbiAqIEBmaWxlb3ZlcnZpZXdcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXG4gKiBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZCB0byBiZSB1c2VkXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgXCJlbnZzXCIuIFdlIHNob3VsZCBub3QgdXNlIHByb2Nlc3MuZW52IGRpcmVjdGx5XG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cbiAqXG4gKiBUaGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSBwYXJzZWQgYW5kIHZhbGlkYXRlZCBvbmx5IG9uY2Ugd2hlblxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXG4gKiBmb3IgZWFjaCBvZiB0aGUgb3B0aW9ucy5cbiAqL1xuXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XG5pbXBvcnQgeyB6IH0gZnJvbSAnem9kJztcblxuaW1wb3J0IHsgc2NyaXB0c05hbWVzIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XG5cbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xuZG90ZW52LmNvbmZpZygpO1xuXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXG4vLyBpbiB0aGUgQ29uZmlnIG9iamVjdFxuY29uc3QgdiA9IHtcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcbiAgLy8gaWYgYW4gYXJyYXkgaXMgY29ycmVjdCwgaWYgaXQgaXMgZW1wdHksIGFuZCBpZiBpdCBpcywgcmV0dXJucyB1bmRlZmluZWRcbiAgYXJyYXk6IChmaWx0ZXJBcnJheSkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PlxuICAgICAgICB2YWx1ZVxuICAgICAgICAgIC5zcGxpdCgnLCcpXG4gICAgICAgICAgLm1hcCgodmFsdWUpID0+IHZhbHVlLnRyaW0oKSlcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxuICAgICAgKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZS5sZW5ndGggPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxuXG4gIC8vIEFsbG93cyBvbmx5IHRydWUsIGZhbHNlIGFuZCBjb3JyZWN0bHkgcGFyc2UgdGhlIHZhbHVlIHRvIGJvb2xlYW5cbiAgLy8gb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSB1bmRlZmluZWRcbiAgYm9vbGVhbjogKCkgPT5cbiAgICB6XG4gICAgICAuZW51bShbJ3RydWUnLCAnZmFsc2UnLCAnJ10pXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcblxuICAvLyBBbGxvd3MgcGFzc2VkIHZhbHVlcyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXG4gIC8vIGJlIHVuZGVmaW5lZFxuICBlbnVtOiAodmFsdWVzKSA9PlxuICAgIHpcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcblxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcbiAgLy8gdmFsdWVzIHN1Y2ggYXMgZmFsc2UsIHVuZGVmaW5lZCwgbnVsbCwgTmFOLCBpZiBpdCBkb2VzLCByZXR1cm5zIHVuZGVmaW5lZFxuICBzdHJpbmc6ICgpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVmaW5lKFxuICAgICAgICAodmFsdWUpID0+XG4gICAgICAgICAgIVsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJ10uaW5jbHVkZXModmFsdWUpIHx8XG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxuICAgICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgICAgbWVzc2FnZTogYFRoZSBzdHJpbmcgY29udGFpbnMgZm9yYmlkZGVuIHZhbHVlcywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcblxuICAvLyBDaGVja3MgaWYgdGhlIHN0cmluZyBpcyBhIHZhbGlkIHBhdGggZGlyZWN0b3J5IChwYXRoIGZvcm1hdClcbiAgcGF0aDogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT4ge1xuICAgICAgICAgIC8vIFNpbXBsaWZpZWQgcmVnZXggdG8gbWF0Y2ggYm90aCBhYnNvbHV0ZSBhbmQgcmVsYXRpdmUgcGF0aHNcbiAgICAgICAgICByZXR1cm4gL14oXFwuXFwvfFxcLlxcLlxcL3xcXC98W2EtekEtWl06XFxcXHxbYS16QS1aXTpcXC8pPygoPzpbXFx3LV0rKVtcXFxcL10/KSskLy50ZXN0KFxuICAgICAgICAgICAgdmFsdWVcbiAgICAgICAgICApO1xuICAgICAgICB9LFxuICAgICAgICB7fSxcbiAgICAgICAge1xuICAgICAgICAgIG1lc3NhZ2U6ICdUaGUgc3RyaW5nIGlzIGFuIGludmFsaWQgcGF0aCBkaXJlY3Rvcnkgc3RyaW5nLidcbiAgICAgICAgfVxuICAgICAgKSxcblxuICAvLyBBbGxvd3MgcG9zaXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXG4gIC8vIGJlIHVuZGVmaW5lZFxuICBwb3NpdGl2ZU51bTogKCkgPT5cbiAgICB6XG4gICAgICAuc3RyaW5nKClcbiAgICAgIC50cmltKClcbiAgICAgIC5yZWZpbmUoXG4gICAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBwb3NpdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcblxuICAvLyBBbGxvd3Mgbm9uLW5lZ2F0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWVcbiAgLy8gd2lsbCBiZSB1bmRlZmluZWRcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVmaW5lKFxuICAgICAgICAodmFsdWUpID0+XG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxuICAgICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIG5vbi1uZWdhdGl2ZSwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgICAgfSlcbiAgICAgIClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKVxufTtcblxuZXhwb3J0IGNvbnN0IENvbmZpZyA9IHoub2JqZWN0KHtcbiAgLy8gcHVwcGV0ZWVyXG4gIFBVUFBFVEVFUl9URU1QX0RJUjogdi5wYXRoKCksXG5cbiAgLy8gaGlnaGNoYXJ0c1xuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcbiAgICAuc3RyaW5nKClcbiAgICAudHJpbSgpXG4gICAgLnJlZmluZShcbiAgICAgICh2YWx1ZSkgPT4gL14obGF0ZXN0fFxcZCsoXFwuXFxkKyl7MCwyfSkkLy50ZXN0KHZhbHVlKSB8fCB2YWx1ZSA9PT0gJycsXG4gICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgIH0pXG4gICAgKVxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcbiAgSElHSENIQVJUU19DRE5fVVJMOiB6XG4gICAgLnN0cmluZygpXG4gICAgLnRyaW0oKVxuICAgIC5yZWZpbmUoXG4gICAgICAodmFsdWUpID0+XG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cDovLycpIHx8XG4gICAgICAgIHZhbHVlID09PSAnJyxcbiAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIEhJR0hDSEFSVFNfQ0ROX1VSTC4gSXQgc2hvdWxkIHN0YXJ0IHdpdGggaHR0cDovLyBvciBodHRwczovLywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgIH0pXG4gICAgKVxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5tb2R1bGVzKSxcbiAgSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMuaW5kaWNhdG9ycyksXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHYuc3RyaW5nKCksXG4gIEhJR0hDSEFSVFNfQURNSU5fVE9LRU46IHYuc3RyaW5nKCksXG5cbiAgLy8gZXhwb3J0XG4gIEVYUE9SVF9UWVBFOiB2LmVudW0oWydqcGVnJywgJ3BuZycsICdwZGYnLCAnc3ZnJ10pLFxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdi5wb3NpdGl2ZU51bSgpLFxuICBFWFBPUlRfREVGQVVMVF9XSURUSDogdi5wb3NpdGl2ZU51bSgpLFxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG5cbiAgLy8gY3VzdG9tXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdi5ib29sZWFuKCksXG4gIENVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUzogdi5ib29sZWFuKCksXG5cbiAgLy8gc2VydmVyXG4gIFNFUlZFUl9FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcbiAgU0VSVkVSX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgU0VSVkVSX01BWF9VUExPQURfU0laRTogdi5wb3NpdGl2ZU51bSgpLFxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcblxuICAvLyBzZXJ2ZXIgcHJveHlcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9QUk9YWV9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9QUk9YWV9VU0VSTkFNRTogdi5zdHJpbmcoKSxcbiAgU0VSVkVSX1BST1hZX1BBU1NXT1JEOiB2LnN0cmluZygpLFxuICBTRVJWRVJfUFJPWFlfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFk6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdi5zdHJpbmcoKSxcblxuICAvLyBzZXJ2ZXIgc3NsXG4gIFNFUlZFUl9TU0xfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1NTTF9GT1JDRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdi5zdHJpbmcoKSxcblxuICAvLyBwb29sXG4gIFBPT0xfTUlOX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9NQVhfV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9DUkVBVEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0lETEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBQT09MX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXG5cbiAgLy8gbG9nZ2VyXG4gIExPR0dJTkdfTEVWRUw6IHpcbiAgICAuc3RyaW5nKClcbiAgICAudHJpbSgpXG4gICAgLnJlZmluZShcbiAgICAgICh2YWx1ZSkgPT5cbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XG4gICAgICAgICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmXG4gICAgICAgICAgcGFyc2VGbG9hdCh2YWx1ZSkgPj0gMCAmJlxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxuICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgTE9HR0lOR19MRVZFTC4gV2Ugb25seSBhY2NlcHQgdmFsdWVzIGZyb20gMCB0byA1IGFzIGxvZ2dpbmcgbGV2ZWxzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxuICAgICAgfSlcbiAgICApXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXG4gIExPR0dJTkdfREVTVDogdi5zdHJpbmcoKSxcbiAgTE9HR0lOR19UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcbiAgTE9HR0lOR19UT19GSUxFOiB2LmJvb2xlYW4oKSxcblxuICAvLyB1aVxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBVSV9ST1VURTogdi5zdHJpbmcoKSxcblxuICAvLyBvdGhlclxuICBPVEhFUl9OT0RFX0VOVjogdi5lbnVtKFsnZGV2ZWxvcG1lbnQnLCAncHJvZHVjdGlvbicsICd0ZXN0J10pLFxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxuICBPVEhFUl9IQVJEX1JFU0VUX1BBR0U6IHYuYm9vbGVhbigpLFxuICBPVEhFUl9CUk9XU0VSX1NIRUxMX01PREU6IHYuYm9vbGVhbigpLFxuICBPVEhFUl9BTExPV19YTElOSzogdi5ib29sZWFuKCksXG5cbiAgLy8gZGVidWdnZXJcbiAgREVCVUdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfSEVBRExFU1M6IHYuYm9vbGVhbigpLFxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXG4gIERFQlVHX0xJU1RFTl9UT19DT05TT0xFOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfRFVNUElPOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxuICBERUJVR19ERUJVR0dJTkdfUE9SVDogdi5wb3NpdGl2ZU51bSgpXG59KTtcblxuZXhwb3J0IGNvbnN0IGVudnMgPSBDb25maWcucGFydGlhbCgpLnBhcnNlKHByb2Nlc3MuZW52KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhcHBlbmRGaWxlLCBleGlzdHNTeW5jLCBta2RpclN5bmMgfSBmcm9tICdmcyc7XG5cbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXG5jb25zdCBjb2xvcnMgPSBbJ3JlZCcsICd5ZWxsb3cnLCAnYmx1ZScsICdncmF5JywgJ2dyZWVuJ107XG5cbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXG5sZXQgbG9nZ2luZyA9IHtcbiAgLy8gRmxhZ3MgZm9yIGxvZ2dpbmcgc3RhdHVzXG4gIHRvQ29uc29sZTogdHJ1ZSxcbiAgdG9GaWxlOiBmYWxzZSxcbiAgcGF0aENyZWF0ZWQ6IGZhbHNlLFxuICAvLyBMb2cgbGV2ZWxzXG4gIGxldmVsc0Rlc2M6IFtcbiAgICB7XG4gICAgICB0aXRsZTogJ2Vycm9yJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbMF1cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAnd2FybmluZycsXG4gICAgICBjb2xvcjogY29sb3JzWzFdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ25vdGljZScsXG4gICAgICBjb2xvcjogY29sb3JzWzJdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxuICAgICAgY29sb3I6IGNvbG9yc1szXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICdiZW5jaG1hcmsnLFxuICAgICAgY29sb3I6IGNvbG9yc1s0XVxuICAgIH1cbiAgXSxcbiAgLy8gTG9nIGxpc3RlbmVyc1xuICBsaXN0ZW5lcnM6IFtdXG59O1xuXG4vKipcbiAqIExvZ3MgdGhlIHByb3ZpZGVkIHRleHRzIHRvIGEgZmlsZSwgaWYgZmlsZSBsb2dnaW5nIGlzIGVuYWJsZWQuIEl0IGNyZWF0ZXNcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxuICogY29udGVudCwgaW5jbHVkaW5nIGFuIG9wdGlvbmFsIHByZWZpeCwgdG8gdGhlIHNwZWNpZmllZCBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcmVmaXggLSBBbiBvcHRpb25hbCBwcmVmaXggdG8gYmUgYWRkZWQgdG8gZWFjaCBsb2cgZW50cnkuXG4gKi9cbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XG4gIGlmICghbG9nZ2luZy5wYXRoQ3JlYXRlZCkge1xuICAgIC8vIENyZWF0ZSBpZiBkb2VzIG5vdCBleGlzdFxuICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XG5cbiAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxuICAgIC8vIG9mIHRoZSB1c2VyIHRvIGNyZWF0ZSB0aGUgcGF0aCB3aXRoIHRoZSBjb3JyZWN0IGFjY2VzcyByaWdodHMuXG4gICAgbG9nZ2luZy5wYXRoQ3JlYXRlZCA9IHRydWU7XG4gIH1cblxuICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXG4gIGFwcGVuZEZpbGUoXG4gICAgYCR7bG9nZ2luZy5kZXN0fSR7bG9nZ2luZy5maWxlfWAsXG4gICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcbiAgICAoZXJyb3IpID0+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/IGh0dHBzIDogaHR0cCk7XG5cbi8qKlxuICogRmV0Y2hlcyBkYXRhIGZyb20gdGhlIHNwZWNpZmllZCBVUkwgdXNpbmcgZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxuICogd2l0aCBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcblxuICAgIHByb3RvY29sXG4gICAgICAuZ2V0KFxuICAgICAgICB1cmwsXG4gICAgICAgIE9iamVjdC5hc3NpZ24oXG4gICAgICAgICAge1xuICAgICAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICAgICAnVXNlci1BZ2VudCc6ICdoaWdoY2hhcnRzL2V4cG9ydCcsXG4gICAgICAgICAgICAgIFJlZmVyZXI6ICdoaWdoY2hhcnRzLmV4cG9ydCdcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIHJlcXVlc3RPcHRpb25zIHx8IHt9XG4gICAgICAgICksXG4gICAgICAgIChyZXMpID0+IHtcbiAgICAgICAgICBsZXQgZGF0YSA9ICcnO1xuXG4gICAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgICB9KTtcblxuICAgICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgICByZWplY3QoJ05vdGhpbmcgd2FzIGZldGNoZWQgZnJvbSB0aGUgVVJMLicpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgIClcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuICB9KTtcbn1cblxuLyoqXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcbiAqIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cbiAqIEBwYXJhbSB7T2JqZWN0fSBib2R5IC0gVGhlIEpTT04gYm9keSB0byBpbmNsdWRlIGluIHRoZSBQT1NUIHJlcXVlc3RcbiAqIChvcHRpb25hbCwgZGVmYXVsdCBpcyBhbiBlbXB0eSBvYmplY3QpLlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdCB3aXRoXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHBvc3QodXJsLCBib2R5ID0ge30sIHJlcXVlc3RPcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XG4gICAgY29uc3QgZGF0YSA9IEpTT04uc3RyaW5naWZ5KGJvZHkpO1xuXG4gICAgLy8gU2V0IGRlZmF1bHQgaGVhZGVycyBhbmQgbWVyZ2Ugd2l0aCByZXF1ZXN0T3B0aW9uc1xuICAgIGNvbnN0IG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKFxuICAgICAge1xuICAgICAgICBtZXRob2Q6ICdQT1NUJyxcbiAgICAgICAgaGVhZGVyczoge1xuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXG4gICAgICAgICAgJ0NvbnRlbnQtTGVuZ3RoJzogZGF0YS5sZW5ndGhcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIHJlcXVlc3RPcHRpb25zXG4gICAgKTtcblxuICAgIGNvbnN0IHJlcSA9IHByb3RvY29sXG4gICAgICAucmVxdWVzdCh1cmwsIG9wdGlvbnMsIChyZXMpID0+IHtcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xuXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2VEYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICByZXMudGV4dCA9IHJlc3BvbnNlRGF0YTtcbiAgICAgICAgICAgIHJlc29sdmUocmVzKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgfSlcbiAgICAgIC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcbiAgICAgIH0pO1xuXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxuICAgIHJlcS53cml0ZShkYXRhKTtcbiAgICByZXEuZW5kKCk7XG4gIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcbmV4cG9ydCB7IGZldGNoLCBwb3N0IH07XG4iLCJjbGFzcyBFeHBvcnRFcnJvciBleHRlbmRzIEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xuICAgIHN1cGVyKCk7XG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XG4gIH1cblxuICBzZXRFcnJvcihlcnJvcikge1xuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcbiAgICBpZiAoZXJyb3IubmFtZSkge1xuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcbiAgICB9XG4gICAgaWYgKGVycm9yLnN0YXR1c0NvZGUpIHtcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XG4gICAgfVxuICAgIGlmIChlcnJvci5zdGFjaykge1xuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBFeHBvcnRFcnJvcjtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBUaGUgY2FjaGUgbWFuYWdlciBtYW5hZ2VzIHRoZSBIaWdoY2hhcnRzIGxpYnJhcnkgYW5kIGl0cyBkZXBlbmRlbmNpZXMuXG4vLyBUaGUgY2FjaGUgaXRzZWxmIGlzIHN0b3JlZCBpbiAuY2FjaGUsIGFuZCBpcyBjaGVja2VkIGJ5IHRoZSBjb25maWcgc3lzdGVtXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcblxuaW1wb3J0IHsgZXhpc3RzU3luYywgbWtkaXJTeW5jLCByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IEh0dHBzUHJveHlBZ2VudCB9IGZyb20gJ2h0dHBzLXByb3h5LWFnZW50JztcblxuaW1wb3J0IHsgZ2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuL2VudnMuanMnO1xuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG5jb25zdCBjYWNoZSA9IHtcbiAgY2RuVVJMOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXG4gIGFjdGl2ZU1hbmlmZXN0OiB7fSxcbiAgc291cmNlczogJycsXG4gIGhjVmVyc2lvbjogJydcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgYW5kIGNhY2hlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGZyb20gdGhlIHNvdXJjZXMgc3RyaW5nLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBleHRyYWN0ZWQgSGlnaGNoYXJ0cyB2ZXJzaW9uLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcbiAgcmV0dXJuIGNhY2hlLnNvdXJjZXNcbiAgICAuc3Vic3RyaW5nKDAsIGNhY2hlLnNvdXJjZXMuaW5kZXhPZignKi8nKSlcbiAgICAucmVwbGFjZSgnLyonLCAnJylcbiAgICAucmVwbGFjZSgnKi8nLCAnJylcbiAgICAucmVwbGFjZSgvXFxuL2csICcnKVxuICAgIC50cmltKCk7XG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBIaWdoY2hhcnRzIG1vZHVsZSBuYW1lIGJhc2VkIG9uIHRoZSBzY3JpcHRQYXRoLlxuICovXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xuICByZXR1cm4gc2NyaXB0UGF0aC5yZXBsYWNlKFxuICAgIC8oLiopXFwvfCguKiltb2R1bGVzXFwvfHN0b2NrXFwvKC4qKWluZGljYXRvcnNcXC98bWFwc1xcLyguKiltb2R1bGVzXFwvL2dpLFxuICAgICcnXG4gICk7XG59O1xuXG4vKipcbiAqIFNhdmVzIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uIGFuZCBmZXRjaGVkIG1vZHVsZXMgdG8gdGhlIGNhY2hlIG1hbmlmZXN0XG4gKiBmaWxlLlxuICpcbiAqIEBwYXJhbSB7b2JqZWN0fSBjb25maWcgLSBIaWdoY2hhcnRzLXJlbGF0ZWQgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcbiAqIGZldGNoZWQgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIHVzZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXG4gKiB0aGUgY2FjaGUgbWFuaWZlc3QuXG4gKi9cbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XG4gIGNvbnN0IG5ld01hbmlmZXN0ID0ge1xuICAgIHZlcnNpb246IGNvbmZpZy52ZXJzaW9uLFxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XG4gIH07XG5cbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcbiAgY2FjaGUuYWN0aXZlTWFuaWZlc3QgPSBuZXdNYW5pZmVzdDtcblxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcbiAgdHJ5IHtcbiAgICB3cml0ZUZpbGVTeW5jKFxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXG4gICAgICBKU09OLnN0cmluZ2lmeShuZXdNYW5pZmVzdCksXG4gICAgICAndXRmOCdcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHNjcmlwdCAtIEEgcGF0aCB0byBzY3JpcHQgdG8gZ2V0LlxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcbiAqIHRvIHVzZSBmb3IgYSByZXF1ZXN0LlxuICogQHBhcmFtIHtPYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxuICogQHBhcmFtIHtib29sZWFufSBzaG91bGRUaHJvd0Vycm9yIC0gQSBmbGFnIHRvIGluZGljYXRlIGlmIHRoZSBlcnJvciBzaG91bGQgYmVcbiAqIHRocm93bi4gVGhpcyBzaG91bGQgYmUgdXNlZCBvbmx5IGZvciB0aGUgY29yZSBzY3JpcHRzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHRleHQgcmVwcmVzZW50YXRpb25cbiAqIG9mIHRoZSBmZXRjaGVkIHNjcmlwdC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGEgcHJvYmxlbSB3aXRoXG4gKiBmZXRjaGluZyB0aGUgc2NyaXB0LlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hBbmRQcm9jZXNzU2NyaXB0ID0gYXN5bmMgKFxuICBzY3JpcHQsXG4gIHJlcXVlc3RPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlcyxcbiAgc2hvdWxkVGhyb3dFcnJvciA9IGZhbHNlXG4pID0+IHtcbiAgLy8gR2V0IHJpZCBvZiB0aGUgLmpzIGZyb20gdGhlIGN1c3RvbSBzdHJpbmdzXG4gIGlmIChzY3JpcHQuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XG4gIH1cblxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XG5cbiAgLy8gRmV0Y2ggdGhlIHNjcmlwdFxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgLy8gSWYgT0ssIHJldHVybiBpdHMgdGV4dCByZXByZXNlbnRhdGlvblxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XG4gICAgaWYgKGZldGNoZWRNb2R1bGVzKSB7XG4gICAgICBjb25zdCBtb2R1bGVOYW1lID0gZXh0cmFjdE1vZHVsZU5hbWUoc2NyaXB0KTtcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcbiAgfVxuXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24gKHN0YXR1cyBjb2RlOiAke3Jlc3BvbnNlLnN0YXR1c0NvZGV9KS5gXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XG4gIH0gZWxzZSB7XG4gICAgbG9nKFxuICAgICAgMixcbiAgICAgIGBbY2FjaGVdIENvdWxkIG5vdCBmZXRjaCB0aGUgJHtzY3JpcHR9LmpzLiBUaGUgc2NyaXB0IG1pZ2h0IG5vdCBleGlzdCBpbiB0aGUgcmVxdWVzdGVkIHZlcnNpb24uYFxuICAgICk7XG4gIH1cblxuICByZXR1cm4gJyc7XG59O1xuXG4vKipcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvcmVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBjb3JlIHNjcmlwdHMgdG8gZmV0Y2guXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21TY3JpcHRzIC0gQXJyYXkgb2YgY3VzdG9tIHNjcmlwdCBwYXRocyB0byBmZXRjaFxuICogKGZ1bGwgVVJMcykuXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcbiAqIGEgcmVxdWVzdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBUaGUgZmV0Y2hlZCBzY3JpcHRzIGNvbnRlbnQgam9pbmVkLlxuICovXG5leHBvcnQgY29uc3QgZmV0Y2hTY3JpcHRzID0gYXN5bmMgKFxuICBjb3JlU2NyaXB0cyxcbiAgbW9kdWxlU2NyaXB0cyxcbiAgY3VzdG9tU2NyaXB0cyxcbiAgcHJveHlPcHRpb25zLFxuICBmZXRjaGVkTW9kdWxlc1xuKSA9PiB7XG4gIC8vIENvbmZpZ3VyZSBwcm94eSBpZiBleGlzdHNcbiAgbGV0IHByb3h5QWdlbnQ7XG4gIGNvbnN0IHsgaG9zdCwgcG9ydCwgdXNlcm5hbWUsIHBhc3N3b3JkIH0gPSBwcm94eU9wdGlvbnM7XG5cbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XG4gIGlmIChob3N0ICYmIHBvcnQpIHtcbiAgICB0cnkge1xuICAgICAgcHJveHlBZ2VudCA9IG5ldyBIdHRwc1Byb3h5QWdlbnQoe1xuICAgICAgICBob3N0LFxuICAgICAgICBwb3J0LFxuICAgICAgICAuLi4odXNlcm5hbWUgJiYgcGFzc3dvcmQgPyB7IHVzZXJuYW1lLCBwYXNzd29yZCB9IDoge30pXG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcbiAgICAgICAgZXJyb3JcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxuICAgID8ge1xuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxuICAgICAgfVxuICAgIDoge307XG5cbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxuICAgICksXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxuICAgICksXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXG4gICAgKVxuICBdO1xuXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKFxuICBoaWdoY2hhcnRzT3B0aW9ucyxcbiAgcHJveHlPcHRpb25zLFxuICBzb3VyY2VQYXRoXG4pID0+IHtcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XG4gIGNvbnN0IGhjVmVyc2lvbiA9IHZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICF2ZXJzaW9uID8gJycgOiBgJHt2ZXJzaW9ufS9gO1xuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xuXG4gIGxvZyhcbiAgICAzLFxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcbiAgKTtcblxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xuICB0cnkge1xuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXG4gICAgICBbXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufSR7Y31gKVxuICAgICAgXSxcbiAgICAgIFtcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XG4gICAgICAgICAgbSA9PT0gJ21hcCdcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxuICAgICAgICAgICAgOiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxuICAgICAgICApLFxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcbiAgICAgICAgICAoaSkgPT4gYCR7Y2RuVVJMfXN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWBcbiAgICAgICAgKVxuICAgICAgXSxcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXG4gICAgICBwcm94eU9wdGlvbnMsXG4gICAgICBmZXRjaGVkTW9kdWxlc1xuICAgICk7XG5cbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XG5cbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5ld1ZlcnNpb24gLSBUaGUgbmV3IEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSBhcHBsaWVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXG4gKiBjb25maWd1cmF0aW9uIHdpdGggdGhlIG5ldyB2ZXJzaW9uLCBvciBmYWxzZSBpZiBubyBhcHBsaWVkIGNvbmZpZ3VyYXRpb25cbiAqIGV4aXN0cy5cbiAqL1xuZXhwb3J0IGNvbnN0IHVwZGF0ZVZlcnNpb24gPSBhc3luYyAobmV3VmVyc2lvbikgPT4ge1xuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xuICAgIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcbiAgfVxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xufTtcblxuLyoqXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcbiAqIGFuZCB1cGRhdGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxuICovXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IHsgaGlnaGNoYXJ0cywgc2VydmVyIH0gPSBvcHRpb25zO1xuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xuXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XG5cbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoKTtcblxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xuXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xuICAgIH1cblxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHM7XG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XG5cbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMixcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcbiAgICAgICk7XG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXG4gICAgICApO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xuICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgIDIsXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcblxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xuXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xuXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XG5cbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xuXG5leHBvcnQgY29uc3QgaGlnaGNoYXJ0cyA9ICgpID0+IGNhY2hlLnNvdXJjZXM7XG5cbmV4cG9ydCBjb25zdCB2ZXJzaW9uID0gKCkgPT4gY2FjaGUuaGNWZXJzaW9uO1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXG4gIGdldENhY2hlUGF0aCxcbiAgdXBkYXRlVmVyc2lvbixcbiAgZ2V0Q2FjaGUsXG4gIGhpZ2hjaGFydHMsXG4gIHZlcnNpb25cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cblxuLyoqXG4gKiBTZXR0aW5nIHRoZSBhbmltT2JqZWN0LiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgY2hhcnQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zLlxuICogQHBhcmFtIHtib29sZWFufSBkaXNwbGF5RXJyb3JzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciB0byBkaXNwbGF5IGVycm9ycy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyaWdnZXJFeHBvcnQoY2hhcnRPcHRpb25zLCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSB7XG4gIC8vIERpc3BsYXkgZXJyb3JzIGZsYWcgdGFrZW4gZnJvbSBjaGFydCBvcHRpb25zIG5hZCBkZWJ1Z2dlciBtb2R1bGVcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcblxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XG5cbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBzZXRPcHRpb25zIHVzYWdlcyBpbiBvcmRlciB0b1xuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xuXG4gIC8vIEJ5IGRlZmF1bHQgYW5pbWF0aW9uIGlzIGRpc2FibGVkXG4gIGNvbnN0IGNoYXJ0ID0ge1xuICAgIGFuaW1hdGlvbjogZmFsc2VcbiAgfTtcblxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcbiAgaWYgKG9wdGlvbnMuZXhwb3J0LnN0ckluaikge1xuICAgIGNoYXJ0LmhlaWdodCA9IGNoYXJ0T3B0aW9ucy5jaGFydC5oZWlnaHQ7XG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XG4gIH1cblxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cbiAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSBmYWxzZTtcbiAgd3JhcChIaWdoY2hhcnRzLkNoYXJ0LnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgdXNlck9wdGlvbnMsIGNiKSB7XG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXG4gICAgdXNlck9wdGlvbnMgPSBtZXJnZSh1c2VyT3B0aW9ucywge1xuICAgICAgZXhwb3J0aW5nOiB7XG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXG4gICAgICB9LFxuICAgICAgcGxvdE9wdGlvbnM6IHtcbiAgICAgICAgc2VyaWVzOiB7XG4gICAgICAgICAgbGFiZWw6IHtcbiAgICAgICAgICAgIGVuYWJsZWQ6IGZhbHNlXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXG4gICAgICAgIGh0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL2hpZ2hjaGFydHMvYmxvYi8zYWQ0MzBhMzUzYjgwNTZiOWU3NjRhYTRlNWNkNjgyOGFhNDc5ZGIyL2pzL3BhcnRzL0NoYXJ0LmpzI0wyNDFcbiAgICAgICAgKi9cbiAgICAgIHRvb2x0aXA6IHt9XG4gICAgfSk7XG5cbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcbiAgICAgIHNlcmllcy5hbmltYXRpb24gPSBmYWxzZTtcbiAgICB9KTtcblxuICAgIC8vIEFkZCBmbGFnIHRvIGtub3cgaWYgY2hhcnQgcmVuZGVyIGhhcyBiZWVuIGNhbGxlZC5cbiAgICBpZiAoIXdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIpIHtcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XG4gICAgICAgIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gdHJ1ZTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW3VzZXJPcHRpb25zLCBjYl0pO1xuICB9KTtcblxuICB3cmFwKEhpZ2hjaGFydHMuU2VyaWVzLnByb3RvdHlwZSwgJ2luaXQnLCBmdW5jdGlvbiAocHJvY2VlZCwgY2hhcnQsIG9wdGlvbnMpIHtcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xuICB9KTtcblxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xuICBjb25zdCB1c2VyT3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0LnN0cklualxuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmV4cG9ydC5zdHJJbmp9YCkoKVxuICAgIDogY2hhcnRPcHRpb25zO1xuXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xuICAgIG5ldyBGdW5jdGlvbignb3B0aW9ucycsIG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkodXNlck9wdGlvbnMpO1xuICB9XG5cbiAgLy8gTWVyZ2UgdGhlIGdsb2JhbE9wdGlvbnMsIHRoZW1lT3B0aW9ucywgb3B0aW9ucyBmcm9tIHRoZSB3cmFwcGVkXG4gIC8vIHNldE9wdGlvbnMgZnVuY3Rpb24gYW5kIHVzZXIgb3B0aW9ucyB0byBjcmVhdGUgdGhlIGZpbmFsIG9wdGlvbnMgb2JqZWN0XG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxuICAgIGZhbHNlLFxuICAgIEpTT04ucGFyc2Uob3B0aW9ucy5leHBvcnQudGhlbWVPcHRpb25zKSxcbiAgICB1c2VyT3B0aW9ucyxcbiAgICAvLyBQbGFjZWQgaXQgaGVyZSBpbnN0ZWFkIGluIHRoZSBpbml0IGJlY2F1c2Ugb2YgdGhlIHNpemUgaXNzdWVzXG4gICAgeyBjaGFydCB9XG4gICk7XG5cbiAgY29uc3QgZmluYWxDYWxsYmFjayA9IG9wdGlvbnMuY3VzdG9tTG9naWMuY2FsbGJhY2tcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXG4gICAgOiB1bmRlZmluZWQ7XG5cbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC5nbG9iYWxPcHRpb25zKTtcbiAgaWYgKGdsb2JhbE9wdGlvbnMpIHtcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xuICB9XG5cbiAgbGV0IGNvbnN0ciA9IG9wdGlvbnMuZXhwb3J0LmNvbnN0ciB8fCAnY2hhcnQnO1xuICBjb25zdHIgPSB0eXBlb2YgSGlnaGNoYXJ0c1tjb25zdHJdICE9PSAndW5kZWZpbmVkJyA/IGNvbnN0ciA6ICdjaGFydCc7XG5cbiAgSGlnaGNoYXJ0c1tjb25zdHJdKCdjb250YWluZXInLCBmaW5hbE9wdGlvbnMsIGZpbmFsQ2FsbGJhY2spO1xuXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIHNldE9wdGlvbnMgd2FzIHVzZWQgaW4gdGhlIGN1c3RvbUNvZGUpXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcbiAgICB9XG4gIH1cblxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcblxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcbn1cbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xuXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLCAndXRmOCcpO1xuXG5sZXQgYnJvd3NlcjtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW5cbiAqIGNyZWF0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXQoKSB7XG4gIGlmICghYnJvd3Nlcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcbiAgfVxuICByZXR1cm4gYnJvd3Nlcjtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbWF4IHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGUocHVwcGV0ZWVyQXJncykge1xuICAvLyBHZXQgZGVidWcgYW5kIG90aGVyIG9wdGlvbnNcbiAgY29uc3QgeyBwdXBwZXRlZXI6IHB1cHBldGVlck9wdGlvbnMsIGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xuXG4gIC8vIEdldCB0aGUgZGVidWcgb3B0aW9uc1xuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xuXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcbiAgICB1c2VyRGF0YURpcjogcHVwcGV0ZWVyT3B0aW9ucy50ZW1wRGlyIHx8ICcuL3RtcC8nLFxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxuICB9O1xuXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgY29uc3QgbWF4VHJpZXMgPSAyNTtcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xuXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxuICAgICAgICApO1xuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIC8vIFRoaXMgaXNuJ3QgYSBmdWxsIGVycm9yIHlldCBhcyBwdXBwZXRlZXIgc29tZXRpbWVzIHRha2VzIHRpbWUgdG9cbiAgICAgICAgLy8gaW5pdGlhbGl6ZSBwcm9wZXJseS5cbiAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgIDIsXG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgYFticm93c2VyXSBGYWlsZWQgdG8gbGF1bmNoIGEgYnJvd3NlciBpbnN0YW5jZSAtIHJldHJ5aW5nIChhdHRlbXB0ICR7dHJ5Q291bnR9LyR7bWF4VHJpZXN9KS5gXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gUmV0cnkgdG8gbGF1bmNoIGJyb3dzZXIgdW50aWwgcmVhY2hpbmcgbWF4IGF0dGVtcHRzXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XG4gICAgICAgICAgbG9nKFxuICAgICAgICAgICAgMyxcbiAgICAgICAgICAgIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKGF0dGVtcHQgJHt0cnlDb3VudH0vJHttYXhUcmllc30pLmBcbiAgICAgICAgICApO1xuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLy4uLiBub3cgaXQncyBhbiBlcnJvciwgd2hpY2ggaXMgY2F1Z2h0IGJ5IHRoZSBjYWxsZXJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH07XG5cbiAgICB0cnkge1xuICAgICAgYXdhaXQgb3BlbigpO1xuXG4gICAgICAvLyBTaGVsbCBtb2RlIGluZm9ybVxuICAgICAgaWYgKGxhdW5jaE9wdGlvbnMuaGVhZGxlc3MgPT09ICdzaGVsbCcpIHtcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xuICAgICAgfVxuXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxuICAgICAgaWYgKGVuYWJsZWREZWJ1Zykge1xuICAgICAgICBsb2coMywgYFticm93c2VyXSBMYXVuY2hlZCBicm93c2VyIGluIGRlYnVnIG1vZGUuYCk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICB9XG5cbiAgICBpZiAoIWJyb3dzZXIpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxuICByZXR1cm4gYnJvd3Nlcjtcbn1cblxuLyoqXG4gKiBDbG9zZXMgdGhlIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIGlmIGl0IGlzIGNvbm5lY3RlZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0cnVlIGFmdGVyIHRoZSBicm93c2VyXG4gKiBpcyBjbG9zZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbG9zZSgpIHtcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgd2hlbiBjb25ubmVjdGVkXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcbiAgICBhd2FpdCBicm93c2VyLmNsb3NlKCk7XG4gIH1cbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXG4gKlxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cbiAqXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxuICpcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UoKSB7XG4gIGlmICghYnJvd3Nlcikge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBhIHBhZ2VcbiAgY29uc3QgcGFnZSA9IGF3YWl0IGJyb3dzZXIubmV3UGFnZSgpO1xuXG4gIC8vIERpc2FibGUgY2FjaGVcbiAgYXdhaXQgcGFnZS5zZXRDYWNoZUVuYWJsZWQoZmFsc2UpO1xuXG4gIC8vIFNldCB0aGUgY29udGVudFxuICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcblxuICAvLyBTZXQgcGFnZSBldmVudHNcbiAgc2V0UGFnZUV2ZW50cyhwYWdlKTtcblxuICByZXR1cm4gcGFnZTtcbn1cblxuLyoqXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIGJlIGNsZWFyZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGhhcmRSZXNldCAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXG4gKiBzdHJ1Y3R1cmUuXG4gKlxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcbiAgdHJ5IHtcbiAgICBpZiAocGFnZSAmJiAhcGFnZS5pc0Nsb3NlZCgpKSB7XG4gICAgICBpZiAoaGFyZFJlc2V0KSB7XG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXG4gICAgICAgIGF3YWl0IHBhZ2UuZ290bygnYWJvdXQ6YmxhbmsnLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xuXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cbiAgICAgICAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcbiAgICAgICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nV2l0aFN0YWNrKFxuICAgICAgMixcbiAgICAgIGVycm9yLFxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xuICAgICk7XG4gIH1cblxuICByZXR1cm4gZmFsc2U7XG59XG5cbi8qKlxuICogQWRkcyBjdXN0b20gSlMgYW5kIENTUyByZXNvdXJjZXMgdG8gYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkXG4gKiBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byB3aGljaCByZXNvdXJjZXMgd2lsbCBiZVxuICogYWRkZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXG4gKiByZXNvdXJjZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5XG4gIGNvbnN0IGluamVjdGVkUmVzb3VyY2VzID0gW107XG5cbiAgLy8gVXNlIHJlc291cmNlc1xuICBjb25zdCByZXNvdXJjZXMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcztcbiAgaWYgKHJlc291cmNlcykge1xuICAgIGNvbnN0IGluamVjdGVkSnMgPSBbXTtcblxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcbiAgICBpZiAocmVzb3VyY2VzLmpzKSB7XG4gICAgICBpbmplY3RlZEpzLnB1c2goe1xuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIExvYWQgc2NyaXB0cyBmcm9tIGFsbCBjdXN0b20gZmlsZXNcbiAgICBpZiAocmVzb3VyY2VzLmZpbGVzKSB7XG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XG4gICAgICAgIGNvbnN0IGlzTG9jYWwgPSAhZmlsZS5zdGFydHNXaXRoKCdodHRwJykgPyB0cnVlIDogZmFsc2U7XG5cbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcbiAgICAgICAgaW5qZWN0ZWRKcy5wdXNoKFxuICAgICAgICAgIGlzTG9jYWxcbiAgICAgICAgICAgID8ge1xuICAgICAgICAgICAgICAgIGNvbnRlbnQ6IHJlYWRGaWxlU3luYyhmaWxlLCAndXRmOCcpXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIDoge1xuICAgICAgICAgICAgICAgIHVybDogZmlsZVxuICAgICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZm9yIChjb25zdCBqc1Jlc291cmNlIG9mIGluamVjdGVkSnMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIEpTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgICB9XG4gICAgfVxuICAgIGluamVjdGVkSnMubGVuZ3RoID0gMDtcblxuICAgIC8vIExvYWQgQ1NTXG4gICAgY29uc3QgaW5qZWN0ZWRDc3MgPSBbXTtcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xuICAgICAgbGV0IGNzc0ltcG9ydHMgPSByZXNvdXJjZXMuY3NzLm1hdGNoKC9AaW1wb3J0XFxzKihbXjtdKik7L2cpO1xuICAgICAgaWYgKGNzc0ltcG9ydHMpIHtcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXG4gICAgICAgIGZvciAobGV0IGNzc0ltcG9ydFBhdGggb2YgY3NzSW1wb3J0cykge1xuICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoKSB7XG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxuICAgICAgICAgICAgICAucmVwbGFjZSgndXJsKCcsICcnKVxuICAgICAgICAgICAgICAucmVwbGFjZSgnQGltcG9ydCcsICcnKVxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC8nL2csICcnKVxuICAgICAgICAgICAgICAucmVwbGFjZSgvOy8sICcnKVxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxuICAgICAgICAgICAgICAudHJpbSgpO1xuXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXG4gICAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aC5zdGFydHNXaXRoKCdodHRwJykpIHtcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcbiAgICAgICAgICAgICAgICBwYXRoOiBwYXRoLmpvaW4oX19kaXJuYW1lLCBjc3NJbXBvcnRQYXRoKVxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gVGhlIHJlc3Qgb2YgdGhlIENTUyBzZWN0aW9uIHdpbGwgYmUgY29udGVudCBieSBub3dcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuY3NzLnJlcGxhY2UoL0BpbXBvcnRcXHMqKFteO10qKTsvZywgJycpIHx8ICcgJ1xuICAgICAgfSk7XG5cbiAgICAgIGZvciAoY29uc3QgY3NzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRDc3MpIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgQ1NTIHJlc291cmNlIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGluamVjdGVkQ3NzLmxlbmd0aCA9IDA7XG4gICAgfVxuICB9XG4gIHJldHVybiBpbmplY3RlZFJlc291cmNlcztcbn1cblxuLyoqXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcbiAqIGluamVjdGVkIHJlc291cmNlcyBhbmQgcmVzZXRzIENTUyBhbmQgc2NyaXB0IHRhZ3Mgb24gdGhlIHBhZ2UuIEFkZGl0aW9uYWxseSxcbiAqIGl0IGRlc3Ryb3lzIHByZXZpb3VzbHkgZXhpc3RpbmcgY2hhcnRzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCBmcm9tIHdoaWNoIHJlc291cmNlcyB3aWxsXG4gKiBiZSBjbGVhcmVkLlxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xuICogdG8gYmUgY2xlYXJlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xuICB0cnkge1xuICAgIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcbiAgICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcbiAgICB9XG5cbiAgICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXG4gICAgYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XG4gICAgICAvLyBXZSBhcmUgbm90IGd1YXJhbnRlZWQgdGhhdCBIaWdoY2hhcnRzIGlzIGxvYWRlZCwgZSxnLCB3aGVuIGRvaW5nIFNWR1xuICAgICAgLy8gZXhwb3J0c1xuICAgICAgaWYgKHR5cGVvZiBIaWdoY2hhcnRzICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XG5cbiAgICAgICAgLy8gQ2hlY2sgaW4gYW55IGFscmVhZHkgZXhpc3RpbmcgY2hhcnRzXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG9sZENoYXJ0cykgJiYgb2xkQ2hhcnRzLmxlbmd0aCkge1xuICAgICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xuICAgICAgICAgIGZvciAoY29uc3Qgb2xkQ2hhcnQgb2Ygb2xkQ2hhcnRzKSB7XG4gICAgICAgICAgICBvbGRDaGFydCAmJiBvbGRDaGFydC5kZXN0cm95KCk7XG4gICAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICAgIEhpZ2hjaGFydHMuY2hhcnRzLnNoaWZ0KCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xuXG4gICAgICAvLyBSZW1vdmUgdGFnc1xuICAgICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcbiAgICAgICAgLi4uc2NyaXB0c1RvUmVtb3ZlLFxuICAgICAgICAuLi5zdHlsZXNUb1JlbW92ZSxcbiAgICAgICAgLi4ubGlua3NUb1JlbW92ZVxuICAgICAgXSkge1xuICAgICAgICBlbGVtZW50LnJlbW92ZSgpO1xuICAgICAgfVxuICAgIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgcGFnZSdzIHJlc291cmNlcy5gKTtcbiAgfVxufVxuXG4vKipcbiAqIFNldHMgdGhlIGNvbnRlbnQgZm9yIGEgUHVwcGV0ZWVyIFBhZ2UgdXNpbmcgYSBwcmVkZWZpbmVkIHRlbXBsYXRlXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcbiAqIGFuZCBkaXNwbGF5IGVycm9ycyBmcm9tIHRoZSB3aW5kb3cgY29udGV4dC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XG4gKiBpcyBiZWluZyBzZXQuXG4gKi9cbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcbiAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHRlbXBsYXRlLCB7IHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnIH0pO1xuXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXG4gIGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKHsgcGF0aDogYCR7Z2V0Q2FjaGVQYXRoKCl9L3NvdXJjZXMuanNgIH0pO1xuXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoc2V0dXBIaWdoY2hhcnRzKTtcbn1cblxuLyoqXG4gKiBTZXQgZXZlbnRzIGZvciBhIFB1cHBldGVlciBQYWdlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byBzZXQgZXZlbnRzIHRvLlxuICovXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcbiAgLy8gR2V0IGRlYnVnIG9wdGlvbnNcbiAgY29uc3QgeyBkZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpO1xuXG4gIC8vIFNldCB0aGUgY29uc29sZSBsaXN0ZW5lciwgaWYgbmVlZGVkXG4gIGlmIChkZWJ1Zy5lbmFibGUgJiYgZGVidWcubGlzdGVuVG9Db25zb2xlKSB7XG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XG4gICAgICBjb25zb2xlLmxvZyhgW2RlYnVnXSAke21lc3NhZ2UudGV4dCgpfWApO1xuICAgIH0pO1xuICB9XG5cbiAgLy8gU2V0IHRoZSBwYWdlZXJyb3IgbGlzdGVuZXJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XG4gICAgLy8gSXQgd291bGQgc2VlbSBsaWtlIHRoaXMgbWF5IGZpcmUgYXQgdGhlIHNhbWUgdGltZSBvciBzaG9ydGx5IGJlZm9yZVxuICAgIC8vIGEgcGFnZSBpcyBjbG9zZWQuXG4gICAgaWYgKHBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cbiAgICBhd2FpdCBwYWdlLiRldmFsKFxuICAgICAgJyNjb250YWluZXInLFxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgaWYgKHdpbmRvdy5fZGlzcGxheUVycm9ycykge1xuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXG4gICAgKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZ2V0LFxuICBjcmVhdGUsXG4gIGNsb3NlLFxuICBuZXdQYWdlLFxuICBjbGVhclBhZ2UsXG4gIGFkZFBhZ2VSZXNvdXJjZXMsXG4gIGNsZWFyUGFnZVJlc291cmNlc1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuaW1wb3J0IHsgZ2V0Q2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudCB3aXRoXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcbiAqIHgsIHksIHdpZHRoLCBhbmQgaGVpZ2h0IHByb3BlcnRpZXMuXG4gKi9cbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cbiAgcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHJldHVybiB7XG4gICAgICB4LFxuICAgICAgeSxcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXG4gICAgfTtcbiAgfSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXG4gKiBpbiBtaWxsaXNlY29uZHMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGltYWdlIGJ1ZmZlciBvciByZWplY3RpbmdcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXG4gKi9cbmNvbnN0IGNyZWF0ZUltYWdlID0gKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwLCByYXN0ZXJpemF0aW9uVGltZW91dCkgPT5cbiAgUHJvbWlzZS5yYWNlKFtcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xuICAgICAgdHlwZSxcbiAgICAgIGVuY29kaW5nLFxuICAgICAgY2xpcCxcbiAgICAgIGNhcHR1cmVCZXlvbmRWaWV3cG9ydDogdHJ1ZSxcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcbiAgICAgIG9wdGltaXplRm9yU3BlZWQ6IHRydWUsXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXG5cbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxuICAgICAgLy8gZm9ybWF0IGlzIFBOR1xuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcbiAgICB9KSxcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cbiAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxuICAgICAgKVxuICAgIClcbiAgXSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXG4gKiBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXG4gKi9cbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcbiAgcGFnZSxcbiAgaGVpZ2h0LFxuICB3aWR0aCxcbiAgZW5jb2RpbmcsXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0XG4pID0+IHtcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcblxuICByZXR1cm4gcGFnZS5wZGYoe1xuICAgIC8vIFRoaXMgd2lsbCByZW1vdmUgYW4gZXh0cmEgZW1wdHkgcGFnZSBpbiBQREYgZXhwb3J0c1xuICAgIGhlaWdodDogaGVpZ2h0ICsgMSxcbiAgICB3aWR0aCxcbiAgICBlbmNvZGluZyxcbiAgICB0aW1lb3V0OiByYXN0ZXJpemF0aW9uVGltZW91dCB8fCAxNTAwXG4gIH0pO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cbiAqL1xuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xuXG4vKipcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cbiAqL1xuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+IHtcbiAgLy8gR2V0IHJpZCBvZiB0aGUgcmVkdW5hbnQgc3RyaW5nIGRhdGFcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBudWxsO1xuICBvcHRpb25zLmV4cG9ydC5pbmZpbGUgPSBudWxsO1xuXG4gIC8vIEdldCB0aGUgc2l6ZSBvZiB0aGUgZXhwb3J0IGlucHV0XG4gIGNvbnN0IHRvdGFsU2l6ZSA9IEJ1ZmZlci5ieXRlTGVuZ3RoKFxuICAgIG9wdGlvbnMuZXhwb3J0Py5zdHJJbmogPyBvcHRpb25zLmV4cG9ydD8uc3RySW5qIDogSlNPTi5zdHJpbmdpZnkoY2hhcnQpLFxuICAgICd1dGYtOCdcbiAgKTtcblxuICAvLyBMb2cgdGhlIHNpemUgaW4gTUJcbiAgbG9nKFxuICAgIDQsXG4gICAgYFtleHBvcnRdIFRoZSBjdXJyZW50IHRvdGFsIHNpemUgb2YgZGF0YSBwYXNzZWQgdG8gYSBwYWdlIGlzIGFyb3VuZCAkeyhcbiAgICAgIHRvdGFsU2l6ZSAvXG4gICAgICAoMTAyNCAqIDEwMjQpXG4gICAgKS50b0ZpeGVkKDIpfSBNQmBcbiAgKTtcblxuICAvLyBDaGVjayB0aGUgc2l6ZSBvZiBkYXRhIHBhc3NlZCB0byB0aGUgcGFnZVxuICBpZiAodG90YWxTaXplID49IDEwMCAqIDEwMjQgKiAxMDI0KSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKGBbZXhwb3J0XSBUaGUgZGF0YSBwYXNzZWQgdG8gYSBwYWdlIGV4Y2VlZGVkIDEwME1CLmApO1xuICB9XG5cbiAgLy8gVHJpZ2dlciB0aGUgSGlnaGNoYXJ0cyBjaGFydCBjcmVhdGlvblxuICByZXR1cm4gcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XG59O1xuXG4vKipcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IG9yIFNWRyBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmcgfCBCdWZmZXIgfCBFeHBvcnRFcnJvcj59IFByb21pc2UgcmVzb2x2aW5nIHRvXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcblxuICB0cnkge1xuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XG5cbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxuICAgICAgZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xuXG4gICAgbGV0IGlzU1ZHO1xuICAgIGlmIChcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXG4gICAgKSB7XG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xuXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAgIHJldHVybiBjaGFydDtcbiAgICAgIH1cblxuICAgICAgaXNTVkcgPSB0cnVlO1xuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcblxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcbiAgICAgICAgICBwYWdlLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNoYXJ0OiB7XG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XG5cbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXG4gICAgaW5qZWN0ZWRSZXNvdXJjZXMgPSBhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpO1xuXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxuICAgICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWVzIGNvcnJlY3RseSBzY2FsZWRcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XG5cbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xuXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjaGFydEhlaWdodCxcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcbiAgICAgICAgICB9O1xuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XG5cbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxuICAgICAgICAgICAgY2hhcnRXaWR0aFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmFicyhcbiAgICAgIE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KVxuICAgICk7XG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguYWJzKFxuICAgICAgTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKVxuICAgICk7XG5cbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcblxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXG4gICAgfSk7XG5cbiAgICBsZXQgZGF0YTtcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgICAgLy8gU1ZHXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcbiAgICAgIC8vIFBORyBvciBKUEVHXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXG4gICAgICAgIHBhZ2UsXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcbiAgICAgICAgJ2Jhc2U2NCcsXG4gICAgICAgIHtcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9LFxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xuICAgICAgLy8gUERGXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKFxuICAgICAgICBwYWdlLFxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcbiAgICAgICAgdmlld3BvcnRXaWR0aCxcbiAgICAgICAgJ2Jhc2U2NCcsXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcbiAgICByZXR1cm4gZXJyb3I7XG4gIH1cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcblxuZXhwb3J0IGRlZmF1bHQgKGNoYXJ0KSA9PiBgXG48IURPQ1RZUEUgaHRtbD5cbjxodG1sIGxhbmc9J2VuLVVTJz5cbiAgPGhlYWQ+XG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxuICA8L2hlYWQ+XG4gIDxzdHlsZT5cbiAgICAke2Nzc1RlbXBsYXRlKCl9XG4gIDwvc3R5bGU+XG4gIDxib2R5PlxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cbiAgICAgICR7Y2hhcnR9XG4gICAgPC9kaXY+XG4gIDwvYm9keT5cbjwvaHRtbD5cblxuYDtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7XG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXG4gIG5ld1BhZ2UsXG4gIGNsZWFyUGFnZVxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8vIFRoZSBwb29sIGluc3RhbmNlXG5sZXQgcG9vbCA9IGZhbHNlO1xuXG4vLyBQb29sIHN0YXRpc3RpY3NcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcbiAgdGltZVNwZW50OiAwLFxuICBkcm9wcGVkRXhwb3J0czogMCxcbiAgc3BlbnRBdmVyYWdlOiAwXG59O1xuXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xuXG5jb25zdCBmYWN0b3J5ID0ge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxuICAgKlxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXG4gICAqXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XG4gICAqIHBhZ2UuXG4gICAqL1xuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xuXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICB0cnkge1xuICAgICAgcGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcblxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xuICAgICAgfVxuXG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcbiAgICAgICAgfSBtcy5gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkLFxuICAgICAgcGFnZSxcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXG4gICAgfTtcbiAgfSxcblxuICAvKipcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcbiAgICogdGhlIHdvcmsgbGltaXQuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cbiAgICpcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxuICAgKi9cbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcbiAgICAvLyBOT1RFOiBJbiBjZXJ0YWluIGNhc2VzIGFjcXVpcmluZyB0aHJvd3MgYSBUYXJnZXRDbG9zZUVycm9yLCB3aGljaCBtYXlcbiAgICAvLyAgICAgICBiZSBjYXVzZWQgYnkgdHdvIHRoaW5nczpcbiAgICAvLyAgICAgICAgIC0gVGhlIHBhZ2UgaXMgY2xvc2VkIGFuZCBhdHRlbXB0ZWQgdG8gYmUgcmV1c2VkLlxuICAgIC8vICAgICAgICAgLSBMb3N0IGNvbnRhY3Qgd2l0aCB0aGUgYnJvd3NlclxuICAgIC8vICAgICAgIFdoYXQgd2UncmUgc2VlaW5nIGluIGxvZ3MgaXMgdGhhdCBzdWNjZXNzaXZlIGV4cG9ydHMgdHlwaWNhbGx5XG4gICAgLy8gICAgICAgc3VjY2VlZHMsIGFuZCB0aGUgc2VydmVyIHJlY292ZXJzLCBpbmRpY2F0aW5nIHRoYXQgaXQncyBsaWtlbHlcbiAgICAvLyAgICAgICB0aGUgZmlyc3QgY2FzZS4gVGhpcyBpcyBhbiBhdHRlbXB0IGF0IGFsbGlldmF0aW5nIHRoZSBpc3N1ZSBieVxuICAgIC8vICAgICAgIHNpbXBseSBub3QgdmFsaWRhdGluZyB0aGUgd29ya2VyIGlmIHRoZSBwYWdlIGlzIG51bGwgb3IgY2xvc2VkLlxuICAgIC8vXG4gICAgLy8gICAgICAgVGhlIGFjdHVhbCByZXN1bHQgZnJvbSB3aGVuIHRoaXMgaGFwcGVuZWQsIHdhcyB0aGF0IGEgd29ya2VyIHdvdWxkXG4gICAgLy8gICAgICAgYmUgY29tcGxldGVseSBsb2NrZWQsIHN0b3BwaW5nIGl0IGZyb20gYmVpbmcgYWNxdWlyZWQgdW50aWxcbiAgICAvLyAgICAgICBpdHMgd29yayBjb3VudCByZWFjaGVkIHRoZSBsaW1pdC5cbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlIHx8IHdvcmtlckhhbmRsZS5wYWdlPy5pc0Nsb3NlZCgpKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcbiAgICAgICsrd29ya2VySGFuZGxlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XG4gICAgKSB7XG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gV29ya2VyIGZhaWxlZCB2YWxpZGF0aW9uOiBleGNlZWRlZCB3b3JrIGxpbWl0IChsaW1pdCBpcyAke3Bvb2xDb25maWcud29ya0xpbWl0fSkuYFxuICAgICAgKTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH0sXG5cbiAgLyoqXG4gICAqIERlc3Ryb3lzIGEgd29ya2VyIGVudHJ5IGluIHRoZSBleHBvcnQgcG9vbCwgY2xvc2luZyBpdHMgYXNzb2NpYXRlZCBwYWdlLlxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXG4gICAqIHRoZSB3b3JrZXIncyBJRCBhbmQgYSByZWZlcmVuY2UgdG8gdGhlIGJyb3dzZXIgcGFnZS5cbiAgICovXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcbiAgICBsb2coMywgYFtwb29sXSBEZXN0cm95aW5nIHBvb2wgZW50cnkgJHt3b3JrZXJIYW5kbGUuaWR9LmApO1xuXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlICYmICF3b3JrZXJIYW5kbGUucGFnZS5pc0Nsb3NlZCgpKSB7XG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGxvZzogKG1lc3NhZ2UsIGxldmVsKSA9PiBsb2coMSwgJ1t0YXJuXSAnICsgIG1lc3NhZ2UpXG59O1xuXG4vKipcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xuICogYSBicm93c2VyIGluc3RhbmNlIGFuZCBzZXR0aW5nIHVwIHdvcmtlciByZXNvdXJjZXMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXG4gKiB3aXRoIGN1c3RvbSBwdXBwZXRlZXIgYXJndW1lbnRzIGZvciB0aGUgcHVwcGV0ZWVyLmxhdW5jaCBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xuICAvLyBGb3IgdGhlIG1vZHVsZSBzY29wZSB1c2FnZVxuICBwb29sQ29uZmlnID0gY29uZmlnICYmIGNvbmZpZy5wb29sID8geyAuLi5jb25maWcucG9vbCB9IDoge307XG5cbiAgLy8gQ3JlYXRlIGEgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBwdXBwZXRlZXIgYXJndW1lbnRzXG4gIGF3YWl0IGNyZWF0ZUJyb3dzZXIoY29uZmlnLnB1cHBldGVlckFyZ3MpO1xuXG4gIGxvZyhcbiAgICAzLFxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcbiAgKTtcblxuICBpZiAocG9vbCkge1xuICAgIHJldHVybiBsb2coXG4gICAgICA0LFxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcbiAgICApO1xuICB9XG5cbiAgaWYgKHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycykgPiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpKSB7XG4gICAgcG9vbENvbmZpZy5taW5Xb3JrZXJzID0gcG9vbENvbmZpZy5tYXhXb3JrZXJzO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcbiAgICBwb29sID0gbmV3IFBvb2woe1xuICAgICAgLy8gR2V0IHRoZSBjcmVhdGUvdmFsaWRhdGUvZGVzdHJveS9sb2cgZnVuY3Rpb25zXG4gICAgICAuLi5mYWN0b3J5LFxuICAgICAgbWluOiBwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpLFxuICAgICAgbWF4OiBwYXJzZUludChwb29sQ29uZmlnLm1heFdvcmtlcnMpLFxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXG4gICAgICBjcmVhdGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVRpbWVvdXQsXG4gICAgICBkZXN0cm95VGltZW91dE1pbGxpczogcG9vbENvbmZpZy5kZXN0cm95VGltZW91dCxcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxuICAgICAgY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVSZXRyeUludGVydmFsLFxuICAgICAgcmVhcEludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLnJlYXBlckludGVydmFsLFxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXG4gICAgfSk7XG5cbiAgICAvLyBTZXQgZXZlbnRzXG4gICAgcG9vbC5vbigncmVsZWFzZScsIGFzeW5jIChyZXNvdXJjZSkgPT4ge1xuICAgICAgLy8gQ2xlYXIgcGFnZVxuICAgICAgY29uc3QgciA9IGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XG4gICAgICBsb2coXG4gICAgICAgIDQsXG4gICAgICAgIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uIENsZWFyIHBhZ2Ugc3RhdHVzOiAke3J9LmBcbiAgICAgICk7XG4gICAgfSk7XG5cbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xuICAgICAgbG9nKDQsIGBbcG9vbF0gRGVzdHJveWVkIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XG4gICAgICByZXNvdXJjZS5wYWdlID0gbnVsbDtcbiAgICB9KTtcblxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XG4gICAgfSk7XG5cbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XG5cbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXG4gIGlmIChwb29sKSB7XG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XG4gICAgfVxuXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxuICogb3B0aW9ucy5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xuICBsZXQgd29ya2VySGFuZGxlO1xuXG4gIHRyeSB7XG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcblxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XG4gICAgICBnZXRQb29sSW5mbygpO1xuICAgIH1cblxuICAgIGlmICghcG9vbCkge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcbiAgICB9XG5cbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xuXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDUsXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcbiAgICAgICAgICA6ICcnKSArXG4gICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XG5cbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xuXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgLy8gTk9URTogSWYgdGhlcmUncyBhIHJhc3Rlcml6YXRpb24gdGltZW91dCwgd2Ugd2FudCBuZWVkIHRvIGZsdXNoIHRoZSBwYWdlLlxuICAgICAgLy8gICAgICAgVGhpcyBpcyBiZWNhdXNlIHRoZSBwYWdlIG1heSBiZSBpbiBhIHN0YXRlIHdoZXJlIGl0J3Mgd2FpdGluZyBmb3JcbiAgICAgIC8vICAgICAgIHRoZSBzY3JlZW5zaG90IHRvIGZpbmlzaCBldmVuIHRob3VnaCB0aGUgdGltZW91dCBoYXMgb2NjdXJlZC5cbiAgICAgIC8vICAgICAgIFdoaWNoIG9mIGNvdXJzZSBjYXVzZXMgYSBsb3Qgb2YgaXNzdWVzIHdpdGggdGhlIGV2ZW50IHN5c3RlbSxcbiAgICAgIC8vICAgICAgIGFuZCBwYWdlIGNvbnNpc3RlbmN5LlxuICAgICAgLy9cbiAgICAgIC8vIE5PVEU6IE9ubHkgcGFnZS5zY3JlZW5zaG90IHdpbGwgdGhyb3cgdGhpcywgdGltZW91dHMgZm9yIFBERidzIGFyZVxuICAgICAgLy8gICAgICAgaGFuZGxlZCBieSB0aGUgcGFnZS5wZGYgZnVuY3Rpb24gaXRzZWxmLlxuICAgICAgLy9cbiAgICAgIC8vICAgICAgIC4uLnllcywgdGhpcyBpcyB1Z2x5LlxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xuICAgICAgICB3b3JrZXJIYW5kbGUud29ya0NvdW50ID0gcG9vbENvbmZpZy53b3JrTGltaXQgKyAxO1xuICAgICAgICB3b3JrZXJIYW5kbGUucGFnZSA9IG51bGw7XG4gICAgICB9XG5cbiAgICAgIGlmIChcbiAgICAgICAgcmVzdWx0Lm5hbWUgPT09ICdUaW1lb3V0RXJyb3InIHx8XG4gICAgICAgIHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0J1xuICAgICAgKSB7XG4gICAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgICAnUmFzdGVyaXphdGlvbiB0aW1lb3V0OiB5b3VyIGNoYXJ0IG1heSBiZSB0b28gY29tcGxleCBvciBsYXJnZSwgYW5kIGZhaWxlZCB0byByZW5kZXIgd2l0aGluIHRoZSBhbGxvdHRlZCB0aW1lLidcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxuICAgICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcbiAgICAgICAgICAgIDogJycpICsgYEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBleHBvcnQ6ICR7ZXhwb3J0Q291bnRlcigpfW1zLmBcbiAgICAgICAgKS5zZXRFcnJvcihyZXN1bHQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIENoZWNrIHRoZSBQdXBwZXRlZXIgZXhwb3J0IHRpbWVcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XG4gICAgICBsb2coXG4gICAgICAgIDUsXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXG4gICAgICAgICAgOiAnW2JlbmNobWFya10nLFxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBSZWxlYXNlIHRoZSByZXNvdXJjZSBiYWNrIHRvIHRoZSBwb29sXG4gICAgcG9vbC5yZWxlYXNlKHdvcmtlckhhbmRsZSk7XG5cbiAgICAvLyBVc2VkIGZvciBzdGF0aXN0aWNzIGluIGF2ZXJhZ2VUaW1lIGFuZCBwcm9jZXNzZWRXb3JrQ291bnQsIHdoaWNoXG4gICAgLy8gaW4gdHVybiBpcyB1c2VkIGJ5IHRoZSAvaGVhbHRoIHJvdXRlLlxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiAgICBjb25zdCBleHBvcnRUaW1lID0gd29ya0VuZCAtIHdvcmtTdGFydDtcbiAgICBzdGF0cy50aW1lU3BlbnQgKz0gZXhwb3J0VGltZTtcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XG5cbiAgICBsb2coNCwgYFtwb29sXSBXb3JrIGNvbXBsZXRlZCBpbiAke2V4cG9ydFRpbWV9IG1zLmApO1xuXG4gICAgLy8gT3RoZXJ3aXNlIHJldHVybiB0aGUgcmVzdWx0XG4gICAgcmV0dXJuIHtcbiAgICAgIHJlc3VsdCxcbiAgICAgIG9wdGlvbnNcbiAgICB9O1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgICsrc3RhdHMuZHJvcHBlZEV4cG9ydHM7XG5cbiAgICBpZiAod29ya2VySGFuZGxlKSB7XG4gICAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoYFtwb29sXSBJbiBwb29sLnBvc3RXb3JrOiAke2Vycm9yLm1lc3NhZ2V9YCkuc2V0RXJyb3IoXG4gICAgICBlcnJvclxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdHxudWxsfSBUaGUgY3VycmVudCBwb29sIGluc3RhbmNlIGlmIGluaXRpYWxpemVkLCBvciBudWxsXG4gKiBpZiB0aGUgcG9vbCBoYXMgbm90IGJlZW4gY3JlYXRlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldFBvb2wgPSAoKSA9PiBwb29sO1xuXG4vKipcbiAqIFJldHJpZXZlcyBwb29sIGluZm9ybWF0aW9uIGluIEpTT04gZm9ybWF0LCBpbmNsdWRpbmcgbWluaW11bSBhbmQgbWF4aW11bVxuICogd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlIHJlcXVlc3RzLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xuICBtaW46IHBvb2wubWluLFxuICBtYXg6IHBvb2wubWF4LFxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXG4gIGF2YWlsYWJsZTogcG9vbC5udW1GcmVlKCksXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXG59KTtcblxuLyoqXG4gKiBMb2dzIGluZm9ybWF0aW9uIGFib3V0IHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBwb29sLCBpbmNsdWRpbmcgdGhlIG1pbmltdW1cbiAqIGFuZCBtYXhpbXVtIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZVxuICogcmVxdWVzdHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXRQb29sSW5mbygpIHtcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xuXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtaW5pbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21pbn0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWxsIGNyZWF0ZWQgcmVzb3VyY2VzOiAke2FsbH0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYXZhaWxhYmxlIHJlc291cmNlczogJHthdmFpbGFibGV9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiByZXNvdXJjZXMgd2FpdGluZyB0byBiZSBhY3F1aXJlZDogJHtwZW5kaW5nfS5gKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBpbml0UG9vbCxcbiAga2lsbFBvb2wsXG4gIHBvc3RXb3JrLFxuICBnZXRQb29sLFxuICBnZXRQb29sSW5mbyxcbiAgZ2V0UG9vbEluZm9KU09OLFxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHtcbiAgZml4VHlwZSxcbiAgaGFuZGxlUmVzb3VyY2VzLFxuICBpc0NvcnJlY3RKU09OLFxuICBvcHRpb25zU3RyaW5naWZ5LFxuICByb3VuZE51bWJlcixcbiAgdG9Cb29sZWFuLFxuICB3cmFwQXJvdW5kXG59IGZyb20gJy4vdXRpbHMuanMnO1xuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcblxuLyoqXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcbiAqIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXG4gKlxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcblxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcblxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcblxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XG4gICAgICAgIG9wdGlvbnMsXG4gICAgICAgIGVuZENhbGxiYWNrXG4gICAgICApO1xuXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicpLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXG4gIGlmIChleHBvcnRPcHRpb25zLmluZmlsZSAmJiBleHBvcnRPcHRpb25zLmluZmlsZS5sZW5ndGgpIHtcbiAgICAvLyBUcnkgdG8gcmVhZCB0aGUgZmlsZSB0byBnZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvblxuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhbiBpbnB1dCBmaWxlLicpO1xuICAgICAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSByZWFkRmlsZVN5bmMoZXhwb3J0T3B0aW9ucy5pbmZpbGUsICd1dGY4Jyk7XG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gRXhwb3J0IHdpdGggb3B0aW9ucyBmcm9tIHRoZSByYXcgcmVwcmVzZW50YXRpb25cbiAgaWYgKFxuICAgIChleHBvcnRPcHRpb25zLmluc3RyICYmIGV4cG9ydE9wdGlvbnMuaW5zdHIgIT09ICcnKSB8fFxuICAgIChleHBvcnRPcHRpb25zLm9wdGlvbnMgJiYgZXhwb3J0T3B0aW9ucy5vcHRpb25zICE9PSAnJylcbiAgKSB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgcmF3IGlucHV0LicpO1xuXG4gICAgICAvLyBVc2Ugd2hpY2hldmVyIG9uZSBpcyBhdmFpbGFibGVcbiAgICAgIGV4cG9ydE9wdGlvbnMuaW5zdHIgPSBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucztcblxuICAgICAgLy8gUGVyZm9ybSBhIGRpcmVjdCBpbmplY3Qgd2hlbiBmb3JjZWRcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xuICAgICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgICB9XG5cbiAgICAgIC8vIEVpdGhlciB0cnkgdG8gcGFyc2UgdG8gSlNPTiBmaXJzdCBvciBkbyB0aGUgZGlyZWN0IGV4cG9ydFxuICAgICAgcmV0dXJuIHR5cGVvZiBleHBvcnRPcHRpb25zLmluc3RyID09PSAnc3RyaW5nJ1xuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcbiAgICAgICAgOiBkb0V4cG9ydChcbiAgICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcbiAgICAgICAgICAgIGVuZENhbGxiYWNrXG4gICAgICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyByYXcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xuICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmBcbiAgICApXG4gICk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgYmF0Y2ggZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcblxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICBleHBvcnQ6IHtcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcblxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgc2luZ2xlIGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxuICovXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XG5cbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cblxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcbiAgICApO1xuXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogY2hhcnQgZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXG4gKi9cbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcblxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XG5cbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXG4gIGxldCBzY2FsZSA9XG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XG4gICAgMTtcblxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XG5cbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcblxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXG4gIGNvbnN0IHNpemUgPSB7XG4gICAgaGVpZ2h0OlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxuICAgICAgNDAwLFxuICAgIHdpZHRoOlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBjaGFydD8ud2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxuICAgICAgNjAwLFxuICAgIHNjYWxlXG4gIH07XG5cbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcbiAgICBzaXplW3BhcmFtXSA9XG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xuICB9XG4gIHJldHVybiBzaXplO1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xuICogaXMgY29tcGxldGVkLlxuICovXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICAgIHJlc291cmNlcyxcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coMiwgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGlmIChcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcbiAgICApIHtcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBSZXNldCBhbGwgYWRkaXRpb25hbCBjdXN0b20gY29kZVxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgPSBmYWxzZTtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IGZhbHNlO1xuICB9XG5cbiAgLy8gQ2xlYW4gcHJvcGVydGllcyB0byBrZWVwIGl0IGxlYW4gYW5kIG1lYW5cbiAgaWYgKGNoYXJ0SnNvbikge1xuICAgIGNoYXJ0SnNvbi5jaGFydCA9IGNoYXJ0SnNvbi5jaGFydCB8fCB7fTtcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nID0gY2hhcnRKc29uLmV4cG9ydGluZyB8fCB7fTtcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcbiAgfVxuXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcbiAgZXhwb3J0T3B0aW9ucy50eXBlID0gZml4VHlwZShleHBvcnRPcHRpb25zLnR5cGUsIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSk7XG4gIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xuICB9XG5cbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcbiAgWydnbG9iYWxPcHRpb25zJywgJ3RoZW1lT3B0aW9ucyddLmZvckVhY2goKG9wdGlvbnNOYW1lKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XG4gICAgICAgIGlmIChcbiAgICAgICAgICB0eXBlb2YgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcbiAgICAgICAgKSB7XG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSBpc0NvcnJlY3RKU09OKFxuICAgICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0sXG4gICAgICAgICAgICB0cnVlXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IHt9O1xuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gUHJlcGFyZSB0aGUgY3VzdG9tQ29kZVxuICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbikge1xuICAgIHRyeSB7XG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSA9IHdyYXBBcm91bmQoXG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlLFxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICB9XG4gIH1cblxuICAvLyBHZXQgdGhlIGNhbGxiYWNrXG4gIGlmIChcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgJiZcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2s/LmluZGV4T2YoJ3snKSA8IDBcbiAgKSB7XG4gICAgLy8gVGhlIGFsbG93RmlsZVJlc291cmNlcyBpcyBhbHdheXMgc2V0IHRvIGZhbHNlIGZvciBIVFRQIHJlcXVlc3RzIHRvIGF2b2lkXG4gICAgLy8gaW5qZWN0aW5nIGFyYml0cmFyeSBmaWxlcyBmcm9tIHRoZSBmc1xuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSByZWFkRmlsZVN5bmMoXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxuICAgICAgICAgICd1dGY4J1xuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICdjYWxsYmFjaycgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gZmFsc2U7XG4gICAgfVxuICB9XG5cbiAgLy8gU2l6ZSBzZWFyY2hcbiAgb3B0aW9ucy5leHBvcnQgPSB7XG4gICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxuICB9O1xuXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcbiAgdHJ5IHtcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwb3N0V29yayhcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXG4gICAgICBvcHRpb25zXG4gICAgKTtcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBQZXJmb3JtcyBhIGRpcmVjdCBpbmplY3Qgb2Ygb3B0aW9ucyBiZWZvcmUgZXhwb3J0LiBUaGUgZnVuY3Rpb24gYXR0ZW1wdHNcbiAqIHRvIHN0cmluZ2lmeSB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgcmVtb3ZlcyB1bm5lY2Vzc2FyeSBjaGFyYWN0ZXJzLFxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xuICogYSBcInN0cmlnaHQgaW5qZWN0XCIgc3RyaW5nIGluIHRoZSBleHBvcnQgb3B0aW9ucy4gSXQgdGhlbiBpbnZva2VzIHRoZVxuICogZG9FeHBvcnQgZnVuY3Rpb24gd2l0aCB0aGUgdXBkYXRlZCBvcHRpb25zLlxuICpcbiAqIElNUE9SVEFOVDogRGFuZ2Vyb3VzIGFuZCBtdXN0IGJlIHVzZWQgZGVsaWJlcmF0ZWx5IGJ5IHNvbWVvbmUgd2hvIHNldHMgdXBcbiAqIGEgc2VydmVyIChzZWUgdGhlICAtLWFsbG93Q29kZUV4ZWN1dGlvbiBvcHRpb24pLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zIGNvbnRhaW5pbmcgdGhlIGlucHV0XG4gKiB0byBiZSBpbmplY3RlZC5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcbiAqIGF0IHRoZSBlbmQgb2YgdGhlIHByb2Nlc3MuXG4gKlxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XG4gKiBvcGVyYXRpb24gb3IgcmVqZWN0cyB3aXRoIGFuIGVycm9yIGlmIGFueSBpc3N1ZXMgb2NjdXIgZHVyaW5nIHRoZSBwcm9jZXNzLlxuICovXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XG4gIHRyeSB7XG4gICAgbGV0IHN0ckluajtcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xuXG4gICAgaWYgKHR5cGVvZiBpbnN0ciAhPT0gJ3N0cmluZycpIHtcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xuICAgICAgc3RySW5qID0gaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxuICAgICAgICBpbnN0cixcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICApO1xuICAgIH1cbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xuXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgO1xuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcbiAgICAgIHN0ckluaiA9IHN0ckluai5zdWJzdHJpbmcoMCwgc3RySW5qLmxlbmd0aCAtIDEpO1xuICAgIH1cblxuICAgIC8vIFNhdmUgYXMgc3RyaWdodCBpbmplY3Qgc3RyaW5nXG4gICAgb3B0aW9ucy5leHBvcnQuc3RySW5qID0gc3RySW5qO1xuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgYFtjaGFydF0gTWFsZm9ybWVkIGlucHV0IGRldGVjdGVkIGZvciAke29wdGlvbnMuZXhwb3J0Py5yZXF1ZXN0SWQgfHwgJz8nfS4gUGxlYXNlIG1ha2Ugc3VyZSB0aGF0IHlvdXIgSlNPTi9KYXZhU2NyaXB0IG9wdGlvbnMgYXJlIHNlbnQgdXNpbmcgdGhlIFwib3B0aW9uc1wiIGF0dHJpYnV0ZSwgYW5kIHRoYXQgaWYgeW91J3JlIHVzaW5nIFNWRywgaXQgaXMgdW5lc2NhcGVkLmBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXG4gKi9cbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcblxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcbiAgaWYgKFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXG4gICkge1xuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XG5cbiAgICAvLyBJZiBhIGNvcnJlY3QgSlNPTiwgZG8gdGhlIGV4cG9ydFxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBjaGFydEpTT04sIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAvLyBOb3QgYSB2YWxpZCBKU09OXG4gICAgaWYgKHRvQm9vbGVhbihhbGxvd0NvZGVFeGVjdXRpb24pKSB7XG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIERvIG5vdCBhbGxvdyBzdHJhaWdodCBpbmplY3Rpb24gd2l0aG91dCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWdcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgICdbY2hhcnRdIE9ubHkgSlNPTiBjb25maWd1cmF0aW9ucyBhbmQgU1ZHIGFyZSBhbGxvd2VkIGZvciB0aGlzIHNlcnZlci4gSWYgdGhpcyBpcyB5b3VyIHNlcnZlciwgSmF2YVNjcmlwdCBjdXN0b20gY29kZSBjYW4gYmUgZW5hYmxlZCBieSBzdGFydGluZyB0aGUgc2VydmVyIHdpdGggdGhlIC0tYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuJ1xuICAgICAgICApLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBjdXJyZW50IHN0YXR1cyBvZiBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uLlxuICpcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAoKSA9PiBhbGxvd0NvZGVFeGVjdXRpb247XG5cbi8qKlxuICogU2V0cyB0aGUgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbiBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgYm9vbGVhbiB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIGFuZCBhc3NpZ25lZFxuICogdG8gYWxsb3dDb2RlRXhlY3V0aW9uLlxuICovXG5leHBvcnQgY29uc3Qgc2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKHZhbHVlKSA9PiB7XG4gIGFsbG93Q29kZUV4ZWN1dGlvbiA9IHRvQm9vbGVhbih2YWx1ZSk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGJhdGNoRXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGdldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzdGFydEV4cG9ydCxcbiAgZmluZENoYXJ0U2l6ZVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vKipcbiAqIEBvdmVydmlldyBVc2VkIHRvIHNhbml0aXplIHRoZSBzdHJpbmdzIGNvbWluZyBmcm9tIHRoZSBleHBvcnRpbmcgbW9kdWxlXG4gKiB0byBwcmV2ZW50IFhTUyBhdHRhY2tzICh3aXRoIHRoZSBET01QdXJpZnkgbGlicmFyeSkuXG4gKiovXG5cbmltcG9ydCB7IEpTRE9NIH0gZnJvbSAnanNkb20nO1xuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xuXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcbi8qKlxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xuICBjb25zdCBmb3JiaWRkZW4gPSBbXTtcblxuICBpZiAoIWVudnMuT1RIRVJfQUxMT1dfWExJTkspIHtcbiAgICBmb3JiaWRkZW4ucHVzaCgneGxpbms6aHJlZicpO1xuICB9XG5cbiAgY29uc3Qgd2luZG93ID0gbmV3IEpTRE9NKCcnKS53aW5kb3c7XG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xuICByZXR1cm4gcHVyaWZ5LnNhbml0aXplKGlucHV0LCB7XG4gICAgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddLFxuICAgIEZPUkJJRF9BVFRSOiBmb3JiaWRkZW5cbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xuXG4vKipcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXG4gKlxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cbiAqL1xuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XG4gIGludGVydmFsSWRzLnB1c2goaWQpO1xufTtcblxuLyoqXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXG4gKi9cbmV4cG9ydCBjb25zdCBjbGVhckFsbEludGVydmFscyA9ICgpID0+IHtcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcbiAgICBjbGVhckludGVydmFsKGlkKTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBhZGRJbnRlcnZhbCxcbiAgY2xlYXJBbGxJbnRlcnZhbHNcbn07XG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuXG4vKipcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXG4gKi9cbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XG5cbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xuICB9XG5cbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXG4gIG5leHQoZXJyb3IpO1xufTtcblxuLyoqXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXG4gKlxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDQwMDtcblxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcblxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxuICpcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xuICBjb25zdCBtc2cgPVxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcblxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcbiAgfTtcblxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xuICAgICAgICBqc29uOiAoKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcbiAgICAgIGlmIChcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXG4gICAgICApIHtcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXG4gIGFwcC51c2UobGltaXRlcik7XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcbiAgKTtcbn07XG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XG5cbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XG4gIH1cblxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHVwZGF0ZVZlcnNpb24sIHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XG5cbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XG5cbi8qKlxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXG4gKlxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAucG9zdChcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xuXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcbiAgICAgICAgICAgICAgICA0MDFcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcbiAgICAgICAgICAgICAgICA0MDFcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcbiAgICAgICAgICAgICAgICBhd2FpdCB1cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogdmVyc2lvbigpLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7XG4gIGZpeFR5cGUsXG4gIGlzQ29ycmVjdEpTT04sXG4gIGlzT2JqZWN0RW1wdHksXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIG1lYXN1cmVUaW1lXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcblxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xuICBwbmc6ICdpbWFnZS9wbmcnLFxuICBqcGVnOiAnaW1hZ2UvanBlZycsXG4gIGdpZjogJ2ltYWdlL2dpZicsXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXG59O1xuXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xuXG4vKipcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcbiAqIHRvIGJlIGV4ZWN1dGVkLlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXG4gKiB0eXBlLCBhbmQgYm9keS5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxuICovXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XG4gIGxldCByZXN1bHQgPSB0cnVlO1xuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcblxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcbiAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcblxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8qKlxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cbiAqXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXG4gKiBpcyBjb21wbGV0ZS5cbiAqL1xuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICB0cnkge1xuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG5cbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xuXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xuXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xuXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XG5cbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xuXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXG4gICAgICAgIH0gd2FzIGluY29ycmVjdDpcbiAgQ29udGVudC1UeXBlOiAke3JlcXVlc3QuaGVhZGVyc1snY29udGVudC10eXBlJ119LiBcbiAgQ2hhcnQgY29uc3RydWN0b3I6ICR7Ym9keS5jb25zdHJ9LlxuICBEaW1lbnNpb25zOiAke2JvZHkud2lkdGh9eCR7Ym9keS5oZWlnaHR9IEAgJHtib2R5LnNjYWxlfSBzY2FsZS5cbiAgVHlwZTogJHt0eXBlfS5cbiAgSXMgU1ZHIHNldD8gJHt0eXBlb2YgYm9keS5zdmcgIT09ICd1bmRlZmluZWQnfS5cbiAgQjY0PyAke3R5cGVvZiBib2R5LmI2NCAhPT0gJ3VuZGVmaW5lZCd9LlxuICBObyBkb3dubG9hZD8gJHt0eXBlb2YgYm9keS5ub0Rvd25sb2FkICE9PSAndW5kZWZpbmVkJ30uXG5cbiAgUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhIHx8IGJvZHkuc3ZnKX1cblxuICBgXG4gICAgICApO1xuXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXG4gICAgICAgIDQwMFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XG5cbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xuICAgICAgaWQsXG4gICAgICB1bmlxdWVJZCxcbiAgICAgIHR5cGUsXG4gICAgICBib2R5XG4gICAgfSk7XG5cbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcblxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoaGFkRXJyb3JzKSA9PiB7XG4gICAgICBpZiAoaGFkRXJyb3JzKSB7XG4gICAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xuXG4gICAgYm9keS5jb25zdHIgPSAodHlwZW9mIGJvZHkuY29uc3RyID09PSAnc3RyaW5nJyAmJiBib2R5LmNvbnN0cikgfHwgJ2NoYXJ0JztcblxuICAgIC8vIEdhdGhlciBhbmQgb3JnYW5pemUgb3B0aW9ucyBmcm9tIHRoZSBwYXlsb2FkXG4gICAgY29uc3QgcmVxdWVzdE9wdGlvbnMgPSB7XG4gICAgICBleHBvcnQ6IHtcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIHR5cGUsXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcbiAgICAgICAgaGVpZ2h0OiBib2R5LmhlaWdodCxcbiAgICAgICAgd2lkdGg6IGJvZHkud2lkdGgsXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcbiAgICAgICAgZ2xvYmFsT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5Lmdsb2JhbE9wdGlvbnMsIHRydWUpLFxuICAgICAgICB0aGVtZU9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS50aGVtZU9wdGlvbnMsIHRydWUpXG4gICAgICB9LFxuICAgICAgY3VzdG9tTG9naWM6IHtcbiAgICAgICAgYWxsb3dDb2RlRXhlY3V0aW9uOiBnZXRBbGxvd0NvZGVFeGVjdXRpb24oKSxcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcbiAgICAgICAgcmVzb3VyY2VzOiBpc0NvcnJlY3RKU09OKGJvZHkucmVzb3VyY2VzLCB0cnVlKSxcbiAgICAgICAgY2FsbGJhY2s6IGJvZHkuY2FsbGJhY2ssXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxuICAgICAgfVxuICAgIH07XG5cbiAgICBpZiAoaW5zdHIpIHtcbiAgICAgIC8vIFN0cmluZ2lmeSBKU09OIHdpdGggb3B0aW9uc1xuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIHJlcXVlc3RPcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXG4gICAgY29uc3Qgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhkZWZhdWx0T3B0aW9ucywgcmVxdWVzdE9wdGlvbnMpO1xuXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcbiAgICBvcHRpb25zLmV4cG9ydC5vcHRpb25zID0gaW5zdHI7XG5cbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxuICAgIG9wdGlvbnMucGF5bG9hZCA9IHtcbiAgICAgIHN2ZzogYm9keS5zdmcgfHwgZmFsc2UsXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxuICAgICAgbm9Eb3dubG9hZDogYm9keS5ub0Rvd25sb2FkIHx8IGZhbHNlLFxuICAgICAgcmVxdWVzdElkOiB1bmlxdWVJZFxuICAgIH07XG5cbiAgICAvLyBUZXN0IHhsaW5rOmhyZWYgZWxlbWVudHMgZnJvbSBwYXlsb2FkJ3MgU1ZHXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICdTVkcgcG90ZW50aWFsbHkgY29udGFpbiBhdCBsZWFzdCBvbmUgZm9yYmlkZGVuIFVSTCBpbiB4bGluazpocmVmIGVsZW1lbnQuIFBsZWFzZSByZXZpZXcgdGhlIFNWRyBjb250ZW50IGFuZCBlbnN1cmUgdGhhdCBhbGwgcmVmZXJlbmNlZCBVUkxzIGNvbXBseSB3aXRoIHNlY3VyaXR5IHBvbGljaWVzLicsXG4gICAgICAgIDQwMFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBTdGFydCB0aGUgZXhwb3J0IHByb2Nlc3NcbiAgICBhd2FpdCBzdGFydEV4cG9ydChvcHRpb25zLCAoZXJyb3IsIGluZm8pID0+IHtcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XG4gICAgICByZXF1ZXN0LnNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Nsb3NlJyk7XG5cbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xuICAgICAgaWYgKGRlZmF1bHRPcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDUsXG4gICAgICAgICAgYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSAtIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2VzczogJHtzdG9wQ291bnRlcigpfW1zLmBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgdGhlIGNvbm5lY3Rpb24gd2FzIGNsb3NlZCwgZG8gbm90aGluZ1xuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XG4gICAgICAgIHJldHVybiBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgZXJyb3IsIGxvZyBpdCBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIHRocm93IGVycm9yO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxuICAgICAgaWYgKCFpbmZvIHx8ICFpbmZvLnJlc3VsdCkge1xuICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcbiAgICAgICAgICA0MDBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgLy8gR2V0IHRoZSB0eXBlIGZyb20gb3B0aW9uc1xuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcblxuICAgICAgLy8gVGhlIGFmdGVyIHJlcXVlc3QgY2FsbGJhY2tzXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcblxuICAgICAgaWYgKGluZm8ucmVzdWx0KSB7XG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcbiAgICAgICAgaWYgKGJvZHkuYjY0KSB7XG4gICAgICAgICAgLy8gU1ZHIEV4Y2VwdGlvbiBmb3IgdGhlIEhpZ2hjaGFydHMgMTEuMy4wIHZlcnNpb25cbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xuICAgICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoXG4gICAgICAgICAgICAgIEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAndXRmOCcpLnRvU3RyaW5nKCdiYXNlNjQnKVxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcbiAgICAgICAgcmVzcG9uc2UuaGVhZGVyKCdDb250ZW50LVR5cGUnLCByZXZlcnNlZE1pbWVbdHlwZV0gfHwgJ2ltYWdlL3BuZycpO1xuXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXG4gICAgICAgIGlmICghYm9keS5ub0Rvd25sb2FkKSB7XG4gICAgICAgICAgcmVzcG9uc2UuYXR0YWNobWVudChcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xuICAgICAgICAgICAgICB0eXBlIHx8ICdwbmcnXG4gICAgICAgICAgICB9YFxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XG4gICAgICAgIHJldHVybiB0eXBlID09PSAnc3ZnJ1xuICAgICAgICAgID8gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdClcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XG4gICAgICB9XG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbmV4dChlcnJvcik7XG4gIH1cbn07XG5cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcbiAgLyoqXG4gICAqIEFkZHMgdGhlIFBPU1QgLyBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIGF0IHRoZSByb290IGVuZHBvaW50LlxuICAgKi9cbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcblxuICAvKipcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxuICAgKiBhIHNwZWNpZmllZCBmaWxlbmFtZSBwYXJhbWV0ZXIuXG4gICAqL1xuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIGFzIHBhdGhlciB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcblxuaW1wb3J0IHsgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcbmltcG9ydCBwb29sIGZyb20gJy4uLy4uL3Bvb2wuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xuXG5jb25zdCBwa2dGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMocGF0aGVyKF9fZGlybmFtZSwgJ3BhY2thZ2UuanNvbicpKSk7XG5cbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XG5cbmNvbnN0IHN1Y2Nlc3NSYXRlcyA9IFtdO1xuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcbmNvbnN0IHdpbmRvd1NpemUgPSAzMDsgLy8gMzAgbWludXRlc1xuXG4vKipcbiAqIENhbGN1bGF0ZXMgbW92aW5nIGF2ZXJhZ2UgaW5kaWNhdG9yIGJhc2VkIG9uIHRoZSBkYXRhIGZyb20gdGhlIHN1Y2Nlc3NSYXRlc1xuICogYXJyYXkuXG4gKlxuICogQHJldHVybnMge251bWJlcn0gLSBBIG1vdmluZyBhdmVyYWdlIGZvciBzdWNjZXNzIHJhdGlvIG9mIHRoZSBzZXJ2ZXIgZXhwb3J0cy5cbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcbiAgY29uc3Qgc3VtID0gc3VjY2Vzc1JhdGVzLnJlZHVjZSgoYSwgYikgPT4gYSArIGIsIDApO1xuICByZXR1cm4gc3VtIC8gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcbn1cblxuLyoqXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xuICogYW5kIGdhdGhlcnNcbiAqXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXG4gKi9cbmV4cG9ydCBjb25zdCBzdGFydFN1Y2Nlc3NSYXRlID0gKCkgPT5cbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xuICAgIGNvbnN0IHN1Y2Nlc3NSYXRpbyA9XG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxuICAgICAgICA/IDFcbiAgICAgICAgOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMDtcblxuICAgIHN1Y2Nlc3NSYXRlcy5wdXNoKHN1Y2Nlc3NSYXRpbyk7XG4gICAgaWYgKHN1Y2Nlc3NSYXRlcy5sZW5ndGggPiB3aW5kb3dTaXplKSB7XG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcbiAgICB9XG4gIH0sIHJlY29yZEludGVydmFsKTtcblxuLyoqXG4gKiBBZGRzIHRoZSAvaGVhbHRoIGFuZCAvc3VjY2Vzcy1tb3ZpbmctYXZlcmFnZSByb3V0ZXNcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgZnVuY3Rpb24gYWRkSGVhbHRoUm91dGVzKGFwcCkge1xuICBpZiAoIWFwcCkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFN0YXJ0IHByb2Nlc3Npbmcgc3VjY2VzcyByYXRlIHJhdGlvIGludGVydmFsIGFuZCBzYXZlIGl0cyBpZCB0byB0aGUgYXJyYXlcbiAgLy8gZm9yIHRoZSBncmFjZWZ1bCBjbGVhcmluZyBvbiBzaHV0ZG93biB3aXRoIGluamVjdGVkIGFkZEludGVydmFsIGZ1bnRpb25cbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcblxuICBhcHAuZ2V0KCcvaGVhbHRoJywgKF8sIHJlcykgPT4ge1xuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xuICAgIGNvbnN0IHBlcmlvZCA9IHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XG4gICAgY29uc3QgbW92aW5nQXZlcmFnZSA9IGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKTtcblxuICAgIGxvZyg0LCAnW2hlYWx0aC5qc10gR0VUIC9oZWFsdGggWzIwMF0gLSByZXR1cm5pbmcgc2VydmVyIGhlYWx0aC4nKTtcblxuICAgIHJlcy5zZW5kKHtcbiAgICAgIHN0YXR1czogJ09LJyxcbiAgICAgIGJvb3RUaW1lOiBzZXJ2ZXJTdGFydFRpbWUsXG4gICAgICB1cHRpbWU6XG4gICAgICAgIE1hdGguZmxvb3IoXG4gICAgICAgICAgKG5ldyBEYXRlKCkuZ2V0VGltZSgpIC0gc2VydmVyU3RhcnRUaW1lLmdldFRpbWUoKSkgLyAxMDAwIC8gNjBcbiAgICAgICAgKSArICcgbWludXRlcycsXG4gICAgICB2ZXJzaW9uOiBwa2dGaWxlLnZlcnNpb24sXG4gICAgICBoaWdoY2hhcnRzVmVyc2lvbjogdmVyc2lvbigpLFxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXG4gICAgICBwZXJmb3JtZWRFeHBvcnRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzLFxuICAgICAgZmFpbGVkRXhwb3J0czogc3RhdHMuZHJvcHBlZEV4cG9ydHMsXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXG4gICAgICBzdWNlc3NSYXRpbzogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDAsXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgaW1wb3J0L25vLW5hbWVkLWFzLWRlZmF1bHQtbWVtYmVyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxuXG4gICAgICAvLyBNb3ZpbmcgYXZlcmFnZVxuICAgICAgcGVyaW9kLFxuICAgICAgbW92aW5nQXZlcmFnZSxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgIGlzTmFOKG1vdmluZ0F2ZXJhZ2UpIHx8ICFzdWNjZXNzUmF0ZXMubGVuZ3RoXG4gICAgICAgICAgPyAnVG9vIGVhcmx5IHRvIHJlcG9ydC4gTm8gZXhwb3J0cyBtYWRlIHlldC4gUGxlYXNlIGNoZWNrIGJhY2sgc29vbi4nXG4gICAgICAgICAgOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxuXG4gICAgICAvLyBTVkcvSlNPTiBhdHRlbXB0c1xuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcbiAgICAgIGpzb25FeHBvcnRBdHRlbXB0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAtIHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0c1xuICAgIH0pO1xuICB9KTtcbn1cbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgcG9zaXggfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IGNvcnMgZnJvbSAnY29ycyc7XG5pbXBvcnQgZXhwcmVzcyBmcm9tICdleHByZXNzJztcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcbmltcG9ydCBtdWx0ZXIgZnJvbSAnbXVsdGVyJztcblxuaW1wb3J0IGVycm9ySGFuZGxlciBmcm9tICcuL2Vycm9yLmpzJztcbmltcG9ydCByYXRlTGltaXQgZnJvbSAnLi9yYXRlX2xpbWl0LmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uL3V0aWxzLmpzJztcblxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XG5pbXBvcnQgZXhwb3J0Um91dGVzIGZyb20gJy4vcm91dGVzL2V4cG9ydC5qcyc7XG5pbXBvcnQgaGVhbHRoUm91dGUgZnJvbSAnLi9yb3V0ZXMvaGVhbHRoLmpzJztcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4uL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8vIEFycmF5IG9mIGFuIGFjdGl2ZSBzZXJ2ZXJzXG5jb25zdCBhY3RpdmVTZXJ2ZXJzID0gbmV3IE1hcCgpO1xuXG4vLyBDcmVhdGUgZXhwcmVzcyBhcHBcbmNvbnN0IGFwcCA9IGV4cHJlc3MoKTtcblxuLy8gRGlzYWJsZSB0aGUgWC1Qb3dlcmVkLUJ5IGhlYWRlclxuYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xuXG4vLyBFbmFibGUgQ09SUyBzdXBwb3J0XG5hcHAudXNlKGNvcnMoKSk7XG5cbi8vIEdldHRpbmcgYSBsb3Qgb2YgUmFuZ2VOb3RTYXRpc2ZpYWJsZUVycm9yIGV4Y2VwdGlvbi5cbi8vIEV2ZW4gdGhvdWdoIHRoaXMgaXMgYSBkZXByZWNhdGVkIG9wdGlvbnMsIGxldCdzIHRyeSB0byBzZXQgaXQgdG8gZmFsc2UuXG5hcHAudXNlKChfcmVxLCByZXMsIG5leHQpID0+IHtcbiAgcmVzLnNldCgnQWNjZXB0LVJhbmdlcycsICdub25lJyk7XG4gIG5leHQoKTtcbn0pO1xuXG4vKipcbiAqIEF0dGFjaCBlcnJvciBoYW5kbGVycyB0byB0aGUgc2VydmVyLlxuICpcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cbiAqL1xuY29uc3QgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyA9IChzZXJ2ZXIpID0+IHtcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvciwgc29ja2V0KSA9PiB7XG4gICAgbG9nV2l0aFN0YWNrKFxuICAgICAgMSxcbiAgICAgIGVycm9yLFxuICAgICAgYFtzZXJ2ZXJdIENsaWVudCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfSwgZGVzdHJveWluZyBzb2NrZXQuYFxuICAgICk7XG4gICAgc29ja2V0LmRlc3Ryb3koKTtcbiAgfSk7XG5cbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICB9KTtcblxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgfSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcbiAqIGFuZCBzdGFydGVkLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gVE9ETzogUmVhZCBmcm9tIGNvbmZpZy9lbnZcbiAgICAvLyBOT1RFOlxuICAgIC8vIFRvbyBiaWcgbGltaXRzIGxlYWQgdG8gdGltZW91dHMgaW4gdGhlIGV4cG9ydCBwcm9jZXNzIHdoZW4gdGhlXG4gICAgLy8gcmFzdGVyaXphdGlvbiB0aW1lb3V0IGlzIHNldCB0b28gbG93LlxuICAgIGNvbnN0IHVwbG9hZExpbWl0TWlCID0gc2VydmVyQ29uZmlnLm1heFVwbG9hZFNpemUgfHwgMztcbiAgICBjb25zdCB1cGxvYWRMaW1pdEJ5dGVzID0gdXBsb2FkTGltaXRNaUIgKiAxMDI0ICogMTAyNDtcblxuICAgIC8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcbiAgICBjb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcbiAgICBjb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xuICAgICAgc3RvcmFnZSxcbiAgICAgIGxpbWl0czoge1xuICAgICAgICBmaWVsZFNpemU6IHVwbG9hZExpbWl0Qnl0ZXNcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIEVuYWJsZSBib2R5IHBhcnNlclxuICAgIGFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IHVwbG9hZExpbWl0Qnl0ZXMgfSkpO1xuICAgIGFwcC51c2UoZXhwcmVzcy51cmxlbmNvZGVkKHsgZXh0ZW5kZWQ6IHRydWUsIGxpbWl0OiB1cGxvYWRMaW1pdEJ5dGVzIH0pKTtcblxuICAgIC8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xuICAgIGFwcC51c2UodXBsb2FkLm5vbmUoKSk7XG5cbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuZW5hYmxlKSB7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLy8gTGlzdGVuIEhUVFAgc2VydmVyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XG4gICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUClcbiAgICAgIGNvbnN0IGh0dHBTZXJ2ZXIgPSBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xuXG4gICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXG4gICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBTZXJ2ZXIpO1xuXG4gICAgICAvLyBMaXN0ZW5cbiAgICAgIGh0dHBTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XG5cbiAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQIHNlcnZlclxuICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnBvcnQsIGh0dHBTZXJ2ZXIpO1xuXG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gTGlzdGVuIEhUVFBTIHNlcnZlclxuICAgIGlmIChzZXJ2ZXJDb25maWcuc3NsLmVuYWJsZSkge1xuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xuICAgICAgbGV0IGtleSwgY2VydDtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wga2V5XG4gICAgICAgIGtleSA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxuICAgICAgICAgICd1dGY4J1xuICAgICAgICApO1xuXG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGNlcnRpZmljYXRlXG4gICAgICAgIGNlcnQgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICAyLFxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICBpZiAoa2V5ICYmIGNlcnQpIHtcbiAgICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFBTKVxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xuXG4gICAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XG5cbiAgICAgICAgLy8gTGlzdGVuXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcblxuICAgICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUFMgc2VydmVyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xuXG4gICAgICAgIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFBTIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5zc2wucG9ydH0uYFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXG4gICAgaWYgKFxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyAmJlxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcbiAgICAgICFbMCwgTmFOXS5pbmNsdWRlcyhzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzKVxuICAgICkge1xuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XG4gICAgfVxuXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxuICAgIGFwcC51c2UoZXhwcmVzcy5zdGF0aWMocG9zaXguam9pbihfX2Rpcm5hbWUsICdwdWJsaWMnKSkpO1xuXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xuICAgIGhlYWx0aFJvdXRlKGFwcCk7XG4gICAgZXhwb3J0Um91dGVzKGFwcCk7XG4gICAgdWlSb3V0ZShhcHApO1xuICAgIHZTd2l0Y2hSb3V0ZShhcHApO1xuXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcbiAgICBlcnJvckhhbmRsZXIoYXBwKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW3NlcnZlcl0gQ291bGQgbm90IGNvbmZpZ3VyZSBhbmQgc3RhcnQgdGhlIHNlcnZlci4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogQ2xvc2VzIGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcbiAgbG9nKDQsIGBbc2VydmVyXSBDbG9zaW5nIGFsbCBzZXJ2ZXJzLmApO1xuICBmb3IgKGNvbnN0IFtwb3J0LCBzZXJ2ZXJdIG9mIGFjdGl2ZVNlcnZlcnMpIHtcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xuICAgICAgYWN0aXZlU2VydmVycy5kZWxldGUocG9ydCk7XG4gICAgICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NlZCBzZXJ2ZXIgb24gcG9ydDogJHtwb3J0fS5gKTtcbiAgICB9KTtcbiAgfVxufTtcblxuLyoqXG4gKiBHZXQgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtBcnJheX0gLSBTZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xuXG4vKipcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBsaW1pdENvbmZpZyAtIENvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByYXRlIGxpbWl0aW5nLlxuICovXG5leHBvcnQgY29uc3QgZW5hYmxlUmF0ZUxpbWl0aW5nID0gKGxpbWl0Q29uZmlnKSA9PiByYXRlTGltaXQoYXBwLCBsaW1pdENvbmZpZyk7XG5cbi8qKlxuICogR2V0IHRoZSBFeHByZXNzIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRFeHByZXNzID0gKCkgPT4gZXhwcmVzcztcblxuLyoqXG4gKiBHZXQgdGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xuXG4vKipcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHBhdGggdG8gd2hpY2ggdGhlIG1pZGRsZXdhcmUocykgc2hvdWxkIGJlIGFwcGxpZWQuXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxuICovXG5leHBvcnQgY29uc3QgdXNlID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIEdFVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLmdldChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG4vKipcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggUE9TVCBtZXRob2QgYW5kIGFwcGx5IG1pZGRsZXdhcmUocykuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBwb3N0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC5wb3N0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgc3RhcnRTZXJ2ZXIsXG4gIGNsb3NlU2VydmVycyxcbiAgZ2V0U2VydmVycyxcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxuICBnZXRFeHByZXNzLFxuICBnZXRBcHAsXG4gIHVzZSxcbiAgZ2V0LFxuICBwb3N0XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xuXG4vKipcbiAqIEFkZHMgdGhlIEdFVCAvIHJvdXRlIGZvciBhIFVJIHdoZW4gZW5hYmxlZCBvbiB0aGUgZXhwb3J0IHNlcnZlci5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cbiAgIWFwcFxuICAgID8gZmFsc2VcbiAgICA6IGFwcC5nZXQoJy8nLCAoX3JlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSwge1xuICAgICAgICAgIGFjY2VwdFJhbmdlczogZmFsc2VcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XG5cbi8qKlxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBwcm9jZXNzLmV4aXQoKSBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcbiAgICBjbGVhckFsbEludGVydmFscygpLFxuXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxuICAgIGNsb3NlU2VydmVycygpLFxuXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXG4gICAga2lsbFBvb2woKVxuICBdKTtcblxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBzaHV0ZG93bkNsZWFuVXBcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0ICdjb2xvcnMnO1xuXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzaW5nbGVFeHBvcnQsXG4gIHN0YXJ0RXhwb3J0XG59IGZyb20gJy4vY2hhcnQuanMnO1xuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7XG4gIGluaXRMb2dnaW5nLFxuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuLyoqXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cbiAqL1xuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cbiAqL1xuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICk7XG5cbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xuXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XG4gIH1cblxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XG5cbiAgLy8gSW5pdCB0aGUgcG9vbFxuICBhd2FpdCBpbml0UG9vbCh7XG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcbiAgICAgIG1pbldvcmtlcnM6IDEsXG4gICAgICBtYXhXb3JrZXJzOiAxXG4gICAgfSxcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlci5hcmdzIHx8IFtdXG4gIH0pO1xuXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcbiAgcmV0dXJuIG9wdGlvbnM7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIC8vIFNlcnZlclxuICBzZXJ2ZXIsXG4gIHN0YXJ0U2VydmVyLFxuXG4gIC8vIEV4cG9ydGluZ1xuICBpbml0RXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGJhdGNoRXhwb3J0LFxuICBzdGFydEV4cG9ydCxcblxuICAvLyBQb29sXG4gIGluaXRQb29sLFxuICBraWxsUG9vbCxcblxuICAvLyBPdGhlclxuICBzZXRPcHRpb25zLFxuICBzaHV0ZG93bkNsZWFuVXAsXG5cbiAgLy8gTG9nc1xuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuXG4gIC8vIFV0aWxzXG4gIG1hcFRvTmV3Q29uZmlnLFxuICBtYW51YWxDb25maWcsXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZVxufTtcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJjdXN0b20iLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwidGVtcERpciIsImVudkxpbmsiLCJoaWdoY2hhcnRzIiwidmVyc2lvbiIsImNkblVSTCIsImNvcmVTY3JpcHRzIiwibW9kdWxlU2NyaXB0cyIsImluZGljYXRvclNjcmlwdHMiLCJjdXN0b21TY3JpcHRzIiwiZm9yY2VGZXRjaCIsImNhY2hlUGF0aCIsImV4cG9ydCIsImluZmlsZSIsImluc3RyIiwib3B0aW9ucyIsIm91dGZpbGUiLCJjb25zdHIiLCJkZWZhdWx0SGVpZ2h0IiwiZGVmYXVsdFdpZHRoIiwiZGVmYXVsdFNjYWxlIiwiaGVpZ2h0Iiwid2lkdGgiLCJzY2FsZSIsImdsb2JhbE9wdGlvbnMiLCJ0aGVtZU9wdGlvbnMiLCJiYXRjaCIsInJhc3Rlcml6YXRpb25UaW1lb3V0IiwiY3VzdG9tTG9naWMiLCJhbGxvd0NvZGVFeGVjdXRpb24iLCJhbGxvd0ZpbGVSZXNvdXJjZXMiLCJjdXN0b21Db2RlIiwiY2FsbGJhY2siLCJyZXNvdXJjZXMiLCJsb2FkQ29uZmlnIiwibGVnYWN5TmFtZSIsImNyZWF0ZUNvbmZpZyIsInNlcnZlciIsIm1heFVwbG9hZFNpemUiLCJlbmFibGUiLCJjbGlOYW1lIiwiaG9zdCIsInBvcnQiLCJiZW5jaG1hcmtpbmciLCJwcm94eSIsInVzZXJuYW1lIiwicGFzc3dvcmQiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInRvQ29uc29sZSIsInRvRmlsZSIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsInRlc3QiLCJpc05hTiIsInBhcnNlRmxvYXQiLCJlbnZzIiwib2JqZWN0IiwiUFVQUEVURUVSX1RFTVBfRElSIiwiSElHSENIQVJUU19WRVJTSU9OIiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfTUFYX1VQTE9BRF9TSVpFIiwiU0VSVkVSX0JFTkNITUFSS0lORyIsIlNFUlZFUl9QUk9YWV9IT1NUIiwiU0VSVkVSX1BST1hZX1BPUlQiLCJTRVJWRVJfUFJPWFlfVVNFUk5BTUUiLCJTRVJWRVJfUFJPWFlfUEFTU1dPUkQiLCJTRVJWRVJfUFJPWFlfVElNRU9VVCIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVyIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4iLCJTRVJWRVJfU1NMX0VOQUJMRSIsIlNFUlZFUl9TU0xfRk9SQ0UiLCJTRVJWRVJfU1NMX1BPUlQiLCJTRVJWRVJfU1NMX0NFUlRfUEFUSCIsIlBPT0xfTUlOX1dPUktFUlMiLCJQT09MX01BWF9XT1JLRVJTIiwiUE9PTF9XT1JLX0xJTUlUIiwiUE9PTF9BQ1FVSVJFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9USU1FT1VUIiwiUE9PTF9ERVNUUk9ZX1RJTUVPVVQiLCJQT09MX0lETEVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMIiwiUE9PTF9SRUFQRVJfSU5URVJWQUwiLCJQT09MX0JFTkNITUFSS0lORyIsIkxPR0dJTkdfTEVWRUwiLCJMT0dHSU5HX0ZJTEUiLCJMT0dHSU5HX0RFU1QiLCJMT0dHSU5HX1RPX0NPTlNPTEUiLCJMT0dHSU5HX1RPX0ZJTEUiLCJVSV9FTkFCTEUiLCJVSV9ST1VURSIsIk9USEVSX05PREVfRU5WIiwiT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMiLCJPVEhFUl9OT19MT0dPIiwiT1RIRVJfSEFSRF9SRVNFVF9QQUdFIiwiT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFIiwiT1RIRVJfQUxMT1dfWExJTksiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInRhZ05hbWUiLCJ0b1VwcGVyQ2FzZSIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwib3B0aW9uIiwiZW50cmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJhc3luYyIsImZldGNoIiwidXJsIiwicmVxdWVzdE9wdGlvbnMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJoZWFkZXJzIiwiUmVmZXJlciIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsImlzQ2xvc2VkIiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJ0b3RhbFNpemUiLCJCdWZmZXIiLCJieXRlTGVuZ3RoIiwidG9GaXhlZCIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImFicyIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsInNldFRpbWVvdXQiLCJjcmVhdGVJbWFnZSIsImVtdWxhdGVNZWRpYVR5cGUiLCJwZGYiLCJjcmVhdGVQREYiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJjcmVhdGUiLCJpZCIsInV1aWQiLCJzdGFydERhdGUiLCJnZXRUaW1lIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsInB1cHBldGVlck9wdGlvbnMiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwibWF4VHJpZXMiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsInIiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiZm9yYmlkZGVuIiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiRk9SQklEX0FUVFIiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwidjQiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImI2NCIsIm5vRG93bmxvYWQiLCJjb25uZWN0aW9uQWJvcnRlZCIsInNvY2tldCIsImhhZEVycm9ycyIsInRvTG93ZXJDYXNlIiwic3Vic3RyIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJfcmVxIiwic2V0IiwiYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyIsInN0YXJ0U2VydmVyIiwic2VydmVyQ29uZmlnIiwidXBsb2FkTGltaXRCeXRlcyIsInN0b3JhZ2UiLCJtdWx0ZXIiLCJtZW1vcnlTdG9yYWdlIiwidXBsb2FkIiwibGltaXRzIiwiZmllbGRTaXplIiwibGltaXQiLCJ1cmxlbmNvZGVkIiwiZXh0ZW5kZWQiLCJub25lIiwiaHR0cFNlcnZlciIsImNyZWF0ZVNlcnZlciIsImxpc3RlbiIsImNlcnQiLCJmc1Byb21pc2VzIiwicmVhZEZpbGUiLCJwb3NpeCIsImh0dHBzU2VydmVyIiwiTmFOIiwic3RhdGljIiwiaGVhbHRoUm91dGUiLCJleHBvcnRSb3V0ZXMiLCJfcmVxdWVzdCIsInNlbmRGaWxlIiwiYWNjZXB0UmFuZ2VzIiwidWlSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwibG9nZ2luZ09wdGlvbnMiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSx1QkFDQSxnQkFFQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVBQ0EseUJBQ0EsU0FDQSxlQUNBLFlBQ0Esa0JBQ0EsU0FDQSxjQUNBLG1CQUNBLGVBQ0Esa0JBQ0EsY0FDQSxlQUVBLGNBQ0EsV0FDQSxlQUNBLFdBQ0EsU0FDQSxPQUNBLFdBQ0EsWUFDQSxTQUNBLHFCQUNBLGFBQ0EsV0FDQSxXQUNBLFdBQ0EsV0FDQSxlQUNBLFVBQ0Esa0JBQ0Esb0JBQ0EsYUFDQSxVQUNBLGNBQ0EsWUFDQSxZQUVGQyxXQUFZLENBQUMsa0JBQ2JDLE9BQVEsQ0FDTix3RUFDQSxtR0FNU0MsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLENBQ0wsbUNBQ0Es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
diff --git a/dist/index.esm.js b/dist/index.esm.js
index de4dab8f..8f17193f 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"]},_={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."},tempDir:{value:"./tmp/",type:"string",envLink:"PUPPETEER_TEMP_DIR",description:"The directory for Puppeteer to store temporary files."}},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",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in MB, 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."},username:{value:!1,type:"string",envLink:"SERVER_PROXY_USERNAME",cliName:"proxyUsername",description:"The username for the proxy server, if it exists."},password:{value:!1,type:"string",envLink:"SERVER_PROXY_PASSWORD",cliName:"proxyPassword",description:"The password for the proxy server, 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."}}},O={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.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:_.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:_.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:_.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:_.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:_.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:_.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:_.debug.debuggingPort.value}]},L=["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(_),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=>/^(\.\/|\.\.\/|\/|[a-zA-Z]:\\|[a-zA-Z]:\/)?((?:[\w-]+)[\\/]?)+$/.test(e)),{},{message:"The string is an invalid path directory string."}),$=()=>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)),D=()=>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({PUPPETEER_TEMP_DIR:H(),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:$(),EXPORT_DEFAULT_WIDTH:$(),EXPORT_DEFAULT_SCALE:$(),EXPORT_RASTERIZATION_TIMEOUT:D(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:N(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:N(),SERVER_ENABLE:N(),SERVER_HOST:P(),SERVER_PORT:$(),SERVER_MAX_UPLOAD_SIZE:$(),SERVER_BENCHMARKING:N(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:$(),SERVER_PROXY_USERNAME:P(),SERVER_PROXY_PASSWORD:P(),SERVER_PROXY_TIMEOUT:D(),SERVER_RATE_LIMITING_ENABLE:N(),SERVER_RATE_LIMITING_MAX_REQUESTS:D(),SERVER_RATE_LIMITING_WINDOW:D(),SERVER_RATE_LIMITING_DELAY:D(),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:$(),SERVER_SSL_CERT_PATH:P(),POOL_MIN_WORKERS:D(),POOL_MAX_WORKERS:D(),POOL_WORK_LIMIT:$(),POOL_ACQUIRE_TIMEOUT:D(),POOL_CREATE_TIMEOUT:D(),POOL_DESTROY_TIMEOUT:D(),POOL_IDLE_TIMEOUT:D(),POOL_CREATE_RETRY_INTERVAL:D(),POOL_REAPER_INTERVAL:D(),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:D(),DEBUG_DEBUGGING_PORT:$()}).partial().parse(process.env),U=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:U[0]},{title:"warning",color:U[1]},{title:"notice",color:U[2]},{title:"verbose",color:U[3]},{title:"benchmark",color:U[4]}],listeners:[]};const j=(r,i)=>{M.pathCreated||(!e(M.dest)&&t(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)}))},F=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=M;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;M.listeners.forEach((e=>{e(s,o.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(o)),M.toFile&&j(o,s)},V=(e,t,o)=>{const r=o||t.message,{level:i,levelsDesc:s}=M;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];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([r[U[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),M.toFile&&j(l,n)},W=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},q=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return F(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},B=d(new URL("../.",import.meta.url)),X=(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"},z=(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 V(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):F(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 J=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]=J(e[o]));return t},Y=(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 Z(){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(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const Q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,ee=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&ee(r(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},te=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const re=()=>oe,ie=(e,t,o=[])=>{const r=J(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]:ie(r[e],s,o);var i;return r};function se(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?se(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 ne(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:ne(r);return t}function ae(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=ae(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function le(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 ce 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 pe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},he=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ue=async(e,t,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),F(4,`[cache] Fetching script - ${e}.js`);const i=await le(`${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 ce(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return F(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},de=async(e,t,o)=>{const r=e.version,i="latest"!==r&&r?`${r}/`:"",n=e.cdnURL||pe.cdnURL;F(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return pe.sources=await(async(e,t,o,r,i)=>{let s;const{host:n,port:a,username:l,password:p}=r;if(n&&a)try{s=new c({host:n,port:a,...l&&p?{username:l,password:p}:{}})}catch(e){throw new ce("[cache] Could not create a Proxy Agent.").setError(e)}const h=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},u=[...e.map((e=>ue(`${e}`,h,i,!0))),...t.map((e=>ue(`${e}`,h,i))),...o.map((e=>ue(`${e}`,h)))];return(await Promise.all(u)).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),pe.hcVersion=he(pe),s(o,pe.sources),a}catch(e){throw new ce("[cache] Unable to update the local Highcharts cache.").setError(e)}},ge=async o=>{const{highcharts:i,server:n}=o,l=a(B,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)F(3,"[cache] Fetching and caching Highcharts dependencies."),c=await de(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?(F(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(F(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 F(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await de(i,n.proxy,h):(F(3,"[cache] Dependency cache is up to date, proceeding."),pe.sources=r(h,"utf8"),c=t.modules,pe.hcVersion=he(pe))}await(async(e,t)=>{const o={version:e.version,modules:t||{}};pe.activeManifest=o,F(3,"[cache] Writing a new manifest.");try{s(a(B,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ce("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},me=()=>a(B,re().highcharts.cachePath),fe=()=>pe.hcVersion;function ve(){Highcharts.animObject=function(){return{duration:0}}}async function ye(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 be=r(B+"/templates/template.html","utf8");let we;async function Ee(){if(!we)return!1;const e=await we.newPage();return await e.setCacheEnabled(!1),await Se(e),function(e){const{debug:t}=re();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 Te(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){V(2,e,"[browser] Could not clear page's resources.")}}async function Se(e){await e.setContent(be,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${me()}/sources.js`}),await e.evaluate(ve)}const xe=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(F(3,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new ce("[export] The data passed to a page exceeded 100MB.");return e.evaluate(ye,t,o,r)};var Re=async(e,t,o)=>{let i=[];try{F(4,"[export] Determining export path.");const s=o.export,a=s?.options?.chart?.displayErrors&&pe.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(F(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 F(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},o,a):(t.chart.height=s.height,t.chart.width=s.width,await xe(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){V(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(B,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{o.push(await e.addStyleTag(t))}catch(e){V(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 ce("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 ce(`[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 Te(e,i),g}catch(t){return await Te(e,i),t}};let _e=!1;const Oe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const ke={create:async()=>{let e=!1;const t=v(),o=(new Date).getTime();try{if(e=await Ee(),!e||e.isClosed())throw new ce("The page is invalid or closed.");F(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw new ce("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)||(F(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1)),destroy:async e=>{F(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},Ie=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{puppeteer:t,debug:o,other:r}=re(),{enable:i,...s}=o,n={headless:!r.browserShellMode||"shell",userDataDir:t.tempDir||"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...i&&s};if(!we){let e=0;const t=async()=>{try{F(3,`[browser] Attempting to get a browser instance (try ${++e}).`),we=await y.launch(n)}catch(o){if(V(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;F(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&&F(3,"[browser] Launched browser in shell mode."),i&&F(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ce("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!we)throw new ce("[browser] Cannot find a browser to open.")}return we}(e.puppeteerArgs),F(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),_e)return F(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{_e=new f({...ke,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}),_e.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 Se(e)):await e.evaluate((()=>{document.body.innerHTML=''})),!0}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);F(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),_e.on("destroySuccess",((e,t)=>{F(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{_e.release(e)})),F(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ce("[pool] Could not create the pool of workers.").setError(e)}};async function Ce(){if(F(3,"[pool] Killing pool with all workers and closing browser."),_e){for(const e of _e.used)_e.release(e.resource);_e.destroyed||(await _e.destroy(),F(4,"[browser] Destroyed the pool of resources."))}await async function(){we?.connected&&await we.close(),F(4,"[browser] Closed the browser.")}()}const Ne=async(e,t)=>{let o;try{if(F(4,"[pool] Work received, starting to process."),++Oe.exportAttempts,Le.benchmarking&&Pe(),!_e)throw new ce("Work received, but pool has not been started.");const r=te();try{F(4,"[pool] Acquiring a worker handle."),o=await _e.acquire().promise,t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new ce((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(F(4,"[pool] Acquired a worker handle."),!o.page)throw new ce("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();F(4,`[pool] Starting work on pool entry with ID ${o.id}.`);const s=te(),n=await Re(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 ce("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new ce((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),_e.release(o);const a=(new Date).getTime()-i;return Oe.timeSpent+=a,Oe.spentAverage=Oe.timeSpent/++Oe.performedExports,F(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Oe.droppedExports,o&&_e.release(o),new ce(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:_e.min,max:_e.max,all:_e.numFree()+_e.numUsed(),available:_e.numFree(),used:_e.numUsed(),pending:_e.numPendingAcquires()});function Pe(){const{min:e,max:t,all:o,available:r,used:i,pending:s}=Ae();F(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),F(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),F(5,`[pool] The number of all created resources: ${o}.`),F(5,`[pool] The number of available resources: ${r}.`),F(5,`[pool] The number of acquired resources: ${i}.`),F(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var He=Ae,$e=()=>Oe;let De=!1;const Ge=async(e,t)=>{F(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=J(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=ie(t,e,L),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,re()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{F(4,"[chart] Attempting to export from a SVG input.");const e=Fe(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 ce("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return F(4,"[chart] Attempting to export from an input file."),o.export.instr=r(i.infile,"utf8"),Fe(o.export.instr.trim(),o,t)}catch(e){return t(new ce("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return F(4,"[chart] Attempting to export from a raw input."),i.instr=i.instr||i.options,Q(o.customLogic?.allowCodeExecution)?je(o,t):"string"==typeof i.instr?Fe(i.instr.trim(),o,t):Me(o,i.instr||i.options,t)}catch(e){return t(new ce("[chart] Error loading raw input.").setError(e))}return t(new ce("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=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},Me=async(e,t,o,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:De;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=z(e.customLogic.resources,Q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=r("resources.json","utf8");e.customLogic.resources=z(t,Q(e.customLogic.allowFileResources))}catch(e){F(2,"[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 ce("[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=X(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]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=ee(n.customCode,n.allowFileResources)}catch(e){V(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,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ue(e)};try{return o(!1,await Ne(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=Y(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,Me(e,!1,t)}catch(o){return t(new ce(`[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))}},Fe=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return F(4,"[chart] Parsing input as SVG."),Me(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Me(t,r,o)}catch(e){return Q(r)?je(t,o):o(new ce("[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))}},Ve=[],We=()=>{F(4,"[server] Clearing all registered intervals.");for(const e of Ve)clearInterval(e)},qe=(e,t,o,r)=>{V(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,r(e)},Be=(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 Xe=(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&&(F(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),F(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class ze extends ce{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 ze("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 ze("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new ze("No new version supplied.",400);try{await(async e=>{const t=re();t?.highcharts&&(t.highcharts.version=e),await ge(t)})(i)}catch(e){throw new ze(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:fe(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){o(e)}}));const Je={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ye=0;const Ze=[],Qe=[],et=(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},tt=async(e,t,o)=>{try{const o=te(),i=v().replace(/-/g,""),s=re(),n=e.body,a=++Ye;let l=X(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new ze("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 F(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 ze("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=et(Ze,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)})),F(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:De,allowFileResources:!1,resources:K(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Y(c,u.customLogic.allowCodeExecution));const d=ie(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 ze("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&&F(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),h)return F(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new ze(`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,et(Qe,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",Je[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 ot=JSON.parse(r(a(B,"package.json"))),rt=new Date,it=[];function st(e){if(!e)return!1;var t;t=setInterval((()=>{const e=$e(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;it.push(t),it.length>30&&it.shift()}),6e4),Ve.push(t),e.get("/health",((e,t)=>{const o=$e(),r=it.length,i=it.reduce(((e,t)=>e+t),0)/it.length;F(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:rt,uptime:Math.floor(((new Date).getTime()-rt.getTime())/1e3/60)+" minutes",version:ot.version,highchartsVersion:fe(),averageProcessingTime:o.spentAverage,performedExports:o.performedExports,failedExports:o.droppedExports,exportAttempts:o.exportAttempts,sucessRatio:o.performedExports/o.exportAttempts*100,pool:He(),period:r,movingAverage:i,message:isNaN(i)||!it.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 nt=new Map,at=T();at.disable("x-powered-by"),at.use(E()),at.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()}));const lt=e=>{e.on("clientError",((e,t)=>{V(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},ct=async e=>{try{const t=1024*(e.maxUploadSize||3)*1024,o=S.memoryStorage(),r=S({storage:o,limits:{fieldSize:t}});if(at.use(T.json({limit:t})),at.use(T.urlencoded({extended:!0,limit:t})),at.use(r.none()),!e.enable)return!1;if(!e.ssl.force){const t=g.createServer(at);lt(t),t.listen(e.port,e.host),nt.set(e.port,t),F(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){F(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},at);lt(r),r.listen(e.ssl.port,e.host),nt.set(e.ssl.port,r),F(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Xe(at,e.rateLimiting),at.use(T.static(l.join(B,"public"))),st(at),(e=>{e.post("/",tt),e.post("/:filename",tt)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(B,"public","index.html"),{acceptRanges:!1})}))})(at),Ke(at),(e=>{e.use(qe),e.use(Be)})(at)}catch(e){throw new ce("[server] Could not configure and start the server.").setError(e)}},pt=()=>{F(4,"[server] Closing all servers.");for(const[e,t]of nt)t.close((()=>{nt.delete(e),F(4,`[server] Closed server on port: ${e}.`)}))};var ht={startServer:ct,closeServers:pt,getServers:()=>nt,enableRateLimiting:e=>Xe(at,e),getExpress:()=>T,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};const ut=async e=>{await Promise.allSettled([We(),pt(),Ce()]),process.exit(e)};var dt={server:ht,startServer:ct,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,De=Q(t),(e=>{for(const[t,o]of Object.entries(e))M[t]=o;W(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&q(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(F(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{F(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await ut(1)}))),await ge(e),await Ie({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 Ce()}))},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 Ce()}catch(e){throw new ce("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,initPool:Ie,killPool:Ce,setOptions:(e,t)=>(t?.length&&(oe=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){V(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(t)),se(_,oe),oe=ne(_),e&&(oe=ie(oe,e,L)),t?.length&&(oe=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]=Q(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(F(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:ut,log:F,logWithStack:V,setLogLevel:W,enableFileLogging:q,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(O).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)O[e]=O[e].map((t=>({...t,section:e}))),n=[...n,...O[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]=ae(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){V(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(r(a(B,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(r(B+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{dt as default};
+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"]},_={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","--pipe","--no-startup-window","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."},tempDir:{value:"./tmp/",type:"string",envLink:"PUPPETEER_TEMP_DIR",description:"The directory for Puppeteer to store temporary files."}},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",envLink:"SERVER_MAX_UPLOAD_SIZE",description:"The maximum upload size, in MB, 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."},username:{value:!1,type:"string",envLink:"SERVER_PROXY_USERNAME",cliName:"proxyUsername",description:"The username for the proxy server, if it exists."},password:{value:!1,type:"string",envLink:"SERVER_PROXY_PASSWORD",cliName:"proxyPassword",description:"The password for the proxy server, 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."}}},O={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:_.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:_.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:_.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:_.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:_.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:_.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:_.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${_.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${_.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:_.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:_.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:_.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:_.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:_.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:_.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:_.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:_.server.host.value},{type:"number",name:"port",message:"Server port",initial:_.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:_.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:_.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:_.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:_.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:_.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:_.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:_.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:_.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:_.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:_.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:_.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:_.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:_.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:_.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:_.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:_.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:_.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:_.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:_.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:_.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:_.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:_.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:_.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:_.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:_.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:_.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:_.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:_.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:_.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:_.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:_.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:_.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:_.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:_.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:_.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:_.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:_.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:_.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:_.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:_.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:_.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:_.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:_.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:_.debug.debuggingPort.value}]},L=["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(_),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)),$=()=>u.string().trim().refine((e=>/^(\.\/|\.\.\/|\/|[a-zA-Z]:\\|[a-zA-Z]:\/)?((?:[\w-]+)[\\/]?)+$/.test(e)),{},{message:"The string is an invalid path directory string."}),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)),D=()=>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({PUPPETEER_TEMP_DIR:$(),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:D(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:N(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:N(),SERVER_ENABLE:N(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_MAX_UPLOAD_SIZE:H(),SERVER_BENCHMARKING:N(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_USERNAME:P(),SERVER_PROXY_PASSWORD:P(),SERVER_PROXY_TIMEOUT:D(),SERVER_RATE_LIMITING_ENABLE:N(),SERVER_RATE_LIMITING_MAX_REQUESTS:D(),SERVER_RATE_LIMITING_WINDOW:D(),SERVER_RATE_LIMITING_DELAY:D(),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:D(),POOL_MAX_WORKERS:D(),POOL_WORK_LIMIT:H(),POOL_ACQUIRE_TIMEOUT:D(),POOL_CREATE_TIMEOUT:D(),POOL_DESTROY_TIMEOUT:D(),POOL_IDLE_TIMEOUT:D(),POOL_CREATE_RETRY_INTERVAL:D(),POOL_REAPER_INTERVAL:D(),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(),OTHER_ALLOW_XLINK:N(),DEBUG_ENABLE:N(),DEBUG_HEADLESS:N(),DEBUG_DEVTOOLS:N(),DEBUG_LISTEN_TO_CONSOLE:N(),DEBUG_DUMPIO:N(),DEBUG_SLOW_MO:D(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),U=["red","yellow","blue","gray","green"];let M={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:U[0]},{title:"warning",color:U[1]},{title:"notice",color:U[2]},{title:"verbose",color:U[3]},{title:"benchmark",color:U[4]}],listeners:[]};const j=(r,i)=>{M.pathCreated||(!e(M.dest)&&t(M.dest),M.pathCreated=!0),o(`${M.dest}${M.file}`,[i].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),M.toFile=!1)}))},F=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=M;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;M.listeners.forEach((e=>{e(s,o.join(" "))})),M.toConsole&&console.log.apply(void 0,[s.toString()[M.levelsDesc[t-1].color]].concat(o)),M.toFile&&j(o,s)},V=(e,t,o)=>{const r=o||t.message,{level:i,levelsDesc:s}=M;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];M.toConsole&&console.log.apply(void 0,[n.toString()[M.levelsDesc[e-1].color]].concat([r[U[e-1]],"\n",a])),M.listeners.forEach((e=>{e(n,l.join(" "))})),M.toFile&&j(l,n)},W=e=>{e>=0&&e<=M.levelsDesc.length&&(M.level=e)},q=(e,t)=>{if(M={...M,dest:e||M.dest,file:t||M.file,toFile:!0},0===M.dest.length)return F(1,"[logger] File logging initialization: no path supplied.");M.dest.endsWith("/")||(M.dest+="/")},B=d(new URL("../.",import.meta.url)),X=(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"},K=(e=!1,t)=>{const o=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=z(r(e,"utf8"))}catch(e){return V(2,e,"[cli] No resources found.")}else i=z(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):F(3,"[cli] No resources found.")};function z(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 J=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]=J(e[o]));return t},Y=(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 Z(){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(_).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(_[t]))})),console.log("\n")}const Q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,ee=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&ee(r(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},te=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let oe={};const re=()=>oe,ie=(e,t,o=[])=>{const r=J(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]:ie(r[e],s,o);var i;return r};function se(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?se(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 ne(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:ne(r);return t}function ae(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=ae(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function le(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 ce 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 pe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},he=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),ue=async(e,t,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),F(4,`[cache] Fetching script - ${e}.js`);const i=await le(`${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 ce(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return F(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},de=async(e,t,o)=>{const r=e.version,i="latest"!==r&&r?`${r}/`:"",n=e.cdnURL||pe.cdnURL;F(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return pe.sources=await(async(e,t,o,r,i)=>{let s;const{host:n,port:a,username:l,password:p}=r;if(n&&a)try{s=new c({host:n,port:a,...l&&p?{username:l,password:p}:{}})}catch(e){throw new ce("[cache] Could not create a Proxy Agent.").setError(e)}const h=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},u=[...e.map((e=>ue(`${e}`,h,i,!0))),...t.map((e=>ue(`${e}`,h,i))),...o.map((e=>ue(`${e}`,h)))];return(await Promise.all(u)).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),pe.hcVersion=he(pe),s(o,pe.sources),a}catch(e){throw new ce("[cache] Unable to update the local Highcharts cache.").setError(e)}},ge=async o=>{const{highcharts:i,server:n}=o,l=a(B,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)F(3,"[cache] Fetching and caching Highcharts dependencies."),c=await de(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?(F(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(F(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 F(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await de(i,n.proxy,h):(F(3,"[cache] Dependency cache is up to date, proceeding."),pe.sources=r(h,"utf8"),c=t.modules,pe.hcVersion=he(pe))}await(async(e,t)=>{const o={version:e.version,modules:t||{}};pe.activeManifest=o,F(3,"[cache] Writing a new manifest.");try{s(a(B,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new ce("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},me=()=>a(B,re().highcharts.cachePath),fe=()=>pe.hcVersion;function ve(){Highcharts.animObject=function(){return{duration:0}}}async function ye(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 be=r(B+"/templates/template.html","utf8");let we;async function Ee(){if(!we)return!1;const e=await we.newPage();return await e.setCacheEnabled(!1),await Se(e),function(e){const{debug:t}=re();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 Te(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){V(2,e,"[browser] Could not clear page's resources.")}}async function Se(e){await e.setContent(be,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${me()}/sources.js`}),await e.evaluate(ve)}const xe=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(F(4,`[export] The current total size of data passed to a page is around ${(i/1048576).toFixed(2)} MB`),i>=104857600)throw new ce("[export] The data passed to a page exceeded 100MB.");return e.evaluate(ye,t,o,r)};var Re=async(e,t,o)=>{let i=[];try{F(4,"[export] Determining export path.");const s=o.export,a=s?.options?.chart?.displayErrors&&pe.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(F(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 F(4,"[export] Treating as config."),s.strInj?await xe(e,{chart:{height:s.height,width:s.width}},o,a):(t.chart.height=s.height,t.chart.width=s.width,await xe(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){V(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(B,e)}));a.push({content:i.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const t of a)try{o.push(await e.addStyleTag(t))}catch(e){V(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 ce("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 ce(`[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 Te(e,i),g}catch(t){return await Te(e,i),t}};let _e=!1;const Oe={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Le={};const ke={create:async()=>{let e=!1;const t=v(),o=(new Date).getTime();try{if(e=await Ee(),!e||e.isClosed())throw new ce("The page is invalid or closed.");F(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-o} ms.`)}catch(e){throw new ce("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)||(F(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Le.workLimit}).`),!1)),destroy:async e=>{F(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&!e.page.isClosed()&&await e.page.close()}},Ie=async e=>{if(Le=e&&e.pool?{...e.pool}:{},await async function(e){const{puppeteer:t,debug:o,other:r}=re(),{enable:i,...s}=o,n={headless:!r.browserShellMode||"shell",userDataDir:t.tempDir||"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...i&&s};if(!we){const e=25;let t=0;const o=async()=>{try{F(3,`[browser] Attempting to get a browser instance (try ${++t}).`),we=await y.launch(n)}catch(r){if(V(2,r,`[browser] Failed to launch a browser instance - retrying (attempt ${t}/${e}).`),!(t<25))throw r;F(3,`[browser] Retry to open a browser (attempt ${t}/${e}).`),await new Promise((e=>setTimeout(e,4e3))),await o()}};try{await o(),"shell"===n.headless&&F(3,"[browser] Launched browser in shell mode."),i&&F(3,"[browser] Launched browser in debug mode.")}catch(e){throw new ce("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!we)throw new ce("[browser] Cannot find a browser to open.")}return we}(e.puppeteerArgs),F(3,`[pool] Initializing pool with workers: min ${Le.minWorkers}, max ${Le.maxWorkers}.`),_e)return F(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Le.minWorkers)>parseInt(Le.maxWorkers)&&(Le.minWorkers=Le.maxWorkers);try{_e=new f({...ke,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}),_e.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 Se(e)):await e.evaluate((()=>{document.body.innerHTML=''})),!0}catch(e){V(2,e,"[browser] Could not clear the content of the page.")}return!1}(e.page,!1);F(4,`[pool] Releasing a worker with ID ${e.id}. Clear page status: ${t}.`)})),_e.on("destroySuccess",((e,t)=>{F(4,`[pool] Destroyed a worker with ID ${t.id}.`),t.page=null}));const e=[];for(let t=0;t{_e.release(e)})),F(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new ce("[pool] Could not create the pool of workers.").setError(e)}};async function Ce(){if(F(3,"[pool] Killing pool with all workers and closing browser."),_e){for(const e of _e.used)_e.release(e.resource);_e.destroyed||(await _e.destroy(),F(4,"[browser] Destroyed the pool of resources."))}await async function(){we?.connected&&await we.close(),F(4,"[browser] Closed the browser.")}()}const Ne=async(e,t)=>{let o;try{if(F(4,"[pool] Work received, starting to process."),++Oe.exportAttempts,Le.benchmarking&&Pe(),!_e)throw new ce("Work received, but pool has not been started.");const r=te();try{F(4,"[pool] Acquiring a worker handle."),o=await _e.acquire().promise,t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new ce((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(F(4,"[pool] Acquired a worker handle."),!o.page)throw new ce("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();F(4,`[pool] Starting work on pool entry with ID ${o.id}.`);const s=te(),n=await Re(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 ce("Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.").setError(n):new ce((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&F(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),_e.release(o);const a=(new Date).getTime()-i;return Oe.timeSpent+=a,Oe.spentAverage=Oe.timeSpent/++Oe.performedExports,F(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Oe.droppedExports,o&&_e.release(o),new ce(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:_e.min,max:_e.max,all:_e.numFree()+_e.numUsed(),available:_e.numFree(),used:_e.numUsed(),pending:_e.numPendingAcquires()});function Pe(){const{min:e,max:t,all:o,available:r,used:i,pending:s}=Ae();F(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),F(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),F(5,`[pool] The number of all created resources: ${o}.`),F(5,`[pool] The number of available resources: ${r}.`),F(5,`[pool] The number of acquired resources: ${i}.`),F(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var $e=Ae,He=()=>Oe;let De=!1;const Ge=async(e,t)=>{F(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=J(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=ie(t,e,L),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,re()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{F(4,"[chart] Attempting to export from a SVG input.");const e=Fe(function(e){const t=[];G.OTHER_ALLOW_XLINK||t.push("xlink:href");const o=new b("").window;return w(o).sanitize(e,{ADD_TAGS:["foreignObject"],FORBID_ATTR:t})}(o.payload.svg),o,t);return++Oe.exportFromSvgAttempts,e}catch(e){return t(new ce("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return F(4,"[chart] Attempting to export from an input file."),o.export.instr=r(i.infile,"utf8"),Fe(o.export.instr.trim(),o,t)}catch(e){return t(new ce("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return F(4,"[chart] Attempting to export from a raw input."),i.instr=i.instr||i.options,Q(o.customLogic?.allowCodeExecution)?je(o,t):"string"==typeof i.instr?Fe(i.instr.trim(),o,t):Me(o,i.instr||i.options,t)}catch(e){return t(new ce("[chart] Error loading raw input.").setError(e))}return t(new ce("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ue=e=>{const{chart:t,exporting:o}=e.export?.options||z(e.export?.instr),r=z(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},Me=async(e,t,o,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:De;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=K(e.customLogic.resources,Q(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=r("resources.json","utf8");e.customLogic.resources=K(t,Q(e.customLogic.allowFileResources))}catch(e){F(2,"[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 ce("[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=X(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]=z(r(s[e],"utf8"),!0):s[e]=z(s[e],!0))}catch(t){s[e]={},V(2,t,`[chart] The '${e}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=ee(n.customCode,n.allowFileResources)}catch(e){V(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,V(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;e.export={...e.export,...Ue(e)};try{return o(!1,await Ne(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=Y(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,Me(e,!1,t)}catch(o){return t(new ce(`[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))}},Fe=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return F(4,"[chart] Parsing input as SVG."),Me(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Me(t,r,o)}catch(e){return Q(r)?je(t,o):o(new ce("[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))}},Ve=[],We=()=>{F(4,"[server] Clearing all registered intervals.");for(const e of Ve)clearInterval(e)},qe=(e,t,o,r)=>{V(1,e),"development"!==G.OTHER_NODE_ENV&&delete e.stack,r(e)},Be=(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 Xe=(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&&(F(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),F(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class Ke extends ce{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var ze=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,o)=>{try{const o=G.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new Ke("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 Ke("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Ke("No new version supplied.",400);try{await(async e=>{const t=re();t?.highcharts&&(t.highcharts.version=e),await ge(t)})(i)}catch(e){throw new Ke(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:fe(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){o(e)}}));const Je={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Ye=0;const Ze=[],Qe=[],et=(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},tt=async(e,t,o)=>{try{const o=te(),i=v().replace(/-/g,""),s=re(),n=e.body,a=++Ye;let l=X(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new Ke("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=z(n.infile||n.options||n.data);if(!c&&!n.svg)throw F(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 Ke("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=et(Ze,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)})),F(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:z(n.globalOptions,!0),themeOptions:z(n.themeOptions,!0)},customLogic:{allowCodeExecution:De,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(u.export.instr=Y(c,u.customLogic.allowCodeExecution));const d=ie(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 Ke("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&&F(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),h)return F(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new Ke(`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,et(Qe,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",Je[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 ot=JSON.parse(r(a(B,"package.json"))),rt=new Date,it=[];function st(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;it.push(t),it.length>30&&it.shift()}),6e4),Ve.push(t),e.get("/health",((e,t)=>{const o=He(),r=it.length,i=it.reduce(((e,t)=>e+t),0)/it.length;F(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:rt,uptime:Math.floor(((new Date).getTime()-rt.getTime())/1e3/60)+" minutes",version:ot.version,highchartsVersion:fe(),averageProcessingTime:o.spentAverage,performedExports:o.performedExports,failedExports:o.droppedExports,exportAttempts:o.exportAttempts,sucessRatio:o.performedExports/o.exportAttempts*100,pool:$e(),period:r,movingAverage:i,message:isNaN(i)||!it.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 nt=new Map,at=T();at.disable("x-powered-by"),at.use(E()),at.use(((e,t,o)=>{t.set("Accept-Ranges","none"),o()}));const lt=e=>{e.on("clientError",((e,t)=>{V(1,e,`[server] Client error: ${e.message}, destroying socket.`),t.destroy()})),e.on("error",(e=>{V(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{V(1,e,`[server] Socket error: ${e.message}`)}))}))},ct=async e=>{try{const t=1024*(e.maxUploadSize||3)*1024,o=S.memoryStorage(),r=S({storage:o,limits:{fieldSize:t}});if(at.use(T.json({limit:t})),at.use(T.urlencoded({extended:!0,limit:t})),at.use(r.none()),!e.enable)return!1;if(!e.ssl.force){const t=g.createServer(at);lt(t),t.listen(e.port,e.host),nt.set(e.port,t),F(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){F(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},at);lt(r),r.listen(e.ssl.port,e.host),nt.set(e.ssl.port,r),F(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Xe(at,e.rateLimiting),at.use(T.static(l.join(B,"public"))),st(at),(e=>{e.post("/",tt),e.post("/:filename",tt)})(at),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(B,"public","index.html"),{acceptRanges:!1})}))})(at),ze(at),(e=>{e.use(qe),e.use(Be)})(at)}catch(e){throw new ce("[server] Could not configure and start the server.").setError(e)}},pt=()=>{F(4,"[server] Closing all servers.");for(const[e,t]of nt)t.close((()=>{nt.delete(e),F(4,`[server] Closed server on port: ${e}.`)}))};var ht={startServer:ct,closeServers:pt,getServers:()=>nt,enableRateLimiting:e=>Xe(at,e),getExpress:()=>T,getApp:()=>at,use:(e,...t)=>{at.use(e,...t)},get:(e,...t)=>{at.get(e,...t)},post:(e,...t)=>{at.post(e,...t)}};const ut=async e=>{await Promise.allSettled([We(),pt(),Ce()]),process.exit(e)};var dt={server:ht,startServer:ct,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,De=Q(t),(e=>{for(const[t,o]of Object.entries(e))M[t]=o;W(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&q(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(F(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{F(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGTERM",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("SIGHUP",(async(e,t)=>{F(4,`The ${e} event with code: ${t}.`),await ut(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await ut(1)}))),await ge(e),await Ie({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 Ce()}))},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 Ce()}catch(e){throw new ce("[chart] Error encountered during batch export.").setError(e)}},startExport:Ge,initPool:Ie,killPool:Ce,setOptions:(e,t)=>(t?.length&&(oe=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){V(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(t)),se(_,oe),oe=ne(_),e&&(oe=ie(oe,e,L)),t?.length&&(oe=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]=Q(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(F(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&Z();return e}(oe,t,_)),oe),shutdownCleanUp:ut,log:F,logWithStack:V,setLogLevel:W,enableFileLogging:q,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(O).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)O[e]=O[e].map((t=>({...t,section:e}))),n=[...n,...O[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]=ae(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){V(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:e=>{const t=JSON.parse(r(a(B,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(r(B+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Z};export{dt as default};
//# sourceMappingURL=index.esm.js.map
diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map
index 07f1c959..bced50bf 100644
--- a/dist/index.esm.js.map
+++ b/dist/index.esm.js.map
@@ -1 +1 @@
-{"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":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'series-on-point',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap',\r\n 'export-data',\r\n 'navigator',\r\n 'textpath'\r\n ],\r\n indicators: ['indicators-all'],\r\n custom: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\r\n ]\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n },\r\n tempDir: {\r\n value: './tmp/',\r\n type: 'string',\r\n envLink: 'PUPPETEER_TEMP_DIR',\r\n description: 'The directory for Puppeteer to store temporary files.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: scriptsNames.custom,\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\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.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\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.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n maxUploadSize: {\r\n value: 3,\r\n type: 'number',\r\n envLink: 'SERVER_MAX_UPLOAD_SIZE',\r\n description: 'The maximum upload size, in MB, for the server.'\r\n },\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n username: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_USERNAME',\r\n cliName: 'proxyUsername',\r\n description: 'The username for the proxy server, if it exists.'\r\n },\r\n password: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_PASSWORD',\r\n cliName: 'proxyPassword',\r\n description: 'The password for the proxy server, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.'\r\n },\r\n toConsole: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'LOGGING_TO_CONSOLE',\r\n cliName: 'logToConsole',\r\n description: 'Enables or disables showing logs in the console.'\r\n },\r\n toFile: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'LOGGING_TO_FILE',\r\n cliName: 'logToFile',\r\n description:\r\n 'Enables or disables creation of the log directory and saving the log into a .log file.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n },\r\n browserShellMode: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_BROWSER_SHELL_MODE',\r\n description: 'Decides if the browser runs in the shell mode.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message:\r\n 'A log file name. Set with --toFile and --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to a log file when the file logging is enabled',\r\n initial: defaultConfig.logging.dest.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'toConsole',\r\n message: 'Enable logging to the console',\r\n initial: defaultConfig.logging.toConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'toFile',\r\n message: 'Enables logging to a file',\r\n initial: defaultConfig.logging.toFile.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'browserShellMode',\r\n message: 'Decides if the browser runs in the shell mode',\r\n initial: defaultConfig.other.browserShellMode.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Checks if the string is a valid path directory (path format)\r\n path: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => {\r\n // Simplified regex to match both absolute and relative paths\r\n return /^(\\.\\/|\\.\\.\\/|\\/|[a-zA-Z]:\\\\|[a-zA-Z]:\\/)?((?:[\\w-]+)[\\\\/]?)+$/.test(\r\n value\r\n );\r\n },\r\n {},\r\n {\r\n message: 'The string is an invalid path directory string.'\r\n }\r\n ),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // puppeteer\r\n PUPPETEER_TEMP_DIR: v.path(),\r\n\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_MAX_UPLOAD_SIZE: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_USERNAME: v.string(),\r\n SERVER_PROXY_PASSWORD: v.string(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n LOGGING_TO_CONSOLE: v.boolean(),\r\n LOGGING_TO_FILE: v.boolean(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { levelsDesc, level } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n logToFile(texts, prefix);\r\n }\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n if (logging.toFile) {\r\n logToFile(texts, prefix);\r\n }\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} loggingOptions - The logging configuration object.\r\n */\r\nexport const initLogging = (loggingOptions) => {\r\n // Set all the logging options on our logging module object\r\n for (const [key, value] of Object.entries(loggingOptions)) {\r\n logging[key] = value;\r\n }\r\n\r\n // Set the log level\r\n setLogLevel(loggingOptions && parseInt(loggingOptions.level));\r\n\r\n // Set the log file path and name\r\n if (loggingOptions && loggingOptions.dest && loggingOptions.toFile) {\r\n enableFileLogging(\r\n loggingOptions.dest,\r\n loggingOptions.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(\r\n url,\r\n Object.assign(\r\n {\r\n headers: {\r\n 'User-Agent': 'highcharts/export',\r\n Referer: 'highcharts/export'\r\n }\r\n },\r\n requestOptions || {}\r\n ),\r\n (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n }\r\n )\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const { host, port, username, password } = proxyOptions;\r\n\r\n // Try to create a Proxy Agent\r\n if (host && port) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host,\r\n port,\r\n ...(username && password ? { username, password } : {})\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport const getCache = () => cache;\r\n\r\nexport const highcharts = () => cache.sources;\r\n\r\nexport const version = () => cache.hcVersion;\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache,\r\n highcharts,\r\n version\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport async function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function('options', options.customLogic.customCode)(userOptions);\r\n }\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n let constr = options.export.constr || 'chart';\r\n constr = typeof Highcharts[constr] !== 'undefined' ? constr : 'chart';\r\n\r\n Highcharts[constr]('container', finalOptions, finalCallback);\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get debug and other options\r\n const { puppeteer: puppeteerOptions, debug, other } = getOptions();\r\n\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debugOptions } = debug;\r\n\r\n const launchOptions = {\r\n headless: other.browserShellMode ? 'shell' : true,\r\n userDataDir: puppeteerOptions.tempDir || './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debugOptions)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n\r\n // Shell mode inform\r\n if (launchOptions.headless === 'shell') {\r\n log(3, `[browser] Launched browser in shell mode.`);\r\n }\r\n\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n // Set page events\r\n setPageEvents(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (page && !page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '';\r\n });\r\n }\r\n return true;\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n\r\n return false;\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to which resources will be\r\n * added.\r\n * @param {Object} options - All options and configuration.\r\n *\r\n * @returns {Promise>} - Promise resolving to an array of injected\r\n * resources.\r\n */\r\nexport async function addPageResources(page, options) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\r\n * injected resources and resets CSS and script tags on the page. Additionally,\r\n * it destroys previously existing charts.\r\n *\r\n * @param {Object} page - The Puppeteer Page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n try {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n } catch (error) {\r\n logWithStack(2, error, `[browser] Could not clear page's resources.`);\r\n }\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events for a Puppeteer Page.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to set events to.\r\n */\r\nfunction setPageEvents(page) {\r\n // Get debug options\r\n const { debug } = getOptions();\r\n\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // It would seem like this may fire at the same time or shortly before\r\n // a page is closed.\r\n if (page.isClosed()) {\r\n return;\r\n }\r\n\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `Chart input data error: ${error.toString()}`\r\n );\r\n });\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { getCache } from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n\r\n return page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding,\r\n timeout: rasterizationTimeout || 1500\r\n });\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = async (page, chart, options, displayErrors) => {\r\n // Get rid of the redunant string data\r\n options.export.instr = null;\r\n options.export.infile = null;\r\n\r\n // Get the size of the export input\r\n const totalSize = Buffer.byteLength(\r\n options.export?.strInj ? options.export?.strInj : JSON.stringify(chart),\r\n 'utf-8'\r\n );\r\n\r\n // Log the size in MB\r\n log(\r\n 3,\r\n `[export] The current total size of data passed to a page is around ${(\r\n totalSize /\r\n (1024 * 1024)\r\n ).toFixed(2)} MB`\r\n );\r\n\r\n // Check the size of data passed to the page\r\n if (totalSize >= 100 * 1024 * 1024) {\r\n throw new ExportError(`[export] The data passed to a page exceeded 100MB.`);\r\n }\r\n\r\n // Trigger the Highcharts chart creation\r\n return page.evaluate(triggerExport, chart, options, displayErrors);\r\n};\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n // Injected resources array (additional JS and CSS)\r\n let injectedResources = [];\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources = await addPageResources(page, options);\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.abs(\r\n Math.ceil(size.chartHeight || exportOptions.height)\r\n );\r\n const viewportWidth = Math.abs(\r\n Math.ceil(size.chartWidth || exportOptions.width)\r\n );\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // Rasterization process\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return data;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export \r\n \r\n \r\n \r\n \r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n create as createBrowser,\r\n close as closeBrowser,\r\n newPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await newPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n // NOTE: In certain cases acquiring throws a TargetCloseError, which may\r\n // be caused by two things:\r\n // - The page is closed and attempted to be reused.\r\n // - Lost contact with the browser\r\n // What we're seeing in logs is that successive exports typically\r\n // succeeds, and the server recovers, indicating that it's likely\r\n // the first case. This is an attempt at allievating the issue by\r\n // simply not validating the worker if the page is null or closed.\r\n //\r\n // The actual result from when this happened, was that a worker would\r\n // be completely locked, stopping it from being acquired until\r\n // its work count reached the limit.\r\n if (!workerHandle.page || workerHandle.page?.isClosed()) {\r\n return false;\r\n }\r\n\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page && !workerHandle.page.isClosed()) {\r\n await workerHandle.page.close();\r\n }\r\n }\r\n\r\n // log: (message, level) => log(1, '[tarn] ' + message)\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n const r = await clearPage(resource.page, false);\r\n log(\r\n 4,\r\n `[pool] Releasing a worker with ID ${resource.id}. Clear page status: ${r}.`\r\n );\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n resource.page = null;\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // NOTE: If there's a rasterization timeout, we want need to flush the page.\r\n // This is because the page may be in a state where it's waiting for\r\n // the screenshot to finish even though the timeout has occured.\r\n // Which of course causes a lot of issues with the event system,\r\n // and page consistency.\r\n //\r\n // NOTE: Only page.screenshot will throw this, timeouts for PDF's are\r\n // handled by the page.pdf function itself.\r\n //\r\n // ...yes, this is ugly.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.workCount = poolConfig.workLimit + 1;\r\n workerHandle.page = null;\r\n }\r\n\r\n if (\r\n result.name === 'TimeoutError' ||\r\n result.message === 'Rasterization timeout'\r\n ) {\r\n throw new ExportError(\r\n 'Rasterization timeout: your chart may be too complex or large, and failed to render within the allotted time.'\r\n ).setError(result);\r\n } else {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Use whichever one is available\r\n exportOptions.instr = exportOptions.instr || exportOptions.options;\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n log(2, `[chart] Unable to load the default resources.json file.`);\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\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.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\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.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, {\r\n ADD_TAGS: ['foreignObject'],\r\n // Disallow all xlinks in incoming SVG\r\n FORBID_ATTR: ['xlink:href']\r\n });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 400;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { updateVersion, version } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect:\r\n Content-Type: ${request.headers['content-type']}. \r\n Chart constructor: ${body.constr}.\r\n Dimensions: ${body.width}x${body.height} @ ${body.scale} scale.\r\n Type: ${type}.\r\n Is SVG set? ${typeof body.svg !== 'undefined'}.\r\n B64? ${typeof body.b64 !== 'undefined'}.\r\n No download? ${typeof body.noDownload !== 'undefined'}.\r\n\r\n Payload received: ${JSON.stringify(body.infile || body.options || body.data || body.svg)}\r\n\r\n `\r\n );\r\n\r\n throw new HttpError(\r\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.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', (hadErrors) => {\r\n if (hadErrors) {\r\n connectionAborted = true;\r\n }\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\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.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport { version } from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message:\r\n isNaN(movingAverage) || !successRates.length\r\n ? 'Too early to report. No exports made yet. Please check back soon.'\r\n : `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Getting a lot of RangeNotSatisfiableError exception.\r\n// Even though this is a deprecated options, let's try to set it to false.\r\napp.use((_req, res, next) => {\r\n res.set('Accept-Ranges', 'none');\r\n next();\r\n});\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error, socket) => {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[server] Client error: ${error.message}, destroying socket.`\r\n );\r\n socket.destroy();\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // TODO: Read from config/env\r\n // NOTE:\r\n // Too big limits lead to timeouts in the export process when the\r\n // rasterization timeout is set too low.\r\n const uploadLimitMiB = serverConfig.maxUploadSize || 3;\r\n const uploadLimitBytes = uploadLimitMiB * 1024 * 1024;\r\n\r\n // Enable parsing of form data (files) with Multer package\r\n const storage = multer.memoryStorage();\r\n const upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: uploadLimitBytes\r\n }\r\n });\r\n\r\n // Enable body parser\r\n app.use(express.json({ limit: uploadLimitBytes }));\r\n app.use(express.urlencoded({ extended: true, limit: uploadLimitBytes }));\r\n\r\n // Use only non-file multipart form fields\r\n app.use(upload.none());\r\n\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (_request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'), {\r\n acceptRanges: false\r\n });\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\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.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","custom","defaultConfig","puppeteer","args","value","type","description","tempDir","envLink","highcharts","version","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","enable","cliName","host","port","benchmarking","proxy","username","password","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","test","isNaN","parseFloat","envs","object","PUPPETEER_TEMP_DIR","HIGHCHARTS_VERSION","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_MAX_UPLOAD_SIZE","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_USERNAME","SERVER_PROXY_PASSWORD","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","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","puppeteerOptions","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,yCAEfC,QAAS,CACPH,MAAO,SACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,0DAGjBG,WAAY,CACVC,QAAS,CACPN,MAAO,SACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,sCAEfK,OAAQ,CACNP,MAAO,+BACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,kDAEfM,YAAa,CACXR,MAAOR,EAAaC,KACpBQ,KAAM,WACNG,QAAS,0BACTF,YAAa,yCAEfO,cAAe,CACbT,MAAOR,EAAaE,QACpBO,KAAM,WACNG,QAAS,4BACTF,YAAa,uCAEfQ,iBAAkB,CAChBV,MAAOR,EAAaG,WACpBM,KAAM,WACNG,QAAS,+BACTF,YAAa,0CAEfS,cAAe,CACbX,MAAOR,EAAaI,OACpBK,KAAM,WACNC,YAAa,uDAEfU,WAAY,CACVZ,OAAO,EACPC,KAAM,UACNG,QAAS,yBACTF,YACE,iFAEJW,UAAW,CACTb,MAAO,SACPC,KAAM,SACNG,QAAS,wBACTF,YACE,oGAGNY,OAAQ,CACNC,OAAQ,CACNf,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJc,MAAO,CACLhB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfgB,QAAS,CACPlB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNG,QAAS,cACTF,YAAa,6DAEfiB,OAAQ,CACNnB,MAAO,QACPC,KAAM,SACNG,QAAS,gBACTF,YACE,8EAEJkB,cAAe,CACbpB,MAAO,IACPC,KAAM,SACNG,QAAS,wBACTF,YACE,wEAEJmB,aAAc,CACZrB,MAAO,IACPC,KAAM,SACNG,QAAS,uBACTF,YACE,uEAEJoB,aAAc,CACZtB,MAAO,EACPC,KAAM,SACNG,QAAS,uBACTF,YACE,uEAEJqB,OAAQ,CACNvB,OAAO,EACPC,KAAM,SACNC,YACE,kFAEJsB,MAAO,CACLxB,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJuB,MAAO,CACLzB,OAAO,EACPC,KAAM,SACNC,YACE,6GAEJwB,cAAe,CACb1B,OAAO,EACPC,KAAM,SACNC,YACE,2GAEJyB,aAAc,CACZ3B,OAAO,EACPC,KAAM,SACNC,YACE,iHAEJ0B,MAAO,CACL5B,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJ2B,qBAAsB,CACpB7B,MAAO,KACPC,KAAM,SACNG,QAAS,+BACTF,YACE,kEAGN4B,YAAa,CACXC,mBAAoB,CAClB/B,OAAO,EACPC,KAAM,UACNG,QAAS,oCACTF,YACE,6FAEJ8B,mBAAoB,CAClBhC,OAAO,EACPC,KAAM,UACNG,QAAS,oCACTF,YACE,sHAEJ+B,WAAY,CACVjC,OAAO,EACPC,KAAM,SACNC,YACE,mJAEJgC,SAAU,CACRlC,OAAO,EACPC,KAAM,SACNC,YACE,0GAEJiC,UAAW,CACTnC,OAAO,EACPC,KAAM,SACNC,YACE,yGAEJkC,WAAY,CACVpC,OAAO,EACPC,KAAM,SACNoC,WAAY,WACZnC,YAAa,yDAEfoC,aAAc,CACZtC,OAAO,EACPC,KAAM,SACNC,YACE,wFAGNqC,OAAQ,CACNC,cAAe,CACbxC,MAAO,EACPC,KAAM,SACNG,QAAS,yBACTF,YAAa,mDAEfuC,OAAQ,CACNzC,OAAO,EACPC,KAAM,UACNG,QAAS,gBACTsC,QAAS,eACTxC,YACE,wEAEJyC,KAAM,CACJ3C,MAAO,UACPC,KAAM,SACNG,QAAS,cACTF,YACE,0FAEJ0C,KAAM,CACJ5C,MAAO,KACPC,KAAM,SACNG,QAAS,cACTF,YAAa,iCAEf2C,aAAc,CACZ7C,OAAO,EACPC,KAAM,UACNG,QAAS,sBACTsC,QAAS,qBACTxC,YACE,qIAEJ4C,MAAO,CACLH,KAAM,CACJ3C,OAAO,EACPC,KAAM,SACNG,QAAS,oBACTsC,QAAS,YACTxC,YAAa,sDAEf0C,KAAM,CACJ5C,MAAO,KACPC,KAAM,SACNG,QAAS,oBACTsC,QAAS,YACTxC,YAAa,sDAEf6C,SAAU,CACR/C,OAAO,EACPC,KAAM,SACNG,QAAS,wBACTsC,QAAS,gBACTxC,YAAa,oDAEf8C,SAAU,CACRhD,OAAO,EACPC,KAAM,SACNG,QAAS,wBACTsC,QAAS,gBACTxC,YAAa,oDAEf+C,QAAS,CACPjD,MAAO,IACPC,KAAM,SACNG,QAAS,uBACTsC,QAAS,eACTxC,YAAa,2DAGjBgD,aAAc,CACZT,OAAQ,CACNzC,OAAO,EACPC,KAAM,UACNG,QAAS,8BACTsC,QAAS,qBACTxC,YAAa,yCAEfiD,YAAa,CACXnD,MAAO,GACPC,KAAM,SACNG,QAAS,oCACTiC,WAAY,YACZnC,YAAa,yDAEfkD,OAAQ,CACNpD,MAAO,EACPC,KAAM,SACNG,QAAS,8BACTF,YAAa,uDAEfmD,MAAO,CACLrD,MAAO,EACPC,KAAM,SACNG,QAAS,6BACTF,YACE,qFAEJoD,WAAY,CACVtD,OAAO,EACPC,KAAM,UACNG,QAAS,mCACTF,YAAa,6DAEfqD,QAAS,CACPvD,OAAO,EACPC,KAAM,SACNG,QAAS,gCACTF,YACE,yFAEJsD,UAAW,CACTxD,OAAO,EACPC,KAAM,SACNG,QAAS,kCACTF,YACE,wFAGNuD,IAAK,CACHhB,OAAQ,CACNzC,OAAO,EACPC,KAAM,UACNG,QAAS,oBACTsC,QAAS,YACTxC,YAAa,yCAEfwD,MAAO,CACL1D,OAAO,EACPC,KAAM,UACNG,QAAS,mBACTsC,QAAS,WACTL,WAAY,UACZnC,YACE,oEAEJ0C,KAAM,CACJ5C,MAAO,IACPC,KAAM,SACNG,QAAS,kBACTsC,QAAS,UACTxC,YAAa,4CAEfyD,SAAU,CACR3D,OAAO,EACPC,KAAM,SACNG,QAAS,uBACTiC,WAAY,UACZnC,YAAa,+CAInB0D,KAAM,CACJC,WAAY,CACV7D,MAAO,EACPC,KAAM,SACNG,QAAS,mBACTF,YAAa,4DAEf4D,WAAY,CACV9D,MAAO,EACPC,KAAM,SACNG,QAAS,mBACTiC,WAAY,UACZnC,YAAa,gDAEf6D,UAAW,CACT/D,MAAO,GACPC,KAAM,SACNG,QAAS,kBACTF,YACE,yFAEJ8D,eAAgB,CACdhE,MAAO,IACPC,KAAM,SACNG,QAAS,uBACTF,YACE,oEAEJ+D,cAAe,CACbjE,MAAO,IACPC,KAAM,SACNG,QAAS,sBACTF,YACE,mEAEJgE,eAAgB,CACdlE,MAAO,IACPC,KAAM,SACNG,QAAS,uBACTF,YACE,qEAEJiE,YAAa,CACXnE,MAAO,IACPC,KAAM,SACNG,QAAS,oBACTF,YACE,6EAEJkE,oBAAqB,CACnBpE,MAAO,IACPC,KAAM,SACNG,QAAS,6BACTF,YACE,mGAEJmE,eAAgB,CACdrE,MAAO,IACPC,KAAM,SACNG,QAAS,uBACTF,YACE,oGAEJ2C,aAAc,CACZ7C,OAAO,EACPC,KAAM,UACNG,QAAS,oBACTsC,QAAS,mBACTxC,YACE,0EAGNoE,QAAS,CACPC,MAAO,CACLvE,MAAO,EACPC,KAAM,SACNG,QAAS,gBACTsC,QAAS,WACTxC,YAAa,iCAEfsE,KAAM,CACJxE,MAAO,+BACPC,KAAM,SACNG,QAAS,eACTsC,QAAS,UACTxC,YACE,6GAEJuE,KAAM,CACJzE,MAAO,OACPC,KAAM,SACNG,QAAS,eACTsC,QAAS,UACTxC,YACE,oGAEJwE,UAAW,CACT1E,OAAO,EACPC,KAAM,UACNG,QAAS,qBACTsC,QAAS,eACTxC,YAAa,oDAEfyE,OAAQ,CACN3E,OAAO,EACPC,KAAM,UACNG,QAAS,kBACTsC,QAAS,YACTxC,YACE,2FAGN0E,GAAI,CACFnC,OAAQ,CACNzC,OAAO,EACPC,KAAM,UACNG,QAAS,YACTsC,QAAS,WACTxC,YACE,sEAEJ2E,MAAO,CACL7E,MAAO,IACPC,KAAM,SACNG,QAAS,WACTsC,QAAS,UACTxC,YACE,4EAGN4E,MAAO,CACLC,QAAS,CACP/E,MAAO,aACPC,KAAM,SACNG,QAAS,iBACTF,YAAa,oCAEf8E,qBAAsB,CACpBhF,OAAO,EACPC,KAAM,UACNG,QAAS,gCACTF,YAAa,2DAEf+E,OAAQ,CACNjF,OAAO,EACPC,KAAM,UACNG,QAAS,gBACTF,YACE,2EAEJgF,cAAe,CACblF,OAAO,EACPC,KAAM,UACNG,QAAS,wBACTF,YAAa,yDAEfiF,iBAAkB,CAChBnF,OAAO,EACPC,KAAM,UACNG,QAAS,2BACTF,YAAa,mDAGjBkF,MAAO,CACL3C,OAAQ,CACNzC,OAAO,EACPC,KAAM,UACNG,QAAS,eACTsC,QAAS,cACTxC,YAAa,8DAEfmF,SAAU,CACRrF,OAAO,EACPC,KAAM,UACNG,QAAS,iBACTF,YACE,8EAEJoF,SAAU,CACRtF,OAAO,EACPC,KAAM,UACNG,QAAS,iBACTF,YACE,8EAEJqF,gBAAiB,CACfvF,OAAO,EACPC,KAAM,UACNG,QAAS,0BACTF,YACE,oFAEJsF,OAAQ,CACNxF,OAAO,EACPC,KAAM,UACNG,QAAS,eACTF,YACE,qFAEJuF,OAAQ,CACNzF,MAAO,EACPC,KAAM,SACNG,QAAS,gBACTF,YACE,4EAEJwF,cAAe,CACb1F,MAAO,KACPC,KAAM,SACNG,QAAS,uBACTF,YAAa,mCAWNyF,EAAgB,CAC3B7F,UAAW,CACT,CACEG,KAAM,OACN2F,KAAM,OACNC,QAAS,sBACTC,QAASjG,EAAcC,UAAUC,KAAKC,MAAM+F,KAAK,KACjDC,UAAW,MAGf3F,WAAY,CACV,CACEJ,KAAM,OACN2F,KAAM,UACNC,QAAS,qBACTC,QAASjG,EAAcQ,WAAWC,QAAQN,OAE5C,CACEC,KAAM,OACN2F,KAAM,SACNC,QAAS,iBACTC,QAASjG,EAAcQ,WAAWE,OAAOP,OAE3C,CACEC,KAAM,cACN2F,KAAM,cACNC,QAAS,yBACTI,aAAc,yDACdC,QAASrG,EAAcQ,WAAWG,YAAYR,OAEhD,CACEC,KAAM,cACN2F,KAAM,gBACNC,QAAS,2BACTI,aAAc,yDACdC,QAASrG,EAAcQ,WAAWI,cAAcT,OAElD,CACEC,KAAM,cACN2F,KAAM,mBACNC,QAAS,8BACTI,aAAc,yDACdC,QAASrG,EAAcQ,WAAWK,iBAAiBV,OAErD,CACEC,KAAM,OACN2F,KAAM,gBACNC,QAAS,iBACTC,QAASjG,EAAcQ,WAAWM,cAAcX,MAAM+F,KAAK,KAC3DC,UAAW,KAEb,CACE/F,KAAM,SACN2F,KAAM,aACNC,QAAS,6BACTC,QAASjG,EAAcQ,WAAWO,WAAWZ,OAE/C,CACEC,KAAM,OACN2F,KAAM,YACNC,QAAS,kCACTC,QAASjG,EAAcQ,WAAWQ,UAAUb,QAGhDc,OAAQ,CACN,CACEb,KAAM,SACN2F,KAAM,OACNC,QAAS,+BACTM,KAAM,YAAYtG,EAAciB,OAAOb,KAAKD,QAC5C8F,QAAS,EACTI,QAAS,CAAC,MAAO,OAAQ,MAAO,QAElC,CACEjG,KAAM,SACN2F,KAAM,SACNC,QAAS,yCACTM,KAAM,YAAYtG,EAAciB,OAAOK,OAAOnB,QAC9C8F,QAAS,EACTI,QAAS,CAAC,QAAS,aAAc,WAAY,eAE/C,CACEjG,KAAM,SACN2F,KAAM,gBACNC,QAAS,oDACTC,QAASjG,EAAciB,OAAOM,cAAcpB,OAE9C,CACEC,KAAM,SACN2F,KAAM,eACNC,QAAS,mDACTC,QAASjG,EAAciB,OAAOO,aAAarB,OAE7C,CACEC,KAAM,SACN2F,KAAM,eACNC,QAAS,mDACTC,QAASjG,EAAciB,OAAOQ,aAAatB,MAC3CoG,IAAK,GACLC,IAAK,GAEP,CACEpG,KAAM,SACN2F,KAAM,uBACNC,QAAS,gDACTC,QAASjG,EAAciB,OAAOe,qBAAqB7B,QAGvD8B,YAAa,CACX,CACE7B,KAAM,SACN2F,KAAM,qBACNC,QAAS,kCACTC,QAASjG,EAAciC,YAAYC,mBAAmB/B,OAExD,CACEC,KAAM,SACN2F,KAAM,qBACNC,QAAS,wBACTC,QAASjG,EAAciC,YAAYE,mBAAmBhC,QAG1DuC,OAAQ,CACN,CACEtC,KAAM,SACN2F,KAAM,SACNC,QAAS,+BACTC,QAASjG,EAAc0C,OAAOE,OAAOzC,OAEvC,CACEC,KAAM,OACN2F,KAAM,OACNC,QAAS,kBACTC,QAASjG,EAAc0C,OAAOI,KAAK3C,OAErC,CACEC,KAAM,SACN2F,KAAM,OACNC,QAAS,cACTC,QAASjG,EAAc0C,OAAOK,KAAK5C,OAErC,CACEC,KAAM,SACN2F,KAAM,eACNC,QAAS,6BACTC,QAASjG,EAAc0C,OAAOM,aAAa7C,OAE7C,CACEC,KAAM,OACN2F,KAAM,aACNC,QAAS,sCACTC,QAASjG,EAAc0C,OAAOO,MAAMH,KAAK3C,OAE3C,CACEC,KAAM,SACN2F,KAAM,aACNC,QAAS,sCACTC,QAASjG,EAAc0C,OAAOO,MAAMF,KAAK5C,OAE3C,CACEC,KAAM,SACN2F,KAAM,gBACNC,QAAS,0CACTC,QAASjG,EAAc0C,OAAOO,MAAMG,QAAQjD,OAE9C,CACEC,KAAM,SACN2F,KAAM,sBACNC,QAAS,uBACTC,QAASjG,EAAc0C,OAAOW,aAAaT,OAAOzC,OAEpD,CACEC,KAAM,SACN2F,KAAM,2BACNC,QAAS,0CACTC,QAASjG,EAAc0C,OAAOW,aAAaC,YAAYnD,OAEzD,CACEC,KAAM,SACN2F,KAAM,sBACNC,QAAS,2CACTC,QAASjG,EAAc0C,OAAOW,aAAaE,OAAOpD,OAEpD,CACEC,KAAM,SACN2F,KAAM,qBACNC,QACE,oEACFC,QAASjG,EAAc0C,OAAOW,aAAaG,MAAMrD,OAEnD,CACEC,KAAM,SACN2F,KAAM,0BACNC,QAAS,wCACTC,QAASjG,EAAc0C,OAAOW,aAAaI,WAAWtD,OAExD,CACEC,KAAM,OACN2F,KAAM,uBACNC,QACE,8EACFC,QAASjG,EAAc0C,OAAOW,aAAaK,QAAQvD,OAErD,CACEC,KAAM,OACN2F,KAAM,yBACNC,QACE,4EACFC,QAASjG,EAAc0C,OAAOW,aAAaM,UAAUxD,OAEvD,CACEC,KAAM,SACN2F,KAAM,aACNC,QAAS,sBACTC,QAASjG,EAAc0C,OAAOkB,IAAIhB,OAAOzC,OAE3C,CACEC,KAAM,SACN2F,KAAM,YACNC,QAAS,gCACTC,QAASjG,EAAc0C,OAAOkB,IAAIC,MAAM1D,OAE1C,CACEC,KAAM,SACN2F,KAAM,WACNC,QAAS,kBACTC,QAASjG,EAAc0C,OAAOkB,IAAIb,KAAK5C,OAEzC,CACEC,KAAM,OACN2F,KAAM,eACNC,QAAS,2CACTC,QAASjG,EAAc0C,OAAOkB,IAAIE,SAAS3D,QAG/C4D,KAAM,CACJ,CACE3D,KAAM,SACN2F,KAAM,aACNC,QAAS,yCACTC,QAASjG,EAAc+D,KAAKC,WAAW7D,OAEzC,CACEC,KAAM,SACN2F,KAAM,aACNC,QAAS,yCACTC,QAASjG,EAAc+D,KAAKE,WAAW9D,OAEzC,CACEC,KAAM,SACN2F,KAAM,YACNC,QACE,iFACFC,QAASjG,EAAc+D,KAAKG,UAAU/D,OAExC,CACEC,KAAM,SACN2F,KAAM,iBACNC,QAAS,8DACTC,QAASjG,EAAc+D,KAAKI,eAAehE,OAE7C,CACEC,KAAM,SACN2F,KAAM,gBACNC,QAAS,6DACTC,QAASjG,EAAc+D,KAAKK,cAAcjE,OAE5C,CACEC,KAAM,SACN2F,KAAM,iBACNC,QAAS,+DACTC,QAASjG,EAAc+D,KAAKM,eAAelE,OAE7C,CACEC,KAAM,SACN2F,KAAM,cACNC,QAAS,iEACTC,QAASjG,EAAc+D,KAAKO,YAAYnE,OAE1C,CACEC,KAAM,SACN2F,KAAM,sBACNC,QACE,kEACFC,QAASjG,EAAc+D,KAAKQ,oBAAoBpE,OAElD,CACEC,KAAM,SACN2F,KAAM,iBACNC,QACE,+FACFC,QAASjG,EAAc+D,KAAKS,eAAerE,OAE7C,CACEC,KAAM,SACN2F,KAAM,eACNC,QAAS,0CACTC,QAASjG,EAAc+D,KAAKf,aAAa7C,QAG7CsE,QAAS,CACP,CACErE,KAAM,SACN2F,KAAM,QACNC,QACE,uFACFC,QAASjG,EAAcyE,QAAQC,MAAMvE,MACrCsG,MAAO,EACPF,IAAK,EACLC,IAAK,GAEP,CACEpG,KAAM,OACN2F,KAAM,OACNC,QACE,0EACFC,QAASjG,EAAcyE,QAAQE,KAAKxE,OAEtC,CACEC,KAAM,OACN2F,KAAM,OACNC,QAAS,0DACTC,QAASjG,EAAcyE,QAAQG,KAAKzE,OAEtC,CACEC,KAAM,SACN2F,KAAM,YACNC,QAAS,gCACTC,QAASjG,EAAcyE,QAAQI,UAAU1E,OAE3C,CACEC,KAAM,SACN2F,KAAM,SACNC,QAAS,4BACTC,QAASjG,EAAcyE,QAAQK,OAAO3E,QAG1C4E,GAAI,CACF,CACE3E,KAAM,SACN2F,KAAM,SACNC,QAAS,kCACTC,QAASjG,EAAc+E,GAAGnC,OAAOzC,OAEnC,CACEC,KAAM,OACN2F,KAAM,QACNC,QAAS,2BACTC,QAASjG,EAAc+E,GAAGC,MAAM7E,QAGpC8E,MAAO,CACL,CACE7E,KAAM,OACN2F,KAAM,UACNC,QAAS,kCACTC,QAASjG,EAAciF,MAAMC,QAAQ/E,OAEvC,CACEC,KAAM,SACN2F,KAAM,uBACNC,QAAS,uDACTC,QAASjG,EAAciF,MAAME,qBAAqBhF,OAEpD,CACEC,KAAM,SACN2F,KAAM,SACNC,QAAS,6DACTC,QAASjG,EAAciF,MAAMG,OAAOjF,OAEtC,CACEC,KAAM,SACN2F,KAAM,gBACNC,QAAS,uDACTC,QAASjG,EAAciF,MAAMI,cAAclF,OAE7C,CACEC,KAAM,SACN2F,KAAM,mBACNC,QAAS,gDACTC,QAASjG,EAAciF,MAAMK,iBAAiBnF,QAGlDoF,MAAO,CACL,CACEnF,KAAM,SACN2F,KAAM,SACNC,QAAS,8CACTC,QAASjG,EAAcuF,MAAM3C,OAAOzC,OAEtC,CACEC,KAAM,SACN2F,KAAM,WACNC,QAAS,mCACTC,QAASjG,EAAcuF,MAAMC,SAASrF,OAExC,CACEC,KAAM,SACN2F,KAAM,WACNC,QAAS,uCACTC,QAASjG,EAAcuF,MAAME,SAAStF,OAExC,CACEC,KAAM,SACN2F,KAAM,kBACNC,QAAS,2DACTC,QAASjG,EAAcuF,MAAMG,gBAAgBvF,OAE/C,CACEC,KAAM,SACN2F,KAAM,SACNC,QAAS,4DACTC,QAASjG,EAAcuF,MAAMI,OAAOxF,OAEtC,CACEC,KAAM,SACN2F,KAAM,SACNC,QAAS,iDACTC,QAASjG,EAAcuF,MAAMK,OAAOzF,OAEtC,CACEC,KAAM,SACN2F,KAAM,gBACNC,QAAS,gCACTC,QAASjG,EAAcuF,MAAMM,cAAc1F,SAMpCuG,EAAgB,CAC3B,UACA,gBACA,eACA,YACA,WAIWC,EAAa,CAAA,EASpBC,EAAmB,CAACC,EAAKC,EAAY,MACzCC,OAAOC,KAAKH,GAAKI,SAASC,IACxB,IAAK,CAAC,YAAa,cAAcC,SAASD,GAAI,CAC5C,MAAME,EAAQP,EAAIK,QACS,IAAhBE,EAAMjH,MAEfyG,EAAiBQ,EAAO,GAAGN,KAAaI,MAGxCP,EAAWS,EAAMvE,SAAWqE,GAAK,GAAGJ,KAAaI,IAAIG,UAAU,QAGtCC,IAArBF,EAAM5E,aACRmE,EAAWS,EAAM5E,YAAc,GAAGsE,KAAaI,IAAIG,UAAU,IAGlE,IACD,EAGJT,EAAiB5G,GC7pCjBuH,EAAOC,SAIP,MAAMC,EAGIC,GACNC,EACGC,SACAC,WAAW1H,GACVA,EACG2H,MAAM,KACNC,KAAK5H,GAAUA,EAAM6H,SACrBC,QAAQ9H,GAAUuH,EAAYP,SAAShH,OAE3C0H,WAAW1H,GAAWA,EAAM+H,OAAS/H,OAAQmH,IAZ9CG,EAgBK,IACPE,EACGQ,KAAK,CAAC,OAAQ,QAAS,KACvBN,WAAW1H,GAAqB,KAAVA,EAAyB,SAAVA,OAAmBmH,IAnBzDG,EAuBGW,GACLT,EACGQ,KAAK,IAAIC,EAAQ,KACjBP,WAAW1H,GAAqB,KAAVA,EAAeA,OAAQmH,IA1B9CG,EA8BI,IACNE,EACGC,SACAI,OACAK,QACElI,IACE,CAAC,QAAS,YAAa,OAAQ,OAAOgH,SAAShH,IACtC,KAAVA,IACDA,IAAW,CACV6F,QAAS,mDAAmD7F,SAG/D0H,WAAW1H,GAAqB,KAAVA,EAAeA,OAAQmH,IA1C9CG,EA6CE,IACJE,EACGC,SACAI,OACAK,QACElI,GAEQ,iEAAiEmI,KACtEnI,IAGJ,CAAE,EACF,CACE6F,QAAS,oDA1DbyB,EAgES,IACXE,EACGC,SACAI,OACAK,QACElI,GACW,KAAVA,IAAkBoI,MAAMC,WAAWrI,KAAWqI,WAAWrI,GAAS,IACnEA,IAAW,CACV6F,QAAS,qDAAqD7F,SAGjE0H,WAAW1H,GAAqB,KAAVA,EAAeqI,WAAWrI,QAASmH,IA3E1DG,EA+EY,IACdE,EACGC,SACAI,OACAK,QACElI,GACW,KAAVA,IAAkBoI,MAAMC,WAAWrI,KAAWqI,WAAWrI,IAAU,IACpEA,IAAW,CACV6F,QAAS,yDAAyD7F,SAGrE0H,WAAW1H,GAAqB,KAAVA,EAAeqI,WAAWrI,QAASmH,IAoInDmB,EAjISd,EAAEe,OAAO,CAE7BC,mBAAoBlB,IAGpBmB,mBAAoBjB,EACjBC,SACAI,OACAK,QACElI,GAAU,6BAA6BmI,KAAKnI,IAAoB,KAAVA,IACtDA,IAAW,CACV6F,QAAS,4FAA4F7F,SAGxG0H,WAAW1H,GAAqB,KAAVA,EAAeA,OAAQmH,IAChDuB,mBAAoBlB,EACjBC,SACAI,OACAK,QACElI,GACCA,EAAM2I,WAAW,aACjB3I,EAAM2I,WAAW,YACP,KAAV3I,IACDA,IAAW,CACV6F,QAAS,6FAA6F7F,SAGzG0H,WAAW1H,GAAqB,KAAVA,EAAeA,OAAQmH,IAChDyB,wBAAyBtB,EAAQ9H,EAAaC,MAC9CoJ,0BAA2BvB,EAAQ9H,EAAaE,SAChDoJ,6BAA8BxB,EAAQ9H,EAAaG,YACnDoJ,uBAAwBzB,IACxB0B,sBAAuB1B,IACvB2B,uBAAwB3B,IAGxB4B,YAAa5B,EAAO,CAAC,OAAQ,MAAO,MAAO,QAC3C6B,cAAe7B,EAAO,CAAC,QAAS,aAAc,WAAY,eAC1D8B,sBAAuB9B,IACvB+B,qBAAsB/B,IACtBgC,qBAAsBhC,IACtBiC,6BAA8BjC,IAG9BkC,kCAAmClC,IACnCmC,kCAAmCnC,IAGnCoC,cAAepC,IACfqC,YAAarC,IACbsC,YAAatC,IACbuC,uBAAwBvC,IACxBwC,oBAAqBxC,IAGrByC,kBAAmBzC,IACnB0C,kBAAmB1C,IACnB2C,sBAAuB3C,IACvB4C,sBAAuB5C,IACvB6C,qBAAsB7C,IAGtB8C,4BAA6B9C,IAC7B+C,kCAAmC/C,IACnCgD,4BAA6BhD,IAC7BiD,2BAA4BjD,IAC5BkD,iCAAkClD,IAClCmD,8BAA+BnD,IAC/BoD,gCAAiCpD,IAGjCqD,kBAAmBrD,IACnBsD,iBAAkBtD,IAClBuD,gBAAiBvD,IACjBwD,qBAAsBxD,IAGtByD,iBAAkBzD,IAClB0D,iBAAkB1D,IAClB2D,gBAAiB3D,IACjB4D,qBAAsB5D,IACtB6D,oBAAqB7D,IACrB8D,qBAAsB9D,IACtB+D,kBAAmB/D,IACnBgE,2BAA4BhE,IAC5BiE,qBAAsBjE,IACtBkE,kBAAmBlE,IAGnBmE,cAAejE,EACZC,SACAI,OACAK,QACElI,GACW,KAAVA,IACEoI,MAAMC,WAAWrI,KACjBqI,WAAWrI,IAAU,GACrBqI,WAAWrI,IAAU,IACxBA,IAAW,CACV6F,QAAS,mGAAmG7F,SAG/G0H,WAAW1H,GAAqB,KAAVA,EAAeqI,WAAWrI,QAASmH,IAC5DuE,aAAcpE,IACdqE,aAAcrE,IACdsE,mBAAoBtE,IACpBuE,gBAAiBvE,IAGjBwE,UAAWxE,IACXyE,SAAUzE,IAGV0E,eAAgB1E,EAAO,CAAC,cAAe,aAAc,SACrD2E,8BAA+B3E,IAC/B4E,cAAe5E,IACf6E,sBAAuB7E,IACvB8E,yBAA0B9E,IAG1B+E,aAAc/E,IACdgF,eAAgBhF,IAChBiF,eAAgBjF,IAChBkF,wBAAyBlF,IACzBmF,aAAcnF,IACdoF,cAAepF,IACfqF,qBAAsBrF,MAGGsF,UAAUC,MAAMC,QAAQC,KCnO7CC,EAAS,CAAC,MAAO,SAAU,OAAQ,OAAQ,SAGjD,IAAI1I,EAAU,CAEZI,WAAW,EACXC,QAAQ,EACRsI,aAAa,EAEbC,WAAY,CACV,CACEC,MAAO,QACPC,MAAOJ,EAAO,IAEhB,CACEG,MAAO,UACPC,MAAOJ,EAAO,IAEhB,CACEG,MAAO,SACPC,MAAOJ,EAAO,IAEhB,CACEG,MAAO,UACPC,MAAOJ,EAAO,IAEhB,CACEG,MAAO,YACPC,MAAOJ,EAAO,KAIlBK,UAAW,IAWb,MAAMC,EAAY,CAACC,EAAOC,KACnBlJ,EAAQ2I,eAEVQ,EAAWnJ,EAAQG,OAASiJ,EAAUpJ,EAAQG,MAI/CH,EAAQ2I,aAAc,GAIxBU,EACE,GAAGrJ,EAAQG,OAAOH,EAAQE,OAC1B,CAACgJ,GAAQI,OAAOL,GAAOxH,KAAK,KAAO,MAClC8H,IACKA,IACFC,QAAQC,IAAI,yCAAyCF,KACrDvJ,EAAQK,QAAS,EAClB,GAEJ,EAWUoJ,EAAM,IAAIhO,KACrB,MAAOiO,KAAaT,GAASxN,GAGvBmN,WAAEA,EAAU3I,MAAEA,GAAUD,EAG9B,GACe,IAAb0J,IACc,IAAbA,GAAkBA,EAAWzJ,GAASA,EAAQ2I,EAAWnF,QAE1D,OAIF,MAGMyF,EAAS,IAHC,IAAIS,MAAOC,WAAWvG,MAAM,KAAK,GAAGE,WAGtBqF,EAAWc,EAAW,GAAGb,WAGvD7I,EAAQ+I,UAAUvG,SAASqH,IACzBA,EAAGX,EAAQD,EAAMxH,KAAK,KAAK,IAIzBzB,EAAQI,WACVoJ,QAAQC,IAAIK,WACVjH,EACA,CAACqG,EAAOU,WAAW5J,EAAQ4I,WAAWc,EAAW,GAAGZ,QAAQQ,OAAOL,IAKnEjJ,EAAQK,QACV2I,EAAUC,EAAOC,EAClB,EAYUa,EAAe,CAACL,EAAUH,EAAOS,KAE5C,MAAMC,EAAcD,GAAiBT,EAAMhI,SAGrCtB,MAAEA,EAAK2I,WAAEA,GAAe5I,EAG9B,GAAiB,IAAb0J,GAAkBA,EAAWzJ,GAASA,EAAQ2I,EAAWnF,OAC3D,OAIF,MAGMyF,EAAS,IAHC,IAAIS,MAAOC,WAAWvG,MAAM,KAAK,GAAGE,WAGtBqF,EAAWc,EAAW,GAAGb,WAGjDqB,EACJX,EAAMhI,UAAYgI,EAAMW,mBAAuCrH,IAAvB0G,EAAMW,aAC1CX,EAAMY,MACNZ,EAAMY,MAAM9G,MAAM,MAAM+G,MAAM,GAAG3I,KAAK,MAGtCwH,EAAQ,CAACgB,EAAa,KAAMC,GAG9BlK,EAAQI,WACVoJ,QAAQC,IAAIK,WACVjH,EACA,CAACqG,EAAOU,WAAW5J,EAAQ4I,WAAWc,EAAW,GAAGZ,QAAQQ,OAAO,CACjEW,EAAYvB,EAAOgB,EAAW,IAC9B,KACAQ,KAMNlK,EAAQ+I,UAAUvG,SAASqH,IACzBA,EAAGX,EAAQD,EAAMxH,KAAK,KAAK,IAIzBzB,EAAQK,QACV2I,EAAUC,EAAOC,EAClB,EASUmB,EAAeX,IACtBA,GAAY,GAAKA,GAAY1J,EAAQ4I,WAAWnF,SAClDzD,EAAQC,MAAQyJ,EACjB,EASUY,EAAoB,CAACC,EAASC,KASzC,GAPAxK,EAAU,IACLA,EACHG,KAAMoK,GAAWvK,EAAQG,KACzBD,KAAMsK,GAAWxK,EAAQE,KACzBG,QAAQ,GAGkB,IAAxBL,EAAQG,KAAKsD,OACf,OAAOgG,EAAI,EAAG,2DAGXzJ,EAAQG,KAAKsK,SAAS,OACzBzK,EAAQG,MAAQ,IACjB,ECvMUuK,EAAYC,EAAc,IAAIC,IAAI,mBAAoBC,MAiEtDC,EAAU,CAACnP,EAAMiB,KAE5B,MAQMmO,EAAU,CAAC,MAAO,OAAQ,MAAO,OAGvC,GAAInO,EAAS,CACX,MAAMoO,EAAUpO,EAAQyG,MAAM,KAAK4H,MAEnB,QAAZD,EACFrP,EAAO,OACEoP,EAAQrI,SAASsI,IAAYrP,IAASqP,IAC/CrP,EAAOqP,EAEV,CAGD,MAtBkB,CAChB,YAAa,MACb,aAAc,OACd,kBAAmB,MACnB,gBAAiB,OAkBFrP,IAASoP,EAAQG,MAAMC,GAAMA,IAAMxP,KAAS,KAAK,EAcvDyP,EAAkB,CAACvN,GAAY,EAAOH,KACjD,MAAM2N,EAAe,CAAC,KAAM,MAAO,SAEnC,IAAIC,EAAmBzN,EACnB0N,GAAmB,EAGvB,GAAI7N,GAAsBG,EAAU4M,SAAS,SAC3C,IACEa,EAAmBE,EAAcC,EAAa5N,EAAW,QAC1D,CAAC,MAAO0L,GACP,OAAOQ,EAAa,EAAGR,EAAO,4BAC/B,MAGD+B,EAAmBE,EAAc3N,GAG7ByN,IAAqB5N,UAChB4N,EAAiBI,MAK5B,IAAK,MAAMC,KAAYL,EAChBD,EAAa3I,SAASiJ,GAEfJ,IACVA,GAAmB,UAFZD,EAAiBK,GAO5B,OAAKJ,GAKDD,EAAiBI,QACnBJ,EAAiBI,MAAQJ,EAAiBI,MAAMpI,KAAKsI,GAASA,EAAKrI,WAC9D+H,EAAiBI,OAASJ,EAAiBI,MAAMjI,QAAU,WACvD6H,EAAiBI,OAKrBJ,GAZE7B,EAAI,EAAG,4BAYO,EAclB,SAAS+B,EAAcK,EAAMjC,GAClC,IAEE,MAAMkC,EAAaC,KAAKxD,MACN,iBAATsD,EAAoBE,KAAKC,UAAUH,GAAQA,GAIpD,MAA0B,iBAAfC,GAA2BlC,EAC7BmC,KAAKC,UAAUF,GAIjBA,CACX,CAAI,MACA,OAAO,CACR,CACH,CASO,MA2CMG,EAAY7J,IACvB,GAAY,OAARA,GAA+B,iBAARA,EACzB,OAAOA,EAGT,MAAM8J,EAAOC,MAAMC,QAAQhK,GAAO,GAAK,GAEvC,IAAK,MAAMiK,KAAOjK,EACZE,OAAOgK,UAAUC,eAAeC,KAAKpK,EAAKiK,KAC5CH,EAAKG,GAAOJ,EAAS7J,EAAIiK,KAI7B,OAAOH,CAAI,EAaAO,EAAmB,CAAC9P,EAAS+P,IAsBjCX,KAAKC,UAAUrP,GArBG,CAAC2E,EAAM5F,KACT,iBAAVA,KACTA,EAAQA,EAAM6H,QAILc,WAAW,cAAgB3I,EAAM2I,WAAW,gBACnD3I,EAAM+O,SAAS,OAEf/O,EAAQgR,EACJ,WAAWhR,EAAQ,IAAIiR,WAAW,YAAa,mBAC/C9J,GAIgB,mBAAVnH,EACV,WAAWA,EAAQ,IAAIiR,WAAW,YAAa,cAC/CjR,KAI2CiR,WAC/C,qBACA,IAiCG,SAASC,IAKdpD,QAAQC,IACN,4BAA4BoD,KAC5B,WACA,yDANa,0DAMmDA,KAAKC,WAGvE,MAAMC,EAAmBpQ,IACvB,IAAK,MAAO2E,EAAM0L,KAAW1K,OAAO2K,QAAQtQ,GAE1C,GAAK2F,OAAOgK,UAAUC,eAAeC,KAAKQ,EAAQ,SAE3C,CACL,IAAIE,EAAW,OAAOF,EAAO5O,SAAWkD,MACrC,IAAM0L,EAAOrR,KAAO,KAAKwR,SAE5B,GAAID,EAASzJ,OAnBP,GAoBJ,IAAK,IAAI2J,EAAIF,EAASzJ,OAAQ2J,EApB1B,GAoBmCA,IACrCF,GAAY,IAKhB1D,QAAQC,IACNyD,EACAF,EAAOpR,YACP,aAAaoR,EAAOtR,MAAMkO,WAAWiD,QAAQQ,KAEhD,MAjBCN,EAAgBC,EAkBnB,EAIH1K,OAAOC,KAAKhH,GAAeiH,SAAS8K,IAE7B,CAAC,YAAa,cAAc5K,SAAS4K,KACxC9D,QAAQC,IAAI,KAAK6D,EAASC,gBAAgBC,KAC1CT,EAAgBxR,EAAc+R,IAC/B,IAEH9D,QAAQC,IAAI,KACd,CAUO,MAYMgE,EAAa7B,IACxB,CAAC,QAAS,YAAa,OAAQ,MAAO,IAAK,IAAIlJ,SAASkJ,MAElDA,EAWK8B,GAAa,CAAC/P,EAAYD,KACrC,GAAIC,GAAoC,iBAAfA,EAGvB,OAFAA,EAAaA,EAAW4F,QAETkH,SAAS,SACf/M,GACHgQ,GAAWjC,EAAa9N,EAAY,SAGxCA,EAAW0G,WAAW,eACtB1G,EAAW0G,WAAW,gBACtB1G,EAAW0G,WAAW,SACtB1G,EAAW0G,WAAW,SAEf,IAAI1G,OAENA,EAAWgQ,QAAQ,KAAM,GACjC,EASUC,GAAc,KACzB,MAAMC,EAAQrF,QAAQsF,OAAOC,SAC7B,MAAO,IAAMC,OAAOxF,QAAQsF,OAAOC,SAAWF,GAAS,GAAO,ECnahE,IAAII,GAAiB,CAAA,EAOd,MAAMC,GAAa,IAAMD,GAgLnBE,GAAqB,CAACxR,EAASyR,EAAYnM,EAAgB,MACtE,MAAMoM,EAAgBpC,EAAStP,GAE/B,IAAK,MAAO0P,EAAK3Q,KAAU4G,OAAO2K,QAAQmB,GACxCC,EAAchC,GDFA,iBADOT,ECIVlQ,IDHgByQ,MAAMC,QAAQR,IAAkB,OAATA,GCI/C3J,EAAcS,SAAS2J,SACDxJ,IAAvBwL,EAAchC,QAEAxJ,IAAVnH,EACEA,EACA2S,EAAchC,GAHhB8B,GAAmBE,EAAchC,GAAM3Q,EAAOuG,GDPhC,IAAC2J,ECavB,OAAOyC,CAAa,EAqFtB,SAASC,GAAoBC,EAAWC,EAAY,CAAA,EAAInM,EAAY,IAClEC,OAAOC,KAAKgM,GAAW/L,SAAS6J,IAC9B,MAAM1J,EAAQ4L,EAAUlC,GAClBoC,EAAcD,GAAaA,EAAUnC,QAEhB,IAAhB1J,EAAMjH,MACf4S,GAAoB3L,EAAO8L,EAAa,GAAGpM,KAAagK,WAGpCxJ,IAAhB4L,IACF9L,EAAMjH,MAAQ+S,GAIZ9L,EAAM7G,WAAWkI,QAAgCnB,IAAxBmB,EAAKrB,EAAM7G,WACtC6G,EAAMjH,MAAQsI,EAAKrB,EAAM7G,UAE5B,GAEL,CAWA,SAAS4S,GAAYC,GACnB,IAAIhS,EAAU,CAAA,EACd,IAAK,MAAO2E,EAAMsK,KAAStJ,OAAO2K,QAAQ0B,GACxChS,EAAQ2E,GAAQgB,OAAOgK,UAAUC,eAAeC,KAAKZ,EAAM,SACvDA,EAAKlQ,MACLgT,GAAY9C,GAElB,OAAOjP,CACT,CA6EA,SAASiS,GAAeC,EAAgBC,EAAapT,GACnD,KAAOoT,EAAYrL,OAAS,GAAG,CAC7B,MAAMkI,EAAWmD,EAAYC,QAc7B,OAXKzM,OAAOgK,UAAUC,eAAeC,KAAKqC,EAAgBlD,KACxDkD,EAAelD,GAAY,IAI7BkD,EAAelD,GAAYiD,GACzBtM,OAAO0M,OAAO,CAAA,EAAIH,EAAelD,IACjCmD,EACApT,GAGKmT,CACR,CAID,OADAA,EAAeC,EAAY,IAAMpT,EAC1BmT,CACT,CCtaAI,eAAeC,GAAMrE,EAAKsE,EAAiB,IACzC,OAAO,IAAIC,SAAQ,CAACC,EAASC,KAC3B,MAAMC,EAbU,CAAC1E,GAASA,EAAIxG,WAAW,SAAWmL,EAAQC,EAa3CC,CAAY7E,GAE7B0E,EACGI,IACC9E,EACAvI,OAAO0M,OACL,CACEY,QAAS,CACP,aAAc,oBACdC,QAAS,sBAGbV,GAAkB,CAAE,IAErBW,IACC,IAAIjE,EAAO,GAGXiE,EAAIC,GAAG,QAASC,IACdnE,GAAQmE,CAAK,IAIfF,EAAIC,GAAG,OAAO,KACPlE,GACHyD,EAAO,qCAGTQ,EAAIG,KAAOpE,EACXwD,EAAQS,EAAI,GACZ,IAGLC,GAAG,SAAUxG,IACZ+F,EAAO/F,EAAM,GACb,GAER,CChEA,MAAM2G,WAAoBC,MACxB,WAAAC,CAAY7O,GACV8O,QACAC,KAAK/O,QAAUA,EACf+O,KAAKpG,aAAe3I,CACrB,CAED,QAAAgP,CAAShH,GAYP,OAXA+G,KAAK/G,MAAQA,EACTA,EAAMjI,OACRgP,KAAKhP,KAAOiI,EAAMjI,MAEhBiI,EAAMiH,aACRF,KAAKE,WAAajH,EAAMiH,YAEtBjH,EAAMY,QACRmG,KAAKpG,aAAeX,EAAMhI,QAC1B+O,KAAKnG,MAAQZ,EAAMY,OAEdmG,IACR,ECWH,MAAMG,GAAQ,CACZxU,OAAQ,+BACRyU,eAAgB,CAAE,EAClBC,QAAS,GACTC,UAAW,IAQAC,GAAkBJ,GACtBA,EAAME,QACV/N,UAAU,EAAG6N,EAAME,QAAQG,QAAQ,OACnCnD,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,MAAO,IACfpK,OAgEQwN,GAAwB9B,MACnC+B,EACA7B,EACA8B,EACAC,GAAmB,KAGfF,EAAOvG,SAAS,SAClBuG,EAASA,EAAOpO,UAAU,EAAGoO,EAAOvN,OAAS,IAG/CgG,EAAI,EAAG,6BAA6BuH,QAGpC,MAAMG,QAAiBjC,GAAM,GAAG8B,OAAa7B,GAG7C,GAA4B,MAAxBgC,EAASX,YAA8C,iBAAjBW,EAASlB,KAAkB,CACnE,GAAIgB,EAAgB,CAElBA,EADqCD,EA5EvBrD,QAChB,qEACA,KA2E+B,CAC9B,CAED,OAAOwD,EAASlB,IACjB,CAED,GAAIiB,EACF,MAAM,IAAIhB,GACR,uBAAuBc,2EAAgFG,EAASX,gBAChHD,SAASY,GAQb,OANE1H,EACE,EACA,+BAA+BuH,8DAI5B,EAAE,EA+EEI,GAAcnC,MACzBoC,EACAC,EACAC,KAEA,MAAMvV,EAAUqV,EAAkBrV,QAC5B4U,EAAwB,WAAZ5U,GAAyBA,EAAe,GAAGA,KAAR,GAC/CC,EAASoV,EAAkBpV,QAAUwU,GAAMxU,OAEjDwN,EACE,EACA,iDAAiDmH,GAAa,aAGhE,MAAMK,EAAiB,CAAA,EACvB,IAwBE,OAvBAR,GAAME,aA9EkB1B,OAC1B/S,EACAC,EACAE,EACAiV,EACAL,KAGA,IAAIO,EACJ,MAAMnT,KAAEA,EAAIC,KAAEA,EAAIG,SAAEA,EAAQC,SAAEA,GAAa4S,EAG3C,GAAIjT,GAAQC,EACV,IACEkT,EAAa,IAAIC,EAAgB,CAC/BpT,OACAC,UACIG,GAAYC,EAAW,CAAED,WAAUC,YAAa,CAAA,GAEvD,CAAC,MAAO6K,GACP,MAAM,IAAI2G,GAAY,2CAA2CK,SAC/DhH,EAEH,CAIH,MAAM4F,EAAiBqC,EACnB,CACEE,MAAOF,EACP7S,QAASqF,EAAK6B,sBAEhB,GAEE8L,EAAmB,IACpBzV,EAAYoH,KAAK0N,GAClBD,GAAsB,GAAGC,IAAU7B,EAAgB8B,GAAgB,QAElE9U,EAAcmH,KAAK0N,GACpBD,GAAsB,GAAGC,IAAU7B,EAAgB8B,QAElD5U,EAAciH,KAAK0N,GACpBD,GAAsB,GAAGC,IAAU7B,MAKvC,aAD6BC,QAAQwC,IAAID,IACnBlQ,KAAK,MAAM,EA+BToQ,CACpB,IACKR,EAAkBnV,YAAYoH,KAAKwO,GAAM,GAAG7V,IAAS2U,IAAYkB,OAEtE,IACKT,EAAkBlV,cAAcmH,KAAKyO,GAChC,QAANA,EACI,GAAG9V,SAAc2U,YAAoBmB,IACrC,GAAG9V,IAAS2U,YAAoBmB,SAEnCV,EAAkBjV,iBAAiBkH,KACnC8J,GAAM,GAAGnR,UAAe2U,eAAuBxD,OAGpDiE,EAAkBhV,cAClBiV,EACAL,GAGFR,GAAMG,UAAYC,GAAeJ,IAGjCuB,EAAcT,EAAYd,GAAME,SACzBM,CACR,CAAC,MAAO1H,GACP,MAAM,IAAI2G,GACR,wDACAK,SAAShH,EACZ,GAiCU0I,GAAsBhD,MAAOtS,IACxC,MAAMZ,WAAEA,EAAUkC,OAAEA,GAAWtB,EACzBJ,EAAYkF,EAAKiJ,EAAW3O,EAAWQ,WAE7C,IAAI0U,EAEJ,MAAMiB,EAAezQ,EAAKlF,EAAW,iBAC/BgV,EAAa9P,EAAKlF,EAAW,cAOnC,IAJC4M,EAAW5M,IAAc6M,EAAU7M,IAI/B4M,EAAW+I,IAAiBnW,EAAWO,WAC1CmN,EAAI,EAAG,yDACPwH,QAAuBG,GAAYrV,EAAYkC,EAAOO,MAAO+S,OACxD,CACL,IAAIY,GAAgB,EAGpB,MAAMC,EAAWrG,KAAKxD,MAAMkD,EAAayG,IAIzC,GAAIE,EAAShX,SAAW+Q,MAAMC,QAAQgG,EAAShX,SAAU,CACvD,MAAMiX,EAAY,CAAA,EAClBD,EAAShX,QAAQoH,SAASuP,GAAOM,EAAUN,GAAK,IAChDK,EAAShX,QAAUiX,CACpB,CAED,MAAMnW,YAAEA,EAAWC,cAAEA,EAAaC,iBAAEA,GAAqBL,EACnDuW,EACJpW,EAAYuH,OAAStH,EAAcsH,OAASrH,EAAiBqH,OAK3D2O,EAASpW,UAAYD,EAAWC,SAClCyN,EACE,EACA,yEAEF0I,GAAgB,GACP7P,OAAOC,KAAK6P,EAAShX,SAAW,IAAIqI,SAAW6O,GACxD7I,EACE,EACA,+EAEF0I,GAAgB,GAGhBA,GAAiBhW,GAAiB,IAAIoW,MAAMC,IAC1C,IAAKJ,EAAShX,QAAQoX,GAKpB,OAJA/I,EACE,EACA,eAAe+I,iDAEV,CACR,IAIDL,EACFlB,QAAuBG,GAAYrV,EAAYkC,EAAOO,MAAO+S,IAE7D9H,EAAI,EAAG,uDAGPgH,GAAME,QAAUlF,EAAa8F,EAAY,QAGzCN,EAAiBmB,EAAShX,QAE1BqV,GAAMG,UAAYC,GAAeJ,IAEpC,MArTiCxB,OAAOlM,EAAQkO,KACjD,MAAMwB,EAAc,CAClBzW,QAAS+G,EAAO/G,QAChBZ,QAAS6V,GAAkB,CAAE,GAI/BR,GAAMC,eAAiB+B,EAEvBhJ,EAAI,EAAG,mCACP,IACEuI,EACEvQ,EAAKiJ,EAAW3H,EAAOxG,UAAW,iBAClCwP,KAAKC,UAAUyG,GACf,OAEH,CAAC,MAAOlJ,GACP,MAAM,IAAI2G,GAAY,6CAA6CK,SACjEhH,EAEH,GAqSKmJ,CAAqB3W,EAAYkV,EAAe,EAG3C0B,GAAe,IAC1BlR,EAAKiJ,EAAWwD,KAAanS,WAAWQ,WAM7BP,GAAU,IAAMyU,GAAMG,UCzX5B,SAASgC,KACdC,WAAWC,WAAa,WACtB,MAAO,CAAEC,SAAU,EACvB,CACA,CASO9D,eAAe+D,GAAcC,EAActW,EAASuW,GAEzDpU,OAAOqU,eAAiBD,EAGxB,MAAMhF,WAAEA,EAAUkF,MAAEA,EAAKC,WAAEA,EAAUC,KAAEA,GAAST,WAIhDA,WAAWU,cAAgBH,GAAM,EAAO,CAAE,EAAElF,KAG5C,MAAMsF,EAAQ,CACZC,WAAW,GAIT9W,EAAQH,OAAOkX,SACjBF,EAAMvW,OAASgW,EAAaO,MAAMvW,OAClCuW,EAAMtW,MAAQ+V,EAAaO,MAAMtW,OAInC4B,OAAO6U,kBAAmB,EAC1BL,EAAKT,WAAWe,MAAMtH,UAAW,QAAQ,SAAUuH,EAASC,EAAaC,KAEvED,EAAcV,EAAMU,EAAa,CAC/BE,UAAW,CACTC,SAAS,GAEXC,YAAa,CACXC,OAAQ,CACNC,MAAO,CACLH,SAAS,KAOfI,QAAS,CAAE,KAGAF,QAAU,IAAI3R,SAAQ,SAAU2R,GAC3CA,EAAOV,WAAY,CACzB,IAGS3U,OAAOwV,qBACVxV,OAAOwV,mBAAqBzB,WAAW0B,SAASjE,KAAM,UAAU,KAC9DxR,OAAO6U,kBAAmB,CAAI,KAIlCE,EAAQ/J,MAAMwG,KAAM,CAACwD,EAAaC,GACtC,IAEET,EAAKT,WAAW2B,OAAOlI,UAAW,QAAQ,SAAUuH,EAASL,EAAO7W,GAClEkX,EAAQ/J,MAAMwG,KAAM,CAACkD,EAAO7W,GAChC,IAGE,MAAMmX,EAAcnX,EAAQH,OAAOkX,OAC/B,IAAIe,SAAS,UAAU9X,EAAQH,OAAOkX,SAAtC,GACAT,EAGAtW,EAAQa,YAAYG,YACtB,IAAI8W,SAAS,UAAW9X,EAAQa,YAAYG,WAA5C,CAAwDmW,GAK1D,MAAMY,EAAetB,GACnB,EACArH,KAAKxD,MAAM5L,EAAQH,OAAOa,cAC1ByW,EAEA,CAAEN,UAGEmB,EAAgBhY,EAAQa,YAAYI,SACtC,IAAI6W,SAAS,UAAU9X,EAAQa,YAAYI,WAA3C,QACAiF,EAGEzF,EAAgB2O,KAAKxD,MAAM5L,EAAQH,OAAOY,eAC5CA,GACFiW,EAAWjW,GAGb,IAAIP,EAASF,EAAQH,OAAOK,QAAU,QACtCA,OAAuC,IAAvBgW,WAAWhW,GAA0BA,EAAS,QAE9DgW,WAAWhW,GAAQ,YAAa6X,EAAcC,GAG9C,MAAMC,EAAiB1G,IAGvB,IAAK,MAAM2G,KAAQD,EACmB,mBAAzBA,EAAeC,WACjBD,EAAeC,GAK1BxB,EAAWR,WAAWU,eAGtBV,WAAWU,cAAgB,EAC7B,CCnHA,MAAMuB,GAAWrJ,EAAaf,EAAY,2BAA4B,QAEtE,IAAIqK,GAiIG9F,eAAe+F,KACpB,IAAKD,GACH,OAAO,EAIT,MAAME,QAAaF,GAAQC,UAW3B,aARMC,EAAKC,iBAAgB,SAGrBC,GAAeF,GAsOvB,SAAuBA,GAErB,MAAMnU,MAAEA,GAAUoN,KAGdpN,EAAM3C,QAAU2C,EAAMG,iBACxBgU,EAAKlF,GAAG,WAAYxO,IAClBiI,QAAQC,IAAI,WAAWlI,EAAQ0O,SAAS,IAK5CgF,EAAKlF,GAAG,aAAad,MAAO1F,IAGtB0L,EAAKG,kBAMHH,EAAKI,MACT,cACA,CAACC,EAASC,KAEJzW,OAAOqU,iBACTmC,EAAQE,UAAYD,EACrB,GAEH,oCAAoChM,EAAMK,aAC3C,GAEL,CAnQE6L,CAAcR,GAEPA,CACT,CA2JOhG,eAAeyG,GAAmBT,EAAMU,GAC7C,IACE,IAAK,MAAMC,KAAYD,QACfC,EAASC,gBAIXZ,EAAKa,UAAS,KAGlB,GAA0B,oBAAfjD,WAA4B,CAErC,MAAMkD,EAAYlD,WAAWmD,OAG7B,GAAI7J,MAAMC,QAAQ2J,IAAcA,EAAUtS,OAExC,IAAK,MAAMwS,KAAYF,EACrBE,GAAYA,EAASC,UAErBrD,WAAWmD,OAAOjH,OAGvB,CAGD,SAAUoH,GAAmBC,SAASC,qBAAqB,WAErD,IAAMC,GAAkBF,SAASC,qBAAqB,aAElDE,GAAiBH,SAASC,qBAAqB,QAGzD,IAAK,MAAMf,IAAW,IACjBa,KACAG,KACAC,GAEHjB,EAAQkB,QACT,GAEJ,CAAC,MAAOjN,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CACH,CAUA0F,eAAekG,GAAeF,SACtBA,EAAKwB,WAAW3B,GAAU,CAAE4B,UAAW,2BAGvCzB,EAAK0B,aAAa,CAAEC,KAAM,GAAGjE,0BAG7BsC,EAAKa,SAASlD,GACtB,CC1WA,MAkGMiE,GAAc5H,MAAOgG,EAAMzB,EAAO7W,EAASuW,KAE/CvW,EAAQH,OAAOE,MAAQ,KACvBC,EAAQH,OAAOC,OAAS,KAGxB,MAAMqa,EAAYC,OAAOC,WACvBra,EAAQH,QAAQkX,OAAS/W,EAAQH,QAAQkX,OAAS3H,KAAKC,UAAUwH,GACjE,SAaF,GATA/J,EACE,EACA,uEACEqN,EACC,SACDG,QAAQ,SAIRH,GAAa,UACf,MAAM,IAAI5G,GAAY,sDAIxB,OAAO+E,EAAKa,SAAS9C,GAAeQ,EAAO7W,EAASuW,EAAc,EAapE,IAAAgE,GAAejI,MAAOgG,EAAMzB,EAAO7W,KAEjC,IAAIgZ,EAAoB,GAExB,IACElM,EAAI,EAAG,qCAEP,MAAM0N,EAAgBxa,EAAQH,OAGxB0W,EACJiE,GAAexa,SAAS6W,OAAON,eHoNPzC,GGnNbC,eAAetV,QAAQgc,SAEpC,IAAIC,EACJ,GACE7D,EAAM1C,UACL0C,EAAM1C,QAAQ,SAAW,GAAK0C,EAAM1C,QAAQ,UAAY,GACzD,CAKA,GAHArH,EAAI,EAAG,6BAGoB,QAAvB0N,EAAcxb,KAChB,OAAO6X,EAGT6D,GAAQ,QACFpC,EAAKwB,WCrLF,CAACjD,GAAU,knBAYlBA,wCDyKoB8D,CAAY9D,GAAQ,CACxCkD,UAAW,oBAEnB,MAEMjN,EAAI,EAAG,gCAGH0N,EAAczD,aAEVmD,GACJ5B,EACA,CACEzB,MAAO,CACLvW,OAAQka,EAAcla,OACtBC,MAAOia,EAAcja,QAGzBP,EACAuW,IAIFM,EAAMA,MAAMvW,OAASka,EAAcla,OACnCuW,EAAMA,MAAMtW,MAAQia,EAAcja,YAE5B2Z,GAAY5B,EAAMzB,EAAO7W,EAASuW,IAO5CyC,QDAG1G,eAAgCgG,EAAMtY,GAE3C,MAAMgZ,EAAoB,GAGpB9X,EAAYlB,EAAQa,YAAYK,UACtC,GAAIA,EAAW,CACb,MAAM0Z,EAAa,GAUnB,GAPI1Z,EAAU2Z,IACZD,EAAWE,KAAK,CACdC,QAAS7Z,EAAU2Z,KAKnB3Z,EAAU6N,MACZ,IAAK,MAAMxL,KAAQrC,EAAU6N,MAAO,CAClC,MAAMiM,GAAWzX,EAAKmE,WAAW,QAGjCkT,EAAWE,KACTE,EACI,CACED,QAASjM,EAAavL,EAAM,SAE9B,CACE2K,IAAK3K,GAGd,CAGH,IAAK,MAAM0X,KAAcL,EACvB,IACE5B,EAAkB8B,WAAWxC,EAAK0B,aAAaiB,GAChD,CAAC,MAAOrO,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAEHgO,EAAW9T,OAAS,EAGpB,MAAMoU,EAAc,GACpB,GAAIha,EAAUia,IAAK,CACjB,IAAIC,EAAala,EAAUia,IAAIE,MAAM,uBACrC,GAAID,EAEF,IAAK,IAAIE,KAAiBF,EACpBE,IACFA,EAAgBA,EACbtK,QAAQ,OAAQ,IAChBA,QAAQ,UAAW,IACnBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,IAAK,IACbA,QAAQ,MAAO,IACfpK,OAGC0U,EAAc5T,WAAW,QAC3BwT,EAAYJ,KAAK,CACf5M,IAAKoN,IAEEtb,EAAQa,YAAYE,oBAC7Bma,EAAYJ,KAAK,CACfb,KAAMA,EAAKnV,KAAKiJ,EAAWuN,MAQrCJ,EAAYJ,KAAK,CACfC,QAAS7Z,EAAUia,IAAInK,QAAQ,sBAAuB,KAAO,MAG/D,IAAK,MAAMuK,KAAeL,EACxB,IACElC,EAAkB8B,WAAWxC,EAAKkD,YAAYD,GAC/C,CAAC,MAAO3O,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CAEHsO,EAAYpU,OAAS,CACtB,CACF,CACD,OAAOkS,CACT,CC1F8ByC,CAAiBnD,EAAMtY,GAGjD,MAAM0b,EAAOhB,QACHpC,EAAKa,UAAU3Y,IACnB,MAAMmb,EAAalC,SAASmC,cAC1B,sCAIIC,EAAcF,EAAWrb,OAAOwb,QAAQ/c,MAAQyB,EAChDub,EAAaJ,EAAWpb,MAAMub,QAAQ/c,MAAQyB,EAWpD,OANAiZ,SAASuC,KAAKC,MAAMC,KAAO1b,EAI3BiZ,SAASuC,KAAKC,MAAME,OAAS,MAEtB,CACLN,cACAE,aACD,GACA3U,WAAWoT,EAAcha,cACtB8X,EAAKa,UAAS,KAElB,MAAM0C,YAAEA,EAAWE,WAAEA,GAAe5Z,OAAO+T,WAAWmD,OAAO,GAO7D,OAFAI,SAASuC,KAAKC,MAAMC,KAAO,EAEpB,CACLL,cACAE,aACD,IAIDK,EAAiBC,KAAKC,IAC1BD,KAAKE,KAAKb,EAAKG,aAAerB,EAAcla,SAExCkc,EAAgBH,KAAKC,IACzBD,KAAKE,KAAKb,EAAKK,YAAcvB,EAAcja,SAIvCkc,EAAEA,EAACC,EAAEA,QAzPO,CAACpE,GACrBA,EAAKI,MAAM,oBAAqBC,IAC9B,MAAM8D,EAAEA,EAACC,EAAEA,EAACnc,MAAEA,EAAKD,OAAEA,GAAWqY,EAAQgE,wBACxC,MAAO,CACLF,IACAC,IACAnc,QACAD,OAAQ+b,KAAKO,MAAMtc,EAAS,EAAIA,EAAS,KAC1C,IAiPsBuc,CAAcvE,GASrC,IAAIpJ,EAEJ,SARMoJ,EAAKwE,YAAY,CACrBxc,OAAQ8b,EACR7b,MAAOic,EACPO,kBAAmBrC,EAAQ,EAAItT,WAAWoT,EAAcha,SAK/B,QAAvBga,EAAcxb,KAEhBkQ,OAjLY,CAACoJ,GACjBA,EAAKI,MAAM,gCAAiCC,GAAYA,EAAQqE,YAgL/CC,CAAU3E,QAClB,GAAI,CAAC,MAAO,QAAQvS,SAASyU,EAAcxb,MAEhDkQ,OAhPc,EAACoJ,EAAMtZ,EAAMke,EAAUC,EAAMvc,IAC/C6R,QAAQ2K,KAAK,CACX9E,EAAK+E,WAAW,CACdre,OACAke,WACAC,OACAG,uBAAuB,EACvBC,UAAU,EACVC,kBAAkB,KACL,QAATxe,EAAiB,CAAEye,QAAS,IAAO,CAAA,EAIvCC,eAAwB,OAAR1e,IAElB,IAAIyT,SAAQ,CAACkL,EAAUhL,IACrBiL,YACE,IAAMjL,EAAO,IAAIY,GAAY,2BAC7B3S,GAAwB,UA8Nbid,CACXvF,EACAkC,EAAcxb,KACd,SACA,CACEuB,MAAOic,EACPlc,OAAQ8b,EACRK,IACAC,KAEFlC,EAAc5Z,0BAEX,IAA2B,QAAvB4Z,EAAcxb,KAUvB,MAAM,IAAIuU,GACR,sCAAsCiH,EAAcxb,SATtDkQ,OA5NYoD,OAChBgG,EACAhY,EACAC,EACA2c,EACAtc,WAEM0X,EAAKwF,iBAAiB,UAErBxF,EAAKyF,IAAI,CAEdzd,OAAQA,EAAS,EACjBC,QACA2c,WACAlb,QAASpB,GAAwB,QA8MlBod,CACX1F,EACA8D,EACAI,EACA,SACAhC,EAAc5Z,qBAMjB,CAID,aADMmY,GAAmBT,EAAMU,GACxB9J,CACR,CAAC,MAAOtC,GAEP,aADMmM,GAAmBT,EAAMU,GACxBpM,CACR,GE5SH,IAAIjK,IAAO,EAGJ,MAAMsb,GAAQ,CACnBC,iBAAkB,EAClBC,eAAgB,EAChBC,sBAAuB,EACvBC,UAAW,EACXC,eAAgB,EAChBC,aAAc,GAGhB,IAAIC,GAAa,CAAA,EAEjB,MAAMC,GAAU,CAUdC,OAAQpM,UACN,IAAIgG,GAAO,EAEX,MAAMqG,EAAKC,IACLC,GAAY,IAAI7R,MAAO8R,UAE7B,IAGE,GAFAxG,QAAaD,MAERC,GAAQA,EAAKG,WAChB,MAAM,IAAIlF,GAAY,kCAGxBzG,EACE,EACA,wCAAwC6R,aACtC,IAAI3R,MAAO8R,UAAYD,QAG5B,CAAC,MAAOjS,GACP,MAAM,IAAI2G,GACR,+CACAK,SAAShH,EACZ,CAED,MAAO,CACL+R,KACArG,OAEAyG,UAAW1C,KAAKhX,MAAMgX,KAAK2C,UAAYR,GAAW1b,UAAY,IAC/D,EAaHmc,SAAU3M,MAAO4M,MAaVA,EAAa5G,MAAQ4G,EAAa5G,MAAMG,gBAK3C+F,GAAW1b,aACToc,EAAaH,UAAYP,GAAW1b,aAEtCgK,EACE,EACA,kEAAkE0R,GAAW1b,gBAExE,IAWXyW,QAASjH,MAAO4M,IACdpS,EAAI,EAAG,gCAAgCoS,EAAaP,OAEhDO,EAAa5G,OAAS4G,EAAa5G,KAAKG,kBACpCyG,EAAa5G,KAAK6G,OACzB,GAaQC,GAAW9M,MAAOlM,IAY7B,GAVAoY,GAAapY,GAAUA,EAAOzD,KAAO,IAAKyD,EAAOzD,MAAS,SH9FrD2P,eAAsB+M,GAE3B,MAAQxgB,UAAWygB,EAAgBnb,MAAEA,EAAKN,MAAEA,GAAU0N,MAG9C/P,OAAQ+d,KAAiBC,GAAiBrb,EAE5Csb,EAAgB,CACpBrb,UAAUP,EAAMK,kBAAmB,QACnCwb,YAAaJ,EAAiBpgB,SAAW,SACzCJ,KAAMugB,EACNM,cAAc,EACdC,eAAe,EACfC,cAAc,EACdC,oBAAoB,EACpBC,gBAAiB,QACbR,GAAgBC,GAItB,IAAKpH,GAAS,CACZ,IAAI4H,EAAW,EAEf,MAAMC,EAAO3N,UACX,IACExF,EACE,EACA,yDAAyDkT,OAE3D5H,SAAgBvZ,EAAUqhB,OAAOT,EAClC,CAAC,MAAO7S,GAQP,GAPAQ,EACE,EACAR,EACA,oDAIEoT,EAAW,IAKb,MAAMpT,EAJNE,EAAI,EAAG,sCAAsCkT,uBACvC,IAAIvN,SAAS+B,GAAaoJ,WAAWpJ,EAAU,aAC/CyL,GAIT,GAGH,UACQA,IAGyB,UAA3BR,EAAcrb,UAChB0I,EAAI,EAAG,6CAILyS,GACFzS,EAAI,EAAG,4CAEV,CAAC,MAAOF,GACP,MAAM,IAAI2G,GACR,iEACAK,SAAShH,EACZ,CAED,IAAKwL,GACH,MAAM,IAAI7E,GAAY,2CAEzB,CAGD,OAAO6E,EACT,CGwBQ+H,CAAc/Z,EAAOiZ,eAE3BvS,EACE,EACA,8CAA8C0R,GAAW5b,mBAAmB4b,GAAW3b,eAGrFF,GACF,OAAOmK,EACL,EACA,yEAIAsT,SAAS5B,GAAW5b,YAAcwd,SAAS5B,GAAW3b,cACxD2b,GAAW5b,WAAa4b,GAAW3b,YAGrC,IAEEF,GAAO,IAAI0d,EAAK,IAEX5B,GACHtZ,IAAKib,SAAS5B,GAAW5b,YACzBwC,IAAKgb,SAAS5B,GAAW3b,YACzByd,qBAAsB9B,GAAWzb,eACjCwd,oBAAqB/B,GAAWxb,cAChCwd,qBAAsBhC,GAAWvb,eACjCwd,kBAAmBjC,GAAWtb,YAC9Bwd,0BAA2BlC,GAAWrb,oBACtCwd,mBAAoBnC,GAAWpb,eAC/Bwd,sBAAsB,IAIxBje,GAAKyQ,GAAG,WAAWd,MAAO2G,IAExB,MAAM4H,QHHLvO,eAAyBgG,EAAMwI,GAAY,GAChD,IACE,GAAIxI,IAASA,EAAKG,WAchB,OAbIqI,SAEIxI,EAAKyI,KAAK,cAAe,CAAEhH,UAAW,2BAGtCvB,GAAeF,UAGfA,EAAKa,UAAS,KAClBM,SAASuC,KAAKnD,UACZ,4DAA4D,KAG3D,CAEV,CAAC,MAAOjM,GACPQ,EACE,EACAR,EACA,qDAEH,CAED,OAAO,CACT,CGxBsBoU,CAAU/H,EAASX,MAAM,GACzCxL,EACE,EACA,qCAAqCmM,EAAS0F,0BAA0BkC,KACzE,IAGHle,GAAKyQ,GAAG,kBAAkB,CAAC6N,EAAShI,KAClCnM,EAAI,EAAG,qCAAqCmM,EAAS0F,OACrD1F,EAASX,KAAO,IAAI,IAGtB,MAAM4I,EAAmB,GAEzB,IAAK,IAAIzQ,EAAI,EAAGA,EAAI+N,GAAW5b,WAAY6N,IACzC,IACE,MAAMwI,QAAiBtW,GAAKwe,UAAUC,QACtCF,EAAiBpG,KAAK7B,EACvB,CAAC,MAAOrM,GACPQ,EAAa,EAAGR,EAAO,+CACxB,CAIHsU,EAAiBrb,SAASoT,IACxBtW,GAAK0e,QAAQpI,EAAS,IAGxBnM,EACE,EACA,4BAA2BoU,EAAiBpa,OAAS,SAASoa,EAAiBpa,oCAAsC,KAExH,CAAC,MAAO8F,GACP,MAAM,IAAI2G,GACR,gDACAK,SAAShH,EACZ,GAUI0F,eAAegP,KAIpB,GAHAxU,EAAI,EAAG,6DAGHnK,GAAM,CAER,IAAK,MAAM4e,KAAU5e,GAAK6e,KACxB7e,GAAK0e,QAAQE,EAAOtI,UAIjBtW,GAAK8e,kBACF9e,GAAK4W,UACXzM,EAAI,EAAG,8CAEV,OHlHIwF,iBAED8F,IAASsJ,iBACLtJ,GAAQ+G,QAEhBrS,EAAI,EAAG,gCACT,CG+GQ6U,EACR,CAeO,MAAMC,GAAWtP,MAAOuE,EAAO7W,KACpC,IAAIkf,EAEJ,IAQE,GAPApS,EAAI,EAAG,gDAELmR,GAAME,eACJK,GAAW5c,cACbigB,MAGGlf,GACH,MAAM,IAAI4Q,GAAY,iDAIxB,MAAMuO,EAAiB7Q,KACvB,IACEnE,EAAI,EAAG,qCACPoS,QAAqBvc,GAAKwe,UAAUC,QAGhCphB,EAAQsB,OAAOM,cACjBkL,EACE,EACA9M,EAAQ+hB,SAASC,UACb,+BAA+BhiB,EAAQ+hB,SAASC,cAChD,cACJ,6BAA6BF,SAGlC,CAAC,MAAOlV,GACP,MAAM,IAAI2G,IACPvT,EAAQ+hB,SAASC,UACd,uBAAuBhiB,EAAQ+hB,SAASC,eACxC,IACF,wDAAwDF,UAC1DlO,SAAShH,EACZ,CAGD,GAFAE,EAAI,EAAG,qCAEFoS,EAAa5G,KAChB,MAAM,IAAI/E,GACR,6DAKJ,IAAI0O,GAAY,IAAIjV,MAAO8R,UAE3BhS,EAAI,EAAG,8CAA8CoS,EAAaP,OAGlE,MAAMuD,EAAgBjR,KAChBkR,QAAe5H,GAAgB2E,EAAa5G,KAAMzB,EAAO7W,GAG/D,GAAImiB,aAAkB3O,MAgBpB,KALuB,0BAAnB2O,EAAOvd,UACTsa,EAAaH,UAAYP,GAAW1b,UAAY,EAChDoc,EAAa5G,KAAO,MAIJ,iBAAhB6J,EAAOxd,MACY,0BAAnBwd,EAAOvd,QAED,IAAI2O,GACR,iHACAK,SAASuO,GAEL,IAAI5O,IACPvT,EAAQ+hB,SAASC,UACd,uBAAuBhiB,EAAQ+hB,SAASC,eACxC,IAAM,oCAAoCE,UAC9CtO,SAASuO,GAKXniB,EAAQsB,OAAOM,cACjBkL,EACE,EACA9M,EAAQ+hB,SAASC,UACb,+BAA+BhiB,EAAQ+hB,SAASC,cAChD,cACJ,iCAAiCE,UAKrCvf,GAAK0e,QAAQnC,GAIb,MACMkD,GADU,IAAIpV,MAAO8R,UACEmD,EAO7B,OANAhE,GAAMI,WAAa+D,EACnBnE,GAAMM,aAAeN,GAAMI,YAAcJ,GAAMC,iBAE/CpR,EAAI,EAAG,4BAA4BsV,SAG5B,CACLD,SACAniB,UAEH,CAAC,MAAO4M,GAOP,OANEqR,GAAMK,eAEJY,GACFvc,GAAK0e,QAAQnC,GAGT,IAAI3L,GAAY,4BAA4B3G,EAAMhI,WAAWgP,SACjEhH,EAEH,GAiBUyV,GAAkB,KAAO,CACpCld,IAAKxC,GAAKwC,IACVC,IAAKzC,GAAKyC,IACV6P,IAAKtS,GAAK2f,UAAY3f,GAAK4f,UAC3BC,UAAW7f,GAAK2f,UAChBd,KAAM7e,GAAK4f,UACXE,QAAS9f,GAAK+f,uBAQT,SAASb,KACd,MAAM1c,IAAEA,EAAGC,IAAEA,EAAG6P,IAAEA,EAAGuN,UAAEA,EAAShB,KAAEA,EAAIiB,QAAEA,GAAYJ,KAEpDvV,EAAI,EAAG,2DAA2D3H,MAClE2H,EAAI,EAAG,2DAA2D1H,MAClE0H,EAAI,EAAG,+CAA+CmI,MACtDnI,EAAI,EAAG,6CAA6C0V,MACpD1V,EAAI,EAAG,4CAA4C0U,MACnD1U,EAAI,EAAG,0DAA0D2V,KACnE,CAEA,IAAeE,GAMbN,GANaM,GAOH,IAAM1E,GClalB,IAAInd,IAAqB,EAgBlB,MAAM8hB,GAActQ,MAAOuQ,EAAUC,KAE1ChW,EAAI,EAAG,2CAGP,MAAM9M,ETyL0B,EAACwa,EAAelJ,EAAiB,MACjE,IAAItR,EAAU,CAAA,EAsBd,OApBIwa,EAAcuI,KAChB/iB,EAAUsP,EAASgC,GACnBtR,EAAQH,OAAOb,KAAOwb,EAAcxb,MAAQwb,EAAc3a,OAAOb,KACjEgB,EAAQH,OAAOW,MAAQga,EAAcha,OAASga,EAAc3a,OAAOW,MACnER,EAAQH,OAAOI,QACbua,EAAcva,SAAWua,EAAc3a,OAAOI,QAChDD,EAAQ+hB,QAAU,CAChBgB,IAAKvI,EAAcuI,MAGrB/iB,EAAUwR,GACRF,EACAkJ,EAEAlV,GAIJtF,EAAQH,OAAOI,QACbD,EAAQH,QAAQI,SAAW,SAASD,EAAQH,QAAQb,MAAQ,QACvDgB,CAAO,EShNEgjB,CAAmBH,EAAUtR,MAGvCiJ,EAAgBxa,EAAQH,OAG9B,GAAIG,EAAQ+hB,SAASgB,KAA+B,KAAxB/iB,EAAQ+hB,QAAQgB,IAC1C,IACEjW,EAAI,EAAG,kDAEP,MAAMqV,EAASc,GChCd,SAAkBC,GACvB,MAAM/gB,EAAS,IAAIghB,EAAM,IAAIhhB,OAE7B,OADeihB,EAAUjhB,GACXkhB,SAASH,EAAO,CAC5BI,SAAU,CAAC,iBAEXC,YAAa,CAAC,eAElB,CDyBQF,CAASrjB,EAAQ+hB,QAAQgB,KACzB/iB,EACA8iB,GAIF,QADE7E,GAAMG,sBACD+D,CACR,CAAC,MAAOvV,GACP,OAAOkW,EACL,IAAIvP,GAAY,oCAAoCK,SAAShH,GAEhE,CAIH,GAAI4N,EAAc1a,QAAU0a,EAAc1a,OAAOgH,OAE/C,IAGE,OAFAgG,EAAI,EAAG,oDACP9M,EAAQH,OAAOE,MAAQ+O,EAAa0L,EAAc1a,OAAQ,QACnDmjB,GAAejjB,EAAQH,OAAOE,MAAM6G,OAAQ5G,EAAS8iB,EAC7D,CAAC,MAAOlW,GACP,OAAOkW,EACL,IAAIvP,GAAY,qCAAqCK,SAAShH,GAEjE,CAIH,GACG4N,EAAcza,OAAiC,KAAxBya,EAAcza,OACrCya,EAAcxa,SAAqC,KAA1Bwa,EAAcxa,QAExC,IAOE,OANA8M,EAAI,EAAG,kDAGP0N,EAAcza,MAAQya,EAAcza,OAASya,EAAcxa,QAGvD8Q,EAAU9Q,EAAQa,aAAaC,oBAC1B0iB,GAAiBxjB,EAAS8iB,GAIG,iBAAxBtI,EAAcza,MACxBkjB,GAAezI,EAAcza,MAAM6G,OAAQ5G,EAAS8iB,GACpDW,GACEzjB,EACAwa,EAAcza,OAASya,EAAcxa,QACrC8iB,EAEP,CAAC,MAAOlW,GACP,OAAOkW,EACL,IAAIvP,GAAY,oCAAoCK,SAAShH,GAEhE,CAIH,OAAOkW,EACL,IAAIvP,GACF,iJAEH,EA+GUmQ,GAAiB1jB,IAC5B,MAAM6W,MAAEA,EAAKQ,UAAEA,GACbrX,EAAQH,QAAQG,SAAW6O,EAAc7O,EAAQH,QAAQE,OAGrDU,EAAgBoO,EAAc7O,EAAQH,QAAQY,eAGpD,IAAID,EACFR,EAAQH,QAAQW,OAChB6W,GAAW7W,OACXC,GAAe4W,WAAW7W,OAC1BR,EAAQH,QAAQQ,cAChB,EAGFG,EAAQ6b,KAAKjX,IAAI,GAAKiX,KAAKlX,IAAI3E,EAAO,IAGtCA,EVwIyB,EAACzB,EAAO4kB,EAAY,KAC7C,MAAMC,EAAavH,KAAKwH,IAAI,GAAIF,GAAa,GAC7C,OAAOtH,KAAKhX,OAAOtG,EAAQ6kB,GAAcA,CAAU,EU1I3CE,CAAYtjB,EAAO,GAG3B,MAAMkb,EAAO,CACXpb,OACEN,EAAQH,QAAQS,QAChB+W,GAAW0M,cACXlN,GAAOvW,QACPG,GAAe4W,WAAW0M,cAC1BtjB,GAAeoW,OAAOvW,QACtBN,EAAQH,QAAQM,eAChB,IACFI,MACEP,EAAQH,QAAQU,OAChB8W,GAAW2M,aACXnN,GAAOtW,OACPE,GAAe4W,WAAW2M,aAC1BvjB,GAAeoW,OAAOtW,OACtBP,EAAQH,QAAQO,cAChB,IACFI,SAIF,IAAK,IAAKyjB,EAAOllB,KAAU4G,OAAO2K,QAAQoL,GACxCA,EAAKuI,GACc,iBAAVllB,GAAsBA,EAAMiS,QAAQ,SAAU,IAAMjS,EAE/D,OAAO2c,CAAI,EAgBP+H,GAAWnR,MAAOtS,EAASkkB,EAAWpB,EAAaC,KACvD,IAAMljB,OAAQ2a,EAAe3Z,YAAasjB,GAAuBnkB,EAEjE,MAAMokB,EAC6C,kBAA1CD,EAAmBrjB,mBACtBqjB,EAAmBrjB,mBACnBA,GAEN,GAAKqjB,GAEE,GAAIC,EACT,GAA6C,iBAAlCpkB,EAAQa,YAAYK,UAE7BlB,EAAQa,YAAYK,UAAYuN,EAC9BzO,EAAQa,YAAYK,UACpB4P,EAAU9Q,EAAQa,YAAYE,0BAE3B,IAAKf,EAAQa,YAAYK,UAC9B,IACE,MAAMA,EAAY4N,EAAa,iBAAkB,QACjD9O,EAAQa,YAAYK,UAAYuN,EAC9BvN,EACA4P,EAAU9Q,EAAQa,YAAYE,oBAEjC,CAAC,MAAO6L,GACPE,EAAI,EAAG,0DACR,OAjBHqX,EAAqBnkB,EAAQa,YAAc,GAyB7C,IAAKujB,GAA4BD,EAAoB,CACnD,GACEA,EAAmBljB,UACnBkjB,EAAmBjjB,WACnBijB,EAAmBnjB,WAInB,OAAO8hB,EACL,IAAIvP,GACF,qGAMN4Q,EAAmBljB,UAAW,EAC9BkjB,EAAmBjjB,WAAY,EAC/BijB,EAAmBnjB,YAAa,CACjC,CAyCD,GAtCIkjB,IACFA,EAAUrN,MAAQqN,EAAUrN,OAAS,CAAA,EACrCqN,EAAU7M,UAAY6M,EAAU7M,WAAa,CAAA,EAC7C6M,EAAU7M,UAAUC,SAAU,GAGhCkD,EAActa,OAASsa,EAActa,QAAU,QAC/Csa,EAAcxb,KAAOmP,EAAQqM,EAAcxb,KAAMwb,EAAcva,SACpC,QAAvBua,EAAcxb,OAChBwb,EAAcja,OAAQ,GAIxB,CAAC,gBAAiB,gBAAgBsF,SAASwe,IACzC,IACM7J,GAAiBA,EAAc6J,KAEO,iBAA/B7J,EAAc6J,IACrB7J,EAAc6J,GAAavW,SAAS,SAEpC0M,EAAc6J,GAAexV,EAC3BC,EAAa0L,EAAc6J,GAAc,SACzC,GAGF7J,EAAc6J,GAAexV,EAC3B2L,EAAc6J,IACd,GAIP,CAAC,MAAOzX,GACP4N,EAAc6J,GAAe,GAC7BjX,EAAa,EAAGR,EAAO,gBAAgByX,uBACxC,KAICF,EAAmBrjB,mBACrB,IACEqjB,EAAmBnjB,WAAa+P,GAC9BoT,EAAmBnjB,WACnBmjB,EAAmBpjB,mBAEtB,CAAC,MAAO6L,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAIH,GACEuX,GACAA,EAAmBljB,UACnBkjB,EAAmBljB,UAAUkT,QAAQ,KAAO,EAI5C,GAAIgQ,EAAmBpjB,mBACrB,IACEojB,EAAmBljB,SAAW6N,EAC5BqV,EAAmBljB,SACnB,OAEH,CAAC,MAAO2L,GACPuX,EAAmBljB,UAAW,EAC9BmM,EAAa,EAAGR,EAAO,2CACxB,MAEDuX,EAAmBljB,UAAW,EAKlCjB,EAAQH,OAAS,IACZG,EAAQH,UACR6jB,GAAc1jB,IAInB,IAKE,OAAO8iB,GAAY,QAJElB,GACnBpH,EAAczD,QAAUmN,GAAanB,EACrC/iB,GAGH,CAAC,MAAO4M,GACP,OAAOkW,EAAYlW,EACpB,GAqBG4W,GAAmB,CAACxjB,EAAS8iB,KACjC,IACE,IAAI/L,EACAhX,EAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,QAkBnD,MAhBqB,iBAAVD,IAETgX,EAAShX,EAAQ+P,EACf/P,EACAC,EAAQa,aAAaC,qBAGzBiW,EAAShX,EAAMiQ,WAAW,YAAa,IAAIpJ,OAGT,MAA9BmQ,EAAOA,EAAOjQ,OAAS,KACzBiQ,EAASA,EAAO9Q,UAAU,EAAG8Q,EAAOjQ,OAAS,IAI/C9G,EAAQH,OAAOkX,OAASA,EACjB0M,GAASzjB,GAAS,EAAO8iB,EACjC,CAAC,MAAOlW,GACP,OAAOkW,EACL,IAAIvP,GACF,wCAAwCvT,EAAQH,QAAQmiB,WAAa,kJACrEpO,SAAShH,GAEd,GAcGqW,GAAiB,CAACqB,EAAgBtkB,EAAS8iB,KAC/C,MAAMhiB,mBAAEA,GAAuBd,EAAQa,YAGvC,GACEyjB,EAAenQ,QAAQ,SAAW,GAClCmQ,EAAenQ,QAAQ,UAAY,EAGnC,OADArH,EAAI,EAAG,iCACA2W,GAASzjB,GAAS,EAAO8iB,EAAawB,GAG/C,IAEE,MAAMC,EAAYnV,KAAKxD,MAAM0Y,EAAetU,WAAW,YAAa,MAGpE,OAAOyT,GAASzjB,EAASukB,EAAWzB,EACrC,CAAC,MAAOlW,GAEP,OAAIkE,EAAUhQ,GACL0iB,GAAiBxjB,EAAS8iB,GAG1BA,EACL,IAAIvP,GACF,kMACAK,SAAShH,GAGhB,GExgBG4X,GAAc,GAcPC,GAAoB,KAC/B3X,EAAI,EAAG,+CACP,IAAK,MAAM6R,KAAM6F,GACfE,cAAc/F,EACf,ECxBGgG,GAAqB,CAAC/X,EAAOgY,EAAKzR,EAAK0R,KAE3CzX,EAAa,EAAGR,GAGY,gBAAxBvF,EAAK0D,uBACA6B,EAAMY,MAIfqX,EAAKjY,EAAM,EAWPkY,GAAwB,CAAClY,EAAOgY,EAAKzR,EAAK0R,KAE9C,MAAQhR,WAAYkR,EAAMC,OAAEA,EAAMpgB,QAAEA,EAAO4I,MAAEA,GAAUZ,EACjDiH,EAAakR,GAAUC,GAAU,IAGvC7R,EAAI6R,OAAOnR,GAAYoR,KAAK,CAAEpR,aAAYjP,UAAS4I,SAAQ,EAG7D,ICjBA0X,GAAe,CAACC,EAAKC,KACnB,MAAMC,EACJ,yEAGIC,EAAc,CAClBlgB,IAAKggB,EAAYljB,aAAe,GAChCC,OAAQijB,EAAYjjB,QAAU,EAC9BC,MAAOgjB,EAAYhjB,OAAS,EAC5BC,WAAY+iB,EAAY/iB,aAAc,EACtCC,QAAS8iB,EAAY9iB,UAAW,EAChCC,UAAW6iB,EAAY7iB,YAAa,GAIlC+iB,EAAYjjB,YACd8iB,EAAI3jB,OAAO,eAIb,MAAM+jB,EAAUL,EAAU,CACxBM,SAA+B,GAArBF,EAAYnjB,OAAc,IAEpCiD,IAAKkgB,EAAYlgB,IAEjBqgB,QAASH,EAAYljB,MACrBsjB,QAAS,CAACC,EAASnR,KACjBA,EAASoR,OAAO,CACdX,KAAM,KACJzQ,EAASwQ,OAAO,KAAKa,KAAK,CAAEjhB,QAASygB,GAAM,EAE7CS,QAAS,KACPtR,EAASwQ,OAAO,KAAKa,KAAKR,EAAI,GAEhC,EAEJU,KAAOJ,IAGqB,IAAxBL,EAAYhjB,UACc,IAA1BgjB,EAAY/iB,WACZojB,EAAQK,MAAMtW,MAAQ4V,EAAYhjB,SAClCqjB,EAAQK,MAAMC,eAAiBX,EAAY/iB,YAE3CuK,EAAI,EAAG,2CACA,KAObqY,EAAIe,IAAIX,GAERzY,EACE,EACA,8CAA8CwY,EAAYlgB,oBAAoBkgB,EAAYnjB,8CAA8CmjB,EAAYjjB,cACrJ,EC/EH,MAAM8jB,WAAkB5S,GACtB,WAAAE,CAAY7O,EAASogB,GACnBtR,MAAM9O,GACN+O,KAAKqR,OAASrR,KAAKE,WAAamR,CACjC,CAED,SAAAoB,CAAUpB,GAER,OADArR,KAAKqR,OAASA,EACPrR,IACR,ECcH,IAAA0S,GAAgBlB,KACbA,GAEGA,EAAImB,KACF,+BACAhU,MAAOqT,EAASnR,EAAUqQ,KACxB,IACE,MAAM0B,EAAalf,EAAKW,uBAGxB,IAAKue,IAAeA,EAAWzf,OAC7B,MAAM,IAAIqf,GACR,uGACA,KAKJ,MAAMK,EAAQb,EAAQ3S,IAAI,WAC1B,IAAKwT,GAASA,IAAUD,EACtB,MAAM,IAAIJ,GACR,iEACA,KAKJ,MAAMM,EAAad,EAAQe,OAAOD,WAClC,IAAIA,EAmBF,MAAM,IAAIN,GAAU,2BAA4B,KAlBhD,SZwOe7T,OAAOmU,IAClC,MAAMzmB,EAAUuR,KACZvR,GAASZ,aACXY,EAAQZ,WAAWC,QAAUonB,SAEzBnR,GAAoBtV,EAAQ,EY3Od2mB,CAAcF,EACrB,CAAC,MAAO7Z,GACP,MAAM,IAAIuZ,GACR,mBAAmBvZ,EAAMhI,UACzBgI,EAAMiH,YACND,SAAShH,EACZ,CAGD4H,EAASwQ,OAAO,KAAKa,KAAK,CACxBhS,WAAY,IACZxU,QAASA,KACTuF,QAAS,+CAA+C6hB,MAM7D,CAAC,MAAO7Z,GACPiY,EAAKjY,EACN,KC7CX,MAAMga,GAAe,CACnBC,IAAK,YACLC,KAAM,aACNC,IAAK,YACLhJ,IAAK,kBACLgF,IAAK,iBAIP,IAAIiE,GAAkB,EAGtB,MAAMC,GAAgB,GAGhBC,GAAe,GAgBfC,GAAc,CAACC,EAAWzB,EAASnR,EAAUtF,KACjD,IAAIiT,GAAS,EACb,MAAMxD,GAAEA,EAAE0I,SAAEA,EAAQroB,KAAEA,EAAIgd,KAAEA,GAAS9M,EAcrC,OAZAkY,EAAUxR,MAAM3U,IACd,GAAIA,EAAU,CACZ,IAAIqmB,EAAermB,EAAS0kB,EAASnR,EAAUmK,EAAI0I,EAAUroB,EAAMgd,GAMnE,YAJqB9V,IAAjBohB,IAA+C,IAAjBA,IAChCnF,EAASmF,IAGJ,CACR,KAGInF,CAAM,EAaToF,GAAgBjV,MAAOqT,EAASnR,EAAUqQ,KAC9C,IAEE,MAAM2C,EAAcvW,KAGdoW,EAAWzI,IAAO5N,QAAQ,KAAM,IAGhCiH,EAAiB1G,KAEjByK,EAAO2J,EAAQ3J,KACf2C,IAAOqI,GAEb,IAAIhoB,EAAOmP,EAAQ6N,EAAKhd,MAGxB,IAAKgd,GjBmHS,iBADY/M,EiBlHC+M,KjBoH5BxM,MAAMC,QAAQR,IACN,OAATA,GAC6B,IAA7BtJ,OAAOC,KAAKqJ,GAAMnI,OiBrHd,MAAM,IAAIqf,GACR,sJACA,KAKJ,IAAIpmB,EAAQ8O,EAAcmN,EAAKlc,QAAUkc,EAAKhc,SAAWgc,EAAK9M,MAG9D,IAAKnP,IAAUic,EAAK+G,IAmBlB,MAlBAjW,EACE,EACA,uBAAuBua,UACrB1B,EAAQ1S,QAAQ,oBAAsB0S,EAAQ8B,WAAWC,iDAEjD/B,EAAQ1S,QAAQ,2CACX+I,EAAK9b,0BACZ8b,EAAKzb,SAASyb,EAAK1b,YAAY0b,EAAKxb,yBAC1CxB,0BAC0B,IAAbgd,EAAK+G,qBACC,IAAb/G,EAAK2L,6BACuB,IAApB3L,EAAK4L,sCAEPxY,KAAKC,UAAU2M,EAAKlc,QAAUkc,EAAKhc,SAAWgc,EAAK9M,MAAQ8M,EAAK+G,cAK1E,IAAIoD,GACR,oQACA,KAIJ,IAAImB,GAAe,EAWnB,GARAA,EAAeH,GAAYF,GAAetB,EAASnR,EAAU,CAC3DmK,KACA0I,WACAroB,OACAgd,UAImB,IAAjBsL,EACF,OAAO9S,EAASqR,KAAKyB,GAGvB,IAAIO,GAAoB,EAGxBlC,EAAQmC,OAAO1U,GAAG,SAAU2U,IACtBA,IACFF,GAAoB,EACrB,IAGH/a,EAAI,EAAG,iDAAiDua,MAExDrL,EAAK9b,OAAiC,iBAAhB8b,EAAK9b,QAAuB8b,EAAK9b,QAAW,QAGlE,MAAMsS,EAAiB,CACrB3S,OAAQ,CACNE,QACAf,OACAkB,OAAQ8b,EAAK9b,OAAO,GAAG8nB,cAAgBhM,EAAK9b,OAAO+nB,OAAO,GAC1D3nB,OAAQ0b,EAAK1b,OACbC,MAAOyb,EAAKzb,MACZC,MAAOwb,EAAKxb,OAASyX,EAAepY,OAAOW,MAC3CC,cAAeoO,EAAcmN,EAAKvb,eAAe,GACjDC,aAAcmO,EAAcmN,EAAKtb,cAAc,IAEjDG,YAAa,CACXC,mBPwWmCA,GOvWnCC,oBAAoB,EACpBG,UAAW2N,EAAcmN,EAAK9a,WAAW,GACzCD,SAAU+a,EAAK/a,SACfD,WAAYgb,EAAKhb,aAIjBjB,IAEFyS,EAAe3S,OAAOE,MAAQ+P,EAC5B/P,EACAyS,EAAe3R,YAAYC,qBAK/B,MAAMd,EAAUwR,GAAmByG,EAAgBzF,GAcnD,GAXAxS,EAAQH,OAAOG,QAAUD,EAGzBC,EAAQ+hB,QAAU,CAChBgB,IAAK/G,EAAK+G,MAAO,EACjB4E,IAAK3L,EAAK2L,MAAO,EACjBC,WAAY5L,EAAK4L,aAAc,EAC/B5F,UAAWqF,GAITrL,EAAK+G,KjBoByB,CAAC9T,GACf,CACpB,mDACA,uEACA,wEACA,uFACA,qEAGmB2G,MAAMsS,GAAYA,EAAQhhB,KAAK+H,KiB7BlCkZ,CAAuBnoB,EAAQ+hB,QAAQgB,KACrD,MAAM,IAAIoD,GACR,6KACA,WAKEvD,GAAY5iB,GAAS,CAAC4M,EAAOwb,KAajC,GAXAzC,EAAQmC,OAAOO,mBAAmB,SAG9BpQ,EAAe3W,OAAOM,cACxBkL,EACE,EACA,+BAA+Bua,0CAAiDG,UAKhFK,EACF,OAAO/a,EACL,EACA,mFAKJ,GAAIF,EACF,MAAMA,EAIR,IAAKwb,IAASA,EAAKjG,OACjB,MAAM,IAAIgE,GACR,oGAAoGkB,oBAA2Be,EAAKjG,UACpI,KAUJ,OALAnjB,EAAOopB,EAAKpoB,QAAQH,OAAOb,KAG3BmoB,GAAYD,GAAcvB,EAASnR,EAAU,CAAEmK,KAAI3C,KAAMoM,EAAKjG,SAE1DiG,EAAKjG,OAEHnG,EAAK2L,IAEM,QAAT3oB,GAA0B,OAARA,EACbwV,EAASqR,KACdzL,OAAOkO,KAAKF,EAAKjG,OAAQ,QAAQlV,SAAS,WAIvCuH,EAASqR,KAAKuC,EAAKjG,SAI5B3N,EAAS+T,OAAO,eAAgB3B,GAAa5nB,IAAS,aAGjDgd,EAAK4L,YACRpT,EAASgU,WACP,GAAG7C,EAAQe,OAAO+B,UAAY9C,EAAQ3J,KAAKyM,UAAY,WACrDzpB,GAAQ,SAME,QAATA,EACHwV,EAASqR,KAAKuC,EAAKjG,QACnB3N,EAASqR,KAAKzL,OAAOkO,KAAKF,EAAKjG,OAAQ,iBA5B7C,CA6BC,GAEJ,CAAC,MAAOvV,GACPiY,EAAKjY,EACN,CjB1E0B,IAACqC,CiB0E3B,ECjRH,MAAMyZ,GAAUtZ,KAAKxD,MAAMkD,EAAa6Z,EAAO5a,EAAW,kBAEpD6a,GAAkB,IAAI5b,KAEtB6b,GAAe,GAuCN,SAASC,GAAgB3D,GACtC,IAAKA,EACH,OAAO,EN5CgB,IAACxG,IMyB1BoK,aAAY,KACV,MAAM9K,EAAQtb,KACRqmB,EACqB,IAAzB/K,EAAME,eACF,EACCF,EAAMC,iBAAmBD,EAAME,eAAkB,IAExD0K,GAAa/N,KAAKkO,GACdH,GAAa/hB,OA5BF,IA6Bb+hB,GAAazW,OACd,GA/BkB,KNHrBoS,GAAY1J,KAAK6D,GMkDjBwG,EAAInS,IAAI,WAAW,CAACiW,EAAG9V,KACrB,MAAM8K,EAAQtb,KACRumB,EAASL,GAAa/hB,OACtBqiB,EAxCIN,GAAaO,QAAO,CAACC,EAAGC,IAAMD,EAAIC,GAAG,GACpCT,GAAa/hB,OAyCxBgG,EAAI,EAAG,4DAEPqG,EAAI0S,KAAK,CACPb,OAAQ,KACRuE,SAAUX,GACVY,OACEnN,KAAKoN,QACF,IAAIzc,MAAO8R,UAAY8J,GAAgB9J,WAAa,IAAO,IAC1D,WACNzf,QAASqpB,GAAQrpB,QACjBqqB,kBAAmBrqB,KACnBsqB,sBAAuB1L,EAAMM,aAC7BL,iBAAkBD,EAAMC,iBACxB0L,cAAe3L,EAAMK,eACrBH,eAAgBF,EAAME,eACtB0L,YAAc5L,EAAMC,iBAAmBD,EAAME,eAAkB,IAE/Dxb,KAAMA,KAGNumB,SACAC,gBACAvkB,QACEuC,MAAMgiB,KAAmBN,GAAa/hB,OAClC,oEACA,QAAQoiB,mCAAwCC,EAAc7O,QAAQ,OAG5EwP,kBAAmB7L,EAAMG,sBACzB2L,mBAAoB9L,EAAMC,iBAAmBD,EAAMG,uBACnD,GAEN,CC5EA,MAAM4L,GAAgB,IAAIC,IAGpB9E,GAAM+E,IAGZ/E,GAAIgF,QAAQ,gBAGZhF,GAAIe,IAAIkE,KAIRjF,GAAIe,KAAI,CAACmE,EAAMlX,EAAK0R,KAClB1R,EAAImX,IAAI,gBAAiB,QACzBzF,GAAM,IAQR,MAAM0F,GAA6BjpB,IACjCA,EAAO8R,GAAG,eAAe,CAACxG,EAAOkb,KAC/B1a,EACE,EACAR,EACA,0BAA0BA,EAAMhI,+BAElCkjB,EAAOvO,SAAS,IAGlBjY,EAAO8R,GAAG,SAAUxG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAMhI,UAAU,IAGnEtD,EAAO8R,GAAG,cAAe0U,IACvBA,EAAO1U,GAAG,SAAUxG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAMhI,UAAU,GACjE,GACF,EAaS4lB,GAAclY,MAAOmY,IAChC,IAKE,MACMC,EAAoC,MADnBD,EAAalpB,eAAiB,GACJ,KAG3CopB,EAAUC,EAAOC,gBACjBC,EAASF,EAAO,CACpBD,UACAI,OAAQ,CACNC,UAAWN,KAYf,GAPAvF,GAAIe,IAAIgE,EAAQjF,KAAK,CAAEgG,MAAOP,KAC9BvF,GAAIe,IAAIgE,EAAQgB,WAAW,CAAEC,UAAU,EAAMF,MAAOP,KAGpDvF,GAAIe,IAAI4E,EAAOM,SAGVX,EAAajpB,OAChB,OAAO,EAIT,IAAKipB,EAAajoB,IAAIC,MAAO,CAE3B,MAAM4oB,EAAavY,EAAKwY,aAAanG,IAGrCoF,GAA0Bc,GAG1BA,EAAWE,OAAOd,EAAa9oB,KAAM8oB,EAAa/oB,MAGlDsoB,GAAcM,IAAIG,EAAa9oB,KAAM0pB,GAErCve,EACE,EACA,mCAAmC2d,EAAa/oB,QAAQ+oB,EAAa9oB,QAExE,CAGD,GAAI8oB,EAAajoB,IAAIhB,OAAQ,CAE3B,IAAIkO,EAAK8b,EAET,IAEE9b,QAAY+b,EAAWC,SACrBC,EAAM7mB,KAAK2lB,EAAajoB,IAAIE,SAAU,cACtC,QAIF8oB,QAAaC,EAAWC,SACtBC,EAAM7mB,KAAK2lB,EAAajoB,IAAIE,SAAU,cACtC,OAEH,CAAC,MAAOkK,GACPE,EACE,EACA,qDAAqD2d,EAAajoB,IAAIE,sDAEzE,CAED,GAAIgN,GAAO8b,EAAM,CAEf,MAAMI,EAAc/Y,EAAMyY,aAAa,CAAE5b,MAAK8b,QAAQrG,IAGtDoF,GAA0BqB,GAG1BA,EAAYL,OAAOd,EAAajoB,IAAIb,KAAM8oB,EAAa/oB,MAGvDsoB,GAAcM,IAAIG,EAAajoB,IAAIb,KAAMiqB,GAEzC9e,EACE,EACA,oCAAoC2d,EAAa/oB,QAAQ+oB,EAAajoB,IAAIb,QAE7E,CACF,CAIC8oB,EAAaxoB,cACbwoB,EAAaxoB,aAAaT,SACzB,CAAC,EAAGqqB,KAAK9lB,SAAS0kB,EAAaxoB,aAAaC,cAE7CgjB,GAAUC,GAAKsF,EAAaxoB,cAI9BkjB,GAAIe,IAAIgE,EAAQ4B,OAAOH,EAAM7mB,KAAKiJ,EAAW,YAG7Cge,GAAY5G,IFsGD,CAACA,IAIdA,EAAImB,KAAK,IAAKiB,IAMdpC,EAAImB,KAAK,aAAciB,GAAc,EE/GnCyE,CAAa7G,ICjLF,CAACA,MACbA,GAEGA,EAAInS,IAAI,KAAK,CAACiZ,EAAUzX,KACtBA,EAAS0X,SAASpnB,EAAKiJ,EAAW,SAAU,cAAe,CACzDoe,cAAc,GACd,GACF,ED2KJC,CAAQjH,IACRkB,GAAalB,IN/JF,CAACA,IAEdA,EAAIe,IAAIvB,IAGRQ,EAAIe,IAAIpB,GAAsB,EM6J5BuH,CAAalH,GACd,CAAC,MAAOvY,GACP,MAAM,IAAI2G,GACR,sDACAK,SAAShH,EACZ,GAMU0f,GAAe,KAC1Bxf,EAAI,EAAG,iCACP,IAAK,MAAOnL,EAAML,KAAW0oB,GAC3B1oB,EAAO6d,OAAM,KACX6K,GAAcuC,OAAO5qB,GACrBmL,EAAI,EAAG,mCAAmCnL,KAAQ,GAErD,EA6DH,IAAeL,GAAA,CACbkpB,eACA8B,gBACAE,WAxDwB,IAAMxC,GAyD9ByC,mBAlDiCrH,GAAgBF,GAAUC,GAAKC,GAmDhEsH,WA5CwB,IAAMxC,EA6C9ByC,OAtCoB,IAAMxH,GAuC1Be,IA/BiB,CAACjM,KAAS2S,KAC3BzH,GAAIe,IAAIjM,KAAS2S,EAAY,EA+B7B5Z,IAtBiB,CAACiH,KAAS2S,KAC3BzH,GAAInS,IAAIiH,KAAS2S,EAAY,EAsB7BtG,KAbkB,CAACrM,KAAS2S,KAC5BzH,GAAImB,KAAKrM,KAAS2S,EAAY,GEhQzB,MAAMC,GAAkBva,MAAOwa,UAE9Bra,QAAQsa,WAAW,CAEvBtI,KAGA6H,KAGAhL,OAIFzV,QAAQmhB,KAAKF,EAAS,EC4ExB,IAAeG,GAAA,CAEb3rB,UACAkpB,eAGA0C,WApCiB5a,MAAOtS,IZsdW,IAACjB,EY3bpC,OZ2boCA,EYndlCiB,EAAQa,aAAeb,EAAQa,YAAYC,mBZod7CA,GAAqBgQ,EAAU/R,GXpUN,CAACouB,IAE1B,IAAK,MAAOzd,EAAK3Q,KAAU4G,OAAO2K,QAAQ6c,GACxC9pB,EAAQqM,GAAO3Q,EAIjB2O,EAAYyf,GAAkB/M,SAAS+M,EAAe7pB,QAGlD6pB,GAAkBA,EAAe3pB,MAAQ2pB,EAAezpB,QAC1DiK,EACEwf,EAAe3pB,KACf2pB,EAAe5pB,MAAQ,+BAE1B,EuB3JD6pB,CAAYptB,EAAQqD,SAGhBrD,EAAQ6D,MAAME,uBAnDlB+I,EAAI,EAAG,sDAGPjB,QAAQuH,GAAG,QAASia,IAClBvgB,EAAI,EAAG,4BAA4BugB,KAAQ,IAI7CxhB,QAAQuH,GAAG,UAAUd,MAAO3N,EAAM0oB,KAChCvgB,EAAI,EAAG,OAAOnI,sBAAyB0oB,YACjCR,GAAgB,EAAE,IAI1BhhB,QAAQuH,GAAG,WAAWd,MAAO3N,EAAM0oB,KACjCvgB,EAAI,EAAG,OAAOnI,sBAAyB0oB,YACjCR,GAAgB,EAAE,IAI1BhhB,QAAQuH,GAAG,UAAUd,MAAO3N,EAAM0oB,KAChCvgB,EAAI,EAAG,OAAOnI,sBAAyB0oB,YACjCR,GAAgB,EAAE,IAI1BhhB,QAAQuH,GAAG,qBAAqBd,MAAO1F,EAAOjI,KAC5CyI,EAAa,EAAGR,EAAO,OAAOjI,kBACxBkoB,GAAgB,EAAE,WA4BpBvX,GAAoBtV,SAGpBof,GAAS,CACbzc,KAAM3C,EAAQ2C,MAAQ,CACpBC,WAAY,EACZC,WAAY,GAEdwc,cAAerf,EAAQnB,UAAUC,MAAQ,KAIpCkB,CAAO,EAUdstB,aZqF0Bhb,MAAOtS,IAEjCA,EAAQH,OAAOE,MAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,cAGxD4iB,GAAY5iB,GAASsS,MAAO1F,EAAOwb,KAEvC,GAAIxb,EACF,MAAMA,EAGR,MAAM3M,QAAEA,EAAOjB,KAAEA,GAASopB,EAAKpoB,QAAQH,OAGvCwV,EACEpV,GAAW,SAASjB,IACX,QAATA,EAAiBob,OAAOkO,KAAKF,EAAKjG,OAAQ,UAAYiG,EAAKjG,cAIvDb,IAAU,GAChB,EYzGFiM,YZuByBjb,MAAOtS,IAChC,MAAMwtB,EAAiB,GAGvB,IAAK,IAAIC,KAAQztB,EAAQH,OAAOc,MAAM+F,MAAM,KAC1C+mB,EAAOA,EAAK/mB,MAAM,KACE,IAAhB+mB,EAAK3mB,QACP0mB,EAAe1S,KACb8H,GACE,IACK5iB,EACHH,OAAQ,IACHG,EAAQH,OACXC,OAAQ2tB,EAAK,GACbxtB,QAASwtB,EAAK,MAGlB,CAAC7gB,EAAOwb,KAEN,GAAIxb,EACF,MAAMA,EAIRyI,EACE+S,EAAKpoB,QAAQH,OAAOI,QACS,QAA7BmoB,EAAKpoB,QAAQH,OAAOb,KAChBob,OAAOkO,KAAKF,EAAKjG,OAAQ,UACzBiG,EAAKjG,OACV,KAOX,UAEQ1P,QAAQwC,IAAIuY,SAGZlM,IACP,CAAC,MAAO1U,GACP,MAAM,IAAI2G,GACR,kDACAK,SAAShH,EACZ,GYpEDgW,eAGAxD,YACAkC,YAGA5K,WrBjFwB,CAACS,EAAarY,KAElCA,GAAMgI,SAERwK,GA6NJ,SAAwBxS,GAEtB,MAAM4uB,EAAc5uB,EAAK6uB,WACtBC,GAAkC,eAA1BA,EAAI5c,QAAQ,KAAM,MAI7B,GAAI0c,GAAe,GAAK5uB,EAAK4uB,EAAc,GAAI,CAC7C,MAAMG,EAAW/uB,EAAK4uB,EAAc,GACpC,IAEE,GAAIG,GAAYA,EAAS/f,SAAS,SAEhC,OAAOsB,KAAKxD,MAAMkD,EAAa+e,GAElC,CAAC,MAAOjhB,GACPQ,EACE,EACAR,EACA,sDAAsDihB,UAEzD,CACF,CAGD,MAAO,EACT,CAvPqBC,CAAehvB,IAIlC6S,GAAoB/S,EAAe0S,IAGnCA,GAAiBS,GAAYnT,GAGzBuY,IAEF7F,GAAiBE,GACfF,GACA6F,EACA7R,IAKAxG,GAAMgI,SAERwK,GA+RJ,SAA2BtR,EAASlB,EAAMF,GACxC,IAAImvB,GAAY,EAChB,IAAK,IAAItd,EAAI,EAAGA,EAAI3R,EAAKgI,OAAQ2J,IAAK,CACpC,MAAMJ,EAASvR,EAAK2R,GAAGO,QAAQ,KAAM,IAG/Bgd,EAAkBzoB,EAAW8K,GAC/B9K,EAAW8K,GAAQ3J,MAAM,KACzB,GAGJ,IAAIunB,EACJD,EAAgB5E,QAAO,CAAC3jB,EAAKyS,EAAM+U,KAC7Be,EAAgBlnB,OAAS,IAAMmmB,IACjCgB,EAAexoB,EAAIyS,GAAMlZ,MAEpByG,EAAIyS,KACVtZ,GAEHovB,EAAgB5E,QAAO,CAAC3jB,EAAKyS,EAAM+U,KAC7Be,EAAgBlnB,OAAS,IAAMmmB,QAER,IAAdxnB,EAAIyS,KACTpZ,IAAO2R,GACY,YAAjBwd,EACFxoB,EAAIyS,GAAQpH,EAAUhS,EAAK2R,IACD,WAAjBwd,EACTxoB,EAAIyS,IAASpZ,EAAK2R,GACTwd,EAAa9Z,QAAQ,MAAQ,EACtC1O,EAAIyS,GAAQpZ,EAAK2R,GAAG/J,MAAM,KAE1BjB,EAAIyS,GAAQpZ,EAAK2R,IAGnB3D,EACE,EACA,mCAAmCuD,yCAErC0d,GAAY,IAIXtoB,EAAIyS,KACVlY,EACJ,CAGG+tB,GACF9d,IAGF,OAAOjQ,CACT,CAnVqBkuB,CAAkB5c,GAAgBxS,EAAMF,IAIpD0S,IqBoDPub,mBAGA/f,MACAM,eACAM,cACAC,oBAGAwgB,erB6C6BC,IAC7B,MAAM3c,EAAa,CAAA,EAEnB,IAAK,MAAO/B,EAAK3Q,KAAU4G,OAAO2K,QAAQ8d,GAAa,CACrD,MAAMJ,EAAkBzoB,EAAWmK,GAAOnK,EAAWmK,GAAKhJ,MAAM,KAAO,GAGvEsnB,EAAgB5E,QACd,CAAC3jB,EAAKyS,EAAM+U,IACTxnB,EAAIyS,GACH8V,EAAgBlnB,OAAS,IAAMmmB,EAAQluB,EAAQ0G,EAAIyS,IAAS,IAChEzG,EAEH,CACD,OAAOA,CAAU,EqB1DjB4c,arBlD0B/b,MAAOgc,IAEjC,IAAIC,EAAa,CAAA,EAGb/hB,EAAW8hB,KACbC,EAAanf,KAAKxD,MAAMkD,EAAawf,EAAgB,UAIvD,MAwDMrpB,EAAUU,OAAOC,KAAKlB,GAAeiC,KAAK6nB,IAAY,CAC1DtiB,MAAO,GAAGsiB,YACVzvB,MAAOyvB,MAIT,OAAOC,EACL,CACEzvB,KAAM,cACN2F,KAAM,WACNC,QAAS,2CACTM,KAAM,yDACNF,aAAc,GACdC,WAEF,CAAEypB,SAvEapc,MAAOqc,EAAGC,KACzB,IAAIC,EAAmB,EACnBC,EAAe,GAGnB,IAAK,MAAMC,KAAWH,EAEpBlqB,EAAcqqB,GAAWrqB,EAAcqqB,GAASpoB,KAAK0J,IAAY,IAC5DA,EACH0e,cAIFD,EAAe,IAAIA,KAAiBpqB,EAAcqqB,IAuCpD,aApCMN,EAAQK,EAAc,CAC1BJ,SAAUpc,MAAO0c,EAAQC,KAgBvB,GAdoB,kBAAhBD,EAAOrqB,MACTsqB,EAASA,EAAOnoB,OACZmoB,EAAOtoB,KAAKuoB,GAAWF,EAAO/pB,QAAQiqB,KACtCF,EAAO/pB,QAEXspB,EAAWS,EAAOD,SAASC,EAAOrqB,MAAQsqB,GAE1CV,EAAWS,EAAOD,SAAW9c,GAC3BtM,OAAO0M,OAAO,GAAIkc,EAAWS,EAAOD,UAAY,IAChDC,EAAOrqB,KAAK+B,MAAM,KAClBsoB,EAAO/pB,QAAU+pB,EAAO/pB,QAAQgqB,GAAUA,KAIxCJ,IAAqBC,EAAahoB,OAAQ,CAC9C,UACQ2kB,EAAW0D,UACfb,EACAlf,KAAKC,UAAUkf,EAAY,KAAM,GACjC,OAEH,CAAC,MAAO3hB,GACPQ,EACE,EACAR,EACA,iDAAiD0hB,UAEpD,CACD,OAAO,CACR,MAIE,CAAI,GAoBZ,EqB/BDc,UtB8KwBprB,IAExB,MAAMqrB,EAAiBjgB,KAAKxD,MAC1BkD,EAAahK,EAAKiJ,EAAW,kBAC7B1O,QAGE2E,EACF6I,QAAQC,IAAI,sCAAsCuiB,QAKpDxiB,QAAQC,IACNgC,EAAaf,EAAY,oBAAoBd,WAAWiD,KAAKC,OAC7D,IAAIkf,MAAmBnf,KACxB,EsB7LDD"}
\ No newline at end of file
+{"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 '--pipe',\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 tempDir: {\n value: './tmp/',\n type: 'string',\n envLink: 'PUPPETEER_TEMP_DIR',\n description: 'The directory for Puppeteer to store temporary files.'\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 envLink: 'SERVER_MAX_UPLOAD_SIZE',\n description: 'The maximum upload size, in MB, for the server.'\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 username: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_USERNAME',\n cliName: 'proxyUsername',\n description: 'The username for the proxy server, if it exists.'\n },\n password: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_PASSWORD',\n cliName: 'proxyPassword',\n description: 'The password for the proxy server, 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 // Checks if the string is a valid path directory (path format)\n path: () =>\n z\n .string()\n .trim()\n .refine(\n (value) => {\n // Simplified regex to match both absolute and relative paths\n return /^(\\.\\/|\\.\\.\\/|\\/|[a-zA-Z]:\\\\|[a-zA-Z]:\\/)?((?:[\\w-]+)[\\\\/]?)+$/.test(\n value\n );\n },\n {},\n {\n message: 'The string is an invalid path directory string.'\n }\n ),\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 // puppeteer\n PUPPETEER_TEMP_DIR: v.path(),\n\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_MAX_UPLOAD_SIZE: 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_USERNAME: v.string(),\n SERVER_PROXY_PASSWORD: v.string(),\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 OTHER_ALLOW_XLINK: 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 { host, port, username, password } = proxyOptions;\n\n // Try to create a Proxy Agent\n if (host && port) {\n try {\n proxyAgent = new HttpsProxyAgent({\n host,\n port,\n ...(username && password ? { username, password } : {})\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 { puppeteer: puppeteerOptions, 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: puppeteerOptions.tempDir || './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 const maxTries = 25;\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 // This isn't a full error yet as puppeteer sometimes takes time to\n // initialize properly.\n logWithStack(\n 2,\n error,\n `[browser] Failed to launch a browser instance - retrying (attempt ${tryCount}/${maxTries}).`\n );\n\n // Retry to launch browser until reaching max attempts\n if (tryCount < 25) {\n log(\n 3,\n `[browser] Retry to open a browser (attempt ${tryCount}/${maxTries}).`\n );\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n //... now it's an error, which is caught by the caller\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 4,\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 // Use whichever one is available\n exportOptions.instr = exportOptions.instr || exportOptions.options;\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 log(2, `[chart] Unable to load the default resources.json file.`);\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\nimport { envs } from './envs.js';\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 forbidden = [];\n\n if (!envs.OTHER_ALLOW_XLINK) {\n forbidden.push('xlink:href');\n }\n\n const window = new JSDOM('').window;\n const purify = DOMPurify(window);\n return purify.sanitize(input, {\n ADD_TAGS: ['foreignObject'],\n FORBID_ATTR: forbidden\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","tempDir","envLink","highcharts","version","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","enable","cliName","host","port","benchmarking","proxy","username","password","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","test","isNaN","parseFloat","envs","object","PUPPETEER_TEMP_DIR","HIGHCHARTS_VERSION","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_MAX_UPLOAD_SIZE","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_USERNAME","SERVER_PROXY_PASSWORD","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","OTHER_ALLOW_XLINK","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","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","puppeteerOptions","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","maxTries","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","forbidden","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,SAEA,sBAEA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,yCAEfC,QAAS,CACPH,MAAO,SACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,0DAGjBG,WAAY,CACVC,QAAS,CACPN,MAAO,SACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,sCAEfK,OAAQ,CACNP,MAAO,+BACPC,KAAM,SACNG,QAAS,qBACTF,YAAa,kDAEfM,YAAa,CACXR,MAAOR,EAAaC,KACpBQ,KAAM,WACNG,QAAS,0BACTF,YAAa,yCAEfO,cAAe,CACbT,MAAOR,EAAaE,QACpBO,KAAM,WACNG,QAAS,4BACTF,YAAa,uCAEfQ,iBAAkB,CAChBV,MAAOR,EAAaG,WACpBM,KAAM,WACNG,QAAS,+BACTF,YAAa,0CAEfS,cAAe,CACbX,MAAOR,EAAaI,OACpBK,KAAM,WACN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"}
\ No newline at end of file
diff --git a/lib/envs.js b/lib/envs.js
index b4cf6e79..5399293e 100644
--- a/lib/envs.js
+++ b/lib/envs.js
@@ -231,6 +231,7 @@ export const Config = z.object({
OTHER_NO_LOGO: v.boolean(),
OTHER_HARD_RESET_PAGE: v.boolean(),
OTHER_BROWSER_SHELL_MODE: v.boolean(),
+ OTHER_ALLOW_XLINK: v.boolean(),
// debugger
DEBUG_ENABLE: v.boolean(),
diff --git a/lib/sanitize.js b/lib/sanitize.js
index 8a90d093..a348a6f1 100644
--- a/lib/sanitize.js
+++ b/lib/sanitize.js
@@ -20,6 +20,7 @@ See LICENSE file in root for details.
import { JSDOM } from 'jsdom';
import DOMPurify from 'dompurify';
+import { envs } from './envs.js';
/**
* Sanitizes a given HTML string by removing