diff --git a/.env.sample b/.env.sample index 7283f259..471e56be 100644 --- a/.env.sample +++ b/.env.sample @@ -57,6 +57,7 @@ POOL_IDLE_TIMEOUT = 30000 POOL_CREATE_RETRY_INTERVAL = 200 POOL_REAPER_INTERVAL = 1000 POOL_BENCHMARKING = false +POOL_RESOURCES_INTERVAL = 30000 # LOGGING CONFIG LOGGING_LEVEL = 4 @@ -75,6 +76,7 @@ OTHER_LISTEN_TO_PROCESS_EXITS = true OTHER_NO_LOGO = false OTHER_HARD_RESET_PAGE = false OTHER_BROWSER_SHELL_MODE = true +OTHER_CONNECTION_OVER_PIPE = false # DEBUG CONFIG DEBUG_ENABLE = false diff --git a/CHANGELOG.md b/CHANGELOG.md index 9254b1bb..c61adc92 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +# 4.0.3 + +_New Features:_ + +- Added support for absolute paths in the `HIGHCHARTS_CACHE_PATH` option [(#562)](https://github.com/highcharts/node-export-server/issues/562) + +_Fixes_: + +- Improved status codes (user errors instead of 500) [(#577)](https://github.com/highcharts/node-export-server/pull/577) + +- Improved memory management/usage [(#586)](https://github.com/highcharts/node-export-server/pull/586) + +_Other:_ + +- Add fair usage policy note on the page [(#583)](https://github.com/highcharts/node-export-server/pull/583) + # 4.0.2 _Hotfix_: diff --git a/README.md b/README.md index effeb48f..1b924df6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +**Note:** If you use the public Export Server at [https://export.highcharts.com](https://export.highcharts.com) you should read our [Terms of use and Fair Usage Policy](https://www.highcharts.com/docs/export-module/privacy-disclaimer-export). Note that a valid Highcharts License is required to do exports. + # Highcharts Node.js Export Server Convert Highcharts.JS charts into static image files. @@ -291,7 +293,7 @@ These variables are set in your environment and take precedence over options fro - `HIGHCHARTS_MODULE_SCRIPTS`: Highcharts module scripts to fetch (defaults to ``). - `HIGHCHARTS_INDICATOR_SCRIPTS`: Highcharts indicator scripts to fetch (defaults to ``). - `HIGHCHARTS_FORCE_FETCH`: The flag that determines whether to refetch all scripts after each server rerun (defaults to `false`). -- `HIGHCHARTS_CACHE_PATH`: In which directory should the fetched Highcharts scripts be placed (defaults to `.cache`). +- `HIGHCHARTS_CACHE_PATH`: In which directory should the fetched Highcharts scripts be placed (defaults to `.cache`). Since v4.0.3 can be either absolute or relative path. - `HIGHCHARTS_ADMIN_TOKEN`: An authentication token that is required to switch the Highcharts version on the server at runtime (defaults to ``). ### Export Config diff --git a/bin/cli.js b/bin/cli.js index 916cfb0d..a240c77d 100755 --- a/bin/cli.js +++ b/bin/cli.js @@ -96,7 +96,8 @@ const start = async () => { } } else { throw new ExportError( - '[cli] No valid options provided. Please check your input and try again.' + '[cli] No valid options provided. Please check your input and try again.', + 400 ); } } catch (error) { diff --git a/dist/index.cjs b/dist/index.cjs index abb4c7cb..b74ff867 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."}},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:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},E={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:w.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:w.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:w.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:w.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:w.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:w.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${w.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${w.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:w.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:w.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:w.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:w.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:w.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:w.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:w.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:w.server.host.value},{type:"number",name:"port",message:"Server port",initial:w.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:w.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:w.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:w.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:w.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:w.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:w.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:w.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:w.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:w.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:w.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:w.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:w.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:w.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:w.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:w.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:w.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:w.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:w.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:w.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:w.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:w.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:w.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:w.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:w.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:w.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:w.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:w.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:w.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:w.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:w.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:w.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:w.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:w.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:w.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:w.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:w.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:w.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:w.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:w.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:w.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:w.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:w.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:w.debug.debuggingPort.value}]},T=["options","globalOptions","themeOptions","resources","payload"],S={},x=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?x(o,`${t}.${r}`):(S[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(S[o.legacyName]=`${t}.${r}`.substring(1)))}}))};x(w),i.config();const R=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),L=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),O=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),_=()=>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=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),I=()=>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)),C=s.z.object({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:L(),HIGHCHARTS_CACHE_PATH:_(),HIGHCHARTS_ADMIN_TOKEN:_(),EXPORT_TYPE:O(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:O(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:k(),EXPORT_DEFAULT_WIDTH:k(),EXPORT_DEFAULT_SCALE:k(),EXPORT_RASTERIZATION_TIMEOUT:I(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:L(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:L(),SERVER_ENABLE:L(),SERVER_HOST:_(),SERVER_PORT:k(),SERVER_BENCHMARKING:L(),SERVER_PROXY_HOST:_(),SERVER_PROXY_PORT:k(),SERVER_PROXY_TIMEOUT:I(),SERVER_RATE_LIMITING_ENABLE:L(),SERVER_RATE_LIMITING_MAX_REQUESTS:I(),SERVER_RATE_LIMITING_WINDOW:I(),SERVER_RATE_LIMITING_DELAY:I(),SERVER_RATE_LIMITING_TRUST_PROXY:L(),SERVER_RATE_LIMITING_SKIP_KEY:_(),SERVER_RATE_LIMITING_SKIP_TOKEN:_(),SERVER_SSL_ENABLE:L(),SERVER_SSL_FORCE:L(),SERVER_SSL_PORT:k(),SERVER_SSL_CERT_PATH:_(),POOL_MIN_WORKERS:I(),POOL_MAX_WORKERS:I(),POOL_WORK_LIMIT:k(),POOL_ACQUIRE_TIMEOUT:I(),POOL_CREATE_TIMEOUT:I(),POOL_DESTROY_TIMEOUT:I(),POOL_IDLE_TIMEOUT:I(),POOL_CREATE_RETRY_INTERVAL:I(),POOL_REAPER_INTERVAL:I(),POOL_BENCHMARKING:L(),LOGGING_LEVEL: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:_(),LOGGING_DEST:_(),LOGGING_TO_CONSOLE:L(),LOGGING_TO_FILE:L(),UI_ENABLE:L(),UI_ROUTE:_(),OTHER_NODE_ENV:O(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:L(),OTHER_NO_LOGO:L(),OTHER_HARD_RESET_PAGE:L(),OTHER_BROWSER_SHELL_MODE:L(),DEBUG_ENABLE:L(),DEBUG_HEADLESS:L(),DEBUG_DEVTOOLS:L(),DEBUG_LISTEN_TO_CONSOLE:L(),DEBUG_DUMPIO:L(),DEBUG_SLOW_MO:I(),DEBUG_DEBUGGING_PORT:k()}).partial().parse(process.env),N=["red","yellow","blue","gray","green"];let A={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:N[0]},{title:"warning",color:N[1]},{title:"notice",color:N[2]},{title:"verbose",color:N[3]},{title:"benchmark",color:N[4]}],listeners:[]};const P=(t,r)=>{A.pathCreated||(!e.existsSync(A.dest)&&e.mkdirSync(A.dest),A.pathCreated=!0),e.appendFile(`${A.dest}${A.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),A.toFile=!1)}))},H=(...e)=>{const[t,...r]=e,{levelsDesc:o,level:i}=A;if(5!==t&&(0===t||t>i||i>o.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${o[t-1].title}] -`;A.listeners.forEach((e=>{e(s,r.join(" "))})),A.toConsole&&console.log.apply(void 0,[s.toString()[A.levelsDesc[t-1].color]].concat(r)),A.toFile&&P(r,s)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=A;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];A.toConsole&&console.log.apply(void 0,[n.toString()[A.levelsDesc[e-1].color]].concat([o[N[e-1]],"\n",a])),A.listeners.forEach((e=>{e(n,l.join(" "))})),A.toFile&&P(l,n)},G=e=>{e>=0&&e<=A.levelsDesc.length&&(A.level=e)},D=(e,t)=>{if(A={...A,dest:e||A.dest,file:t||A.file,toFile:!0},0===A.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");A.dest.endsWith("/")||(A.dest+="/")},F=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),U=(e,t)=>{const r=["png","jpeg","pdf","svg"];if(t){const o=t.split(".").pop();"jpg"===o?e="jpeg":r.includes(o)&&e!==o&&(e=o)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||r.find((t=>t===e))||"png"},j=(t=!1,r)=>{const o=["js","css","files"];let i=t,s=!1;if(r&&t.endsWith(".json"))try{i=M(e.readFileSync(t,"utf8"))}catch(e){return $(2,e,"[cli] No resources found.")}else i=M(t),i&&!r&&delete i.files;for(const e in i)o.includes(e)?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):H(3,"[cli] No resources found.")};function M(e,t){try{const r=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof r&&t?JSON.stringify(r):r}catch{return!1}}const q=e=>{if(null===e||"object"!=typeof e)return e;const t=Array.isArray(e)?[]:{};for(const r in e)Object.prototype.hasOwnProperty.call(e,r)&&(t[r]=q(e[r]));return t},W=(e,t)=>JSON.stringify(e,((e,r)=>("string"==typeof r&&((r=r.trim()).startsWith("function(")||r.startsWith("function ("))&&r.endsWith("}")&&(r=t?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof r?`EXP_FUN${(r+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:r))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function V(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[r,o]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(o,"value")){let e=` --${o.cliName||r} ${("<"+o.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,o.description,`[Default: ${o.value.toString().bold}]`.blue)}else e(o)};Object.keys(w).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(w[t]))})),console.log("\n")}const B=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,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(/;$/,"")},z=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let K={};const J=()=>K,Y=(e,t,r=[])=>{const o=q(e);for(const[e,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]:Y(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 C&&void 0!==C[i.envLink]&&(i.value=C[i.envLink]))}))}function Z(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:Z(o);return t}function ee(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ee(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function te(e,t={}){return new Promise(((r,o)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(e)}))}))}class re extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const oe={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},ie=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),se=async(e,t,r,o=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const i=await te(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)throw new re(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return H(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ne=async(t,o,i)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||oe.cdnURL;H(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return oe.sources=await(async(e,t,o,i,s)=>{let n;const a=i.host,l=i.port;if(a&&l)try{n=new r.HttpsProxyAgent({host:a,port:l})}catch(e){throw new re("[cache] Could not create a Proxy Agent.").setError(e)}const c=n?{agent:n,timeout:C.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>se(`${e}`,c,s,!0))),...t.map((e=>se(`${e}`,c,s))),...o.map((e=>se(`${e}`,c)))];return(await Promise.all(p)).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),oe.hcVersion=ie(oe),e.writeFileSync(i,oe.sources),l}catch(e){throw new re("[cache] Unable to update the local Highcharts cache.").setError(e)}},ae=async r=>{const{highcharts:o,server:i}=r,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)H(3,"[cache] Fetching and caching Highcharts dependencies."),n=await ne(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?(H(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(r.modules||{}).length!==h?(H(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!r.modules[e])return H(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await ne(o,i.proxy,l):(H(3,"[cache] Dependency cache is up to date, proceeding."),oe.sources=e.readFileSync(l,"utf8"),n=r.modules,oe.hcVersion=ie(oe))}await(async(r,o)=>{const i={version:r.version,modules:o||{}};oe.activeManifest=i,H(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(F,r.cachePath,"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new re("[cache] Error writing the cache manifest.").setError(e)}})(o,n)},le=()=>t.join(F,J().highcharts.cachePath),ce=()=>oe.hcVersion;function pe(){Highcharts.animObject=function(){return{duration:0}}}async function he(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();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,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),Highcharts[t.export.constr||"chart"]("container",c,p);const u=o();for(const e in u)"function"!=typeof u[e]&&delete u[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ue=e.readFileSync(F+"/templates/template.html","utf8");let de;async function ge(){if(!de)return!1;const e=await de.newPage();return await e.setCacheEnabled(!1),await fe(e),function(e){const{debug:t}=J();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)}))}(e),e}async function me(e,t){for(const e of t)await e.dispose();await e.evaluate((()=>{if("undefined"!=typeof Highcharts){const e=Highcharts.charts;if(Array.isArray(e)&&e.length)for(const t of e)t&&t.destroy(),Highcharts.charts.shift()}const[...e]=document.getElementsByTagName("script"),[,...t]=document.getElementsByTagName("style"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.remove()}))}async function fe(e){await e.setContent(ue,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${le()}/sources.js`}),await e.evaluate(pe)}const ve=async(e,t,r,o)=>e.evaluate(he,t,r,o);var ye=async(r,o,i)=>{let s=[];try{H(4,"[export] Determining export path.");const n=i.export,a=n?.options?.chart?.displayErrors&&oe.activeManifest.modules.debugger;let l;if(o.indexOf&&(o.indexOf("=0||o.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===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 H(4,"[export] Treating as config."),n.strInj?await ve(r,{chart:{height:n.height,width:n.width}},i,a):(o.chart.height=n.height,o.chart.width=n.width,await ve(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){$(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){$(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.ceil(c.chartHeight||n.height),h=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 re("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 re(`[export] Unsupported output format ${n.type}.`);g=await(async(e,t,r,o,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:r,encoding:o}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout"))),i||1500)))])))(r,p,h,"base64",n.rasterizationTimeout)}return await me(r,s),g}catch(e){return await me(r,s),e}};let be=!1;const we={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Ee={};const Te={create:async()=>{let e=!1;const t=p.v4(),r=(new Date).getTime();try{if(e=await ge(),!e||e.isClosed())throw new re("The page is invalid or closed.");H(3,`[pool] Successfully created a worker ${t} - took ${(new Date).getTime()-r} ms.`)}catch(e){throw new re("Error encountered when creating a new page.").setError(e)}return{id:t,page:e,workCount:Math.round(Math.random()*(Ee.workLimit/2))}},validate:async e=>!(Ee.workLimit&&++e.workCount>Ee.workLimit)||(H(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Ee.workLimit}).`),!1),destroy:async e=>{H(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},Se=async e=>{if(Ee=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=J(),{enable:o,...i}=t,s={headless:!r.browserShellMode||"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...o&&i};if(!de){let e=0;const t=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),de=await h.launch(s)}catch(r){if($(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;H(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===s.headless&&H(3,"[browser] Launched browser in shell mode."),o&&H(3,"[browser] Launched browser in debug mode.")}catch(e){throw new re("[browser] Maximum retries to open a browser instance reached.").setError(e)}if(!de)throw new re("[browser] Cannot find a browser to open.")}return de}(e.puppeteerArgs),H(3,`[pool] Initializing pool with workers: min ${Ee.minWorkers}, max ${Ee.maxWorkers}.`),be)return H(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Ee.minWorkers)>parseInt(Ee.maxWorkers)&&(Ee.minWorkers=Ee.maxWorkers);try{be=new c.Pool({...Te,min:parseInt(Ee.minWorkers),max:parseInt(Ee.maxWorkers),acquireTimeoutMillis:Ee.acquireTimeout,createTimeoutMillis:Ee.createTimeout,destroyTimeoutMillis:Ee.destroyTimeout,idleTimeoutMillis:Ee.idleTimeout,createRetryIntervalMillis:Ee.createRetryInterval,reapIntervalMillis:Ee.reaperInterval,propagateCreateError:!1}),be.on("release",(async e=>{await async function(e,t=!1){try{e.isClosed()||(t?(await e.goto("about:blank",{waitUntil:"domcontentloaded"}),await fe(e)):await e.evaluate((()=>{document.body.innerHTML='
'})))}catch(e){$(2,e,"[browser] Could not clear the content of the page.")}}(e.page,!1),H(4,`[pool] Releasing a worker with ID ${e.id}.`)})),be.on("destroySuccess",((e,t)=>{H(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{be.release(e)})),H(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new re("[pool] Could not create the pool of workers.").setError(e)}};async function xe(){if(H(3,"[pool] Killing pool with all workers and closing browser."),be){for(const e of be.used)be.release(e.resource);be.destroyed||(await be.destroy(),H(4,"[browser] Destroyed the pool of resources."))}await async function(){de?.connected&&await de.close(),H(4,"[browser] Closed the browser.")}()}const Re=async(e,t)=>{let r;try{if(H(4,"[pool] Work received, starting to process."),++we.exportAttempts,Ee.benchmarking&&Oe(),!be)throw new re("Work received, but pool has not been started.");const o=z();try{H(4,"[pool] Acquiring a worker handle."),r=await be.acquire().promise,t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(H(4,"[pool] Acquired a worker handle."),!r.page)throw new re("Resolved worker page is invalid: the pool setup is wonky.");let i=(new Date).getTime();H(4,`[pool] Starting work on pool entry with ID ${r.id}.`);const s=z(),n=await ye(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.page=await ge()),new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),be.release(r);const a=(new Date).getTime()-i;return we.timeSpent+=a,we.spentAverage=we.timeSpent/++we.performedExports,H(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++we.droppedExports,r&&be.release(r),new re(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Le=()=>({min:be.min,max:be.max,all:be.numFree()+be.numUsed(),available:be.numFree(),used:be.numUsed(),pending:be.numPendingAcquires()});function Oe(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Le();H(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(5,`[pool] The number of all created resources: ${r}.`),H(5,`[pool] The number of available resources: ${o}.`),H(5,`[pool] The number of acquired resources: ${i}.`),H(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var _e=Le,ke=()=>we;let Ie=!1;const Ce=async(t,r)=>{H(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let r={};return e.svg?(r=q(t),r.export.type=e.type||e.export.type,r.export.scale=e.scale||e.export.scale,r.export.outfile=e.outfile||e.export.outfile,r.payload={svg:e.svg}):r=Y(t,e,T),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(t,J()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{H(4,"[chart] Attempting to export from a SVG input.");const e=He(function(e){const t=new u.JSDOM("").window;return d(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,r);return++we.exportFromSvgAttempts,e}catch(e){return r(new re("[chart] Error loading SVG input.").setError(e))}if(i.infile&&i.infile.length)try{return H(4,"[chart] Attempting to export from an input file."),o.export.instr=e.readFileSync(i.infile,"utf8"),He(o.export.instr.trim(),o,r)}catch(e){return r(new re("[chart] Error loading input file.").setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return H(4,"[chart] Attempting to export from a raw input."),B(o.customLogic?.allowCodeExecution)?Pe(o,r):"string"==typeof i.instr?He(i.instr.trim(),o,r):Ae(o,i.instr||i.options,r)}catch(e){return r(new re("[chart] Error loading raw input.").setError(e))}return r(new re("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'."))},Ne=e=>{const{chart:t,exporting:r}=e.export?.options||M(e.export?.instr),o=M(e.export?.globalOptions);let i=e.export?.scale||r?.scale||o?.exporting?.scale||e.export?.defaultScale||1;i=Math.max(.1,Math.min(i,5)),i=((e,t=1)=>{const r=Math.pow(10,t||0);return Math.round(+e*r)/r})(i,2);const 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},Ae=async(t,r,o,i)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Ie;if(n){if(a)if("string"==typeof t.customLogic.resources)t.customLogic.resources=j(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=j(r,B(t.customLogic.allowFileResources))}catch(e){$(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new re("[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=U(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]=M(e.readFileSync(s[t],"utf8"),!0):s[t]=M(s[t],!0))}catch(e){s[t]={},$(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=X(n.customCode,n.allowFileResources)}catch(e){$(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,$(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...Ne(t)};try{return o(!1,await Re(s.strInj||r||i,t))}catch(e){return o(e)}},Pe=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=W(o,e.customLogic?.allowCodeExecution)),r=o.replaceAll(/\t|\n|\r/g,"").trim(),";"===r[r.length-1]&&(r=r.substring(0,r.length-1)),e.export.strInj=r,Ae(e,!1,t)}catch(r){return t(new re(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`).setError(r))}},He=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),Ae(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ae(t,o,r)}catch(e){return B(o)?Pe(t,r):r(new re("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.").setError(e))}},$e=[],Ge=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of $e)clearInterval(e)},De=(e,t,r,o)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,o(e)},Fe=(e,t,r,o)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;r.status(l).json({statusCode:l,message:n,stack:a})};var Ue=(e,t)=>{const r="Too many requests, you have been rate limited. Please try again later.",o={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};o.trustProxy&&e.enable("trust proxy");const i=v({windowMs:60*o.window*1e3,max:o.max,delayMs:o.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:r})},default:()=>{t.status(429).send(r)}})},skip:e=>!1!==o.skipKey&&!1!==o.skipToken&&e.query.key===o.skipKey&&e.query.access_token===o.skipToken&&(H(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),H(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.trustProxy}.`)};class je extends re{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var Me=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,r)=>{try{const r=C.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new je("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const o=e.get("hc-auth");if(!o||o!==r)throw new je("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new je("No new version supplied.",400);try{await(async e=>{const t=J();t?.highcharts&&(t.highcharts.version=e),await ae(t)})(i)}catch(e){throw new je(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ce(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){r(e)}}));const qe={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let We=0;const Ve=[],Be=[],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},ze=async(e,t,r)=>{try{const r=z(),i=p.v4().replace(/-/g,""),s=J(),n=e.body,a=++We;let l=U(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new je("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=M(n.infile||n.options||n.data);if(!c&&!n.svg)throw H(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new je("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let h=!1;if(h=Xe(Ve,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==h)return t.send(h);let u=!1;e.socket.on("close",(()=>{u=!0})),H(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:M(n.globalOptions,!0),themeOptions:M(n.themeOptions,!0)},customLogic:{allowCodeExecution:Ie,allowFileResources:!1,resources:M(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(d.export.instr=W(c,d.customLogic.allowCodeExecution));const g=Y(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 je("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ce(g,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&H(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),u)return H(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new je(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Xe(Be,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",qe[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 Ke=JSON.parse(e.readFileSync(t.join(F,"package.json"))),Je=new Date,Ye=[];function Qe(e){if(!e)return!1;var t;t=setInterval((()=>{const e=ke(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;Ye.push(t),Ye.length>30&&Ye.shift()}),6e4),$e.push(t),e.get("/health",((e,t)=>{const r=ke(),o=Ye.length,i=Ye.reduce(((e,t)=>e+t),0)/Ye.length;H(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:Je,uptime:Math.floor(((new Date).getTime()-Je.getTime())/1e3/60)+" minutes",version:Ke.version,highchartsVersion:ce(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:_e(),period:o,movingAverage:i,message:isNaN(i)||!Ye.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.exportFromSvgAttempts})}))}const Ze=new Map,et=m();et.disable("x-powered-by"),et.use(g());const tt=f.memoryStorage(),rt=f({storage:tt,limits:{fieldSize:52428800}});et.use(m.json({limit:52428800})),et.use(m.urlencoded({extended:!0,limit:52428800})),et.use(rt.none());const ot=e=>{e.on("clientError",(e=>{$(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{$(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{$(1,e,`[server] Socket error: ${e.message}`)}))}))},it=async r=>{try{if(!r.enable)return!1;if(!r.ssl.force){const e=a.createServer(et);ot(e),e.listen(r.port,r.host),Ze.set(r.port,e),H(3,`[server] Started HTTP server on ${r.host}:${r.port}.`)}if(r.ssl.enable){let o,i;try{o=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(r.ssl.certPath,"server.crt"),"utf8")}catch(e){H(2,`[server] Unable to load key/certificate from the '${r.ssl.certPath}' path. Could not run secured layer server.`)}if(o&&i){const e=l.createServer({key:o,cert:i},et);ot(e),e.listen(r.ssl.port,r.host),Ze.set(r.ssl.port,e),H(3,`[server] Started HTTPS server on ${r.host}:${r.ssl.port}.`)}}r.rateLimiting&&r.rateLimiting.enable&&![0,NaN].includes(r.rateLimiting.maxRequests)&&Ue(et,r.rateLimiting),et.use(m.static(t.posix.join(F,"public"))),Qe(et),(e=>{e.post("/",ze),e.post("/:filename",ze)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(F,"public","index.html"))}))})(et),Me(et),(e=>{e.use(De),e.use(Fe)})(et)}catch(e){throw new re("[server] Could not configure and start the server.").setError(e)}},st=()=>{H(4,"[server] Closing all servers.");for(const[e,t]of Ze)t.close((()=>{Ze.delete(e),H(4,`[server] Closed server on port: ${e}.`)}))};var nt={startServer:it,closeServers:st,getServers:()=>Ze,enableRateLimiting:e=>Ue(et,e),getExpress:()=>m,getApp:()=>et,use:(e,...t)=>{et.use(e,...t)},get:(e,...t)=>{et.get(e,...t)},post:(e,...t)=>{et.post(e,...t)}};const at=async e=>{await Promise.allSettled([Ge(),st(),xe()]),process.exit(e)};var lt={server:nt,startServer:it,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Ie=B(t),(e=>{for(const[t,r]of Object.entries(e))A[t]=r;G(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&D(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(H(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{H(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("SIGTERM",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("SIGHUP",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await at(0)})),process.on("uncaughtException",(async(e,t)=>{$(1,e,`The ${t} error.`),await at(1)}))),await ae(e),await Se({pool:e.pool||{minWorkers:1,maxWorkers:1},puppeteerArgs:e.puppeteer.args||[]}),e},singleExport:async t=>{t.export.instr=t.export.instr||t.export.options,await Ce(t,(async(t,r)=>{if(t)throw t;const{outfile:o,type:i}=r.options.export;e.writeFileSync(o||`chart.${i}`,"svg"!==i?Buffer.from(r.result,"base64"):r.result),await xe()}))},batchExport:async t=>{const r=[];for(let o of t.export.batch.split(";"))o=o.split("="),2===o.length&&r.push(Ce({...t,export:{...t.export,infile:o[0],outfile:o[1]}},((t,r)=>{if(t)throw t;e.writeFileSync(r.options.export.outfile,"svg"!==r.options.export.type?Buffer.from(r.result,"base64"):r.result)})));try{await Promise.all(r),await xe()}catch(e){throw new re("[chart] Error encountered during batch export.").setError(e)}},startExport:Ce,initPool:Se,killPool:xe,setOptions:(t,r)=>(r?.length&&(K=function(t){const r=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(r>-1&&t[r+1]){const o=t[r+1];try{if(o&&o.endsWith(".json"))return JSON.parse(e.readFileSync(o))}catch(e){$(2,e,`[config] Unable to load the configuration from the ${o} file.`)}}return{}}(r)),Q(w,K),K=Z(w),t&&(K=Y(K,t,T)),r?.length&&(K=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]=B(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(H(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&V();return e}(K,r,w)),K),shutdownCleanUp:at,log:H,logWithStack:$,setLogLevel:G,enableFileLogging:D,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=S[r]?S[r].split("."):[];e.reduce(((t,r,i)=>t[r]=e.length-1===i?o:t[r]||{}),t)}return t},manualConfig:async t=>{let r={};e.existsSync(t)&&(r=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(E).map((e=>({title:`${e} options`,value:e})));return o({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:i},{onSubmit:async(i,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]=ee(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){$(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:V};module.exports=lt; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBQb3NzaWJsZSBuYW1lcyBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcbiAgbW9kdWxlczogW1xuICAgICdzdG9jaycsXG4gICAgJ21hcCcsXG4gICAgJ2dhbnR0JyxcbiAgICAnZXhwb3J0aW5nJyxcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxuICAgICdhY2Nlc3NpYmlsaXR5JyxcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICdib29zdC1jYW52YXMnLFxuICAgICdib29zdCcsXG4gICAgJ2RhdGEnLFxuICAgICdkYXRhLXRvb2xzJyxcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgJ3N0YXRpYy1zY2FsZScsXG4gICAgJ2Jyb2tlbi1heGlzJyxcbiAgICAnaGVhdG1hcCcsXG4gICAgJ3RpbGVtYXAnLFxuICAgICd0aWxlZHdlYm1hcCcsXG4gICAgJ3RpbWVsaW5lJyxcbiAgICAndHJlZW1hcCcsXG4gICAgJ3RyZWVncmFwaCcsXG4gICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAnZHJpbGxkb3duJyxcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXG4gICAgJ2J1bGxldCcsXG4gICAgJ2Z1bm5lbCcsXG4gICAgJ2Z1bm5lbDNkJyxcbiAgICAnZ2VvaGVhdG1hcCcsXG4gICAgJ3B5cmFtaWQzZCcsXG4gICAgJ25ldHdvcmtncmFwaCcsXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxuICAgICdwYXJldG8nLFxuICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICdwaWN0b3JpYWwnLFxuICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICdzYW5rZXknLFxuICAgICdhcmMtZGlhZ3JhbScsXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICdzZXJpZXMtb24tcG9pbnQnLFxuICAgICdzb2xpZC1nYXVnZScsXG4gICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcbiAgICAnc3RyZWFtZ3JhcGgnLFxuICAgICdzdW5idXJzdCcsXG4gICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgJ3Zhcml3aWRlJyxcbiAgICAndmVjdG9yJyxcbiAgICAndmVubicsXG4gICAgJ3dpbmRiYXJiJyxcbiAgICAnd29yZGNsb3VkJyxcbiAgICAneHJhbmdlJyxcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcbiAgICAnZHJhZy1wYW5lcycsXG4gICAgJ2RlYnVnZ2VyJyxcbiAgICAnZHVtYmJlbGwnLFxuICAgICdsb2xsaXBvcCcsXG4gICAgJ2N5bGluZGVyJyxcbiAgICAnb3JnYW5pemF0aW9uJyxcbiAgICAnZG90cGxvdCcsXG4gICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcbiAgICAnaGVpa2luYXNoaScsXG4gICAgJ2Zsb3dtYXAnLFxuICAgICdleHBvcnQtZGF0YScsXG4gICAgJ25hdmlnYXRvcicsXG4gICAgJ3RleHRwYXRoJ1xuICBdLFxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gIGN1c3RvbTogW1xuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICBdXG59O1xuXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xuICBwdXBwZXRlZXI6IHtcbiAgICBhcmdzOiB7XG4gICAgICB2YWx1ZTogW1xuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxuICAgICAgICAnLS1uby1waW5ncycsXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXG4gICAgICAgICctLW5vLXp5Z290ZScsXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXG4gICAgICBdLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcbiAgICB9XG4gIH0sXG4gIGhpZ2hjaGFydHM6IHtcbiAgICB2ZXJzaW9uOiB7XG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgY2RuVVJMOiB7XG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGNvcmVTY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIG1vZHVsZVNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBjdXN0b21TY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXG4gICAgfSxcbiAgICBjYWNoZVBhdGg6IHtcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvdXRmaWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRTY2FsZToge1xuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXG4gICAgfSxcbiAgICBoZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xuICAgIH0sXG4gICAgc2NhbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXG4gICAgfSxcbiAgICBiYXRjaDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xuICAgIH0sXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAxNTAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Mb2dpYzoge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjcmVhdGVDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjoge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgc3RhcnRzIG9uIHRoZSBsb2NhbCBJUCBhZGRyZXNzIDAuMC4wLjAuJ1xuICAgIH0sXG4gICAgaG9zdDoge1xuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXG4gICAgfSxcbiAgICBwb3J0OiB7XG4gICAgICB2YWx1ZTogNzgwMSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXG4gICAgfSxcbiAgICBiZW5jaG1hcmtpbmc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdJbmRpY2F0ZXMgd2hldGhlciB0byBkaXNwbGF5IHRoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBvZiBzcGVjaWZpYyBhY3Rpb25zIHRoYXQgb2NjdXIgb24gdGhlIHNlcnZlciB3aGlsZSBzZXJ2aW5nIGEgcmVxdWVzdC4nXG4gICAgfSxcbiAgICBwcm94eToge1xuICAgICAgaG9zdDoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH0sXG4gICAgICBwb3J0OiB7XG4gICAgICAgIHZhbHVlOiA4MDgwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9LFxuICAgICAgdGltZW91dDoge1xuICAgICAgICB2YWx1ZTogNTAwMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH1cbiAgICB9LFxuICAgIHJhdGVMaW1pdGluZzoge1xuICAgICAgZW5hYmxlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcbiAgICAgIH0sXG4gICAgICBtYXhSZXF1ZXN0czoge1xuICAgICAgICB2YWx1ZTogMTAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXG4gICAgICB9LFxuICAgICAgd2luZG93OiB7XG4gICAgICAgIHZhbHVlOiAxLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xuICAgICAgfSxcbiAgICAgIGRlbGF5OiB7XG4gICAgICAgIHZhbHVlOiAwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcbiAgICAgIH0sXG4gICAgICB0cnVzdFByb3h5OiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcbiAgICAgIH0sXG4gICAgICBza2lwS2V5OiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xuICAgICAgfSxcbiAgICAgIHNraXBUb2tlbjoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcbiAgICAgIH1cbiAgICB9LFxuICAgIHNzbDoge1xuICAgICAgZW5hYmxlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xuICAgICAgfSxcbiAgICAgIGZvcmNlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXG4gICAgICB9LFxuICAgICAgcG9ydDoge1xuICAgICAgICB2YWx1ZTogNDQzLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xuICAgICAgfSxcbiAgICAgIGNlcnRQYXRoOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHBvb2w6IHtcbiAgICBtaW5Xb3JrZXJzOiB7XG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcbiAgICB9LFxuICAgIG1heFdvcmtlcnM6IHtcbiAgICAgIHZhbHVlOiA4LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xuICAgIH0sXG4gICAgd29ya0xpbWl0OiB7XG4gICAgICB2YWx1ZTogNDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgbnVtYmVyIG9mIHdvcmsgcGllY2VzIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyB0aGUgd29ya2VyIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgY3JlYXRlVGltZW91dDoge1xuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGlkbGVUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogMzAwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXG4gICAgfSxcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XG4gICAgICB2YWx1ZTogMjAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcbiAgICB9LFxuICAgIHJlYXBlckludGVydmFsOiB7XG4gICAgICB2YWx1ZTogMTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveSBpcyB0cmlnZ2VyZWQuJ1xuICAgIH0sXG4gICAgYmVuY2htYXJraW5nOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXG4gICAgfVxuICB9LFxuICBsb2dnaW5nOiB7XG4gICAgbGV2ZWw6IHtcbiAgICAgIHZhbHVlOiA0LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGZpbGU6IHtcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCBvcHRpb25zIGFsc28gbmVlZCB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXG4gICAgfSxcbiAgICBkZXN0OiB7XG4gICAgICB2YWx1ZTogJ2xvZy8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIHBhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBUaGUgYGxvZ1RvRmlsZWAgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xuICAgIH0sXG4gICAgdG9Db25zb2xlOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0NPTlNPTEUnLFxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgc2hvd2luZyBsb2dzIGluIHRoZSBjb25zb2xlLidcbiAgICB9LFxuICAgIHRvRmlsZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0ZpbGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGNyZWF0aW9uIG9mIHRoZSBsb2cgZGlyZWN0b3J5IGFuZCBzYXZpbmcgdGhlIGxvZyBpbnRvIGEgLmxvZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHVpOiB7XG4gICAgZW5hYmxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcbiAgICB9LFxuICAgIHJvdXRlOiB7XG4gICAgICB2YWx1ZTogJy8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcbiAgICB9XG4gIH0sXG4gIG90aGVyOiB7XG4gICAgbm9kZUVudjoge1xuICAgICAgdmFsdWU6ICdwcm9kdWN0aW9uJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudC4nXG4gICAgfSxcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIHdoZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMuJ1xuICAgIH0sXG4gICAgbm9Mb2dvOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xuICAgIH0sXG4gICAgaGFyZFJlc2V0UGFnZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0hBUkRfUkVTRVRfUEFHRScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xuICAgIH0sXG4gICAgYnJvd3NlclNoZWxsTW9kZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlLidcbiAgICB9XG4gIH0sXG4gIGRlYnVnOiB7XG4gICAgZW5hYmxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3Nlci4nXG4gICAgfSxcbiAgICBoZWFkbGVzczoge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdDb250cm9scyB0aGUgbW9kZSBpbiB3aGljaCB0aGUgYnJvd3NlciBpcyBsYXVuY2hlZCB3aGVuIGluIHRoZSBkZWJ1ZyBtb2RlLidcbiAgICB9LFxuICAgIGRldnRvb2xzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcbiAgICB9LFxuICAgIGxpc3RlblRvQ29uc29sZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBhIGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIHNlbnQgZnJvbSB0aGUgYnJvd3Nlci4nXG4gICAgfSxcbiAgICBkdW1waW86IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdSZWRpcmVjdHMgYnJvd3NlciBwcm9jZXNzIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVyci4nXG4gICAgfSxcbiAgICBzbG93TW86IHtcbiAgICAgIHZhbHVlOiAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcbiAgICB9LFxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcbiAgICAgIHZhbHVlOiA5MjIyLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcbiAgICB9XG4gIH1cbn07XG5cbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcbi8vIGluZm9ybWF0aW9uIGxpa2U6XG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXG4vLyAqIEluaXRpYWwgdmFsdWVcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xuICBwdXBwZXRlZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbGlzdCcsXG4gICAgICBuYW1lOiAnYXJncycsXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcbiAgICAgIHNlcGFyYXRvcjogJywnXG4gICAgfVxuICBdLFxuICBoaWdoY2hhcnRzOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2NkblVSTCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGUgc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnaW5kaWNhdG9yU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuaW5kaWNhdG9yU2NyaXB0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ2xpc3QnLFxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jdXN0b21TY3JpcHRzLnZhbHVlLmpvaW4oJywnKSxcbiAgICAgIHNlcGFyYXRvcjogJywnXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSByZS1mZXRjaCB0aGUgc2NyaXB0cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXG4gICAgfVxuICBdLFxuICBleHBvcnQ6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnc2VsZWN0JyxcbiAgICAgIG5hbWU6ICd0eXBlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAnY29uc3RyJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxuICAgICAgbWluOiAwLjEsXG4gICAgICBtYXg6IDVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQucmFzdGVyaXphdGlvblRpbWVvdXQudmFsdWVcbiAgICB9XG4gIF0sXG4gIGN1c3RvbUxvZ2ljOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdhbGxvd0ZpbGVSZXNvdXJjZXMnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxuICAgIH1cbiAgXSxcbiAgc2VydmVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgdGhlIHNlcnZlciBvbiAwLjAuMC4wJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2hvc3QnLFxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBob3N0bmFtZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgcG9ydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBzZXJ2ZXIgYmVuY2htYXJraW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFNTTCBwcm90b2NvbCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHNlcnZpbmcgb25seSBvdmVyIEhUVFBTJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxuICAgICAgbWVzc2FnZTogJ1NTTCBzZXJ2ZXIgcG9ydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcbiAgICB9XG4gIF0sXG4gIHBvb2w6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWluV29ya2Vycy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIFB1cHBldGVlciBwcm9jZXNzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYWZ0ZXIgYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JlYXBlckludGVydmFsJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVySW50ZXJ2YWwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5iZW5jaG1hcmtpbmcudmFsdWVcbiAgICB9XG4gIF0sXG4gIGxvZ2dpbmc6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdsZXZlbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5sZXZlbC52YWx1ZSxcbiAgICAgIHJvdW5kOiAwLFxuICAgICAgbWluOiAwLFxuICAgICAgbWF4OiA1XG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnZmlsZScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCAtLXRvRmlsZSBhbmQgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdkZXN0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBhIGxvZyBmaWxlIHdoZW4gdGhlIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5kZXN0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICd0b0NvbnNvbGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBsb2dnaW5nIHRvIHRoZSBjb25zb2xlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy50b0NvbnNvbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3RvRmlsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcudG9GaWxlLnZhbHVlXG4gICAgfVxuICBdLFxuICB1aTogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JvdXRlJyxcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxuICAgIH1cbiAgXSxcbiAgb3RoZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnbm9kZUVudicsXG4gICAgICBtZXNzYWdlOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ25vTG9nbycsXG4gICAgICBtZXNzYWdlOiAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwLiBSZXBsYWNlZCBieSBzaW1wbGUgdGV4dCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnaGFyZFJlc2V0UGFnZScsXG4gICAgICBtZXNzYWdlOiAnRGVjaWRlcyBpZiB0aGUgcGFnZSBjb250ZW50IHNob3VsZCBiZSByZXNldCBlbnRpcmVseScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2Jyb3dzZXJTaGVsbE1vZGUnLFxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmJyb3dzZXJTaGVsbE1vZGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIGRlYnVnOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG1vZGUgc2V0dGluZyBmb3IgdGhlIGJyb3dzZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5oZWFkbGVzcy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBEZXZUb29scyBmb3IgdGhlIGhlYWRmdWwgYnJvd3NlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRldnRvb2xzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBldmVudCBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcubGlzdGVuVG9Db25zb2xlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxuICAgICAgbWVzc2FnZTogJ1JlZGlyZWN0cyB0aGUgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBOb2RlSlMgcHJvY2VzcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmR1bXBpby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnc2xvd01vJyxcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgb3BlcmF0aW9ucyBzbG93IGRvd24gaW4gbWlsbGlzZWNvbmRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuc2xvd01vLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBudW1iZXIgZm9yIGRlYnVnZ2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRlYnVnZ2luZ1BvcnQudmFsdWVcbiAgICB9XG4gIF1cbn07XG5cbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xuICAnb3B0aW9ucycsXG4gICdnbG9iYWxPcHRpb25zJyxcbiAgJ3RoZW1lT3B0aW9ucycsXG4gICdyZXNvdXJjZXMnLFxuICAncGF5bG9hZCdcbl07XG5cbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcblxuLyoqXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXG4gKi9cbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XG5cbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG59O1xuXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xuIiwiLyoqXG4gKiBAZmlsZW92ZXJ2aWV3XG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJ1xuICogbGlicmFyeS4gVGhlIHBhcnNlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHRoZW4gZXhwb3J0ZWQgdG8gYmUgdXNlZFxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXG4gKlxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cbiAqIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXG4gKi9cblxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbmltcG9ydCB7IHNjcmlwdHNOYW1lcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xuXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbmRvdGVudi5jb25maWcoKTtcblxuLy8gT2JqZWN0IHdpdGggY3VzdG9tIHZhbGlkYXRvcnMgYW5kIHRyYW5zZm9ybWVycywgdG8gYXZvaWQgcmVwZXRpdGlvblxuLy8gaW4gdGhlIENvbmZpZyBvYmplY3RcbmNvbnN0IHYgPSB7XG4gIC8vIFNwbGl0cyBzdHJpbmcgdmFsdWUgaW50byBlbGVtZW50cyBpbiBhbiBhcnJheSwgdHJpbXMgZXZlcnkgZWxlbWVudCwgY2hlY2tzXG4gIC8vIGlmIGFuIGFycmF5IGlzIGNvcnJlY3QsIGlmIGl0IGlzIGVtcHR5LCBhbmQgaWYgaXQgaXMsIHJldHVybnMgdW5kZWZpbmVkXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cbiAgICAgICAgdmFsdWVcbiAgICAgICAgICAuc3BsaXQoJywnKVxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXG4gICAgICAgICAgLmZpbHRlcigodmFsdWUpID0+IGZpbHRlckFycmF5LmluY2x1ZGVzKHZhbHVlKSlcbiAgICAgIClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcblxuICAvLyBBbGxvd3Mgb25seSB0cnVlLCBmYWxzZSBhbmQgY29ycmVjdGx5IHBhcnNlIHRoZSB2YWx1ZSB0byBib29sZWFuXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXG4gIGJvb2xlYW46ICgpID0+XG4gICAgelxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA9PT0gJ3RydWUnIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxuICAvLyBiZSB1bmRlZmluZWRcbiAgZW51bTogKHZhbHVlcykgPT5cbiAgICB6XG4gICAgICAuZW51bShbLi4udmFsdWVzLCAnJ10pXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gVHJpbXMgdGhlIHN0cmluZyB2YWx1ZSBhbmQgY2hlY2tzIGlmIGl0IGlzIGVtcHR5IG9yIGNvbnRhaW5zIHN0cmluZ2lmaWVkXG4gIC8vIHZhbHVlcyBzdWNoIGFzIGZhbHNlLCB1bmRlZmluZWQsIG51bGwsIE5hTiwgaWYgaXQgZG9lcywgcmV0dXJucyB1bmRlZmluZWRcbiAgc3RyaW5nOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxuICAgICAgICAgIHZhbHVlID09PSAnJyxcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIHBvc2l0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxuICAvLyBiZSB1bmRlZmluZWRcbiAgcG9zaXRpdmVOdW06ICgpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVmaW5lKFxuICAgICAgICAodmFsdWUpID0+XG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID4gMCksXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIG5vbi1uZWdhdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXG4gIG5vbk5lZ2F0aXZlTnVtOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwKSxcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcbn07XG5cbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XG4gIC8vIGhpZ2hjaGFydHNcbiAgSElHSENIQVJUU19WRVJTSU9OOiB6XG4gICAgLnN0cmluZygpXG4gICAgLnRyaW0oKVxuICAgIC5yZWZpbmUoXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxuICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICBtZXNzYWdlOiBgSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlosIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PlxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpIHx8XG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxuICAgICAgICB2YWx1ZSA9PT0gJycsXG4gICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5jb3JlKSxcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMubW9kdWxlcyksXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcbiAgSElHSENIQVJUU19DQUNIRV9QQVRIOiB2LnN0cmluZygpLFxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxuXG4gIC8vIGV4cG9ydFxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcbiAgRVhQT1JUX0NPTlNUUjogdi5lbnVtKFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10pLFxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX0RFRkFVTFRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuXG4gIC8vIGN1c3RvbVxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHNlcnZlclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX0hPU1Q6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHNlcnZlciBwcm94eVxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcblxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IHYuc3RyaW5nKCksXG5cbiAgLy8gc2VydmVyIHNzbFxuICBTRVJWRVJfU1NMX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfU1NMX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHYuc3RyaW5nKCksXG5cbiAgLy8gcG9vbFxuICBQT09MX01JTl9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9XT1JLX0xJTUlUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxuXG4gIC8vIGxvZ2dlclxuICBMT0dHSU5HX0xFVkVMOiB6XG4gICAgLnN0cmluZygpXG4gICAgLnRyaW0oKVxuICAgIC5yZWZpbmUoXG4gICAgICAodmFsdWUpID0+XG4gICAgICAgIHZhbHVlID09PSAnJyB8fFxuICAgICAgICAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJlxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA8PSA1KSxcbiAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgIH0pXG4gICAgKVxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcbiAgTE9HR0lOR19GSUxFOiB2LnN0cmluZygpLFxuICBMT0dHSU5HX0RFU1Q6IHYuc3RyaW5nKCksXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdi5ib29sZWFuKCksXG4gIExPR0dJTkdfVE9fRklMRTogdi5ib29sZWFuKCksXG5cbiAgLy8gdWlcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXG5cbiAgLy8gb3RoZXJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxuICBPVEhFUl9OT19MT0dPOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcblxuICAvLyBkZWJ1Z2dlclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBERUJVR19IRUFETEVTUzogdi5ib29sZWFuKCksXG4gIERFQlVHX0RFVlRPT0xTOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxuICBERUJVR19EVU1QSU86IHYuYm9vbGVhbigpLFxuICBERUJVR19TTE9XX01POiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcbn0pO1xuXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcblxuLy8gVGhlIGF2YWlsYWJsZSBjb2xvcnNcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcblxuLy8gVGhlIGRlZmF1bHQgbG9nZ2luZyBjb25maWdcbmxldCBsb2dnaW5nID0ge1xuICAvLyBGbGFncyBmb3IgbG9nZ2luZyBzdGF0dXNcbiAgdG9Db25zb2xlOiB0cnVlLFxuICB0b0ZpbGU6IGZhbHNlLFxuICBwYXRoQ3JlYXRlZDogZmFsc2UsXG4gIC8vIExvZyBsZXZlbHNcbiAgbGV2ZWxzRGVzYzogW1xuICAgIHtcbiAgICAgIHRpdGxlOiAnZXJyb3InLFxuICAgICAgY29sb3I6IGNvbG9yc1swXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbMV1cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAnbm90aWNlJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbMl1cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAndmVyYm9zZScsXG4gICAgICBjb2xvcjogY29sb3JzWzNdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXG4gICAgICBjb2xvcjogY29sb3JzWzRdXG4gICAgfVxuICBdLFxuICAvLyBMb2cgbGlzdGVuZXJzXG4gIGxpc3RlbmVyczogW11cbn07XG5cbi8qKlxuICogTG9ncyB0aGUgcHJvdmlkZWQgdGV4dHMgdG8gYSBmaWxlLCBpZiBmaWxlIGxvZ2dpbmcgaXMgZW5hYmxlZC4gSXQgY3JlYXRlc1xuICogdGhlIG5lY2Vzc2FyeSBkaXJlY3Rvcnkgc3RydWN0dXJlIGlmIG5vdCBhbHJlYWR5IGNyZWF0ZWQgYW5kIGFwcGVuZHMgdGhlXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nW119IHRleHRzIC0gQW4gYXJyYXkgb2YgdGV4dHMgdG8gYmUgbG9nZ2VkLlxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cbiAqL1xuY29uc3QgbG9nVG9GaWxlID0gKHRleHRzLCBwcmVmaXgpID0+IHtcbiAgaWYgKCFsb2dnaW5nLnBhdGhDcmVhdGVkKSB7XG4gICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XG4gICAgIWV4aXN0c1N5bmMobG9nZ2luZy5kZXN0KSAmJiBta2RpclN5bmMobG9nZ2luZy5kZXN0KTtcblxuICAgIC8vIFdlIG5vdyBhc3N1bWUgdGhlIHBhdGggaXMgYXZhaWxhYmxlLCBlLmcuIGl0J3MgdGhlIHJlc3BvbnNpYmlsaXR5XG4gICAgLy8gb2YgdGhlIHVzZXIgdG8gY3JlYXRlIHRoZSBwYXRoIHdpdGggdGhlIGNvcnJlY3QgYWNjZXNzIHJpZ2h0cy5cbiAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcbiAgfVxuXG4gIC8vIEFkZCB0aGUgY29udGVudCB0byBhIGZpbGVcbiAgYXBwZW5kRmlsZShcbiAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcbiAgICBbcHJlZml4XS5jb25jYXQodGV4dHMpLmpvaW4oJyAnKSArICdcXG4nLFxuICAgIChlcnJvcikgPT4ge1xuICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKGBbbG9nZ2VyXSBVbmFibGUgdG8gd3JpdGUgdG8gbG9nIGZpbGU6ICR7ZXJyb3J9YCk7XG4gICAgICAgIGxvZ2dpbmcudG9GaWxlID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICApO1xufTtcblxuLyoqXG4gKiBMb2dzIGEgbWVzc2FnZS4gQWNjZXB0cyBhIHZhcmlhYmxlIGFtb3VudCBvZiBhcmd1bWVudHMuIEFyZ3VtZW50cyBhZnRlclxuICogYGxldmVsYCB3aWxsIGJlIHBhc3NlZCBkaXJlY3RseSB0byBjb25zb2xlLmxvZywgYW5kL29yIHdpbGwgYmUgam9pbmVkXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxuICpcbiAqIEBwYXJhbSB7YW55fSBhcmdzIC0gQW4gYXJyYXkgb2YgYXJndW1lbnRzIHdoZXJlIHRoZSBmaXJzdCBpcyB0aGUgbG9nIGxldmVsXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXG4gKi9cbmV4cG9ydCBjb25zdCBsb2cgPSAoLi4uYXJncykgPT4ge1xuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XG5cbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcbiAgY29uc3QgeyBsZXZlbHNEZXNjLCBsZXZlbCB9ID0gbG9nZ2luZztcblxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZSBvciBpcyBhIGJlbmNobWFyayBsb2dcbiAgaWYgKFxuICAgIG5ld0xldmVsICE9PSA1ICYmXG4gICAgKG5ld0xldmVsID09PSAwIHx8IG5ld0xldmVsID4gbGV2ZWwgfHwgbGV2ZWwgPiBsZXZlbHNEZXNjLmxlbmd0aClcbiAgKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcblxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xuXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcbiAgbG9nZ2luZy5saXN0ZW5lcnMuZm9yRWFjaCgoZm4pID0+IHtcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XG4gIH0pO1xuXG4gIC8vIExvZyB0byBjb25zb2xlXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KHRleHRzKVxuICAgICk7XG4gIH1cblxuICAvLyBMb2cgdG8gZmlsZVxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcbiAgICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XG4gIH1cbn07XG5cbi8qKlxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXG4gKiBjYW4gYmUgcHJvdmlkZWQuXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21NZXNzYWdlIC0gQW4gb3B0aW9uYWwgY3VzdG9tIG1lc3NhZ2UgdG8gYmUgbG9nZ2VkIGFsb25nXG4gKiB3aXRoIHRoZSBlcnJvci5cbiAqL1xuZXhwb3J0IGNvbnN0IGxvZ1dpdGhTdGFjayA9IChuZXdMZXZlbCwgZXJyb3IsIGN1c3RvbU1lc3NhZ2UpID0+IHtcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcbiAgY29uc3QgbWFpbk1lc3NhZ2UgPSBjdXN0b21NZXNzYWdlIHx8IGVycm9yLm1lc3NhZ2U7XG5cbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcblxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxuICBpZiAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gR2V0IHJpZCBvZiB0aGUgR01UIHRleHQgaW5mb3JtYXRpb25cbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcblxuICAvLyBDcmVhdGUgYSBtZXNzYWdlJ3MgcHJlZml4XG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xuXG4gIC8vIElmIHRoZSBjdXN0b21NZXNzYWdlIGV4aXN0cywgd2Ugd2FudCB0byBkaXNwbGF5IHRoZSB3aG9sZSBzdGFjayBtZXNzYWdlXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XG4gICAgZXJyb3IubWVzc2FnZSAhPT0gZXJyb3Iuc3RhY2tNZXNzYWdlIHx8IGVycm9yLnN0YWNrTWVzc2FnZSA9PT0gdW5kZWZpbmVkXG4gICAgICA/IGVycm9yLnN0YWNrXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcblxuICAvLyBDb21iaW5lIGN1c3RvbSBtZXNzYWdlIG9yIGVycm9yIG1lc3NhZ2Ugd2l0aCBlcnJvciBzdGFjayBtZXNzYWdlXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcblxuICAvLyBMb2cgdG8gY29uc29sZVxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcbiAgICBjb25zb2xlLmxvZy5hcHBseShcbiAgICAgIHVuZGVmaW5lZCxcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXG4gICAgICAgIG1haW5NZXNzYWdlW2NvbG9yc1tuZXdMZXZlbCAtIDFdXSxcbiAgICAgICAgJ1xcbicsXG4gICAgICAgIHN0YWNrTWVzc2FnZVxuICAgICAgXSlcbiAgICApO1xuICB9XG5cbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcbiAgfSk7XG5cbiAgLy8gTG9nIHRvIGZpbGVcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XG4gICAgbG9nVG9GaWxlKHRleHRzLCBwcmVmaXgpO1xuICB9XG59O1xuXG4vKipcbiAqIFNldHMgdGhlIGxvZyBsZXZlbCB0byB0aGUgc3BlY2lmaWVkIHZhbHVlLiBMb2cgbGV2ZWxzIGFyZSAoMCA9IG5vIGxvZ2dpbmcsXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSBuZXdMZXZlbCAtIFRoZSBuZXcgbG9nIGxldmVsIHRvIGJlIHNldC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldExvZ0xldmVsID0gKG5ld0xldmVsKSA9PiB7XG4gIGlmIChuZXdMZXZlbCA+PSAwICYmIG5ld0xldmVsIDw9IGxvZ2dpbmcubGV2ZWxzRGVzYy5sZW5ndGgpIHtcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XG4gIH1cbn07XG5cbi8qKlxuICogRW5hYmxlcyBmaWxlIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGRlc3RpbmF0aW9uIGFuZCBsb2cgZmlsZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRGVzdCAtIFRoZSBkZXN0aW5hdGlvbiBwYXRoIGZvciBsb2cgZmlsZXMuXG4gKiBAcGFyYW0ge3N0cmluZ30gbG9nRmlsZSAtIFRoZSBsb2cgZmlsZSBuYW1lLlxuICovXG5leHBvcnQgY29uc3QgZW5hYmxlRmlsZUxvZ2dpbmcgPSAobG9nRGVzdCwgbG9nRmlsZSkgPT4ge1xuICAvLyBVcGRhdGUgbG9nZ2luZyBvcHRpb25zXG4gIGxvZ2dpbmcgPSB7XG4gICAgLi4ubG9nZ2luZyxcbiAgICBkZXN0OiBsb2dEZXN0IHx8IGxvZ2dpbmcuZGVzdCxcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcbiAgICB0b0ZpbGU6IHRydWVcbiAgfTtcblxuICBpZiAobG9nZ2luZy5kZXN0Lmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiBsb2coMSwgJ1tsb2dnZXJdIEZpbGUgbG9nZ2luZyBpbml0aWFsaXphdGlvbjogbm8gcGF0aCBzdXBwbGllZC4nKTtcbiAgfVxuXG4gIGlmICghbG9nZ2luZy5kZXN0LmVuZHNXaXRoKCcvJykpIHtcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xuICB9XG59O1xuXG4vKipcbiAqIEluaXRpYWxpemVzIGxvZ2dpbmcgd2l0aCB0aGUgc3BlY2lmaWVkIGxvZ2dpbmcgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbG9nZ2luZ09wdGlvbnMgLSBUaGUgbG9nZ2luZyBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGluaXRMb2dnaW5nID0gKGxvZ2dpbmdPcHRpb25zKSA9PiB7XG4gIC8vIFNldCBhbGwgdGhlIGxvZ2dpbmcgb3B0aW9ucyBvbiBvdXIgbG9nZ2luZyBtb2R1bGUgb2JqZWN0XG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGxvZ2dpbmdPcHRpb25zKSkge1xuICAgIGxvZ2dpbmdba2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgLy8gU2V0IHRoZSBsb2cgbGV2ZWxcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZ09wdGlvbnMgJiYgcGFyc2VJbnQobG9nZ2luZ09wdGlvbnMubGV2ZWwpKTtcblxuICAvLyBTZXQgdGhlIGxvZyBmaWxlIHBhdGggYW5kIG5hbWVcbiAgaWYgKGxvZ2dpbmdPcHRpb25zICYmIGxvZ2dpbmdPcHRpb25zLmRlc3QgJiYgbG9nZ2luZ09wdGlvbnMudG9GaWxlKSB7XG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXG4gICAgICBsb2dnaW5nT3B0aW9ucy5kZXN0LFxuICAgICAgbG9nZ2luZ09wdGlvbnMuZmlsZSB8fCAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZydcbiAgICApO1xuICB9XG59O1xuXG4vKipcbiAqIEFkZHMgYSBsaXN0ZW5lciBmdW5jdGlvbiB0byB0aGUgbG9nZ2luZyBzeXN0ZW0uXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBsaXN0ZW4gPSAoZm4pID0+IHtcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGxvZyxcbiAgbG9nV2l0aFN0YWNrLFxuICBzZXRMb2dMZXZlbCxcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXG4gIGluaXRMb2dnaW5nLFxuICBsaXN0ZW5cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuaW1wb3J0IHsgZmlsZVVSTFRvUGF0aCB9IGZyb20gJ3VybCc7XG5cbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5cbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcblxuZXhwb3J0IGNvbnN0IF9fZGlybmFtZSA9IGZpbGVVUkxUb1BhdGgobmV3IFVSTCgnLi4vLicsIGltcG9ydC5tZXRhLnVybCkpO1xuXG4vKipcbiAqIENsZWFycyBhbmQgc3RhbmRhcmRpemVzIHRleHQgYnkgcmVwbGFjaW5nIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2VcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcbiAqIHdoaXRlc3BhY2UuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxuICogQHBhcmFtIHtSZWdFeHB9IFtydWxlPS9cXHNcXHMrL2ddIC0gVGhlIHJlZ3VsYXIgZXhwcmVzc2lvbiBydWxlIHRvIG1hdGNoXG4gKiBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxuICogY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxuICovXG5leHBvcnQgY29uc3QgY2xlYXJUZXh0ID0gKHRleHQsIHJ1bGUgPSAvXFxzXFxzKy9nLCByZXBsYWNlciA9ICcgJykgPT5cbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XG5cbi8qKlxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXG4gKiBhIGNlcnRhaW4gbnVtYmVyIG9mIGF0dGVtcHRzIGFyZSByZWFjaGVkLlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXG4gKiBAcGFyYW0ge251bWJlcn0gW2F0dGVtcHQ9MF0gLSBUaGUgY3VycmVudCBhdHRlbXB0IG51bWJlci5cbiAqIEBwYXJhbSB7Li4uYW55fSBhcmdzIC0gQXJndW1lbnRzIHRvIGJlIHBhc3NlZCB0byB0aGUgZnVuY3Rpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdGhlIHJlc3VsdCBvZiB0aGUgZnVuY3Rpb25cbiAqIGlmIHN1Y2Nlc3NmdWwuXG4gKlxuICogQHRocm93cyB7RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBtYXhpbXVtIG51bWJlciBvZiBhdHRlbXB0c1xuICogaXMgcmVhY2hlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGV4cEJhY2tvZmYgPSBhc3luYyAoZm4sIGF0dGVtcHQgPSAwLCAuLi5hcmdzKSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXG4gICAgcmV0dXJuIGF3YWl0IGZuKC4uLmFyZ3MpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xuICAgIGNvbnN0IGRlbGF5SW5NcyA9IDIgKiogYXR0ZW1wdCAqIDEwMDA7XG5cbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXG4gICAgaWYgKCsrYXR0ZW1wdCA+PSBNQVhfQkFDS09GRl9BVFRFTVBUUykge1xuICAgICAgdGhyb3cgZXJyb3I7XG4gICAgfVxuXG4gICAgLy8gV2FpdCBnaXZlbiBhbW91bnQgb2YgdGltZVxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XG4gICAgbG9nKFxuICAgICAgMyxcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcbiAgICApO1xuXG4gICAgLy8gVHJ5IGFnYWluXG4gICAgcmV0dXJuIGV4cEJhY2tvZmYoZm4sIGF0dGVtcHQsIC4uLmFyZ3MpO1xuICB9XG59O1xuXG4vKipcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgb3JpZ2luYWwgZXhwb3J0IHR5cGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfSAtIFRoZSBjb3JyZWN0ZWQgZXhwb3J0IHR5cGUuXG4gKi9cbmV4cG9ydCBjb25zdCBmaXhUeXBlID0gKHR5cGUsIG91dGZpbGUpID0+IHtcbiAgLy8gTUlNRSB0eXBlc1xuICBjb25zdCBtaW1lVHlwZXMgPSB7XG4gICAgJ2ltYWdlL3BuZyc6ICdwbmcnLFxuICAgICdpbWFnZS9qcGVnJzogJ2pwZWcnLFxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcbiAgICAnaW1hZ2Uvc3ZnK3htbCc6ICdzdmcnXG4gIH07XG5cbiAgLy8gRm9ybWF0c1xuICBjb25zdCBmb3JtYXRzID0gWydwbmcnLCAnanBlZycsICdwZGYnLCAnc3ZnJ107XG5cbiAgLy8gQ2hlY2sgaWYgdHlwZSBhbmQgb3V0ZmlsZSdzIGV4dGVuc2lvbnMgYXJlIHRoZSBzYW1lXG4gIGlmIChvdXRmaWxlKSB7XG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcblxuICAgIGlmIChvdXRUeXBlID09PSAnanBnJykge1xuICAgICAgdHlwZSA9ICdqcGVnJztcbiAgICB9IGVsc2UgaWYgKGZvcm1hdHMuaW5jbHVkZXMob3V0VHlwZSkgJiYgdHlwZSAhPT0gb3V0VHlwZSkge1xuICAgICAgdHlwZSA9IG91dFR5cGU7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXG4gIHJldHVybiBtaW1lVHlwZXNbdHlwZV0gfHwgZm9ybWF0cy5maW5kKCh0KSA9PiB0ID09PSB0eXBlKSB8fCAncG5nJztcbn07XG5cbi8qKlxuICogSGFuZGxlcyBhbmQgdmFsaWRhdGVzIHJlc291cmNlcyBmb3IgZXhwb3J0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gcmVzb3VyY2VzIC0gVGhlIHJlc291cmNlcyB0byBiZSBoYW5kbGVkLiBDYW4gYmUgZWl0aGVyXG4gKiBhIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OIG9yIGEgcGF0aCB0byBhIEpTT04gZmlsZS5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXG4gKiBmaWxlcy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXG4gKiByZXNvdXJjZXMgYXJlIGZvdW5kLlxuICovXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcbiAgY29uc3QgYWxsb3dlZFByb3BzID0gWydqcycsICdjc3MnLCAnZmlsZXMnXTtcblxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcbiAgbGV0IGNvcnJlY3RSZXNvdXJjZXMgPSBmYWxzZTtcblxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcbiAgaWYgKGFsbG93RmlsZVJlc291cmNlcyAmJiByZXNvdXJjZXMuZW5kc1dpdGgoJy5qc29uJykpIHtcbiAgICB0cnkge1xuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIC8vIFRyeSB0byBnZXQgSlNPTlxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XG5cbiAgICAvLyBHZXQgcmlkIG9mIHRoZSBmaWxlcyBzZWN0aW9uXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XG4gICAgfVxuICB9XG5cbiAgLy8gRmlsdGVyIGZyb20gdW5uZWNlc3NhcnkgcHJvcGVydGllc1xuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcbiAgICBpZiAoIWFsbG93ZWRQcm9wcy5pbmNsdWRlcyhwcm9wTmFtZSkpIHtcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzW3Byb3BOYW1lXTtcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XG4gICAgICBjb3JyZWN0UmVzb3VyY2VzID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICAvLyBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgYWxsb3dlZCBwcm9wZXJ0aWVzIGlzIHByZXNlbnRcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XG4gICAgcmV0dXJuIGxvZygzLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xuICB9XG5cbiAgLy8gSGFuZGxlIGZpbGVzIHNlY3Rpb25cbiAgaWYgKGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMpIHtcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcbiAgICBpZiAoIWhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgfHwgaGFuZGxlZFJlc291cmNlcy5maWxlcy5sZW5ndGggPD0gMCkge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXM7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIHJlc291cmNlc1xuICByZXR1cm4gaGFuZGxlZFJlc291cmNlcztcbn07XG5cbi8qKlxuICogVmFsaWRhdGVzIGFuZCBwYXJzZXMgSlNPTiBkYXRhLiBDaGVja3MgaWYgcHJvdmlkZWQgZGF0YSBpcyBvciBjYW5cbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fHN0cmluZ30gZGF0YSAtIFRoZSBKU09OIGRhdGEgdG8gYmUgdmFsaWRhdGVkIGFuZCBwYXJzZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxuICogb2YgdGhlIHBhcnNlZCBKU09OLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcbiAqIG9yIGZhbHNlIGlmIHZhbGlkYXRpb24gZmFpbHMuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XG4gIHRyeSB7XG4gICAgLy8gR2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb24gaWYgbm90IGFscmVhZHkgYmVmb3JlIHBhcnNpbmdcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcbiAgICAgIHR5cGVvZiBkYXRhICE9PSAnc3RyaW5nJyA/IEpTT04uc3RyaW5naWZ5KGRhdGEpIDogZGF0YVxuICAgICk7XG5cbiAgICAvLyBSZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvbiBvZiBhIEpTT04gaWYgcmVxdWlyZWRcbiAgICBpZiAodHlwZW9mIHBhcnNlZERhdGEgIT09ICdzdHJpbmcnICYmIHRvU3RyaW5nKSB7XG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XG4gICAgfVxuXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxuICAgIHJldHVybiBwYXJzZWREYXRhO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cbn1cblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIGl0ZW0gaXMgYW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIGl0ZW0gdG8gYmUgY2hlY2tlZC5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgY29uc3QgaXNPYmplY3QgPSAoaXRlbSkgPT5cbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XG5cbi8qKlxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW0gLSBUaGUgb2JqZWN0IHRvIGJlIGNoZWNrZWQuXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiB0aGUgb2JqZWN0IGlzIGVtcHR5LCBmYWxzZSBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XG4gIHR5cGVvZiBpdGVtID09PSAnb2JqZWN0JyAmJlxuICAhQXJyYXkuaXNBcnJheShpdGVtKSAmJlxuICBpdGVtICE9PSBudWxsICYmXG4gIE9iamVjdC5rZXlzKGl0ZW0pLmxlbmd0aCA9PT0gMDtcblxuLyoqXG4gKiBDaGVja3MgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCBpbiB0aGUgZ2l2ZW4gc3RyaW5nLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgYSBwcml2YXRlIElQIHJhbmdlIFVSTCBpcyBmb3VuZCwgZmFsc2VcbiAqIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQgPSAoaXRlbSkgPT4ge1xuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT9sb2NhbGhvc3RcXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xMFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE3MlxcLigxWzYtOV18MlswLTldfDNbMC0xXSlcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTkyXFwuMTY4XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi9cbiAgXTtcblxuICByZXR1cm4gcmVnZXhQYXR0ZXJucy5zb21lKChwYXR0ZXJuKSA9PiBwYXR0ZXJuLnRlc3QoaXRlbSkpO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R8QXJyYXl9IG9iaiAtIFRoZSBvYmplY3Qgb3IgYXJyYXkgdG8gYmUgZGVlcGx5IGNvcGllZC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fEFycmF5fSAtIFRoZSBkZWVwIGNvcHkgb2YgdGhlIHByb3ZpZGVkIG9iamVjdCBvciBhcnJheS5cbiAqL1xuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xuICBpZiAob2JqID09PSBudWxsIHx8IHR5cGVvZiBvYmogIT09ICdvYmplY3QnKSB7XG4gICAgcmV0dXJuIG9iajtcbiAgfVxuXG4gIGNvbnN0IGNvcHkgPSBBcnJheS5pc0FycmF5KG9iaikgPyBbXSA6IHt9O1xuXG4gIGZvciAoY29uc3Qga2V5IGluIG9iaikge1xuICAgIGlmIChPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqLCBrZXkpKSB7XG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGNvcHk7XG59O1xuXG4vKipcbiAqIENvbnZlcnRzIHRoZSBwcm92aWRlZCBvcHRpb25zIG9iamVjdCB0byBhIEpTT04tZm9ybWF0dGVkIHN0cmluZyB3aXRoIHRoZVxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCB0byBiZSBjb252ZXJ0ZWQgdG8gYSBzdHJpbmcuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXG4gKiBpbiB0aGUgb3V0cHV0LlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXG4gKi9cbmV4cG9ydCBjb25zdCBvcHRpb25zU3RyaW5naWZ5ID0gKG9wdGlvbnMsIGFsbG93RnVuY3Rpb25zKSA9PiB7XG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJykge1xuICAgICAgdmFsdWUgPSB2YWx1ZS50cmltKCk7XG5cbiAgICAgIC8vIElmIGFsbG93RnVuY3Rpb25zIGlzIHNldCB0byB0cnVlLCBwcmVzZXJ2ZSBmdW5jdGlvbnNcbiAgICAgIGlmIChcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcbiAgICAgICAgdmFsdWUuZW5kc1dpdGgoJ30nKVxuICAgICAgKSB7XG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcbiAgICAgICAgICA/IGBFWFBfRlVOJHsodmFsdWUgKyAnJykucmVwbGFjZUFsbCgvXFxufFxcdHxcXHIvZywgJyAnKX1FWFBfRlVOYFxuICAgICAgICAgIDogdW5kZWZpbmVkO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcbiAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXG4gICAgICA6IHZhbHVlO1xuICB9O1xuXG4gIC8vIFN0cmluZ2lmeSBvcHRpb25zIGFuZCBpZiByZXF1aXJlZCwgcmVwbGFjZSBzcGVjaWFsIGZ1bmN0aW9ucyBtYXJrc1xuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcbiAgICAvXCJFWFBfRlVOfEVYUF9GVU5cIi9nLFxuICAgICcnXG4gICk7XG59O1xuXG4vKipcbiAqIFByaW50cyB0aGUgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIGxvZ28gYW5kIHZlcnNpb24gaW5mb3JtYXRpb24uXG4gKlxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcbiAqIHRoZSBsb2dvLlxuICovXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xuICAvLyBHZXQgcGFja2FnZSB2ZXJzaW9uIGVpdGhlciBmcm9tIGVudiBvciBmcm9tIHBhY2thZ2UuanNvblxuICBjb25zdCBwYWNrYWdlVmVyc2lvbiA9IEpTT04ucGFyc2UoXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXG4gICkudmVyc2lvbjtcblxuICAvLyBQcmludCB0ZXh0IG9ubHlcbiAgaWYgKG5vTG9nbykge1xuICAgIGNvbnNvbGUubG9nKGBTdGFydGluZyBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgdiR7cGFja2FnZVZlcnNpb259Li4uYCk7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gUHJpbnQgdGhlIGxvZ29cbiAgY29uc29sZS5sb2coXG4gICAgcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvbXNnL3N0YXJ0dXAubXNnJykudG9TdHJpbmcoKS5ib2xkLnllbGxvdyxcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXG4gICk7XG59O1xuXG4vKipcbiAqIFByaW50cyB0aGUgdXNhZ2UgaW5mb3JtYXRpb24gZm9yIENMSSBhcmd1bWVudHMuIElmIHJlcXVpcmVkLCBpdCBjYW4gbGlzdFxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxuICovXG5leHBvcnQgZnVuY3Rpb24gcHJpbnRVc2FnZSgpIHtcbiAgY29uc3QgcGFkID0gNDg7XG4gIGNvbnN0IHJlYWRtZSA9ICdodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9ub2RlLWV4cG9ydC1zZXJ2ZXIjcmVhZG1lJztcblxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxuICBjb25zb2xlLmxvZyhcbiAgICAnXFxuVXNhZ2Ugb2YgQ0xJIGFyZ3VtZW50czonLmJvbGQsXG4gICAgJ1xcbi0tLS0tLScsXG4gICAgYFxcbkZvciBtb3JlIGRldGFpbGVkIGluZm9ybWF0aW9uLCB2aXNpdCB0aGUgcmVhZG1lIGF0OiAke3JlYWRtZS5ib2xkLnllbGxvd30uYFxuICApO1xuXG4gIGNvbnN0IGN5Y2xlQ2F0ZWdvcmllcyA9IChvcHRpb25zKSA9PiB7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgb3B0aW9uXSBvZiBPYmplY3QuZW50cmllcyhvcHRpb25zKSkge1xuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXG4gICAgICBpZiAoIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvcHRpb24sICd2YWx1ZScpKSB7XG4gICAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhvcHRpb24pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV0IGRlc2NOYW1lID0gYCAgLS0ke29wdGlvbi5jbGlOYW1lIHx8IG5hbWV9ICR7XG4gICAgICAgICAgKCc8JyArIG9wdGlvbi50eXBlICsgJz4nKS5ncmVlblxuICAgICAgICB9IGA7XG4gICAgICAgIGlmIChkZXNjTmFtZS5sZW5ndGggPCBwYWQpIHtcbiAgICAgICAgICBmb3IgKGxldCBpID0gZGVzY05hbWUubGVuZ3RoOyBpIDwgcGFkOyBpKyspIHtcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcbiAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBEaXNwbGF5IGNvcnJlY3RseSBhbGlnbmVkIG1lc3NhZ2VzXG4gICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgIGRlc2NOYW1lLFxuICAgICAgICAgIG9wdGlvbi5kZXNjcmlwdGlvbixcbiAgICAgICAgICBgW0RlZmF1bHQ6ICR7b3B0aW9uLnZhbHVlLnRvU3RyaW5nKCkuYm9sZH1dYC5ibHVlXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIEN5Y2xlIHRocm91Z2ggb3B0aW9ucyBvZiBlYWNoIGNhdGVnb3JpZXMgYW5kIGRpc3BsYXkgdGhlIHVzYWdlIGluZm9cbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcbiAgICAvLyBPbmx5IHB1cHBldGVlciBhbmQgaGlnaGNoYXJ0cyBjYXRlZ29yaWVzIGNhbm5vdCBiZSBjb25maWd1cmVkIHRocm91Z2ggQ0xJXG4gICAgaWYgKCFbJ3B1cHBldGVlcicsICdoaWdoY2hhcnRzJ10uaW5jbHVkZXMoY2F0ZWdvcnkpKSB7XG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcbiAgICAgIGN5Y2xlQ2F0ZWdvcmllcyhkZWZhdWx0Q29uZmlnW2NhdGVnb3J5XSk7XG4gICAgfVxuICB9KTtcbiAgY29uc29sZS5sb2coJ1xcbicpO1xufVxuXG4vKipcbiAqIFJvdW5kcyBhIG51bWJlciB0byB0aGUgc3BlY2lmaWVkIHByZWNpc2lvbi5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gdmFsdWUgLSBUaGUgbnVtYmVyIHRvIGJlIHJvdW5kZWQuXG4gKiBAcGFyYW0ge251bWJlcn0gcHJlY2lzaW9uIC0gVGhlIG51bWJlciBvZiBkZWNpbWFsIHBsYWNlcyB0byByb3VuZCB0by5cbiAqXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIFRoZSByb3VuZGVkIG51bWJlci5cbiAqL1xuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XG4gIGNvbnN0IG11bHRpcGxpZXIgPSBNYXRoLnBvdygxMCwgcHJlY2lzaW9uIHx8IDApO1xuICByZXR1cm4gTWF0aC5yb3VuZCgrdmFsdWUgKiBtdWx0aXBsaWVyKSAvIG11bHRpcGxpZXI7XG59O1xuXG4vKipcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxuICpcbiAqIEBwYXJhbSB7YW55fSBpdGVtIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCB0byBhIGJvb2xlYW4uXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVGhlIGJvb2xlYW4gcmVwcmVzZW50YXRpb24gb2YgdGhlIGlucHV0IHZhbHVlLlxuICovXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XG4gIFsnZmFsc2UnLCAndW5kZWZpbmVkJywgJ251bGwnLCAnTmFOJywgJzAnLCAnJ10uaW5jbHVkZXMoaXRlbSlcbiAgICA/IGZhbHNlXG4gICAgOiAhIWl0ZW07XG5cbi8qKlxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbUNvZGUgLSBUaGUgY3VzdG9tIGNvZGUgdG8gYmUgd3JhcHBlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXG4gKlxuICogQHJldHVybnMge3N0cmluZ3xib29sZWFufSAtIFRoZSB3cmFwcGVkIGN1c3RvbSBjb2RlIG9yIGZhbHNlIGlmIHdyYXBwaW5nXG4gKiBmYWlscy5cbiAqL1xuZXhwb3J0IGNvbnN0IHdyYXBBcm91bmQgPSAoY3VzdG9tQ29kZSwgYWxsb3dGaWxlUmVzb3VyY2VzKSA9PiB7XG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xuICAgIGN1c3RvbUNvZGUgPSBjdXN0b21Db2RlLnRyaW0oKTtcblxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xuICAgICAgcmV0dXJuIGFsbG93RmlsZVJlc291cmNlc1xuICAgICAgICA/IHdyYXBBcm91bmQocmVhZEZpbGVTeW5jKGN1c3RvbUNvZGUsICd1dGY4JykpXG4gICAgICAgIDogZmFsc2U7XG4gICAgfSBlbHNlIGlmIChcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oKScpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCk9PicpIHx8XG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJygpID0+JylcbiAgICApIHtcbiAgICAgIHJldHVybiBgKCR7Y3VzdG9tQ29kZX0pKClgO1xuICAgIH1cbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcbiAgfVxufTtcblxuLyoqXG4gKiBVdGlsaXR5IHRvIG1lYXN1cmUgZWxhcHNlZCB0aW1lIHVzaW5nIHRoZSBOb2RlLmpzIHByb2Nlc3MuaHJ0aW1lKCkgbWV0aG9kLlxuICpcbiAqIEByZXR1cm5zIHtmdW5jdGlvbigpOiBudW1iZXJ9IC0gQSBmdW5jdGlvbiB0byBjYWxjdWxhdGUgdGhlIGVsYXBzZWQgdGltZVxuICogaW4gbWlsbGlzZWNvbmRzLlxuICovXG5leHBvcnQgY29uc3QgbWVhc3VyZVRpbWUgPSAoKSA9PiB7XG4gIGNvbnN0IHN0YXJ0ID0gcHJvY2Vzcy5ocnRpbWUuYmlnaW50KCk7XG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBfX2Rpcm5hbWUsXG4gIGNsZWFyVGV4dCxcbiAgZXhwQmFja29mZixcbiAgZml4VHlwZSxcbiAgaGFuZGxlUmVzb3VyY2VzLFxuICBpc0NvcnJlY3RKU09OLFxuICBpc09iamVjdCxcbiAgaXNPYmplY3RFbXB0eSxcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgcHJpbnRMb2dvLFxuICBwcmludFVzYWdlLFxuICByb3VuZE51bWJlcixcbiAgdG9Cb29sZWFuLFxuICB3cmFwQXJvdW5kLFxuICBtZWFzdXJlVGltZVxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBleGlzdHNTeW5jLCByZWFkRmlsZVN5bmMsIHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XG5cbmltcG9ydCBwcm9tcHRzIGZyb20gJ3Byb21wdHMnO1xuXG5pbXBvcnQge1xuICBhYnNvbHV0ZVByb3BzLFxuICBkZWZhdWx0Q29uZmlnLFxuICBuZXN0ZWRBcmdzLFxuICBwcm9tcHRzQ29uZmlnXG59IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGRlZXBDb3B5LCBpc09iamVjdCwgcHJpbnRVc2FnZSwgdG9Cb29sZWFuIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmxldCBnZW5lcmFsT3B0aW9ucyA9IHt9O1xuXG4vKipcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHByb2Nlc3MuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRPcHRpb25zID0gKCkgPT4gZ2VuZXJhbE9wdGlvbnM7XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgYW5kIHNldHMgdGhlIGdlbmVyYWwgb3B0aW9ucyBmb3IgdGhlIHNlcnZlciBpbnN0YWNlLCBrZWVwaW5nXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcbiAqIGFuZCBhcmdzIGZyb20gdGhlIENMSS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXG4gKiBAcGFyYW0ge0FycmF5fSBhcmdzIC0gQ29tbWFuZC1saW5lIGFyZ3VtZW50cyBmb3IgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uXG4gKiAoQ0xJIHVzYWdlKS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgdXBkYXRlZCBnZW5lcmFsIG9wdGlvbnMgb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXG4gIGlmIChhcmdzPy5sZW5ndGgpIHtcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBsb2FkQ29uZmlnRmlsZShhcmdzKTtcbiAgfVxuXG4gIC8vIFVwZGF0ZSB0aGUgZGVmYXVsdCBjb25maWcgd2l0aCBhIGNvcnJlY3Qgb3B0aW9uIHZhbHVlc1xuICB1cGRhdGVEZWZhdWx0Q29uZmlnKGRlZmF1bHRDb25maWcsIGdlbmVyYWxPcHRpb25zKTtcblxuICAvLyBTZXQgdmFsdWVzIGZvciBzZXJ2ZXIncyBvcHRpb25zIGFuZCByZXR1cm5zIHRoZW1cbiAgZ2VuZXJhbE9wdGlvbnMgPSBpbml0T3B0aW9ucyhkZWZhdWx0Q29uZmlnKTtcblxuICAvLyBBcHBseSB1c2VyIG9wdGlvbnMgaWYgdGhlcmUgYXJlIGFueVxuICBpZiAodXNlck9wdGlvbnMpIHtcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcbiAgICBnZW5lcmFsT3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxuICAgICAgdXNlck9wdGlvbnMsXG4gICAgICBhYnNvbHV0ZVByb3BzXG4gICAgKTtcbiAgfVxuXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xuICAgIC8vIFBhaXIgcHJvdmlkZWQgYXJndW1lbnRzXG4gICAgZ2VuZXJhbE9wdGlvbnMgPSBwYWlyQXJndW1lbnRWYWx1ZShnZW5lcmFsT3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZyk7XG4gIH1cblxuICAvLyBSZXR1cm4gZmluYWwgZ2VuZXJhbCBvcHRpb25zXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcbn07XG5cbi8qKlxuICogQWxsb3dzIG1hbnVhbCBjb25maWd1cmF0aW9uIGJhc2VkIG9uIHNwZWNpZmllZCBwcm9tcHRzIGFuZCBzYXZlc1xuICogdGhlIGNvbmZpZ3VyYXRpb24gdG8gYSBmaWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb25maWdGaWxlTmFtZSAtIFRoZSBuYW1lIG9mIHRoZSBjb25maWd1cmF0aW9uIGZpbGUuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXG4gKiBjb25maWd1cmF0aW9uIGlzIGNvbXBsZXRlZCBhbmQgc2F2ZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcbiAgLy8gUHJlcGFyZSBhIGNvbmZpZyBvYmplY3RcbiAgbGV0IGNvbmZpZ0ZpbGUgPSB7fTtcblxuICAvLyBDaGVjayBpZiBwcm92aWRlZCBjb25maWcgZmlsZSBleGlzdHNcbiAgaWYgKGV4aXN0c1N5bmMoY29uZmlnRmlsZU5hbWUpKSB7XG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcbiAgfVxuXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxuICBjb25zdCBvblN1Ym1pdCA9IGFzeW5jIChwLCBjYXRlZ29yaWVzKSA9PiB7XG4gICAgbGV0IHF1ZXN0aW9uc0NvdW50ZXIgPSAwO1xuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcblxuICAgIC8vIENyZWF0ZSBhIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gdGhlIG1hbnVhbENvbmZpZyBvYmplY3RcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xuICAgICAgLy8gTWFyayBlYWNoIG9wdGlvbiB3aXRoIGEgc2VjdGlvblxuICAgICAgcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXSA9IHByb21wdHNDb25maWdbc2VjdGlvbl0ubWFwKChvcHRpb24pID0+ICh7XG4gICAgICAgIC4uLm9wdGlvbixcbiAgICAgICAgc2VjdGlvblxuICAgICAgfSkpO1xuXG4gICAgICAvLyBDb2xsZWN0IHRoZSBxdWVzdGlvbnNcbiAgICAgIGFsbFF1ZXN0aW9ucyA9IFsuLi5hbGxRdWVzdGlvbnMsIC4uLnByb21wdHNDb25maWdbc2VjdGlvbl1dO1xuICAgIH1cblxuICAgIGF3YWl0IHByb21wdHMoYWxsUXVlc3Rpb25zLCB7XG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XG4gICAgICAgIC8vIEdldCB0aGUgZGVmYXVsdCBtb2R1bGUgc2NyaXB0c1xuICAgICAgICBpZiAocHJvbXB0Lm5hbWUgPT09ICdtb2R1bGVTY3JpcHRzJykge1xuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcbiAgICAgICAgICAgID8gYW5zd2VyLm1hcCgobW9kdWxlKSA9PiBwcm9tcHQuY2hvaWNlc1ttb2R1bGVdKVxuICAgICAgICAgICAgOiBwcm9tcHQuY2hvaWNlcztcblxuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dW3Byb21wdC5uYW1lXSA9IGFuc3dlcjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbih7fSwgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl0gfHwge30pLFxuICAgICAgICAgICAgcHJvbXB0Lm5hbWUuc3BsaXQoJy4nKSxcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxuICAgICAgICAgICk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoKytxdWVzdGlvbnNDb3VudGVyID09PSBhbGxRdWVzdGlvbnMubGVuZ3RoKSB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxuICAgICAgICAgICAgICBjb25maWdGaWxlTmFtZSxcbiAgICAgICAgICAgICAgSlNPTi5zdHJpbmdpZnkoY29uZmlnRmlsZSwgbnVsbCwgMiksXG4gICAgICAgICAgICAgICd1dGY4J1xuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG5cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfTtcblxuICAvLyBGaW5kIHRoZSBjYXRlZ29yaWVzXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcbiAgICB0aXRsZTogYCR7Y2hvaWNlfSBvcHRpb25zYCxcbiAgICB2YWx1ZTogY2hvaWNlXG4gIH0pKTtcblxuICAvLyBDYXRlZ29yeSBwcm9tcHRcbiAgcmV0dXJuIHByb21wdHMoXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXG4gICAgICBtZXNzYWdlOiAnV2hpY2ggY2F0ZWdvcnkgZG8geW91IHdhbnQgdG8gY29uZmlndXJlPycsXG4gICAgICBoaW50OiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcbiAgICAgIGluc3RydWN0aW9uczogJycsXG4gICAgICBjaG9pY2VzXG4gICAgfSxcbiAgICB7IG9uU3VibWl0IH1cbiAgKTtcbn07XG5cbi8qKlxuICogTWFwcyBvbGQtc3RydWN0dXJlZCAoUGhhbnRvbUpTKSBvcHRpb25zIHRvIGEgbmV3IGNvbmZpZ3VyYXRpb24gZm9ybWF0XG4gKiAoUHVwcGV0ZWVyKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2xkT3B0aW9ucyAtIE9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnMgdG8gYmUgbWFwcGVkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IE5ldyBvcHRpb25zIHN0cnVjdHVyZWQgYmFzZWQgb24gdGhlIGRlZmluZWQgbmVzdGVkQXJnc1xuICogbWFwcGluZy5cbiAqL1xuZXhwb3J0IGNvbnN0IG1hcFRvTmV3Q29uZmlnID0gKG9sZE9wdGlvbnMpID0+IHtcbiAgY29uc3QgbmV3T3B0aW9ucyA9IHt9O1xuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMob2xkT3B0aW9ucykpIHtcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW2tleV0gPyBuZXN0ZWRBcmdzW2tleV0uc3BsaXQoJy4nKSA6IFtdO1xuXG4gICAgLy8gUG9wdWxhdGUgb2JqZWN0IGluIGNvcnJlY3QgcHJvcGVydGllcyBsZXZlbHNcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKFxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XG4gICAgICAgIChvYmpbcHJvcF0gPVxuICAgICAgICAgIHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCA/IHZhbHVlIDogb2JqW3Byb3BdIHx8IHt9KSxcbiAgICAgIG5ld09wdGlvbnNcbiAgICApO1xuICB9XG4gIHJldHVybiBuZXdPcHRpb25zO1xufTtcblxuLyoqXG4gKiBNZXJnZXMgdHdvIHNldHMgb2YgY29uZmlndXJhdGlvbiBvcHRpb25zLCBjb25zaWRlcmluZyBhYnNvbHV0ZSBwcm9wZXJ0aWVzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICogQHBhcmFtIHtPYmplY3R9IG5ld09wdGlvbnMgLSBOZXcgY29uZmlndXJhdGlvbiBvcHRpb25zIHRvIGJlIG1lcmdlZC5cbiAqIEBwYXJhbSB7QXJyYXl9IGFic29sdXRlUHJvcHMgLSBMaXN0IG9mIHByb3BlcnRpZXMgdGhhdCBzaG91bGRcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gTWVyZ2VkIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGNvbnN0IG1lcmdlQ29uZmlnT3B0aW9ucyA9IChvcHRpb25zLCBuZXdPcHRpb25zLCBhYnNvbHV0ZVByb3BzID0gW10pID0+IHtcbiAgY29uc3QgbWVyZ2VkT3B0aW9ucyA9IGRlZXBDb3B5KG9wdGlvbnMpO1xuXG4gIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKG5ld09wdGlvbnMpKSB7XG4gICAgbWVyZ2VkT3B0aW9uc1trZXldID1cbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxuICAgICAgIWFic29sdXRlUHJvcHMuaW5jbHVkZXMoa2V5KSAmJlxuICAgICAgbWVyZ2VkT3B0aW9uc1trZXldICE9PSB1bmRlZmluZWRcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcbiAgICAgICAgOiB2YWx1ZSAhPT0gdW5kZWZpbmVkXG4gICAgICAgICAgPyB2YWx1ZVxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xuICB9XG5cbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XG59O1xuXG4vKipcbiAqIEluaXRpYWxpemVzIGV4cG9ydCBzZXR0aW5ncyBiYXNlZCBvbiBwcm92aWRlZCBleHBvcnRPcHRpb25zXG4gKiBhbmQgZ2VuZXJhbE9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGV4cG9ydE9wdGlvbnMgLSBPcHRpb25zIHNwZWNpZmljIHRvIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBnZW5lcmFsT3B0aW9ucyAtIEdlbmVyYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIGV4cG9ydCBzZXR0aW5ncy5cbiAqL1xuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XG4gIGxldCBvcHRpb25zID0ge307XG5cbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XG4gICAgb3B0aW9ucyA9IGRlZXBDb3B5KGdlbmVyYWxPcHRpb25zKTtcbiAgICBvcHRpb25zLmV4cG9ydC50eXBlID0gZXhwb3J0T3B0aW9ucy50eXBlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnR5cGU7XG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xuICAgIG9wdGlvbnMuZXhwb3J0Lm91dGZpbGUgPVxuICAgICAgZXhwb3J0T3B0aW9ucy5vdXRmaWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0Lm91dGZpbGU7XG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xuICAgICAgc3ZnOiBleHBvcnRPcHRpb25zLnN2Z1xuICAgIH07XG4gIH0gZWxzZSB7XG4gICAgb3B0aW9ucyA9IG1lcmdlQ29uZmlnT3B0aW9ucyhcbiAgICAgIGdlbmVyYWxPcHRpb25zLFxuICAgICAgZXhwb3J0T3B0aW9ucyxcbiAgICAgIC8vIE9taXQgZ29pbmcgZG93biByZWN1cnNpdmVseSB3aXRoIHRoZSBiZWxvd3NcbiAgICAgIGFic29sdXRlUHJvcHNcbiAgICApO1xuICB9XG5cbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XG4gICAgb3B0aW9ucy5leHBvcnQ/Lm91dGZpbGUgfHwgYGNoYXJ0LiR7b3B0aW9ucy5leHBvcnQ/LnR5cGUgfHwgJ3BuZyd9YDtcbiAgcmV0dXJuIG9wdGlvbnM7XG59O1xuXG4vKipcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcbiAqIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uLlxuICpcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXG4gKlxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcbiAqIG9yIGFuIGVtcHR5IG9iamVjdCBpZiBub3QgZm91bmQgb3IgaW52YWxpZC5cbiAqL1xuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbiB3YXMgdXNlZFxuICBjb25zdCBjb25maWdJbmRleCA9IGFyZ3MuZmluZEluZGV4KFxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXG4gICk7XG5cbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxuICBpZiAoY29uZmlnSW5kZXggPiAtMSAmJiBhcmdzW2NvbmZpZ0luZGV4ICsgMV0pIHtcbiAgICBjb25zdCBmaWxlTmFtZSA9IGFyZ3NbY29uZmlnSW5kZXggKyAxXTtcbiAgICB0cnkge1xuICAgICAgLy8gQ2hlY2sgaWYgYW4gYWRkaXRpb25hbCBjb25maWcgZmlsZSBpcyBhIGNvcnJlY3QgSlNPTiBmaWxlXG4gICAgICBpZiAoZmlsZU5hbWUgJiYgZmlsZU5hbWUuZW5kc1dpdGgoJy5qc29uJykpIHtcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxuICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoZmlsZU5hbWUpKTtcbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAyLFxuICAgICAgICBlcnJvcixcbiAgICAgICAgYFtjb25maWddIFVuYWJsZSB0byBsb2FkIHRoZSBjb25maWd1cmF0aW9uIGZyb20gdGhlICR7ZmlsZU5hbWV9IGZpbGUuYFxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXG4gIHJldHVybiB7fTtcbn1cblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggdmFsdWVzIGZyb20gYSBjdXN0b20gb2JqZWN0XG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWdPYmogLSBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gUHJvcGVydHkgY2hhaW4gZm9yIHRyYWNraW5nIG5lc3RlZCBwcm9wZXJ0aWVzXG4gKiBkdXJpbmcgcmVjdXJzaW9uLlxuICovXG5mdW5jdGlvbiB1cGRhdGVEZWZhdWx0Q29uZmlnKGNvbmZpZ09iaiwgY3VzdG9tT2JqID0ge30sIHByb3BDaGFpbiA9ICcnKSB7XG4gIE9iamVjdC5rZXlzKGNvbmZpZ09iaikuZm9yRWFjaCgoa2V5KSA9PiB7XG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcbiAgICBjb25zdCBjdXN0b21WYWx1ZSA9IGN1c3RvbU9iaiAmJiBjdXN0b21PYmpba2V5XTtcblxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICB1cGRhdGVEZWZhdWx0Q29uZmlnKGVudHJ5LCBjdXN0b21WYWx1ZSwgYCR7cHJvcENoYWlufS4ke2tleX1gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcbiAgICAgIGlmIChjdXN0b21WYWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGVudHJ5LnZhbHVlID0gY3VzdG9tVmFsdWU7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGEgdmFsdWUgZnJvbSBhbiBlbnYgdmFyaWFibGUgZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIGVudHJ5LnZhbHVlID0gZW52c1tlbnRyeS5lbnZMaW5rXTtcbiAgICAgIH1cbiAgICB9XG4gIH0pO1xufVxuXG4vKipcbiAqIEluaXRpYWxpemVzIG9wdGlvbnMgb2JqZWN0IGJhc2VkIG9uIHByb3ZpZGVkIGl0ZW1zLCBzZXR0aW5nIHZhbHVlcyBmcm9tXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbXMgLSBDb25maWd1cmF0aW9uIGl0ZW1zIHRvIGJlIHVzZWQgZm9yIGluaXRpYWxpemluZ1xuICogb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBJbml0aWFsaXplZCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gaW5pdE9wdGlvbnMoaXRlbXMpIHtcbiAgbGV0IG9wdGlvbnMgPSB7fTtcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XG4gICAgb3B0aW9uc1tuYW1lXSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChpdGVtLCAndmFsdWUnKVxuICAgICAgPyBpdGVtLnZhbHVlXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xuICB9XG4gIHJldHVybiBvcHRpb25zO1xufVxuXG4vKipcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcbiAqIHVwZGF0aW5nIHRoZSBvcHRpb25zIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGNvbnRhaW5pbmcgdmFsdWVzIGZvciBzcGVjaWZpY1xuICogb3B0aW9ucy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFVwZGF0ZWQgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmZ1bmN0aW9uIHBhaXJBcmd1bWVudFZhbHVlKG9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpIHtcbiAgbGV0IHNob3dVc2FnZSA9IGZhbHNlO1xuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcbiAgICBjb25zdCBvcHRpb24gPSBhcmdzW2ldLnJlcGxhY2UoLy0vZywgJycpO1xuXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcbiAgICBjb25zdCBwcm9wZXJ0aWVzQ2hhaW4gPSBuZXN0ZWRBcmdzW29wdGlvbl1cbiAgICAgID8gbmVzdGVkQXJnc1tvcHRpb25dLnNwbGl0KCcuJylcbiAgICAgIDogW107XG5cbiAgICAvLyBHZXQgdGhlIGNvcnJlY3QgdHlwZSBmb3IgQ0xJIGFyZ3Mgd2hpY2ggYXJlIHBhc3NlZCBhcyBzdHJpbmdzXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XG4gICAgICBpZiAocHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4KSB7XG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcblxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcbiAgICAgICAgLy8gRmluZHMgYW4gb3B0aW9uIGFuZCBzZXQgYSBjb3JyZXNwb25kaW5nIHZhbHVlXG4gICAgICAgIGlmICh0eXBlb2Ygb2JqW3Byb3BdICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcbiAgICAgICAgICAgIGlmIChhcmd1bWVudFR5cGUgPT09ICdib29sZWFuJykge1xuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSB0b0Jvb2xlYW4oYXJnc1tpXSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gK2FyZ3NbaV07XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZS5pbmRleE9mKCddJykgPj0gMCkge1xuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBsb2coXG4gICAgICAgICAgICAgIDIsXG4gICAgICAgICAgICAgIGBbY29uZmlnXSBNaXNzaW5nIHZhbHVlIGZvciB0aGUgJyR7b3B0aW9ufScgYXJndW1lbnQuIFVzaW5nIHRoZSBkZWZhdWx0IHZhbHVlLmBcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIG9ialtwcm9wXTtcbiAgICB9LCBvcHRpb25zKTtcbiAgfVxuXG4gIC8vIERpc3BsYXkgdGhlIHVzYWdlIGZvciB0aGUgcmVmZXJlbmNlIGlmIG5lZWRlZFxuICBpZiAoc2hvd1VzYWdlKSB7XG4gICAgcHJpbnRVc2FnZShkZWZhdWx0Q29uZmlnKTtcbiAgfVxuXG4gIHJldHVybiBvcHRpb25zO1xufVxuXG4vKipcbiAqIFJlY3Vyc2l2ZWx5IHVwZGF0ZXMgcHJvcGVydGllcyBpbiBhbiBvYmplY3QgYmFzZWQgb24gbmVzdGVkIG5hbWVzIGFuZCBhc3NpZ25zXG4gKiB0aGUgZmluYWwgdmFsdWUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9iamVjdFRvVXBkYXRlIC0gVGhlIG9iamVjdCB0byBiZSB1cGRhdGVkLlxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXG4gKiBAcGFyYW0ge2FueX0gdmFsdWUgLSBUaGUgZmluYWwgdmFsdWUgdG8gYmUgYXNzaWduZWQuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXG4gKi9cbmZ1bmN0aW9uIHJlY3Vyc2l2ZVByb3BzKG9iamVjdFRvVXBkYXRlLCBuZXN0ZWROYW1lcywgdmFsdWUpIHtcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcbiAgICBjb25zdCBwcm9wTmFtZSA9IG5lc3RlZE5hbWVzLnNoaWZ0KCk7XG5cbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxuICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iamVjdFRvVXBkYXRlLCBwcm9wTmFtZSkpIHtcbiAgICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHt9O1xuICAgIH1cblxuICAgIC8vIENhbGwgZnVuY3Rpb24gYWdhaW4gaWYgdGhlcmUgc3RpbGwgbmFtZXMgdG8gZ29cbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcbiAgICAgIE9iamVjdC5hc3NpZ24oe30sIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSksXG4gICAgICBuZXN0ZWROYW1lcyxcbiAgICAgIHZhbHVlXG4gICAgKTtcblxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcbiAgfVxuXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcbiAgb2JqZWN0VG9VcGRhdGVbbmVzdGVkTmFtZXNbMF1dID0gdmFsdWU7XG4gIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBnZXRPcHRpb25zLFxuICBzZXRPcHRpb25zLFxuICBtYW51YWxDb25maWcsXG4gIG1hcFRvTmV3Q29uZmlnLFxuICBtZXJnZUNvbmZpZ09wdGlvbnMsXG4gIGluaXRFeHBvcnRTZXR0aW5nc1xufTtcbiIsIi8qKlxuICogVGhpcyBtb2R1bGUgZXhwb3J0cyB0d28gZnVuY3Rpb25zOiBmZXRjaCAoZm9yIEdFVCByZXF1ZXN0cykgYW5kIHBvc3QgKGZvciBQT1NUIHJlcXVlc3RzKS5cbiAqL1xuXG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XG5cbi8qKlxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBkZXRlcm1pbmUgdGhlIHByb3RvY29sLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSAoaHR0cCBvciBodHRwcykuXG4gKi9cbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcblxuLyoqXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBmZXRjaCBkYXRhIGZyb20uXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0XG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gZmV0Y2godXJsLCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xuXG4gICAgcHJvdG9jb2xcbiAgICAgIC5nZXQodXJsLCByZXF1ZXN0T3B0aW9ucywgKHJlcykgPT4ge1xuICAgICAgICBsZXQgZGF0YSA9ICcnO1xuXG4gICAgICAgIC8vIEEgY2h1bmsgb2YgZGF0YSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICBpZiAoIWRhdGEpIHtcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xuICAgICAgICAgIHJlc29sdmUocmVzKTtcbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIFNlbmRzIGEgUE9TVCByZXF1ZXN0IHRvIHRoZSBzcGVjaWZpZWQgVVJMIHdpdGggdGhlIHByb3ZpZGVkIEpTT04gYm9keSB1c2luZ1xuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gc2VuZCB0aGUgUE9TVCByZXF1ZXN0IHRvLlxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxuICogKG9wdGlvbmFsLCBkZWZhdWx0IGlzIGFuIGVtcHR5IG9iamVjdCkuXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIEhUVFAgcmVzcG9uc2Ugb2JqZWN0IHdpdGhcbiAqIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcG9zdCh1cmwsIGJvZHkgPSB7fSwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcbiAgICBjb25zdCBkYXRhID0gSlNPTi5zdHJpbmdpZnkoYm9keSk7XG5cbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXG4gICAgY29uc3Qgb3B0aW9ucyA9IE9iamVjdC5hc3NpZ24oXG4gICAgICB7XG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxuICAgICAgICBoZWFkZXJzOiB7XG4gICAgICAgICAgJ0NvbnRlbnQtVHlwZSc6ICdhcHBsaWNhdGlvbi9qc29uJyxcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgcmVxdWVzdE9wdGlvbnNcbiAgICApO1xuXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcbiAgICAgIC5yZXF1ZXN0KHVybCwgb3B0aW9ucywgKHJlcykgPT4ge1xuICAgICAgICBsZXQgcmVzcG9uc2VEYXRhID0gJyc7XG5cbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cbiAgICAgICAgcmVzLm9uKCdlbmQnLCAoKSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xuICAgICAgICAgICAgcmVzb2x2ZShyZXMpO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICB9KVxuICAgICAgLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgICByZWplY3QoZXJyb3IpO1xuICAgICAgfSk7XG5cbiAgICAvLyBXcml0ZSB0aGUgcmVxdWVzdCBib2R5IGFuZCBlbmQgdGhlIHJlcXVlc3QuXG4gICAgcmVxLndyaXRlKGRhdGEpO1xuICAgIHJlcS5lbmQoKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IGZldGNoO1xuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcbiIsImNsYXNzIEV4cG9ydEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlKSB7XG4gICAgc3VwZXIoKTtcbiAgICB0aGlzLm1lc3NhZ2UgPSBtZXNzYWdlO1xuICAgIHRoaXMuc3RhY2tNZXNzYWdlID0gbWVzc2FnZTtcbiAgfVxuXG4gIHNldEVycm9yKGVycm9yKSB7XG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xuICAgIGlmIChlcnJvci5uYW1lKSB7XG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xuICAgIH1cbiAgICBpZiAoZXJyb3Iuc3RhdHVzQ29kZSkge1xuICAgICAgdGhpcy5zdGF0dXNDb2RlID0gZXJyb3Iuc3RhdHVzQ29kZTtcbiAgICB9XG4gICAgaWYgKGVycm9yLnN0YWNrKSB7XG4gICAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IGVycm9yLm1lc3NhZ2U7XG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cbi8vIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmljZVxuXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xuXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbmNvbnN0IGNhY2hlID0ge1xuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxuICBzb3VyY2VzOiAnJyxcbiAgaGNWZXJzaW9uOiAnJ1xufTtcblxuLyoqXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBleHRyYWN0VmVyc2lvbiA9IChjYWNoZSkgPT4ge1xuICByZXR1cm4gY2FjaGUuc291cmNlc1xuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXG4gICAgLnRyaW0oKTtcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXG4gKi9cbmV4cG9ydCBjb25zdCBleHRyYWN0TW9kdWxlTmFtZSA9IChzY3JpcHRQYXRoKSA9PiB7XG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXG4gICAgJydcbiAgKTtcbn07XG5cbi8qKlxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcbiAqIGZpbGUuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIG1hcHBlZCBuYW1lcyBvZlxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlIHdyaXRpbmdcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cbiAgfTtcblxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xuXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xuICB0cnkge1xuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBqb2luKF9fZGlybmFtZSwgY29uZmlnLmNhY2hlUGF0aCwgJ21hbmlmZXN0Lmpzb24nKSxcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcbiAgICAgICd1dGY4J1xuICAgICk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIEVycm9yIHdyaXRpbmcgdGhlIGNhY2hlIG1hbmlmZXN0LicpLnNldEVycm9yKFxuICAgICAgZXJyb3JcbiAgICApO1xuICB9XG59O1xuXG4vKipcbiAqIEZldGNoZXMgYSBzaW5nbGUgc2NyaXB0IGFuZCB1cGRhdGVzIHRoZSBmZXRjaGVkTW9kdWxlcyBhY2NvcmRpbmdseS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc2NyaXB0IC0gQSBwYXRoIHRvIHNjcmlwdCB0byBnZXQuXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBBZGRpdGlvbmFsIG9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudFxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXG4gKiBAcGFyYW0ge09iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxuICogdGhyb3duLiBUaGlzIHNob3VsZCBiZSB1c2VkIG9ubHkgZm9yIHRoZSBjb3JlIHNjcmlwdHMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxuICogb2YgdGhlIGZldGNoZWQgc2NyaXB0LlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcbiAqIGZldGNoaW5nIHRoZSBzY3JpcHQuXG4gKi9cbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXG4gIHNjcmlwdCxcbiAgcmVxdWVzdE9wdGlvbnMsXG4gIGZldGNoZWRNb2R1bGVzLFxuICBzaG91bGRUaHJvd0Vycm9yID0gZmFsc2VcbikgPT4ge1xuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcbiAgaWYgKHNjcmlwdC5lbmRzV2l0aCgnLmpzJykpIHtcbiAgICBzY3JpcHQgPSBzY3JpcHQuc3Vic3RyaW5nKDAsIHNjcmlwdC5sZW5ndGggLSAzKTtcbiAgfVxuXG4gIGxvZyg0LCBgW2NhY2hlXSBGZXRjaGluZyBzY3JpcHQgLSAke3NjcmlwdH0uanNgKTtcblxuICAvLyBGZXRjaCB0aGUgc2NyaXB0XG4gIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgZmV0Y2goYCR7c2NyaXB0fS5qc2AsIHJlcXVlc3RPcHRpb25zKTtcblxuICAvLyBJZiBPSywgcmV0dXJuIGl0cyB0ZXh0IHJlcHJlc2VudGF0aW9uXG4gIGlmIChyZXNwb25zZS5zdGF0dXNDb2RlID09PSAyMDAgJiYgdHlwZW9mIHJlc3BvbnNlLnRleHQgPT0gJ3N0cmluZycpIHtcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcbiAgICAgIGNvbnN0IG1vZHVsZU5hbWUgPSBleHRyYWN0TW9kdWxlTmFtZShzY3JpcHQpO1xuICAgICAgZmV0Y2hlZE1vZHVsZXNbbW9kdWxlTmFtZV0gPSAxO1xuICAgIH1cblxuICAgIHJldHVybiByZXNwb25zZS50ZXh0O1xuICB9XG5cbiAgaWYgKHNob3VsZFRocm93RXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICBgQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbiAoc3RhdHVzIGNvZGU6ICR7cmVzcG9uc2Uuc3RhdHVzQ29kZX0pLmBcbiAgICApLnNldEVycm9yKHJlc3BvbnNlKTtcbiAgfSBlbHNlIHtcbiAgICBsb2coXG4gICAgICAyLFxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXG4gICAgKTtcbiAgfVxuXG4gIHJldHVybiAnJztcbn07XG5cbi8qKlxuICogRmV0Y2hlcyBIaWdoY2hhcnRzIHNjcmlwdHMgYW5kIGN1c3RvbVNjcmlwdHMgZnJvbSB0aGUgZ2l2ZW4gQ0ROcy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY29yZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIGNvcmUgc2NyaXB0cyB0byBmZXRjaC5cbiAqIEBwYXJhbSB7c3RyaW5nfSBtb2R1bGVTY3JpcHRzIC0gQXJyYXkgb2YgSGlnaGNoYXJ0cyBtb2R1bGVzIHRvIGZldGNoLlxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXG4gKiAoZnVsbCBVUkxzKS5cbiAqIEBwYXJhbSB7b2JqZWN0fSBwcm94eU9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnQgdG8gdXNlIGZvclxuICogYSByZXF1ZXN0LlxuICogQHBhcmFtIHtvYmplY3R9IGZldGNoZWRNb2R1bGVzIC0gQW4gb2JqZWN0IHdoaWNoIHRyYWNrcyB3aGljaCBIaWdoY2hhcnRzXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFRoZSBmZXRjaGVkIHNjcmlwdHMgY29udGVudCBqb2luZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXG4gIGNvcmVTY3JpcHRzLFxuICBtb2R1bGVTY3JpcHRzLFxuICBjdXN0b21TY3JpcHRzLFxuICBwcm94eU9wdGlvbnMsXG4gIGZldGNoZWRNb2R1bGVzXG4pID0+IHtcbiAgLy8gQ29uZmlndXJlIHByb3h5IGlmIGV4aXN0c1xuICBsZXQgcHJveHlBZ2VudDtcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XG4gIGNvbnN0IHByb3h5UG9ydCA9IHByb3h5T3B0aW9ucy5wb3J0O1xuXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxuICBpZiAocHJveHlIb3N0ICYmIHByb3h5UG9ydCkge1xuICAgIHRyeSB7XG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XG4gICAgICAgIGhvc3Q6IHByb3h5SG9zdCxcbiAgICAgICAgcG9ydDogcHJveHlQb3J0XG4gICAgICB9KTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nKS5zZXRFcnJvcihcbiAgICAgICAgZXJyb3JcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgZXhpc3RzLCBhZGQgcHJveHkgYWdlbnQgdG8gcmVxdWVzdCBvcHRpb25zXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxuICAgID8ge1xuICAgICAgICBhZ2VudDogcHJveHlBZ2VudCxcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxuICAgICAgfVxuICAgIDoge307XG5cbiAgY29uc3QgYWxsRmV0Y2hQcm9taXNlcyA9IFtcbiAgICAuLi5jb3JlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxuICAgICksXG4gICAgLi4ubW9kdWxlU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxuICAgICksXG4gICAgLi4uY3VzdG9tU2NyaXB0cy5tYXAoKHNjcmlwdCkgPT5cbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXG4gICAgKVxuICBdO1xuXG4gIGNvbnN0IGZldGNoZWRTY3JpcHRzID0gYXdhaXQgUHJvbWlzZS5hbGwoYWxsRmV0Y2hQcm9taXNlcyk7XG4gIHJldHVybiBmZXRjaGVkU2NyaXB0cy5qb2luKCc7XFxuJyk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IHJlcHJlc2VudGluZ1xuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cbiAqL1xuZXhwb3J0IGNvbnN0IHVwZGF0ZUNhY2hlID0gYXN5bmMgKFxuICBoaWdoY2hhcnRzT3B0aW9ucyxcbiAgcHJveHlPcHRpb25zLFxuICBzb3VyY2VQYXRoXG4pID0+IHtcbiAgY29uc3QgdmVyc2lvbiA9IGhpZ2hjaGFydHNPcHRpb25zLnZlcnNpb247XG4gIGNvbnN0IGhjVmVyc2lvbiA9IHZlcnNpb24gPT09ICdsYXRlc3QnIHx8ICF2ZXJzaW9uID8gJycgOiBgJHt2ZXJzaW9ufS9gO1xuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xuXG4gIGxvZyhcbiAgICAzLFxuICAgIGBbY2FjaGVdIFVwZGF0aW5nIGNhY2hlIHZlcnNpb24gdG8gSGlnaGNoYXJ0czogJHtoY1ZlcnNpb24gfHwgJ2xhdGVzdCd9LmBcbiAgKTtcblxuICBjb25zdCBmZXRjaGVkTW9kdWxlcyA9IHt9O1xuICB0cnkge1xuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXG4gICAgICBbXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmNvcmVTY3JpcHRzLm1hcCgoYykgPT4gYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufSR7Y31gKVxuICAgICAgXSxcbiAgICAgIFtcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMubW9kdWxlU2NyaXB0cy5tYXAoKG0pID0+XG4gICAgICAgICAgbSA9PT0gJ21hcCdcbiAgICAgICAgICAgID8gYCR7Y2RuVVJMfW1hcHMvJHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxuICAgICAgICAgICAgOiBgJHtjZG5VUkx9JHtoY1ZlcnNpb259bW9kdWxlcy8ke219YFxuICAgICAgICApLFxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5pbmRpY2F0b3JTY3JpcHRzLm1hcChcbiAgICAgICAgICAoaSkgPT4gYCR7Y2RuVVJMfXN0b2NrLyR7aGNWZXJzaW9ufWluZGljYXRvcnMvJHtpfWBcbiAgICAgICAgKVxuICAgICAgXSxcbiAgICAgIGhpZ2hjaGFydHNPcHRpb25zLmN1c3RvbVNjcmlwdHMsXG4gICAgICBwcm94eU9wdGlvbnMsXG4gICAgICBmZXRjaGVkTW9kdWxlc1xuICAgICk7XG5cbiAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XG5cbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXG4gICAgd3JpdGVGaWxlU3luYyhzb3VyY2VQYXRoLCBjYWNoZS5zb3VyY2VzKTtcbiAgICByZXR1cm4gZmV0Y2hlZE1vZHVsZXM7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tjYWNoZV0gVW5hYmxlIHRvIHVwZGF0ZSB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIGluIHRoZSBhcHBsaWVkIGNvbmZpZ3VyYXRpb24gYW5kIGNoZWNrc1xuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IG5ld1ZlcnNpb24gLSBUaGUgbmV3IEhpZ2hjaGFydHMgdmVyc2lvbiB0byBiZSBhcHBsaWVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPChvYmplY3R8Ym9vbGVhbik+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB1cGRhdGVkXG4gKiBjb25maWd1cmF0aW9uIHdpdGggdGhlIG5ldyB2ZXJzaW9uLCBvciBmYWxzZSBpZiBubyBhcHBsaWVkIGNvbmZpZ3VyYXRpb25cbiAqIGV4aXN0cy5cbiAqL1xuZXhwb3J0IGNvbnN0IHVwZGF0ZVZlcnNpb24gPSBhc3luYyAobmV3VmVyc2lvbikgPT4ge1xuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xuICBpZiAob3B0aW9ucz8uaGlnaGNoYXJ0cykge1xuICAgIG9wdGlvbnMuaGlnaGNoYXJ0cy52ZXJzaW9uID0gbmV3VmVyc2lvbjtcbiAgfVxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xufTtcblxuLyoqXG4gKiBDaGVja3MgdGhlIGNhY2hlIGZvciBIaWdoY2hhcnRzIGRlcGVuZGVuY2llcywgdXBkYXRlcyB0aGUgY2FjaGUgaWYgbmVlZGVkLFxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT2JqZWN0IGNvbnRhaW5pbmcgYWxsIG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGNhY2hlIGlzIGNoZWNrZWRcbiAqIGFuZCB1cGRhdGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYW4gaXNzdWUgdXBkYXRpbmdcbiAqIG9yIHJlYWRpbmcgdGhlIGNhY2hlLlxuICovXG5leHBvcnQgY29uc3QgY2hlY2tBbmRVcGRhdGVDYWNoZSA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IHsgaGlnaGNoYXJ0cywgc2VydmVyIH0gPSBvcHRpb25zO1xuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xuXG4gIGxldCBmZXRjaGVkTW9kdWxlcztcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XG5cbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoKTtcblxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xuXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xuICAgIH1cblxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHM7XG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XG5cbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMixcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcbiAgICAgICk7XG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXG4gICAgICApO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xuICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgIDIsXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcblxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xuXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xuXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XG59O1xuXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cbiAgam9pbihfX2Rpcm5hbWUsIGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aCk7XG5cbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xuXG5leHBvcnQgY29uc3QgaGlnaGNoYXJ0cyA9ICgpID0+IGNhY2hlLnNvdXJjZXM7XG5cbmV4cG9ydCBjb25zdCB2ZXJzaW9uID0gKCkgPT4gY2FjaGUuaGNWZXJzaW9uO1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGNoZWNrQW5kVXBkYXRlQ2FjaGUsXG4gIGdldENhY2hlUGF0aCxcbiAgdXBkYXRlVmVyc2lvbixcbiAgZ2V0Q2FjaGUsXG4gIGhpZ2hjaGFydHMsXG4gIHZlcnNpb25cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLyogZXNsaW50LWRpc2FibGUgbm8tdW5kZWYgKi9cblxuLyoqXG4gKiBTZXR0aW5nIHRoZSBhbmltT2JqZWN0LiBDYWxsZWQgd2hlbiBpbml0aW5nIHRoZSBwYWdlLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xuICBIaWdoY2hhcnRzLmFuaW1PYmplY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHsgZHVyYXRpb246IDAgfTtcbiAgfTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBhY3R1YWwgY2hhcnQuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGhlIGV4cG9ydCBvcHRpb25zLlxuICogQHBhcmFtIHtib29sZWFufSBkaXNwbGF5RXJyb3JzIC0gQSBmbGFnIGluZGljYXRpbmcgd2hldGhlciB0byBkaXNwbGF5IGVycm9ycy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHRyaWdnZXJFeHBvcnQoY2hhcnRPcHRpb25zLCBvcHRpb25zLCBkaXNwbGF5RXJyb3JzKSB7XG4gIC8vIERpc3BsYXkgZXJyb3JzIGZsYWcgdGFrZW4gZnJvbSBjaGFydCBvcHRpb25zIG5hZCBkZWJ1Z2dlciBtb2R1bGVcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcblxuICAvLyBHZXQgcmVxdWlyZWQgZnVuY3Rpb25zXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XG5cbiAgLy8gQ3JlYXRlIGEgc2VwYXJhdGUgb2JqZWN0IGZvciBhIHBvdGVudGlhbCBzZXRPcHRpb25zIHVzYWdlcyBpbiBvcmRlciB0b1xuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcbiAgSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqID0gbWVyZ2UoZmFsc2UsIHt9LCBnZXRPcHRpb25zKCkpO1xuXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcbiAgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuY3VzdG9tQ29kZSkge1xuICAgIG5ldyBGdW5jdGlvbihvcHRpb25zLmN1c3RvbUxvZ2ljLmN1c3RvbUNvZGUpKCk7XG4gIH1cblxuICAvLyBCeSBkZWZhdWx0IGFuaW1hdGlvbiBpcyBkaXNhYmxlZFxuICBjb25zdCBjaGFydCA9IHtcbiAgICBhbmltYXRpb246IGZhbHNlXG4gIH07XG5cbiAgLy8gV2hlbiBzdHJhaWdodCBpbmplY3QsIHRoZSBzaXplIGlzIHNldCB0aHJvdWdoIENTUyBvbmx5XG4gIGlmIChvcHRpb25zLmV4cG9ydC5zdHJJbmopIHtcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xuICAgIGNoYXJ0LndpZHRoID0gY2hhcnRPcHRpb25zLmNoYXJ0LndpZHRoO1xuICB9XG5cbiAgLy8gTk9URTogSXMgdGhpcyB1c2VkIGZvciBhbnl0aGluZyB1c2VmdWw/XG4gIHdpbmRvdy5pc1JlbmRlckNvbXBsZXRlID0gZmFsc2U7XG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xuICAgIC8vIE92ZXJyaWRlIHVzZXJPcHRpb25zIHdpdGggaW1hZ2UgZnJpZW5kbHkgb3B0aW9uc1xuICAgIHVzZXJPcHRpb25zID0gbWVyZ2UodXNlck9wdGlvbnMsIHtcbiAgICAgIGV4cG9ydGluZzoge1xuICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgfSxcbiAgICAgIHBsb3RPcHRpb25zOiB7XG4gICAgICAgIHNlcmllczoge1xuICAgICAgICAgIGxhYmVsOiB7XG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIC8qIEV4cGVjdHMgdG9vbHRpcCBpbiB1c2VyT3B0aW9ucyB3aGVuIGZvckV4cG9ydCBpcyB0cnVlLlxuICAgICAgICBodHRwczovL2dpdGh1Yi5jb20vaGlnaGNoYXJ0cy9oaWdoY2hhcnRzL2Jsb2IvM2FkNDMwYTM1M2I4MDU2YjllNzY0YWE0ZTVjZDY4MjhhYTQ3OWRiMi9qcy9wYXJ0cy9DaGFydC5qcyNMMjQxXG4gICAgICAgICovXG4gICAgICB0b29sdGlwOiB7fVxuICAgIH0pO1xuXG4gICAgKHVzZXJPcHRpb25zLnNlcmllcyB8fCBbXSkuZm9yRWFjaChmdW5jdGlvbiAoc2VyaWVzKSB7XG4gICAgICBzZXJpZXMuYW5pbWF0aW9uID0gZmFsc2U7XG4gICAgfSk7XG5cbiAgICAvLyBBZGQgZmxhZyB0byBrbm93IGlmIGNoYXJ0IHJlbmRlciBoYXMgYmVlbiBjYWxsZWQuXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XG4gICAgICB3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyID0gSGlnaGNoYXJ0cy5hZGRFdmVudCh0aGlzLCAncmVuZGVyJywgKCkgPT4ge1xuICAgICAgICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IHRydWU7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcbiAgfSk7XG5cbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbY2hhcnQsIG9wdGlvbnNdKTtcbiAgfSk7XG5cbiAgLy8gR2V0IHRoZSB1c2VyIG9wdGlvbnNcbiAgY29uc3QgdXNlck9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydC5zdHJJbmpcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcbiAgICA6IGNoYXJ0T3B0aW9ucztcblxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcbiAgLy8gc2V0T3B0aW9ucyBmdW5jdGlvbiBhbmQgdXNlciBvcHRpb25zIHRvIGNyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3RcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXG4gICAgZmFsc2UsXG4gICAgSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnMpLFxuICAgIHVzZXJPcHRpb25zLFxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcbiAgICB7IGNoYXJ0IH1cbiAgKTtcblxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcbiAgICA6IHVuZGVmaW5lZDtcblxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XG4gIH1cblxuICBIaWdoY2hhcnRzW29wdGlvbnMuZXhwb3J0LmNvbnN0ciB8fCAnY2hhcnQnXShcbiAgICAnY29udGFpbmVyJyxcbiAgICBmaW5hbE9wdGlvbnMsXG4gICAgZmluYWxDYWxsYmFja1xuICApO1xuXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIHNldE9wdGlvbnMgd2FzIHVzZWQgaW4gdGhlIGN1c3RvbUNvZGUpXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcbiAgICB9XG4gIH1cblxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcblxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcbn1cbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xuXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcbmNvbnN0IHRlbXBsYXRlID0gcmVhZEZpbGVTeW5jKF9fZGlybmFtZSArICcvdGVtcGxhdGVzL3RlbXBsYXRlLmh0bWwnLCAndXRmOCcpO1xuXG5sZXQgYnJvd3NlcjtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW5cbiAqIGNyZWF0ZWQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBnZXQoKSB7XG4gIGlmICghYnJvd3Nlcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIE5vIHZhbGlkIGJyb3dzZXIgaGFzIGJlZW4gY3JlYXRlZC4nKTtcbiAgfVxuICByZXR1cm4gYnJvd3Nlcjtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgc3BlY2lmaWVkIGFyZ3VtZW50cy5cbiAqXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbWF4IHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjcmVhdGUocHVwcGV0ZWVyQXJncykge1xuICAvLyBHZXQgZGVidWcgYW5kIG90aGVyIG9wdGlvbnNcbiAgY29uc3QgeyBkZWJ1Zywgb3RoZXIgfSA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcbiAgY29uc3QgeyBlbmFibGU6IGVuYWJsZWREZWJ1ZywgLi4uZGVidWdPcHRpb25zIH0gPSBkZWJ1ZztcblxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xuICAgIGhlYWRsZXNzOiBvdGhlci5icm93c2VyU2hlbGxNb2RlID8gJ3NoZWxsJyA6IHRydWUsXG4gICAgdXNlckRhdGFEaXI6ICcuL3RtcC8nLFxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXG4gICAgaGFuZGxlU0lHSU5UOiBmYWxzZSxcbiAgICBoYW5kbGVTSUdURVJNOiBmYWxzZSxcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxuICAgIHdhaXRGb3JJbml0aWFsUGFnZTogZmFsc2UsXG4gICAgZGVmYXVsdFZpZXdwb3J0OiBudWxsLFxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxuICB9O1xuXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgbGV0IHRyeUNvdW50ID0gMDtcblxuICAgIGNvbnN0IG9wZW4gPSBhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcbiAgICAgICAgKTtcbiAgICAgICAgYnJvd3NlciA9IGF3YWl0IHB1cHBldGVlci5sYXVuY2gobGF1bmNoT3B0aW9ucyk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgMSxcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IG9wZW4oKTtcblxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcbiAgICAgIH1cblxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJ1xuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgfVxuXG4gICAgaWYgKCFicm93c2VyKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gYSBicm93c2VyIHByb21pc2VcbiAgcmV0dXJuIGJyb3dzZXI7XG59XG5cbi8qKlxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdHJ1ZSBhZnRlciB0aGUgYnJvd3NlclxuICogaXMgY2xvc2VkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xvc2UoKSB7XG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxuICBpZiAoYnJvd3Nlcj8uY29ubmVjdGVkKSB7XG4gICAgYXdhaXQgYnJvd3Nlci5jbG9zZSgpO1xuICB9XG4gIGxvZyg0LCAnW2Jyb3dzZXJdIENsb3NlZCB0aGUgYnJvd3Nlci4nKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgbmV3IFB1cHBldGVlciBQYWdlIHdpdGhpbiBhbiBleGlzdGluZyBicm93c2VyIGluc3RhbmNlLlxuICpcbiAqIElmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdCBhdmFpbGFibGUsIHJldHVybnMgZmFsc2UuXG4gKlxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXG4gKiBzZXRQYWdlQ29udGVudCgpLCBhbmQgcmV0dXJucyB0aGUgY3JlYXRlZCBQdXBwZXRlZXIgUGFnZS5cbiAqXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcbiAqIGF2YWlsYWJsZSwgb3IgYSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgcmVwcmVzZW50aW5nIHRoZSBuZXdseSBjcmVhdGVkIHBhZ2UuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xuICBpZiAoIWJyb3dzZXIpIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBDcmVhdGUgYSBwYWdlXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcblxuICAvLyBEaXNhYmxlIGNhY2hlXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcblxuICAvLyBTZXQgdGhlIGNvbnRlbnRcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XG5cbiAgLy8gU2V0IHBhZ2UgZXZlbnRzXG4gIHNldFBhZ2VFdmVudHMocGFnZSk7XG5cbiAgcmV0dXJuIHBhZ2U7XG59XG5cbi8qKlxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gVGhlIFB1cHBldGVlciBQYWdlIG9iamVjdCB0byBiZSBjbGVhcmVkLlxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xuICogdG8gYmUgcGVyZm9ybWVkLiBJZiB0cnVlLCBuYXZpZ2F0ZXMgdG8gJ2Fib3V0OmJsYW5rJyBhbmQgcmVzZXRzIGNvbnRlbnRcbiAqIGFuZCBzY3JpcHRzLiBJZiBmYWxzZSwgY2xlYXJzIHRoZSBib2R5IGNvbnRlbnQgYnkgc2V0dGluZyBhIHByZWRlZmluZWQgSFRNTFxuICogc3RydWN0dXJlLlxuICpcbiAqIEB0aHJvd3Mge0Vycm9yfSBMb2dzIHRocm93biBlcnJvciBpZiBjbGVhcmluZyB0aGUgcGFnZSBjb250ZW50IGZhaWxzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlKHBhZ2UsIGhhcmRSZXNldCA9IGZhbHNlKSB7XG4gIHRyeSB7XG4gICAgaWYgKCFwYWdlLmlzQ2xvc2VkKCkpIHtcbiAgICAgIGlmIChoYXJkUmVzZXQpIHtcbiAgICAgICAgLy8gTmF2aWdhdGUgdG8gYWJvdXQ6YmxhbmtcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XG5cbiAgICAgICAgLy8gU2V0IHRoZSBjb250ZW50IGFuZCBhbmQgc2NyaXB0cyBhZ2FpblxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LmlubmVySFRNTCA9XG4gICAgICAgICAgICAnPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPjxkaXYgaWQ9XCJjb250YWluZXJcIj48L2Rpdj48L2Rpdj4nO1xuICAgICAgICB9KTtcbiAgICAgIH1cbiAgICB9XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgbG9nV2l0aFN0YWNrKFxuICAgICAgMixcbiAgICAgIGVycm9yLFxuICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xlYXIgdGhlIGNvbnRlbnQgb2YgdGhlIHBhZ2UuJ1xuICAgICk7XG4gIH1cbn1cblxuLyoqXG4gKiBBZGRzIGN1c3RvbSBKUyBhbmQgQ1NTIHJlc291cmNlcyB0byBhIFB1cHBldGVlciBQYWdlIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWRcbiAqIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHdoaWNoIHJlc291cmNlcyB3aWxsIGJlXG4gKiBhZGRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QXJyYXk8T2JqZWN0Pj59IC0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gYXJyYXkgb2YgaW5qZWN0ZWRcbiAqIHJlc291cmNlcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucykge1xuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcbiAgY29uc3QgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcblxuICAvLyBVc2UgcmVzb3VyY2VzXG4gIGNvbnN0IHJlc291cmNlcyA9IG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzO1xuICBpZiAocmVzb3VyY2VzKSB7XG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xuXG4gICAgLy8gTG9hZCBjdXN0b20gSlMgY29kZVxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcbiAgICAgIGluamVjdGVkSnMucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5qc1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xuICAgIGlmIChyZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgIGZvciAoY29uc3QgZmlsZSBvZiByZXNvdXJjZXMuZmlsZXMpIHtcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcblxuICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gc2NyaXB0IGZyb20gcmVzb3VyY2VzJyBmaWxlc1xuICAgICAgICBpbmplY3RlZEpzLnB1c2goXG4gICAgICAgICAgaXNMb2NhbFxuICAgICAgICAgICAgPyB7XG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgOiB7XG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyhqc1Jlc291cmNlKSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbZXhwb3J0XSBUaGUgSlMgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgIH1cbiAgICB9XG4gICAgaW5qZWN0ZWRKcy5sZW5ndGggPSAwO1xuXG4gICAgLy8gTG9hZCBDU1NcbiAgICBjb25zdCBpbmplY3RlZENzcyA9IFtdO1xuICAgIGlmIChyZXNvdXJjZXMuY3NzKSB7XG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XG4gICAgICBpZiAoY3NzSW1wb3J0cykge1xuICAgICAgICAvLyBIYW5kbGUgY3NzIHNlY3Rpb25cbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XG4gICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGgpIHtcbiAgICAgICAgICAgIGNzc0ltcG9ydFBhdGggPSBjc3NJbXBvcnRQYXRoXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCdAaW1wb3J0JywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cIi9nLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC87LywgJycpXG4gICAgICAgICAgICAgIC5yZXBsYWNlKC9cXCkvZywgJycpXG4gICAgICAgICAgICAgIC50cmltKCk7XG5cbiAgICAgICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBjc3MgZnJvbSByZXNvdXJjZXNcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcbiAgICAgICAgICAgICAgICB1cmw6IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBUaGUgcmVzdCBvZiB0aGUgQ1NTIHNlY3Rpb24gd2lsbCBiZSBjb250ZW50IGJ5IG5vd1xuICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXG4gICAgICB9KTtcblxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xuICAgICAgICB0cnkge1xuICAgICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTdHlsZVRhZyhjc3NSZXNvdXJjZSkpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBDU1MgcmVzb3VyY2UgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaW5qZWN0ZWRDc3MubGVuZ3RoID0gMDtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIGluamVjdGVkUmVzb3VyY2VzO1xufVxuXG4vKipcbiAqIENsZWFycyBvdXQgYWxsIHN0YXRlIHNldCBvbiB0aGUgcGFnZSB3aXRoIGFkZFNjcmlwdFRhZy9hZGRTdHlsZVRhZy4gUmVtb3Zlc1xuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxuICogaXQgZGVzdHJveXMgcHJldmlvdXNseSBleGlzdGluZyBjaGFydHMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcbiAqIGJlIGNsZWFyZWQuXG4gKiBAcGFyYW0ge0FycmF5PE9iamVjdD59IGluamVjdGVkUmVzb3VyY2VzIC0gQXJyYXkgb2YgaW5qZWN0ZWQgcmVzb3VyY2VzXG4gKiB0byBiZSBjbGVhcmVkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKSB7XG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcbiAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XG4gIH1cblxuICAvLyBEZXN0cm95IG9sZCBjaGFydHMgYWZ0ZXIgZXhwb3J0IGlzIGRvbmUgYW5kIHJlc2V0IGFsbCBDU1MgYW5kIHNjcmlwdCB0YWdzXG4gIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXG4gICAgLy8gZXhwb3J0c1xuICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3Qgb2xkQ2hhcnRzID0gSGlnaGNoYXJ0cy5jaGFydHM7XG5cbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xuICAgICAgaWYgKEFycmF5LmlzQXJyYXkob2xkQ2hhcnRzKSAmJiBvbGRDaGFydHMubGVuZ3RoKSB7XG4gICAgICAgIC8vIERlc3Ryb3kgb2xkIGNoYXJ0c1xuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xuICAgICAgICAgIG9sZENoYXJ0ICYmIG9sZENoYXJ0LmRlc3Ryb3koKTtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWywgLi4uc3R5bGVzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3N0eWxlJyk7XG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcblxuICAgIC8vIFJlbW92ZSB0YWdzXG4gICAgZm9yIChjb25zdCBlbGVtZW50IG9mIFtcbiAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxuICAgICAgLi4ubGlua3NUb1JlbW92ZVxuICAgIF0pIHtcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XG4gICAgfVxuICB9KTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXG4gKiBhbmQgZGlzcGxheSBlcnJvcnMgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxuICogaXMgYmVpbmcgc2V0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcblxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcblxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XG59XG5cbi8qKlxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gc2V0IGV2ZW50cyB0by5cbiAqL1xuZnVuY3Rpb24gc2V0UGFnZUV2ZW50cyhwYWdlKSB7XG4gIC8vIEdldCBkZWJ1ZyBvcHRpb25zXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xuICAgIHBhZ2Uub24oJ2NvbnNvbGUnLCAobWVzc2FnZSkgPT4ge1xuICAgICAgY29uc29sZS5sb2coYFtkZWJ1Z10gJHttZXNzYWdlLnRleHQoKX1gKTtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXG4gIHBhZ2Uub24oJ3BhZ2VlcnJvcicsIGFzeW5jIChlcnJvcikgPT4ge1xuICAgIC8vIFRPRE86IENvbnNpZGVyIGFkZGluZyBhIHN3aXRjaCBoZXJlIHRoYXQgdHVybnMgb24gbG9nKDApIGxvZ2dpbmdcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cbiAgICBhd2FpdCBwYWdlLiRldmFsKFxuICAgICAgJyNjb250YWluZXInLFxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xuICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgaWYgKHdpbmRvdy5fZGlzcGxheUVycm9ycykge1xuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXG4gICAgKTtcbiAgfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgZ2V0LFxuICBjcmVhdGUsXG4gIGNsb3NlLFxuICBuZXdQYWdlLFxuICBjbGVhclBhZ2UsXG4gIGFkZFBhZ2VSZXNvdXJjZXMsXG4gIGNsZWFyUGFnZVJlc291cmNlc1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBhZGRQYWdlUmVzb3VyY2VzLCBjbGVhclBhZ2VSZXNvdXJjZXMgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuaW1wb3J0IHsgZ2V0Q2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcblxuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGNsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcyBvZiB0aGUgc3BlY2lmaWVkIHBhZ2UgZWxlbWVudCB3aXRoXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gYW4gb2JqZWN0IGNvbnRhaW5pbmdcbiAqIHgsIHksIHdpZHRoLCBhbmQgaGVpZ2h0IHByb3BlcnRpZXMuXG4gKi9cbmNvbnN0IGdldENsaXBSZWdpb24gPSAocGFnZSkgPT5cbiAgcGFnZS4kZXZhbCgnI2NoYXJ0LWNvbnRhaW5lcicsIChlbGVtZW50KSA9PiB7XG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHJldHVybiB7XG4gICAgICB4LFxuICAgICAgeSxcbiAgICAgIHdpZHRoLFxuICAgICAgaGVpZ2h0OiBNYXRoLnRydW5jKGhlaWdodCA+IDEgPyBoZWlnaHQgOiA1MDApXG4gICAgfTtcbiAgfSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhbiBpbWFnZSB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHNjcmVlbnNob3QgZnVuY3Rpb25hbGl0eSB3aXRoXG4gKiBzcGVjaWZpZWQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gSW1hZ2UgdHlwZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxuICogQHBhcmFtIHtPYmplY3R9IGNsaXAgLSBDbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMuXG4gKiBAcGFyYW0ge251bWJlcn0gcmFzdGVyaXphdGlvblRpbWVvdXQgLSBUaW1lb3V0IGZvciByYXN0ZXJpemF0aW9uXG4gKiBpbiBtaWxsaXNlY29uZHMuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIGltYWdlIGJ1ZmZlciBvciByZWplY3RpbmdcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXG4gKi9cbmNvbnN0IGNyZWF0ZUltYWdlID0gKHBhZ2UsIHR5cGUsIGVuY29kaW5nLCBjbGlwLCByYXN0ZXJpemF0aW9uVGltZW91dCkgPT5cbiAgUHJvbWlzZS5yYWNlKFtcbiAgICBwYWdlLnNjcmVlbnNob3Qoe1xuICAgICAgdHlwZSxcbiAgICAgIGVuY29kaW5nLFxuICAgICAgY2xpcCxcbiAgICAgIGNhcHR1cmVCZXlvbmRWaWV3cG9ydDogdHJ1ZSxcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcbiAgICAgIG9wdGltaXplRm9yU3BlZWQ6IHRydWUsXG4gICAgICAuLi4odHlwZSAhPT0gJ3BuZycgPyB7IHF1YWxpdHk6IDgwIH0gOiB7fSksXG5cbiAgICAgIC8vICM0NDcsICM0NjMgLSBhbHdheXMgcmVuZGVyIG9uIGEgdHJhbnNwYXJlbnQgcGFnZSBpZiB0aGUgZXhwZWN0ZWQgdHlwZVxuICAgICAgLy8gZm9ybWF0IGlzIFBOR1xuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcbiAgICB9KSxcbiAgICBuZXcgUHJvbWlzZSgoX3Jlc29sdmUsIHJlamVjdCkgPT5cbiAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICgpID0+IHJlamVjdChuZXcgRXhwb3J0RXJyb3IoJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpKSxcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxuICAgICAgKVxuICAgIClcbiAgXSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXG4gKiBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXG4gKi9cbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcbiAgcGFnZSxcbiAgaGVpZ2h0LFxuICB3aWR0aCxcbiAgZW5jb2RpbmcsXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0XG4pID0+IHtcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgcGFnZS5wZGYoe1xuICAgICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXG4gICAgICBoZWlnaHQ6IGhlaWdodCArIDEsXG4gICAgICB3aWR0aCxcbiAgICAgIGVuY29kaW5nXG4gICAgfSksXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XG4gICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSksXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcbiAgICAgIClcbiAgICApXG4gIF0pO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGFuIFNWRyBzdHJpbmcgYnkgZXZhbHVhdGluZyB0aGUgb3V0ZXJIVE1MIG9mIHRoZSBmaXJzdCAnc3ZnJyBlbGVtZW50XG4gKiBpbnNpZGUgYW4gZWxlbWVudCB3aXRoIHRoZSBpZCAnY29udGFpbmVyJy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cbiAqL1xuY29uc3QgY3JlYXRlU1ZHID0gKHBhZ2UpID0+XG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xuXG4vKipcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcbiAqIGZ1bmN0aW9uIHdpdGhpbiB0aGUgd2luZG93IGNvbnRleHQgdXNpbmcgcGFnZS5ldmFsdWF0ZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3QgdG8gYmUgY29uZmlndXJlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgY2hhcnQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IFByb21pc2UgcmVzb2x2aW5nIGFmdGVyIHRoZSBjb25maWd1cmF0aW9uIGlzIHNldC5cbiAqL1xuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XG4gIHBhZ2UuZXZhbHVhdGUodHJpZ2dlckV4cG9ydCwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xuXG4vKipcbiAqIEV4cG9ydHMgdG8gYSBjaGFydCBmcm9tIGEgcGFnZSB1c2luZyBQdXBwZXRlZXIuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge2FueX0gY2hhcnQgLSBUaGUgY2hhcnQgb2JqZWN0IG9yIFNWRyBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmcgfCBCdWZmZXIgfCBFeHBvcnRFcnJvcj59IFByb21pc2UgcmVzb2x2aW5nIHRvXG4gKiB0aGUgZXhwb3J0ZWQgZGF0YSBvciByZWplY3Rpbmcgd2l0aCBhbiBFeHBvcnRFcnJvci5cbiAqL1xuZXhwb3J0IGRlZmF1bHQgYXN5bmMgKHBhZ2UsIGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheSAoYWRkaXRpb25hbCBKUyBhbmQgQ1NTKVxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcblxuICB0cnkge1xuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XG5cbiAgICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBEZWNpZGUgd2hldGhlciBkaXNwbGF5IGVycm9yIG9yIGRlYmJ1Z2VyIHdyYXBwZXIgYXJvdW5kIGl0XG4gICAgY29uc3QgZGlzcGxheUVycm9ycyA9XG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxuICAgICAgZ2V0Q2FjaGUoKS5hY3RpdmVNYW5pZmVzdC5tb2R1bGVzLmRlYnVnZ2VyO1xuXG4gICAgbGV0IGlzU1ZHO1xuICAgIGlmIChcbiAgICAgIGNoYXJ0LmluZGV4T2YgJiZcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXG4gICAgKSB7XG4gICAgICAvLyBTVkcgaW5wdXQgaGFuZGxpbmdcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xuXG4gICAgICAvLyBJZiBpbnB1dCBpcyBhbHNvIFNWRywganVzdCByZXR1cm4gaXRcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAgIHJldHVybiBjaGFydDtcbiAgICAgIH1cblxuICAgICAgaXNTVkcgPSB0cnVlO1xuICAgICAgYXdhaXQgcGFnZS5zZXRDb250ZW50KHN2Z1RlbXBsYXRlKGNoYXJ0KSwge1xuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xuICAgICAgfSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXG4gICAgICBsb2coNCwgJ1tleHBvcnRdIFRyZWF0aW5nIGFzIGNvbmZpZy4nKTtcblxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMuc3RySW5qKSB7XG4gICAgICAgIC8vIEluamVjdGlvbiBiYXNlZCBjb25maWd1cmF0aW9uIGV4cG9ydFxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcbiAgICAgICAgICBwYWdlLFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIGNoYXJ0OiB7XG4gICAgICAgICAgICAgIGhlaWdodDogZXhwb3J0T3B0aW9ucy5oZWlnaHQsXG4gICAgICAgICAgICAgIHdpZHRoOiBleHBvcnRPcHRpb25zLndpZHRoXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSxcbiAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcbiAgICAgICAgKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG4gICAgICAgIGNoYXJ0LmNoYXJ0LmhlaWdodCA9IGV4cG9ydE9wdGlvbnMuaGVpZ2h0O1xuICAgICAgICBjaGFydC5jaGFydC53aWR0aCA9IGV4cG9ydE9wdGlvbnMud2lkdGg7XG5cbiAgICAgICAgYXdhaXQgc2V0QXNDb25maWcocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEtlZXBzIHRyYWNrIG9mIGFsbCByZXNvdXJjZXMgYWRkZWQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRYWFhUYWcuIGV0Y1xuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXG4gICAgLy8gb3V0IHdoZW4gZG9pbmcgYSBuZXcgZXhwb3J0IGluIHRoZSBzYW1lIHBhZ2UhXG4gICAgaW5qZWN0ZWRSZXNvdXJjZXMgPSBhd2FpdCBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpO1xuXG4gICAgLy8gR2V0IHRoZSByZWFsIGNoYXJ0IHNpemUgYW5kIHNldCB0aGUgem9vbSBhY2NvcmRpbmdseVxuICAgIGNvbnN0IHNpemUgPSBpc1NWR1xuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xuICAgICAgICAgIGNvbnN0IHN2Z0VsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKFxuICAgICAgICAgICAgJyNjaGFydC1jb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnXG4gICAgICAgICAgKTtcblxuICAgICAgICAgIC8vIEdldCB0aGUgdmFsdWVzIGNvcnJlY3RseSBzY2FsZWRcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcbiAgICAgICAgICBjb25zdCBjaGFydFdpZHRoID0gc3ZnRWxlbWVudC53aWR0aC5iYXNlVmFsLnZhbHVlICogc2NhbGU7XG5cbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxuICAgICAgICAgIC8vIFNldCB0aGUgem9vbSBhcyBzY2FsZVxuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xuXG4gICAgICAgICAgLy8gU2V0IHRoZSBtYXJnaW4gdG8gMHB4XG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS5tYXJnaW4gPSAnMHB4JztcblxuICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBjaGFydEhlaWdodCxcbiAgICAgICAgICAgIGNoYXJ0V2lkdGhcbiAgICAgICAgICB9O1xuICAgICAgICB9LCBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpKVxuICAgICAgOiBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBjb25zdCB7IGNoYXJ0SGVpZ2h0LCBjaGFydFdpZHRoIH0gPSB3aW5kb3cuSGlnaGNoYXJ0cy5jaGFydHNbMF07XG5cbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcbiAgICAgICAgICAvLyBSZXNldCB0aGUgem9vbSBmb3Igb3RoZXIgZXhwb3J0cyB0aGFuIHRvIFNWR3NcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxuICAgICAgICAgICAgY2hhcnRXaWR0aFxuICAgICAgICAgIH07XG4gICAgICAgIH0pO1xuXG4gICAgLy8gU2V0IGZpbmFsIGhlaWdodCBhbmQgd2lkdGggZm9yIHZpZXdwb3J0XG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XG4gICAgY29uc3Qgdmlld3BvcnRXaWR0aCA9IE1hdGguY2VpbChzaXplLmNoYXJ0V2lkdGggfHwgZXhwb3J0T3B0aW9ucy53aWR0aCk7XG5cbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxuICAgIGNvbnN0IHsgeCwgeSB9ID0gYXdhaXQgZ2V0Q2xpcFJlZ2lvbihwYWdlKTtcblxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcbiAgICBhd2FpdCBwYWdlLnNldFZpZXdwb3J0KHtcbiAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcbiAgICAgIGRldmljZVNjYWxlRmFjdG9yOiBpc1NWRyA/IDEgOiBwYXJzZUZsb2F0KGV4cG9ydE9wdGlvbnMuc2NhbGUpXG4gICAgfSk7XG5cbiAgICBsZXQgZGF0YTtcbiAgICAvLyBSYXN0ZXJpemF0aW9uIHByb2Nlc3NcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgICAgLy8gU1ZHXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlU1ZHKHBhZ2UpO1xuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcbiAgICAgIC8vIFBORyBvciBKUEVHXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlSW1hZ2UoXG4gICAgICAgIHBhZ2UsXG4gICAgICAgIGV4cG9ydE9wdGlvbnMudHlwZSxcbiAgICAgICAgJ2Jhc2U2NCcsXG4gICAgICAgIHtcbiAgICAgICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcbiAgICAgICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICAgIHgsXG4gICAgICAgICAgeVxuICAgICAgICB9LFxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XG4gICAgICApO1xuICAgIH0gZWxzZSBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAncGRmJykge1xuICAgICAgLy8gUERGXG4gICAgICBkYXRhID0gYXdhaXQgY3JlYXRlUERGKFxuICAgICAgICBwYWdlLFxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcbiAgICAgICAgdmlld3BvcnRXaWR0aCxcbiAgICAgICAgJ2Jhc2U2NCcsXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgYFtleHBvcnRdIFVuc3VwcG9ydGVkIG91dHB1dCBmb3JtYXQgJHtleHBvcnRPcHRpb25zLnR5cGV9LmBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQ2xlYXIgcHJldmlvdXNseSBpbmplY3RlZCBKUyBhbmQgQ1NTIHJlc291cmNlc1xuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XG4gICAgcmV0dXJuIGRhdGE7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcbiAgICByZXR1cm4gZXJyb3I7XG4gIH1cbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcblxuZXhwb3J0IGRlZmF1bHQgKGNoYXJ0KSA9PiBgXG48IURPQ1RZUEUgaHRtbD5cbjxodG1sIGxhbmc9J2VuLVVTJz5cbiAgPGhlYWQ+XG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cbiAgICA8dGl0bGU+SGlnaGNoYXJ0cyBFeHBvcnQ8L3RpdGxlPlxuICA8L2hlYWQ+XG4gIDxzdHlsZT5cbiAgICAke2Nzc1RlbXBsYXRlKCl9XG4gIDwvc3R5bGU+XG4gIDxib2R5PlxuICAgIDxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj5cbiAgICAgICR7Y2hhcnR9XG4gICAgPC9kaXY+XG4gIDwvYm9keT5cbjwvaHRtbD5cblxuYDtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7XG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXG4gIG5ld1BhZ2UsXG4gIGNsZWFyUGFnZVxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuaW1wb3J0IHB1cHBldGVlckV4cG9ydCBmcm9tICcuL2V4cG9ydC5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8vIFRoZSBwb29sIGluc3RhbmNlXG5sZXQgcG9vbCA9IGZhbHNlO1xuXG4vLyBQb29sIHN0YXRpc3RpY3NcbmV4cG9ydCBjb25zdCBzdGF0cyA9IHtcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcbiAgZXhwb3J0QXR0ZW1wdHM6IDAsXG4gIGV4cG9ydEZyb21TdmdBdHRlbXB0czogMCxcbiAgdGltZVNwZW50OiAwLFxuICBkcm9wcGVkRXhwb3J0czogMCxcbiAgc3BlbnRBdmVyYWdlOiAwXG59O1xuXG5sZXQgcG9vbENvbmZpZyA9IHt9O1xuXG5jb25zdCBmYWN0b3J5ID0ge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxuICAgKlxuICAgKiBAcmV0dXJucyB7T2JqZWN0fSAtIEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3b3JrZXIgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZVxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXG4gICAqXG4gICAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIElmIHRoZXJlJ3MgYW4gZXJyb3IgZHVyaW5nIHRoZSBjcmVhdGlvbiBvZiB0aGUgbmV3XG4gICAqIHBhZ2UuXG4gICAqL1xuICBjcmVhdGU6IGFzeW5jICgpID0+IHtcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xuXG4gICAgY29uc3QgaWQgPSB1dWlkKCk7XG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICB0cnkge1xuICAgICAgcGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcblxuICAgICAgaWYgKCFwYWdlIHx8IHBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xuICAgICAgfVxuXG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gU3VjY2Vzc2Z1bGx5IGNyZWF0ZWQgYSB3b3JrZXIgJHtpZH0gLSB0b29rICR7XG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcbiAgICAgICAgfSBtcy5gXG4gICAgICApO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGNyZWF0aW5nIGEgbmV3IHBhZ2UuJ1xuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkLFxuICAgICAgcGFnZSxcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcbiAgICAgIHdvcmtDb3VudDogTWF0aC5yb3VuZChNYXRoLnJhbmRvbSgpICogKHBvb2xDb25maWcud29ya0xpbWl0IC8gMikpXG4gICAgfTtcbiAgfSxcblxuICAvKipcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcbiAgICogdGhlIHdvcmsgbGltaXQuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXG4gICAqIHdvcmtlcidzIElELCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLCBhbmQgd29yayBjb3VudC5cbiAgICpcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxuICAgKiB0aGUgd29yayBsaW1pdDsgb3RoZXJ3aXNlLCByZXR1cm5zIGZhbHNlLlxuICAgKi9cbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcbiAgICBpZiAoXG4gICAgICBwb29sQ29uZmlnLndvcmtMaW1pdCAmJlxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcbiAgICApIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtwb29sXSBXb3JrZXIgZmFpbGVkIHZhbGlkYXRpb246IGV4Y2VlZGVkIHdvcmsgbGltaXQgKGxpbWl0IGlzICR7cG9vbENvbmZpZy53b3JrTGltaXR9KS5gXG4gICAgICApO1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfSxcblxuICAvKipcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXG4gICAqXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmdcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxuICAgKi9cbiAgZGVzdHJveTogYXN5bmMgKHdvcmtlckhhbmRsZSkgPT4ge1xuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICBpZiAod29ya2VySGFuZGxlLnBhZ2UpIHtcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXG4gICAgICBhd2FpdCB3b3JrZXJIYW5kbGUucGFnZS5jbG9zZSgpO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHBvb2wgd2l0aCB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiwgY3JlYXRpbmdcbiAqIGEgYnJvd3NlciBpbnN0YW5jZSBhbmQgc2V0dGluZyB1cCB3b3JrZXIgcmVzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBjb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcG9vbCBhbG9uZ1xuICogd2l0aCBjdXN0b20gcHVwcGV0ZWVyIGFyZ3VtZW50cyBmb3IgdGhlIHB1cHBldGVlci5sYXVuY2ggZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBpbml0UG9vbCA9IGFzeW5jIChjb25maWcpID0+IHtcbiAgLy8gRm9yIHRoZSBtb2R1bGUgc2NvcGUgdXNhZ2VcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xuXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXIgaW5zdGFuY2Ugd2l0aCB0aGUgcHVwcGV0ZWVyIGFyZ3VtZW50c1xuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW3Bvb2xdIEluaXRpYWxpemluZyBwb29sIHdpdGggd29ya2VyczogbWluICR7cG9vbENvbmZpZy5taW5Xb3JrZXJzfSwgbWF4ICR7cG9vbENvbmZpZy5tYXhXb3JrZXJzfS5gXG4gICk7XG5cbiAgaWYgKHBvb2wpIHtcbiAgICByZXR1cm4gbG9nKFxuICAgICAgNCxcbiAgICAgICdbcG9vbF0gQWxyZWFkeSBpbml0aWFsaXplZCwgcGxlYXNlIGtpbGwgaXQgYmVmb3JlIGNyZWF0aW5nIGEgbmV3IG9uZS4nXG4gICAgKTtcbiAgfVxuXG4gIGlmIChwYXJzZUludChwb29sQ29uZmlnLm1pbldvcmtlcnMpID4gcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSkge1xuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gQ3JlYXRlIGEgcG9vbCBhbG9uZyB3aXRoIGEgbWluaW1hbCBudW1iZXIgb2YgcmVzb3VyY2VzXG4gICAgcG9vbCA9IG5ldyBQb29sKHtcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xuICAgICAgLi4uZmFjdG9yeSxcbiAgICAgIG1pbjogcGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSxcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcbiAgICAgIGFjcXVpcmVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmFjcXVpcmVUaW1lb3V0LFxuICAgICAgY3JlYXRlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5jcmVhdGVUaW1lb3V0LFxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXG4gICAgICBpZGxlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5pZGxlVGltZW91dCxcbiAgICAgIGNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlUmV0cnlJbnRlcnZhbCxcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcbiAgICAgIHByb3BhZ2F0ZUNyZWF0ZUVycm9yOiBmYWxzZVxuICAgIH0pO1xuXG4gICAgLy8gU2V0IGV2ZW50c1xuICAgIHBvb2wub24oJ3JlbGVhc2UnLCBhc3luYyAocmVzb3VyY2UpID0+IHtcbiAgICAgIC8vIENsZWFyIHBhZ2VcbiAgICAgIGF3YWl0IGNsZWFyUGFnZShyZXNvdXJjZS5wYWdlLCBmYWxzZSk7XG4gICAgICBsb2coNCwgYFtwb29sXSBSZWxlYXNpbmcgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKGV2ZW50SWQsIHJlc291cmNlKSA9PiB7XG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcbiAgICAvLyBDcmVhdGUgYW4gaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzXG4gICAgZm9yIChsZXQgaSA9IDA7IGkgPCBwb29sQ29uZmlnLm1pbldvcmtlcnM7IGkrKykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2UgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xuICAgICAgICBpbml0aWFsUmVzb3VyY2VzLnB1c2gocmVzb3VyY2UpO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCAnW3Bvb2xdIENvdWxkIG5vdCBjcmVhdGUgYW4gaW5pdGlhbCByZXNvdXJjZS4nKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBSZWxlYXNlIHRoZSBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXMgYmFjayB0byB0aGUgcG9vbFxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcbiAgICAgIHBvb2wucmVsZWFzZShyZXNvdXJjZSk7XG4gICAgfSk7XG5cbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XG5cbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXG4gIGlmIChwb29sKSB7XG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XG4gICAgfVxuXG4gICAgLy8gRGVzdHJveSB0aGUgcG9vbCBpZiBpdCBpcyBzdGlsbCBhdmFpbGFibGVcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XG4gICAgICBhd2FpdCBwb29sLmRlc3Ryb3koKTtcbiAgICAgIGxvZyg0LCAnW2Jyb3dzZXJdIERlc3Ryb3llZCB0aGUgcG9vbCBvZiByZXNvdXJjZXMuJyk7XG4gICAgfVxuICB9XG5cbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcbiAgYXdhaXQgY2xvc2VCcm93c2VyKCk7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VzIHRoZSBleHBvcnQgd29yayB1c2luZyBhIHdvcmtlciBmcm9tIHRoZSBwb29sLiBBY3F1aXJlcyBhIHdvcmtlclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcbiAqIHRoZSB3b3JrZXIgaGFuZGxlIGJhY2sgdG8gdGhlIHBvb2wuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxuICogb3B0aW9ucy5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBwb3N0V29yayA9IGFzeW5jIChjaGFydCwgb3B0aW9ucykgPT4ge1xuICBsZXQgd29ya2VySGFuZGxlO1xuXG4gIHRyeSB7XG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcblxuICAgICsrc3RhdHMuZXhwb3J0QXR0ZW1wdHM7XG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XG4gICAgICBnZXRQb29sSW5mbygpO1xuICAgIH1cblxuICAgIGlmICghcG9vbCkge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nKTtcbiAgICB9XG5cbiAgICAvLyBBY3F1aXJlIHRoZSB3b3JrZXIgYWxvbmcgd2l0aCB0aGUgaWQgb2YgcmVzb3VyY2UgYW5kIHdvcmsgY291bnRcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW3Bvb2xdIEFjcXVpcmluZyBhIHdvcmtlciBoYW5kbGUuJyk7XG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xuXG4gICAgICAvLyBDaGVjayB0aGUgcGFnZSBhY3F1aXJlIHRpbWVcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDUsXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICAgID8gYFtiZW5jaG1hcmtdIFJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtYFxuICAgICAgICAgICAgOiAnW2JlbmNobWFya10nLFxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcbiAgICAgICAgICA6ICcnKSArXG4gICAgICAgICAgYEVycm9yIGVuY291bnRlcmVkIHdoZW4gYWNxdWlyaW5nIGFuIGF2YWlsYWJsZSBlbnRyeTogJHthY3F1aXJlQ291bnRlcigpfW1zLmBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGUuJyk7XG5cbiAgICBpZiAoIXdvcmtlckhhbmRsZS5wYWdlKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFNhdmUgdGhlIHN0YXJ0IHRpbWVcbiAgICBsZXQgd29ya1N0YXJ0ID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG5cbiAgICBsb2coNCwgYFtwb29sXSBTdGFydGluZyB3b3JrIG9uIHBvb2wgZW50cnkgd2l0aCBJRCAke3dvcmtlckhhbmRsZS5pZH0uYCk7XG5cbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxuICAgIGNvbnN0IGV4cG9ydENvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHB1cHBldGVlckV4cG9ydCh3b3JrZXJIYW5kbGUucGFnZSwgY2hhcnQsIG9wdGlvbnMpO1xuXG4gICAgLy8gQ2hlY2sgaWYgaXQncyBhbiBlcnJvclxuICAgIGlmIChyZXN1bHQgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cbiAgICAgIGlmIChyZXN1bHQubWVzc2FnZSA9PT0gJ1Jhc3Rlcml6YXRpb24gdGltZW91dCcpIHtcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UuY2xvc2UoKTtcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICApLnNldEVycm9yKHJlc3VsdCk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgNSxcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcblxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdWx0LFxuICAgICAgb3B0aW9uc1xuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcblxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxuICovXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XG5cbi8qKlxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XG4gIG1pbjogcG9vbC5taW4sXG4gIG1heDogcG9vbC5tYXgsXG4gIGFsbDogcG9vbC5udW1GcmVlKCkgKyBwb29sLm51bVVzZWQoKSxcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcbiAgdXNlZDogcG9vbC5udW1Vc2VkKCksXG4gIHBlbmRpbmc6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKClcbn0pO1xuXG4vKipcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXG4gKiByZXF1ZXN0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xuICBjb25zdCB7IG1pbiwgbWF4LCBhbGwsIGF2YWlsYWJsZSwgdXNlZCwgcGVuZGluZyB9ID0gZ2V0UG9vbEluZm9KU09OKCk7XG5cbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWlufS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBhbGxvd2VkIGJ5IHBvb2w6ICR7bWF4fS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhdmFpbGFibGUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgYWNxdWlyZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGluaXRQb29sLFxuICBraWxsUG9vbCxcbiAgcG9zdFdvcmssXG4gIGdldFBvb2wsXG4gIGdldFBvb2xJbmZvLFxuICBnZXRQb29sSW5mb0pTT04sXG4gIGdldFN0YXRzOiAoKSA9PiBzdGF0c1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMsIHdyaXRlRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5cbmltcG9ydCB7IGdldE9wdGlvbnMsIGluaXRFeHBvcnRTZXR0aW5ncyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQge1xuICBmaXhUeXBlLFxuICBoYW5kbGVSZXNvdXJjZXMsXG4gIGlzQ29ycmVjdEpTT04sXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIHJvdW5kTnVtYmVyLFxuICB0b0Jvb2xlYW4sXG4gIHdyYXBBcm91bmRcbn0gZnJvbSAnLi91dGlscy5qcyc7XG5pbXBvcnQgeyBzYW5pdGl6ZSB9IGZyb20gJy4vc2FuaXRpemUuanMnO1xuaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxubGV0IGFsbG93Q29kZUV4ZWN1dGlvbiA9IGZhbHNlO1xuXG4vKipcbiAqIFN0YXJ0cyBhbiBleHBvcnQgcHJvY2Vzcy4gVGhlIGBzZXR0aW5nc2AgY29udGFpbnMgZmluYWwgb3B0aW9ucyBnYXRoZXJlZFxuICogZnJvbSBhbGwgcG9zc2libGUgc291cmNlcyAoY29uZmlnLCBlbnYsIGNsaSwganNvbikuIFRoZSBgZW5kQ2FsbGJhY2tgIGlzXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XG4gKiBhcmd1bWVudCBhbmQgdGhlIHNlY29uZCBjb250YWluaW5nIHRoZSBiYXNlNjQgcmVzcHJlc2VudGF0aW9uIG9mIGEgY2hhcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxuICogY29uZmlndXJhdGlvbi5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgdXBvblxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cbiAqXG4gKiBAcmV0dXJucyB7dm9pZH0gVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCByZXR1cm4gYSB2YWx1ZSBkaXJlY3RseTsgaW5zdGVhZCxcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXG4gKi9cbmV4cG9ydCBjb25zdCBzdGFydEV4cG9ydCA9IGFzeW5jIChzZXR0aW5ncywgZW5kQ2FsbGJhY2spID0+IHtcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxuICBsb2coNCwgJ1tjaGFydF0gU3RhcnRpbmcgdGhlIGV4cG9ydGluZyBwcm9jZXNzLicpO1xuXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xuICBjb25zdCBvcHRpb25zID0gaW5pdEV4cG9ydFNldHRpbmdzKHNldHRpbmdzLCBnZXRPcHRpb25zKCkpO1xuXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcbiAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xuXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcbiAgaWYgKG9wdGlvbnMucGF5bG9hZD8uc3ZnICYmIG9wdGlvbnMucGF5bG9hZC5zdmcgIT09ICcnKSB7XG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xuXG4gICAgICBjb25zdCByZXN1bHQgPSBleHBvcnRBc1N0cmluZyhcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcbiAgICAgICAgb3B0aW9ucyxcbiAgICAgICAgZW5kQ2FsbGJhY2tcbiAgICAgICk7XG5cbiAgICAgICsrc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzO1xuICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicpLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxuICBpZiAoXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxuICApIHtcbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XG5cbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgICAgfVxuXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXG4gICAgICAgIDogZG9FeHBvcnQoXG4gICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xuICAgICAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBObyBpbnB1dCBzcGVjaWZpZWQsIHBhc3MgYW4gZXJyb3IgbWVzc2FnZSB0byB0aGUgY2FsbGJhY2tcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgIGBbY2hhcnRdIE5vIHZhbGlkIGlucHV0IHNwZWNpZmllZC4gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIHRoZSBmb2xsb3dpbmcgcGFyYW1ldGVycyBpcyBjb3JyZWN0bHkgc2V0OiAnaW5maWxlJywgJ2luc3RyJywgJ29wdGlvbnMnLCBvciAnc3ZnJy5gXG4gICAgKVxuICApO1xufTtcblxuLyoqXG4gKiBTdGFydHMgYSBiYXRjaCBleHBvcnQgcHJvY2VzcyBmb3IgbXVsdGlwbGUgY2hhcnRzIGJhc2VkIG9uIHRoZSBpbmZvcm1hdGlvblxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxuICogXCJpbmZpbGUxLmpzb249b3V0ZmlsZTEucG5nO2luZmlsZTIuanNvbj1vdXRmaWxlMi5wbmc7Li4uXCJcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXG4gKiBhIGJhdGNoIGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcbiAqIGFueSBvZiB0aGUgYmF0Y2ggZXhwb3J0IHByb2Nlc3MuXG4gKi9cbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IGJhdGNoRnVuY3Rpb25zID0gW107XG5cbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXG4gIGZvciAobGV0IHBhaXIgb2Ygb3B0aW9ucy5leHBvcnQuYmF0Y2guc3BsaXQoJzsnKSkge1xuICAgIHBhaXIgPSBwYWlyLnNwbGl0KCc9Jyk7XG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XG4gICAgICBiYXRjaEZ1bmN0aW9ucy5wdXNoKFxuICAgICAgICBzdGFydEV4cG9ydChcbiAgICAgICAgICB7XG4gICAgICAgICAgICAuLi5vcHRpb25zLFxuICAgICAgICAgICAgZXhwb3J0OiB7XG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgICAgICAgICAgICBpbmZpbGU6IHBhaXJbMF0sXG4gICAgICAgICAgICAgIG91dGZpbGU6IHBhaXJbMV1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIChlcnJvciwgaW5mbykgPT4ge1xuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcbiAgICAgICAgICAgIGlmIChlcnJvcikge1xuICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQub3V0ZmlsZSxcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC50eXBlICE9PSAnc3ZnJ1xuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxuICAgICAgICAgICAgICAgIDogaW5mby5yZXN1bHRcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuICAgICAgICApXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIHRyeSB7XG4gICAgLy8gQXdhaXQgYWxsIGV4cG9ydHMgYXJlIGRvbmVcbiAgICBhd2FpdCBQcm9taXNlLmFsbChiYXRjaEZ1bmN0aW9ucyk7XG5cbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIGJhdGNoIGV4cG9ydFxuICAgIGF3YWl0IGtpbGxQb29sKCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tjaGFydF0gRXJyb3IgZW5jb3VudGVyZWQgZHVyaW5nIGJhdGNoIGV4cG9ydC4nXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogU3RhcnRzIGEgc2luZ2xlIGV4cG9ydCBwcm9jZXNzIGJhc2VkIG9uIHRoZSBzcGVjaWZpZWQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXG4gKiBhIHNpbmdsZSBleHBvcnQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIHNpbmdsZSBleHBvcnRcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xuICogdGhlIHNpbmdsZSBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IHNpbmdsZUV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIC8vIFVzZSBpbnN0ciBvciBpdHMgYWxpYXMsIG9wdGlvbnNcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xuXG4gIC8vIFBlcmZvcm0gYW4gZXhwb3J0XG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xuICAgIC8vIEV4aXQgcHJvY2VzcyB3aGVuIGVycm9yXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XG5cbiAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBvdXRmaWxlIHx8IGBjaGFydC4ke3R5cGV9YCxcbiAgICAgIHR5cGUgIT09ICdzdmcnID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSA6IGluZm8ucmVzdWx0XG4gICAgKTtcblxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgc2luZ2xlIGV4cG9ydFxuICAgIGF3YWl0IGtpbGxQb29sKCk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHRoZSBzaXplIGFuZCBzY2FsZSBmb3IgY2hhcnQgZXhwb3J0IGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGNoYXJ0IGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgY2FsY3VsYXRlZCBoZWlnaHQsIHdpZHRoLFxuICogYW5kIHNjYWxlIGZvciB0aGUgY2hhcnQgZXhwb3J0LlxuICovXG5leHBvcnQgY29uc3QgZmluZENoYXJ0U2l6ZSA9IChvcHRpb25zKSA9PiB7XG4gIGNvbnN0IHsgY2hhcnQsIGV4cG9ydGluZyB9ID1cbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XG5cbiAgLy8gU2VlIGlmIGdsb2JhbE9wdGlvbnMgaG9sZHMgY2hhcnQgb3IgZXhwb3J0aW5nIHNpemVcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xuXG4gIC8vIFNlY3VyZSBzY2FsZSB2YWx1ZVxuICBsZXQgc2NhbGUgPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5zY2FsZSB8fFxuICAgIGV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XG4gICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRTY2FsZSB8fFxuICAgIDE7XG5cbiAgLy8gdGhlIHNjYWxlIGNhbm5vdCBiZSBsb3dlciB0aGFuIDAuMSBhbmQgY2Fubm90IGJlIGhpZ2hlciB0aGFuIDUuMFxuICBzY2FsZSA9IE1hdGgubWF4KDAuMSwgTWF0aC5taW4oc2NhbGUsIDUuMCkpO1xuXG4gIC8vIHdlIHdhbnQgdG8gcm91bmQgdGhlIG51bWJlcnMgbGlrZSAwLjIzMjM0IC0+IDAuMjNcbiAgc2NhbGUgPSByb3VuZE51bWJlcihzY2FsZSwgMik7XG5cbiAgLy8gRmluZCBjaGFydCBzaXplIGFuZCBzY2FsZVxuICBjb25zdCBzaXplID0ge1xuICAgIGhlaWdodDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5oZWlnaHQgfHxcbiAgICAgIGV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxuICAgICAgZ2xvYmFsT3B0aW9ucz8uY2hhcnQ/LmhlaWdodCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcbiAgICAgIDQwMCxcbiAgICB3aWR0aDpcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VXaWR0aCB8fFxuICAgICAgY2hhcnQ/LndpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8ud2lkdGggfHxcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py5kZWZhdWx0V2lkdGggfHxcbiAgICAgIDYwMCxcbiAgICBzY2FsZVxuICB9O1xuXG4gIC8vIEdldCByaWQgb2YgcG90ZW50aWFsIHB4IGFuZCAlXG4gIGZvciAobGV0IFtwYXJhbSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKHNpemUpKSB7XG4gICAgc2l6ZVtwYXJhbV0gPVxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyA/ICt2YWx1ZS5yZXBsYWNlKC9weHwlL2dpLCAnJykgOiB2YWx1ZTtcbiAgfVxuICByZXR1cm4gc2l6ZTtcbn07XG5cbi8qKlxuICogRnVuY3Rpb24gZm9yIGZpbmFsaXppbmcgb3B0aW9ucyBiZWZvcmUgZXhwb3J0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjaGFydEpzb24gLSBUaGUgSlNPTiByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxuICogY29tcGxldGlvbiBvciBlcnJvci5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzdmcgLSBUaGUgU1ZHIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcbiAqIGlzIGNvbXBsZXRlZC5cbiAqL1xuY29uc3QgZG9FeHBvcnQgPSBhc3luYyAob3B0aW9ucywgY2hhcnRKc29uLCBlbmRDYWxsYmFjaywgc3ZnKSA9PiB7XG4gIGxldCB7IGV4cG9ydDogZXhwb3J0T3B0aW9ucywgY3VzdG9tTG9naWM6IGN1c3RvbUxvZ2ljT3B0aW9ucyB9ID0gb3B0aW9ucztcblxuICBjb25zdCBhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQgPVxuICAgIHR5cGVvZiBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uID09PSAnYm9vbGVhbidcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgOiBhbGxvd0NvZGVFeGVjdXRpb247XG5cbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgPSBvcHRpb25zLmN1c3RvbUxvZ2ljID0ge307XG4gIH0gZWxzZSBpZiAoYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkKSB7XG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcbiAgICAgIC8vIFByb2Nlc3MgcmVzb3VyY2VzXG4gICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXG4gICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc291cmNlcyA9IHJlYWRGaWxlU3luYygncmVzb3VyY2VzLmpzb24nLCAndXRmOCcpO1xuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcbiAgICAgICAgICByZXNvdXJjZXMsXG4gICAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAgIDIsXG4gICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgYFtjaGFydF0gVW5hYmxlIHRvIGxvYWQgdGhlIGRlZmF1bHQgcmVzb3VyY2VzLmpzb24gZmlsZS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gSWYgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnIGlzbid0IHNldCwgd2Ugc2hvdWxkIHJlZnVzZSB0aGUgdXNhZ2VcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxuICAvLyByZWZ1c2UgdG8gcnVuIGFyYml0cmFyeSBKYXZhU2NyaXB0LiBQcmlvcml0aXplZCBzaG91bGQgYmUgdGhlIHNjb3BlZFxuICAvLyBvcHRpb24sIHRoZW4gd2Ugc2hvdWxkIHRha2UgYSBsb29rIGF0IHRoZSBvdmVyYWxsIHBvb2wgb3B0aW9uLlxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcbiAgICBpZiAoXG4gICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgfHxcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlXG4gICAgKSB7XG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XG4gICAgICAvLyB0aGVzZSBzZXR0aW5ncy5cbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAgIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snLCAncmVzb3VyY2VzJyBhbmQgJ2N1c3RvbUNvZGUnIG9wdGlvbnMgaGF2ZSBiZWVuIGRpc2FibGVkIGZvciB0aGlzIHNlcnZlci5gXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXG4gIGlmIChjaGFydEpzb24pIHtcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XG4gIH1cblxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcbiAgfVxuXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXG4gICAgICAgICkge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcbiAgICAgICAgICAgIHRydWVcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcbiAgICB0cnkge1xuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgfVxuICB9XG5cbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xuICBpZiAoXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXG4gICkge1xuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFNpemUgc2VhcmNoXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcbiAgfTtcblxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxuICAgICAgb3B0aW9uc1xuICAgICk7XG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cbiAqXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxuICogdG8gYmUgaW5qZWN0ZWQuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cbiAqL1xuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICB0cnkge1xuICAgIGxldCBzdHJJbmo7XG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcblxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgKTtcbiAgICB9XG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcbiAgICB9XG5cbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gXG4gICAgICApLnNldEVycm9yKGVycm9yKVxuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHN0cmluZ1RvRXhwb3J0IC0gVGhlIHN0cmluZyBjb250ZW50IHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcbiAqIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZW5kQ2FsbGJhY2sgLSBDYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIGF0IHRoZSBlbmRcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqXG4gKiBAcmV0dXJucyB7YW55fSBSZXN1bHQgb2YgdGhlIGV4cG9ydCBwcm9jZXNzIG9yIGFuIGVycm9yIGlmIGVuY291bnRlcmVkLlxuICovXG5jb25zdCBleHBvcnRBc1N0cmluZyA9IChzdHJpbmdUb0V4cG9ydCwgb3B0aW9ucywgZW5kQ2FsbGJhY2spID0+IHtcbiAgY29uc3QgeyBhbGxvd0NvZGVFeGVjdXRpb24gfSA9IG9wdGlvbnMuY3VzdG9tTG9naWM7XG5cbiAgLy8gQ2hlY2sgaWYgaXQgaXMgU1ZHXG4gIGlmIChcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzw/eG1sJykgPj0gMFxuICApIHtcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XG4gICAgcmV0dXJuIGRvRXhwb3J0KG9wdGlvbnMsIGZhbHNlLCBlbmRDYWxsYmFjaywgc3RyaW5nVG9FeHBvcnQpO1xuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBUcnkgdG8gcGFyc2UgdG8gSlNPTiBhbmQgY2FsbCB0aGUgZG9FeHBvcnQgZnVuY3Rpb25cbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xuXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcbiAgICAgICAgKS5zZXRFcnJvcihlcnJvcilcbiAgICAgICk7XG4gICAgfVxuICB9XG59O1xuXG4vKipcbiAqIFJldHJpZXZlcyBhbmQgcmV0dXJucyB0aGUgY3VycmVudCBzdGF0dXMgb2YgY29kZSBleGVjdXRpb24gcGVybWlzc2lvbi5cbiAqXG4gKiBAcmV0dXJucyB7YW55fSBUaGUgdmFsdWUgb2YgYWxsb3dDb2RlRXhlY3V0aW9uLlxuICovXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xuXG4vKipcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXG4gKlxuICogQHBhcmFtIHthbnl9IHZhbHVlIC0gVGhlIHZhbHVlIHRvIGJlIGNvbnZlcnRlZCBhbmQgYXNzaWduZWRcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IHNldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICh2YWx1ZSkgPT4ge1xuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2luZ2xlRXhwb3J0LFxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbixcbiAgc3RhcnRFeHBvcnQsXG4gIGZpbmRDaGFydFNpemVcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuLyoqXG4gKiBAb3ZlcnZpZXcgVXNlZCB0byBzYW5pdGl6ZSB0aGUgc3RyaW5ncyBjb21pbmcgZnJvbSB0aGUgZXhwb3J0aW5nIG1vZHVsZVxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxuICoqL1xuXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcbmltcG9ydCBET01QdXJpZnkgZnJvbSAnZG9tcHVyaWZ5JztcblxuLyoqXG4gKiBTYW5pdGl6ZXMgYSBnaXZlbiBIVE1MIHN0cmluZyBieSByZW1vdmluZyA8c2NyaXB0PiB0YWdzLlxuICogVGhpcyBmdW5jdGlvbiB1c2VzIGEgcmVndWxhciBleHByZXNzaW9uIHRvIGZpbmQgYW5kIHJlbW92ZSBhbGxcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dCBUaGUgSFRNTCBzdHJpbmcgdG8gYmUgc2FuaXRpemVkLlxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHNhbml0aXplKGlucHV0KSB7XG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xuICBjb25zdCBwdXJpZnkgPSBET01QdXJpZnkod2luZG93KTtcbiAgcmV0dXJuIHB1cmlmeS5zYW5pdGl6ZShpbnB1dCwgeyBBRERfVEFHUzogWydmb3JlaWduT2JqZWN0J10gfSk7XG59XG5cbmV4cG9ydCBkZWZhdWx0IHNhbml0aXplO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuLy8gQXJyYXkgdGhhdCBjb250YWlucyBpZHMgb2YgYWxsIG9uZ29pbmcgaW50ZXJ2YWxzXG5jb25zdCBpbnRlcnZhbElkcyA9IFtdO1xuXG4vKipcbiAqIEFkZHMgaWQgb2YgYSBzZXRJbnRlcnZhbCB0byB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXG4gKlxuICogQHBhcmFtIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cbiAqL1xuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XG4gIGludGVydmFsSWRzLnB1c2goaWQpO1xufTtcblxuLyoqXG4gKiBDbGVhcnMgYWxsIG9mIG9uZ29pbmcgaW50ZXJ2YWxzIGJ5IGlkcyBnYXRoZXJlZCBpbiB0aGUgaW50ZXJ2YWxJZHMgYXJyYXkuXG4gKi9cbmV4cG9ydCBjb25zdCBjbGVhckFsbEludGVydmFscyA9ICgpID0+IHtcbiAgbG9nKDQsIGBbc2VydmVyXSBDbGVhcmluZyBhbGwgcmVnaXN0ZXJlZCBpbnRlcnZhbHMuYCk7XG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcbiAgICBjbGVhckludGVydmFsKGlkKTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBhZGRJbnRlcnZhbCxcbiAgY2xlYXJBbGxJbnRlcnZhbHNcbn07XG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XG5pbXBvcnQgeyBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuXG4vKipcbiAqIE1pZGRsZXdhcmUgZm9yIGxvZ2dpbmcgZXJyb3JzIHdpdGggc3RhY2sgdHJhY2UgYW5kIGhhbmRsaW5nIGVycm9yIHJlc3BvbnNlLlxuICpcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXEgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXG4gKi9cbmNvbnN0IGxvZ0Vycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XG4gIGxvZ1dpdGhTdGFjaygxLCBlcnJvcik7XG5cbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XG4gIGlmIChlbnZzLk9USEVSX05PREVfRU5WICE9PSAnZGV2ZWxvcG1lbnQnKSB7XG4gICAgZGVsZXRlIGVycm9yLnN0YWNrO1xuICB9XG5cbiAgLy8gQ2FsbCB0aGUgcmV0dXJuRXJyb3JNaWRkbGV3YXJlXG4gIG5leHQoZXJyb3IpO1xufTtcblxuLyoqXG4gKiBNaWRkbGV3YXJlIGZvciByZXR1cm5pbmcgZXJyb3IgcmVzcG9uc2UuXG4gKlxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgcmV0dXJuRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxuICBjb25zdCB7IHN0YXR1c0NvZGU6IHN0Q29kZSwgc3RhdHVzLCBtZXNzYWdlLCBzdGFjayB9ID0gZXJyb3I7XG4gIGNvbnN0IHN0YXR1c0NvZGUgPSBzdENvZGUgfHwgc3RhdHVzIHx8IDUwMDtcblxuICAvLyBTZXQgYW5kIHJldHVybiByZXNwb25zZVxuICByZXMuc3RhdHVzKHN0YXR1c0NvZGUpLmpzb24oeyBzdGF0dXNDb2RlLCBtZXNzYWdlLCBzdGFjayB9KTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+IHtcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXG4gIGFwcC51c2UobG9nRXJyb3JNaWRkbGV3YXJlKTtcblxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShyZXR1cm5FcnJvck1pZGRsZXdhcmUpO1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJ2V4cHJlc3MtcmF0ZS1saW1pdCc7XG5cbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogTWlkZGxld2FyZSBmb3IgZW5hYmxpbmcgcmF0ZSBsaW1pdGluZyBvbiB0aGUgc3BlY2lmaWVkIEV4cHJlc3MgYXBwLlxuICpcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciByYXRlIGxpbWl0aW5nLlxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xuICBjb25zdCBtc2cgPVxuICAgICdUb28gbWFueSByZXF1ZXN0cywgeW91IGhhdmUgYmVlbiByYXRlIGxpbWl0ZWQuIFBsZWFzZSB0cnkgYWdhaW4gbGF0ZXIuJztcblxuICAvLyBPcHRpb25zIGZvciB0aGUgcmF0ZSBsaW1pdGVyXG4gIGNvbnN0IHJhdGVPcHRpb25zID0ge1xuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXG4gICAgd2luZG93OiBsaW1pdENvbmZpZy53aW5kb3cgfHwgMSxcbiAgICBkZWxheTogbGltaXRDb25maWcuZGVsYXkgfHwgMCxcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxuICAgIHNraXBLZXk6IGxpbWl0Q29uZmlnLnNraXBLZXkgfHwgZmFsc2UsXG4gICAgc2tpcFRva2VuOiBsaW1pdENvbmZpZy5za2lwVG9rZW4gfHwgZmFsc2VcbiAgfTtcblxuICAvLyBTZXQgaWYgYmVoaW5kIGEgcHJveHlcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcbiAgICBhcHAuZW5hYmxlKCd0cnVzdCBwcm94eScpO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgbGltaXRlclxuICBjb25zdCBsaW1pdGVyID0gcmF0ZUxpbWl0KHtcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxuICAgIC8vIExpbWl0IGVhY2ggSVAgdG8gMTAwIHJlcXVlc3RzIHBlciB3aW5kb3dNc1xuICAgIG1heDogcmF0ZU9wdGlvbnMubWF4LFxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXG4gICAgZGVsYXlNczogcmF0ZU9wdGlvbnMuZGVsYXksXG4gICAgaGFuZGxlcjogKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xuICAgICAgICBqc29uOiAoKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZCh7IG1lc3NhZ2U6IG1zZyB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgZGVmYXVsdDogKCkgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQobXNnKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xuICAgICAgLy8gQWxsb3cgYnlwYXNzaW5nIHRoZSBsaW1pdGVyIGlmIGEgdmFsaWQga2V5L3Rva2VuIGhhcyBiZWVuIHNlbnRcbiAgICAgIGlmIChcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcFRva2VuICE9PSBmYWxzZSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmtleSA9PT0gcmF0ZU9wdGlvbnMuc2tpcEtleSAmJlxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXG4gICAgICApIHtcbiAgICAgICAgbG9nKDQsICdbcmF0ZSBsaW1pdGluZ10gU2tpcHBpbmcgcmF0ZSBsaW1pdGVyLicpO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXG4gIGFwcC51c2UobGltaXRlcik7XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgYFtyYXRlIGxpbWl0aW5nXSBFbmFibGVkIHJhdGUgbGltaXRpbmcgd2l0aCAke3JhdGVPcHRpb25zLm1heH0gcmVxdWVzdHMgcGVyICR7cmF0ZU9wdGlvbnMud2luZG93fSBtaW51dGUgZm9yIGVhY2ggSVAsIHRydXN0aW5nIHByb3h5OiAke3JhdGVPcHRpb25zLnRydXN0UHJveHl9LmBcbiAgKTtcbn07XG4iLCJpbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9FeHBvcnRFcnJvci5qcyc7XG5cbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEV4cG9ydEVycm9yIHtcbiAgY29uc3RydWN0b3IobWVzc2FnZSwgc3RhdHVzKSB7XG4gICAgc3VwZXIobWVzc2FnZSk7XG4gICAgdGhpcy5zdGF0dXMgPSB0aGlzLnN0YXR1c0NvZGUgPSBzdGF0dXM7XG4gIH1cblxuICBzZXRTdGF0dXMoc3RhdHVzKSB7XG4gICAgdGhpcy5zdGF0dXMgPSBzdGF0dXM7XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cbn1cblxuZXhwb3J0IGRlZmF1bHQgSHR0cEVycm9yO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHVwZGF0ZVZlcnNpb24sIHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vLi4vZW52cy5qcyc7XG5cbmltcG9ydCBIdHRwRXJyb3IgZnJvbSAnLi4vLi4vZXJyb3JzL0h0dHBFcnJvci5qcyc7XG5cbi8qKlxuICogQWRkcyB0aGUgUE9TVCAvY2hhbmdlX2hjX3ZlcnNpb24vOm5ld1ZlcnNpb24gcm91dGUgdGhhdCBjYW4gYmUgdXRpbGl6ZWQgdG8gbW9kaWZ5XG4gKiB0aGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIG9uIHRoZSBzZXJ2ZXIuXG4gKlxuICogVE9ETzogQWRkIGF1dGggdG9rZW4gYW5kIGNvbm5lY3QgdG8gQVBJXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAucG9zdChcbiAgICAgICAgJy92ZXJzaW9uL2NoYW5nZS86bmV3VmVyc2lvbicsXG4gICAgICAgIGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBjb25zdCBhZG1pblRva2VuID0gZW52cy5ISUdIQ0hBUlRTX0FETUlOX1RPS0VOO1xuXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxuICAgICAgICAgICAgaWYgKCFhZG1pblRva2VuIHx8ICFhZG1pblRva2VuLmxlbmd0aCkge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcbiAgICAgICAgICAgICAgICA0MDFcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgdGhlIGhjLWF1dGggaGVhZGVyIGNvbnRhaW4gYSBjb3JyZWN0IHRva2VuXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XG4gICAgICAgICAgICBpZiAoIXRva2VuIHx8IHRva2VuICE9PSBhZG1pblRva2VuKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcbiAgICAgICAgICAgICAgICA0MDFcbiAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gQ29tcGFyZSB2ZXJzaW9uc1xuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XG4gICAgICAgICAgICBpZiAobmV3VmVyc2lvbikge1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcbiAgICAgICAgICAgICAgICBhd2FpdCB1cGRhdGVWZXJzaW9uKG5ld1ZlcnNpb24pO1xuICAgICAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgICBgVmVyc2lvbiBjaGFuZ2U6ICR7ZXJyb3IubWVzc2FnZX1gLFxuICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhdHVzQ29kZVxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xuICAgICAgICAgICAgICByZXNwb25zZS5zdGF0dXMoMjAwKS5zZW5kKHtcbiAgICAgICAgICAgICAgICBzdGF0dXNDb2RlOiAyMDAsXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogdmVyc2lvbigpLFxuICAgICAgICAgICAgICAgIG1lc3NhZ2U6IGBTdWNjZXNzZnVsbHkgdXBkYXRlZCBIaWdoY2hhcnRzIHRvIHZlcnNpb246ICR7bmV3VmVyc2lvbn0uYFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIC8vIE5vIHZlcnNpb24gc3BlY2lmaWVkXG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoJ05vIG5ldyB2ZXJzaW9uIHN1cHBsaWVkLicsIDQwMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIG5leHQoZXJyb3IpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgKTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7IGdldEFsbG93Q29kZUV4ZWN1dGlvbiwgc3RhcnRFeHBvcnQgfSBmcm9tICcuLi8uLi9jaGFydC5qcyc7XG5pbXBvcnQgeyBnZXRPcHRpb25zLCBtZXJnZUNvbmZpZ09wdGlvbnMgfSBmcm9tICcuLi8uLi9jb25maWcuanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcbmltcG9ydCB7XG4gIGZpeFR5cGUsXG4gIGlzQ29ycmVjdEpTT04sXG4gIGlzT2JqZWN0RW1wdHksXG4gIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQsXG4gIG9wdGlvbnNTdHJpbmdpZnksXG4gIG1lYXN1cmVUaW1lXG59IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcblxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xuY29uc3QgcmV2ZXJzZWRNaW1lID0ge1xuICBwbmc6ICdpbWFnZS9wbmcnLFxuICBqcGVnOiAnaW1hZ2UvanBlZycsXG4gIGdpZjogJ2ltYWdlL2dpZicsXG4gIHBkZjogJ2FwcGxpY2F0aW9uL3BkZicsXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXG59O1xuXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxubGV0IHJlcXVlc3RzQ291bnRlciA9IDA7XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XG5jb25zdCBiZWZvcmVSZXF1ZXN0ID0gW107XG5cbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcbmNvbnN0IGFmdGVyUmVxdWVzdCA9IFtdO1xuXG4vKipcbiAqIEludm9rZXMgYW4gYXJyYXkgb2YgY2FsbGJhY2sgZnVuY3Rpb25zIHdpdGggc3BlY2lmaWVkIHBhcmFtZXRlcnMsIGFsbG93aW5nXG4gKiBjdXN0b21pemF0aW9uIG9mIHJlcXVlc3QgaGFuZGxpbmcuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbltdfSBjYWxsYmFja3MgLSBBbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnNcbiAqIHRvIGJlIGV4ZWN1dGVkLlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzcG9uc2UgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge09iamVjdH0gZGF0YSAtIEFuIG9iamVjdCBjb250YWluaW5nIHBhcmFtZXRlcnMgbGlrZSBpZCwgdW5pcXVlSWQsXG4gKiB0eXBlLCBhbmQgYm9keS5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIGEgYm9vbGVhbiBpbmRpY2F0aW5nIHRoZSBvdmVyYWxsIHJlc3VsdFxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxuICovXG5jb25zdCBkb0NhbGxiYWNrcyA9IChjYWxsYmFja3MsIHJlcXVlc3QsIHJlc3BvbnNlLCBkYXRhKSA9PiB7XG4gIGxldCByZXN1bHQgPSB0cnVlO1xuICBjb25zdCB7IGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSB9ID0gZGF0YTtcblxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcbiAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgIGxldCBjYWxsUmVzcG9uc2UgPSBjYWxsYmFjayhyZXF1ZXN0LCByZXNwb25zZSwgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5KTtcblxuICAgICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdW5kZWZpbmVkICYmIGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xuICAgICAgICByZXN1bHQgPSBjYWxsUmVzcG9uc2U7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbiAgfSk7XG5cbiAgcmV0dXJuIHJlc3VsdDtcbn07XG5cbi8qKlxuICogSGFuZGxlcyB0aGUgZXhwb3J0IHJlcXVlc3RzIGZyb20gdGhlIGNsaWVudC5cbiAqXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSAtIEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIG9uY2UgdGhlIGV4cG9ydCBwcm9jZXNzXG4gKiBpcyBjb21wbGV0ZS5cbiAqL1xuY29uc3QgZXhwb3J0SGFuZGxlciA9IGFzeW5jIChyZXF1ZXN0LCByZXNwb25zZSwgbmV4dCkgPT4ge1xuICB0cnkge1xuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcbiAgICBjb25zdCBzdG9wQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG5cbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxuICAgIGNvbnN0IHVuaXF1ZUlkID0gdXVpZCgpLnJlcGxhY2UoLy0vZywgJycpO1xuXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xuICAgIGNvbnN0IGRlZmF1bHRPcHRpb25zID0gZ2V0T3B0aW9ucygpO1xuXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcbiAgICBjb25zdCBpZCA9ICsrcmVxdWVzdHNDb3VudGVyO1xuXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XG5cbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gYm9keVxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAnVGhlIHJlcXVlc3QgYm9keSBpcyByZXF1aXJlZC4gUGxlYXNlIGVuc3VyZSB0aGF0IHlvdXIgQ29udGVudC1UeXBlIGhlYWRlciBpcyBjb3JyZWN0IChhY2NlcHRlZCB0eXBlcyBhcmUgYXBwbGljYXRpb24vanNvbiBhbmQgbXVsdGlwYXJ0L2Zvcm0tZGF0YSkuJyxcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIEFsbCBvZiB0aGUgYmVsb3cgY2FuIGJlIHVzZWRcbiAgICBsZXQgaW5zdHIgPSBpc0NvcnJlY3RKU09OKGJvZHkuaW5maWxlIHx8IGJvZHkub3B0aW9ucyB8fCBib2R5LmRhdGEpO1xuXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIEpTT04gb3IgU1ZHIHRvIGV4cG9ydFxuICAgIGlmICghaW5zdHIgJiYgIWJvZHkuc3ZnKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgIGBUaGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IGZyb20gJHtcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXG4gICAgICAgIH0gd2FzIGluY29ycmVjdC4gUGF5bG9hZCByZWNlaXZlZDogJHtKU09OLnN0cmluZ2lmeShib2R5KX0uYFxuICAgICAgKTtcblxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgXCJObyBjb3JyZWN0IGNoYXJ0IGRhdGEgZm91bmQuIEVuc3VyZSB0aGF0IHlvdSBhcmUgdXNpbmcgZWl0aGVyIGFwcGxpY2F0aW9uL2pzb24gb3IgbXVsdGlwYXJ0L2Zvcm0tZGF0YSBoZWFkZXJzLiBJZiBzZW5kaW5nIEpTT04sIG1ha2Ugc3VyZSB0aGUgY2hhcnQgZGF0YSBpcyBpbiB0aGUgJ2luZmlsZScsICdvcHRpb25zJywgb3IgJ2RhdGEnIGF0dHJpYnV0ZS4gSWYgc2VuZGluZyBTVkcsIGVuc3VyZSBpdCBpcyBpbiB0aGUgJ3N2ZycgYXR0cmlidXRlLlwiLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgbGV0IGNhbGxSZXNwb25zZSA9IGZhbHNlO1xuXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXG4gICAgY2FsbFJlc3BvbnNlID0gZG9DYWxsYmFja3MoYmVmb3JlUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHtcbiAgICAgIGlkLFxuICAgICAgdW5pcXVlSWQsXG4gICAgICB0eXBlLFxuICAgICAgYm9keVxuICAgIH0pO1xuXG4gICAgLy8gQmxvY2sgdGhlIHJlcXVlc3QgaWYgb25lIG9mIGEgY2FsbGJhY2tzIGZhaWxlZFxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcbiAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGNhbGxSZXNwb25zZSk7XG4gICAgfVxuXG4gICAgbGV0IGNvbm5lY3Rpb25BYm9ydGVkID0gZmFsc2U7XG5cbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXG4gICAgcmVxdWVzdC5zb2NrZXQub24oJ2Nsb3NlJywgKCkgPT4ge1xuICAgICAgY29ubmVjdGlvbkFib3J0ZWQgPSB0cnVlO1xuICAgIH0pO1xuXG4gICAgbG9nKDQsIGBbZXhwb3J0XSBHb3QgYW4gaW5jb21pbmcgSFRUUCByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0uYCk7XG5cbiAgICBib2R5LmNvbnN0ciA9ICh0eXBlb2YgYm9keS5jb25zdHIgPT09ICdzdHJpbmcnICYmIGJvZHkuY29uc3RyKSB8fCAnY2hhcnQnO1xuXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcbiAgICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHtcbiAgICAgIGV4cG9ydDoge1xuICAgICAgICBpbnN0cixcbiAgICAgICAgdHlwZSxcbiAgICAgICAgY29uc3RyOiBib2R5LmNvbnN0clswXS50b0xvd2VyQ2FzZSgpICsgYm9keS5jb25zdHIuc3Vic3RyKDEpLFxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxuICAgICAgICB3aWR0aDogYm9keS53aWR0aCxcbiAgICAgICAgc2NhbGU6IGJvZHkuc2NhbGUgfHwgZGVmYXVsdE9wdGlvbnMuZXhwb3J0LnNjYWxlLFxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXG4gICAgICAgIHRoZW1lT3B0aW9uczogaXNDb3JyZWN0SlNPTihib2R5LnRoZW1lT3B0aW9ucywgdHJ1ZSlcbiAgICAgIH0sXG4gICAgICBjdXN0b21Mb2dpYzoge1xuICAgICAgICBhbGxvd0NvZGVFeGVjdXRpb246IGdldEFsbG93Q29kZUV4ZWN1dGlvbigpLFxuICAgICAgICBhbGxvd0ZpbGVSZXNvdXJjZXM6IGZhbHNlLFxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxuICAgICAgICBjYWxsYmFjazogYm9keS5jYWxsYmFjayxcbiAgICAgICAgY3VzdG9tQ29kZTogYm9keS5jdXN0b21Db2RlXG4gICAgICB9XG4gICAgfTtcblxuICAgIGlmIChpbnN0cikge1xuICAgICAgLy8gU3RyaW5naWZ5IEpTT04gd2l0aCBvcHRpb25zXG4gICAgICByZXF1ZXN0T3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zU3RyaW5naWZ5KFxuICAgICAgICBpbnN0cixcbiAgICAgICAgcmVxdWVzdE9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIE1lcmdlIHRoZSByZXF1ZXN0IG9wdGlvbnMgaW50byBkZWZhdWx0IG9uZXNcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XG5cbiAgICAvLyBTYXZlIHRoZSBKU09OIGlmIGV4aXN0c1xuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcblxuICAgIC8vIExhc3RseSwgYWRkIHRoZSBzZXJ2ZXIgc3BlY2lmaWMgYXJndW1lbnRzIGludG8gb3B0aW9ucyBhcyBwYXlsb2FkXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xuICAgICAgc3ZnOiBib2R5LnN2ZyB8fCBmYWxzZSxcbiAgICAgIGI2NDogYm9keS5iNjQgfHwgZmFsc2UsXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXG4gICAgICByZXF1ZXN0SWQ6IHVuaXF1ZUlkXG4gICAgfTtcblxuICAgIC8vIFRlc3QgeGxpbms6aHJlZiBlbGVtZW50cyBmcm9tIHBheWxvYWQncyBTVkdcbiAgICBpZiAoYm9keS5zdmcgJiYgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZChvcHRpb25zLnBheWxvYWQuc3ZnKSkge1xuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgJ1NWRyBwb3RlbnRpYWxseSBjb250YWluIGF0IGxlYXN0IG9uZSBmb3JiaWRkZW4gVVJMIGluIHhsaW5rOmhyZWYgZWxlbWVudC4gUGxlYXNlIHJldmlldyB0aGUgU1ZHIGNvbnRlbnQgYW5kIGVuc3VyZSB0aGF0IGFsbCByZWZlcmVuY2VkIFVSTHMgY29tcGx5IHdpdGggc2VjdXJpdHkgcG9saWNpZXMuJyxcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xuICAgIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIChlcnJvciwgaW5mbykgPT4ge1xuICAgICAgLy8gUmVtb3ZlIHRoZSBjbG9zZSBldmVudCBmcm9tIHRoZSBzb2NrZXRcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcblxuICAgICAgLy8gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xuICAgICAgICBsb2coXG4gICAgICAgICAgNSxcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiB0aGUgY29ubmVjdGlvbiB3YXMgY2xvc2VkLCBkbyBub3RoaW5nXG4gICAgICBpZiAoY29ubmVjdGlvbkFib3J0ZWQpIHtcbiAgICAgICAgcmV0dXJuIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbZXhwb3J0XSBUaGUgY2xpZW50IGNsb3NlZCB0aGUgY29ubmVjdGlvbiBiZWZvcmUgdGhlIGNoYXJ0IGZpbmlzaGVkIHByb2Nlc3NpbmcuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGRhdGEgaXMgbWlzc2luZywgbG9nIHRoZSBtZXNzYWdlIGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XG4gICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgYFVuZXhwZWN0ZWQgcmV0dXJuIGZyb20gY2hhcnQgZ2VuZXJhdGlvbi4gUGxlYXNlIGNoZWNrIHlvdXIgcmVxdWVzdCBkYXRhLiBGb3IgdGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSwgdGhlIHJlc3VsdCBpcyAke2luZm8ucmVzdWx0fS5gLFxuICAgICAgICAgIDQwMFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBHZXQgdGhlIHR5cGUgZnJvbSBvcHRpb25zXG4gICAgICB0eXBlID0gaW5mby5vcHRpb25zLmV4cG9ydC50eXBlO1xuXG4gICAgICAvLyBUaGUgYWZ0ZXIgcmVxdWVzdCBjYWxsYmFja3NcbiAgICAgIGRvQ2FsbGJhY2tzKGFmdGVyUmVxdWVzdCwgcmVxdWVzdCwgcmVzcG9uc2UsIHsgaWQsIGJvZHk6IGluZm8ucmVzdWx0IH0pO1xuXG4gICAgICBpZiAoaW5mby5yZXN1bHQpIHtcbiAgICAgICAgLy8gSWYgb25seSBiYXNlNjQgaXMgcmVxdWlyZWQsIHJldHVybiBpdFxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcbiAgICAgICAgICAvLyBTVkcgRXhjZXB0aW9uIGZvciB0aGUgSGlnaGNoYXJ0cyAxMS4zLjAgdmVyc2lvblxuICAgICAgICAgIGlmICh0eXBlID09PSAncGRmJyB8fCB0eXBlID09ICdzdmcnKSB7XG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcbiAgICAgICAgICAgICAgQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICd1dGY4JykudG9TdHJpbmcoJ2Jhc2U2NCcpXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNldCBjb3JyZWN0IGNvbnRlbnQgdHlwZVxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XG5cbiAgICAgICAgLy8gRGVjaWRlIHdoZXRoZXIgdG8gZG93bmxvYWQgb3Igbm90IGNoYXJ0IGZpbGVcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcbiAgICAgICAgICByZXNwb25zZS5hdHRhY2htZW50KFxuICAgICAgICAgICAgYCR7cmVxdWVzdC5wYXJhbXMuZmlsZW5hbWUgfHwgcmVxdWVzdC5ib2R5LmZpbGVuYW1lIHx8ICdjaGFydCd9LiR7XG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcbiAgICAgICAgICAgIH1gXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIElmIFNWRywgcmV0dXJuIHBsYWluIGNvbnRlbnRcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXG4gICAgICAgICAgPyByZXNwb25zZS5zZW5kKGluZm8ucmVzdWx0KVxuICAgICAgICAgIDogcmVzcG9uc2Uuc2VuZChCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBuZXh0KGVycm9yKTtcbiAgfVxufTtcblxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xuICAvKipcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXG4gICAqL1xuICBhcHAucG9zdCgnLycsIGV4cG9ydEhhbmRsZXIpO1xuXG4gIC8qKlxuICAgKiBBZGRzIHRoZSBQT1NUIC86ZmlsZW5hbWUgYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyB3aXRoXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cbiAgICovXG4gIGFwcC5wb3N0KCcvOmZpbGVuYW1lJywgZXhwb3J0SGFuZGxlcik7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGpvaW4gYXMgcGF0aGVyIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xuXG5pbXBvcnQgeyB2ZXJzaW9uIH0gZnJvbSAnLi4vLi4vY2FjaGUuanMnO1xuaW1wb3J0IHsgYWRkSW50ZXJ2YWwgfSBmcm9tICcuLi8uLi9pbnRlcnZhbHMuanMnO1xuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG5cbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcblxuY29uc3Qgc2VydmVyU3RhcnRUaW1lID0gbmV3IERhdGUoKTtcblxuY29uc3Qgc3VjY2Vzc1JhdGVzID0gW107XG5jb25zdCByZWNvcmRJbnRlcnZhbCA9IDYwICogMTAwMDsgLy8gcmVjb3JkIGV2ZXJ5IG1pbnV0ZVxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXG5cbi8qKlxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXG4gKiBhcnJheS5cbiAqXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxuICovXG5mdW5jdGlvbiBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCkge1xuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XG4gIHJldHVybiBzdW0gLyBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xufVxuXG4vKipcbiAqIFN0YXJ0cyB0aGUgaW50ZXJ2YWwgcmVzcG9uc2libGUgZm9yIGNhbGN1bGF0aW5nIGN1cnJlbnQgc3VjY2VzcyByYXRlIHJhdGlvXG4gKiBhbmQgZ2F0aGVyc1xuICpcbiAqIEByZXR1cm5zIHtOb2RlSlMuVGltZW91dH0gaWQgLSBJZCBvZiBhbiBpbnRlcnZhbC5cbiAqL1xuZXhwb3J0IGNvbnN0IHN0YXJ0U3VjY2Vzc1JhdGUgPSAoKSA9PlxuICBzZXRJbnRlcnZhbCgoKSA9PiB7XG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XG4gICAgY29uc3Qgc3VjY2Vzc1JhdGlvID1cbiAgICAgIHN0YXRzLmV4cG9ydEF0dGVtcHRzID09PSAwXG4gICAgICAgID8gMVxuICAgICAgICA6IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwO1xuXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcbiAgICBpZiAoc3VjY2Vzc1JhdGVzLmxlbmd0aCA+IHdpbmRvd1NpemUpIHtcbiAgICAgIHN1Y2Nlc3NSYXRlcy5zaGlmdCgpO1xuICAgIH1cbiAgfSwgcmVjb3JkSW50ZXJ2YWwpO1xuXG4vKipcbiAqIEFkZHMgdGhlIC9oZWFsdGggYW5kIC9zdWNjZXNzLW1vdmluZy1hdmVyYWdlIHJvdXRlc1xuICogd2hpY2ggb3V0cHV0IGJhc2ljIHN0YXRzIGZvciB0aGUgc2VydmVyLlxuICovXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiBhZGRIZWFsdGhSb3V0ZXMoYXBwKSB7XG4gIGlmICghYXBwKSB7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxuICAvLyBmb3IgdGhlIGdyYWNlZnVsIGNsZWFyaW5nIG9uIHNodXRkb3duIHdpdGggaW5qZWN0ZWQgYWRkSW50ZXJ2YWwgZnVudGlvblxuICBhZGRJbnRlcnZhbChzdGFydFN1Y2Nlc3NSYXRlKCkpO1xuXG4gIGFwcC5nZXQoJy9oZWFsdGgnLCAoXywgcmVzKSA9PiB7XG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcbiAgICBjb25zdCBtb3ZpbmdBdmVyYWdlID0gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpO1xuXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xuXG4gICAgcmVzLnNlbmQoe1xuICAgICAgc3RhdHVzOiAnT0snLFxuICAgICAgYm9vdFRpbWU6IHNlcnZlclN0YXJ0VGltZSxcbiAgICAgIHVwdGltZTpcbiAgICAgICAgTWF0aC5mbG9vcihcbiAgICAgICAgICAobmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzZXJ2ZXJTdGFydFRpbWUuZ2V0VGltZSgpKSAvIDEwMDAgLyA2MFxuICAgICAgICApICsgJyBtaW51dGVzJyxcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcbiAgICAgIGhpZ2hjaGFydHNWZXJzaW9uOiB2ZXJzaW9uKCksXG4gICAgICBhdmVyYWdlUHJvY2Vzc2luZ1RpbWU6IHN0YXRzLnNwZW50QXZlcmFnZSxcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXG4gICAgICBmYWlsZWRFeHBvcnRzOiBzdGF0cy5kcm9wcGVkRXhwb3J0cyxcbiAgICAgIGV4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRBdHRlbXB0cyxcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcbiAgICAgIHBvb2w6IHBvb2wuZ2V0UG9vbEluZm9KU09OKCksXG5cbiAgICAgIC8vIE1vdmluZyBhdmVyYWdlXG4gICAgICBwZXJpb2QsXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgaXNOYU4obW92aW5nQXZlcmFnZSkgfHwgIXN1Y2Nlc3NSYXRlcy5sZW5ndGhcbiAgICAgICAgICA/ICdUb28gZWFybHkgdG8gcmVwb3J0LiBObyBleHBvcnRzIG1hZGUgeWV0LiBQbGVhc2UgY2hlY2sgYmFjayBzb29uLidcbiAgICAgICAgICA6IGBMYXN0ICR7cGVyaW9kfSBtaW51dGVzIGhhZCBhIHN1Y2Nlc3MgcmF0ZSBvZiAke21vdmluZ0F2ZXJhZ2UudG9GaXhlZCgyKX0lLmAsXG5cbiAgICAgIC8vIFNWRy9KU09OIGF0dGVtcHRzXG4gICAgICBzdmdFeHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzLFxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXG4gICAgfSk7XG4gIH0pO1xufVxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBwb3NpeCB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcbmltcG9ydCBleHByZXNzIGZyb20gJ2V4cHJlc3MnO1xuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xuaW1wb3J0IG11bHRlciBmcm9tICdtdWx0ZXInO1xuXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICcuL3JhdGVfbGltaXQuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xuXG5pbXBvcnQgdlN3aXRjaFJvdXRlIGZyb20gJy4vcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzJztcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcbmltcG9ydCBoZWFsdGhSb3V0ZSBmcm9tICcuL3JvdXRlcy9oZWFsdGguanMnO1xuaW1wb3J0IHVpUm91dGUgZnJvbSAnLi9yb3V0ZXMvdWkuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi4vZXJyb3JzL0V4cG9ydEVycm9yLmpzJztcblxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcbmNvbnN0IGFjdGl2ZVNlcnZlcnMgPSBuZXcgTWFwKCk7XG5cbi8vIENyZWF0ZSBleHByZXNzIGFwcFxuY29uc3QgYXBwID0gZXhwcmVzcygpO1xuXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXG5hcHAuZGlzYWJsZSgneC1wb3dlcmVkLWJ5Jyk7XG5cbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcbmFwcC51c2UoY29ycygpKTtcblxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxuY29uc3Qgc3RvcmFnZSA9IG11bHRlci5tZW1vcnlTdG9yYWdlKCk7XG5jb25zdCB1cGxvYWQgPSBtdWx0ZXIoe1xuICBzdG9yYWdlLFxuICBsaW1pdHM6IHtcbiAgICBmaWVsZFNpemU6IDUwICogMTAyNCAqIDEwMjRcbiAgfVxufSk7XG5cbi8vIEVuYWJsZSBib2R5IHBhcnNlclxuYXBwLnVzZShleHByZXNzLmpzb24oeyBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XG5hcHAudXNlKGV4cHJlc3MudXJsZW5jb2RlZCh7IGV4dGVuZGVkOiB0cnVlLCBsaW1pdDogNTAgKiAxMDI0ICogMTAyNCB9KSk7XG5cbi8vIFVzZSBvbmx5IG5vbi1maWxlIG11bHRpcGFydCBmb3JtIGZpZWxkc1xuYXBwLnVzZSh1cGxvYWQubm9uZSgpKTtcblxuLyoqXG4gKiBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgdG8gdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge2h0dHAuU2VydmVyfSBzZXJ2ZXIgLSBUaGUgSFRUUC9IVFRQUyBzZXJ2ZXIgaW5zdGFuY2UuXG4gKi9cbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XG4gIHNlcnZlci5vbignY2xpZW50RXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBDbGllbnQgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfSk7XG5cbiAgc2VydmVyLm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICB9KTtcblxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XG4gICAgc29ja2V0Lm9uKCdlcnJvcicsIChlcnJvcikgPT4ge1xuICAgICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gU29ja2V0IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gICAgfSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBTdGFydHMgYW4gSFRUUCBzZXJ2ZXIgYmFzZWQgb24gdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24uIFRoZSBgc2VydmVyQ29uZmlnYFxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cbiAqIGluIHRoZSBgbGliL3NjaGVtYXMvY29uZmlnLmpzYCBmaWxlIGZvciBhIHJlZmVyZW5jZSkuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IC0gVGhyb3dzIGFuIGVycm9yIGlmIHRoZSBzZXJ2ZXIgY2Fubm90IGJlIGNvbmZpZ3VyZWRcbiAqIGFuZCBzdGFydGVkLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRTZXJ2ZXIgPSBhc3luYyAoc2VydmVyQ29uZmlnKSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gU3RvcCBpZiBub3QgZW5hYmxlZFxuICAgIGlmICghc2VydmVyQ29uZmlnLmVuYWJsZSkge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cblxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxuICAgIGlmICghc2VydmVyQ29uZmlnLnNzbC5mb3JjZSkge1xuICAgICAgLy8gTWFpbiBzZXJ2ZXIgaW5zdGFuY2UgKEhUVFApXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcblxuICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcblxuICAgICAgLy8gTGlzdGVuXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgICAvLyBTYXZlIHRoZSByZWZlcmVuY2UgdG8gSFRUUCBzZXJ2ZXJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcblxuICAgICAgbG9nKFxuICAgICAgICAzLFxuICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQIHNlcnZlciBvbiAke3NlcnZlckNvbmZpZy5ob3N0fToke3NlcnZlckNvbmZpZy5wb3J0fS5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIExpc3RlbiBIVFRQUyBzZXJ2ZXJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcbiAgICAgIC8vIFNldCB1cCBhbiBTU0wgc2VydmVyIGFsc29cbiAgICAgIGxldCBrZXksIGNlcnQ7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIEdldCB0aGUgU1NMIGtleVxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5rZXknKSxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBjZXJ0aWZpY2F0ZVxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIuY3J0JyksXG4gICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMixcbiAgICAgICAgICBgW3NlcnZlcl0gVW5hYmxlIHRvIGxvYWQga2V5L2NlcnRpZmljYXRlIGZyb20gdGhlICcke3NlcnZlckNvbmZpZy5zc2wuY2VydFBhdGh9JyBwYXRoLiBDb3VsZCBub3QgcnVuIHNlY3VyZWQgbGF5ZXIgc2VydmVyLmBcbiAgICAgICAgKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGtleSAmJiBjZXJ0KSB7XG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcbiAgICAgICAgY29uc3QgaHR0cHNTZXJ2ZXIgPSBodHRwcy5jcmVhdGVTZXJ2ZXIoeyBrZXksIGNlcnQgfSwgYXBwKTtcblxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXG4gICAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cHNTZXJ2ZXIpO1xuXG4gICAgICAgIC8vIExpc3RlblxuICAgICAgICBodHRwc1NlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBzZXJ2ZXJDb25maWcuaG9zdCk7XG5cbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxuICAgICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIGh0dHBzU2VydmVyKTtcblxuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW3NlcnZlcl0gU3RhcnRlZCBIVFRQUyBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcuc3NsLnBvcnR9LmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBFbmFibGUgdGhlIHJhdGUgbGltaXRlciBpZiBjb25maWcgc2F5cyBzb1xuICAgIGlmIChcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcuZW5hYmxlICYmXG4gICAgICAhWzAsIE5hTl0uaW5jbHVkZXMoc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cylcbiAgICApIHtcbiAgICAgIHJhdGVMaW1pdChhcHAsIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcpO1xuICAgIH1cblxuICAgIC8vIFNldCB1cCBzdGF0aWMgZm9sZGVyJ3Mgcm91dGVcbiAgICBhcHAudXNlKGV4cHJlc3Muc3RhdGljKHBvc2l4LmpvaW4oX19kaXJuYW1lLCAncHVibGljJykpKTtcblxuICAgIC8vIFNldCB1cCByb3V0ZXNcbiAgICBoZWFsdGhSb3V0ZShhcHApO1xuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xuICAgIHVpUm91dGUoYXBwKTtcbiAgICB2U3dpdGNoUm91dGUoYXBwKTtcblxuICAgIC8vIFNldCB1cCBjZW50cmFsaXplZCBlcnJvciBoYW5kbGVyXG4gICAgZXJyb3JIYW5kbGVyKGFwcCk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgJ1tzZXJ2ZXJdIENvdWxkIG5vdCBjb25maWd1cmUgYW5kIHN0YXJ0IHRoZSBzZXJ2ZXIuJ1xuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIENsb3NlcyBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBjbG9zZVNlcnZlcnMgPSAoKSA9PiB7XG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2luZyBhbGwgc2VydmVycy5gKTtcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XG4gICAgc2VydmVyLmNsb3NlKCgpID0+IHtcbiAgICAgIGFjdGl2ZVNlcnZlcnMuZGVsZXRlKHBvcnQpO1xuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XG4gICAgfSk7XG4gIH1cbn07XG5cbi8qKlxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7QXJyYXl9IC0gU2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRTZXJ2ZXJzID0gKCkgPT4gYWN0aXZlU2VydmVycztcblxuLyoqXG4gKiBFbmFibGUgcmF0ZSBsaW1pdGluZyBmb3IgdGhlIHNlcnZlci5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cbiAqL1xuZXhwb3J0IGNvbnN0IGVuYWJsZVJhdGVMaW1pdGluZyA9IChsaW1pdENvbmZpZykgPT4gcmF0ZUxpbWl0KGFwcCwgbGltaXRDb25maWcpO1xuXG4vKipcbiAqIEdldCB0aGUgRXhwcmVzcyBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XG5cbi8qKlxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSAtIFRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEFwcCA9ICgpID0+IGFwcDtcblxuLyoqXG4gKiBBcHBseSBtaWRkbGV3YXJlKHMpIHRvIGEgc3BlY2lmaWMgcGF0aC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAudXNlKHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbi8qKlxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBHRVQgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxuICovXG5leHBvcnQgY29uc3QgZ2V0ID0gKHBhdGgsIC4uLm1pZGRsZXdhcmVzKSA9PiB7XG4gIGFwcC5nZXQocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuLyoqXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBwYXRoIC0gVGhlIHJvdXRlIHBhdGguXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxuICovXG5leHBvcnQgY29uc3QgcG9zdCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIHN0YXJ0U2VydmVyLFxuICBjbG9zZVNlcnZlcnMsXG4gIGdldFNlcnZlcnMsXG4gIGVuYWJsZVJhdGVMaW1pdGluZyxcbiAgZ2V0RXhwcmVzcyxcbiAgZ2V0QXBwLFxuICB1c2UsXG4gIGdldCxcbiAgcG9zdFxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuLyoqXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XG4gICFhcHBcbiAgICA/IGZhbHNlXG4gICAgOiBhcHAuZ2V0KCcvJywgKHJlcXVlc3QsIHJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XG4gICAgICB9KTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBjbGVhckFsbEludGVydmFscyB9IGZyb20gJy4vaW50ZXJ2YWxzLmpzJztcbmltcG9ydCB7IGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XG5cbi8qKlxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gZXhpdENvZGUgLSBBbiBleGl0IGNvZGUgZm9yIHRoZSBwcm9jZXNzLmV4aXQoKSBmdW5jdGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IHNodXRkb3duQ2xlYW5VcCA9IGFzeW5jIChleGl0Q29kZSkgPT4ge1xuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcbiAgICBjbGVhckFsbEludGVydmFscygpLFxuXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxuICAgIGNsb3NlU2VydmVycygpLFxuXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXG4gICAga2lsbFBvb2woKVxuICBdKTtcblxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBzaHV0ZG93bkNsZWFuVXBcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0ICdjb2xvcnMnO1xuXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzaW5nbGVFeHBvcnQsXG4gIHN0YXJ0RXhwb3J0XG59IGZyb20gJy4vY2hhcnQuanMnO1xuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7XG4gIGluaXRMb2dnaW5nLFxuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuLyoqXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cbiAqL1xuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cbiAqL1xuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICk7XG5cbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xuXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XG4gIH1cblxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XG5cbiAgLy8gSW5pdCB0aGUgcG9vbFxuICBhd2FpdCBpbml0UG9vbCh7XG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcbiAgICAgIG1pbldvcmtlcnM6IDEsXG4gICAgICBtYXhXb3JrZXJzOiAxXG4gICAgfSxcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlci5hcmdzIHx8IFtdXG4gIH0pO1xuXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcbiAgcmV0dXJuIG9wdGlvbnM7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIC8vIFNlcnZlclxuICBzZXJ2ZXIsXG4gIHN0YXJ0U2VydmVyLFxuXG4gIC8vIEV4cG9ydGluZ1xuICBpbml0RXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGJhdGNoRXhwb3J0LFxuICBzdGFydEV4cG9ydCxcblxuICAvLyBQb29sXG4gIGluaXRQb29sLFxuICBraWxsUG9vbCxcblxuICAvLyBPdGhlclxuICBzZXRPcHRpb25zLFxuICBzaHV0ZG93bkNsZWFuVXAsXG5cbiAgLy8gTG9nc1xuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuXG4gIC8vIFV0aWxzXG4gIG1hcFRvTmV3Q29uZmlnLFxuICBtYW51YWxDb25maWcsXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZVxufTtcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJjdXN0b20iLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInRvQ29uc29sZSIsInRvRmlsZSIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIkxPR0dJTkdfVE9fQ09OU09MRSIsIkxPR0dJTkdfVE9fRklMRSIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwib3B0aW9uIiwiZW50cmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiRnVuY3Rpb24iLCJjaGFydCIsImFuaW1hdGlvbiIsInN0ckluaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsImlubmVySFRNTCIsInNldFBhZ2VFdmVudHMiLCJjbGVhclBhZ2VSZXNvdXJjZXMiLCJpbmplY3RlZFJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsImV2YWx1YXRlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJyZW1vdmUiLCJzZXRDb250ZW50Iiwid2FpdFVudGlsIiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiYWRkUGFnZVJlc291cmNlcyIsInNpemUiLCJzdmdFbGVtZW50IiwicXVlcnlTZWxlY3RvciIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJib2R5Iiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJ4IiwieSIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiY2xvc2UiLCJpbml0UG9vbCIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiY3JlYXRlQnJvd3NlciIsInBhcnNlSW50IiwiUG9vbCIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInZTd2l0Y2hSb3V0ZSIsInBvc3QiLCJhZG1pblRva2VuIiwidG9rZW4iLCJuZXdWZXJzaW9uIiwicGFyYW1zIiwidXBkYXRlVmVyc2lvbiIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwibG9nZ2luZ09wdGlvbnMiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSx1QkFDQSxnQkFFQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVBQ0EseUJBQ0EsU0FDQSxlQUNBLFlBQ0Esa0JBQ0EsU0FDQSxjQUNBLG1CQUNBLGVBQ0Esa0JBQ0EsY0FDQSxlQUVBLGNBQ0EsV0FDQSxlQUNBLFdBQ0EsU0FDQSxPQUNBLFdBQ0EsWUFDQSxTQUNBLHFCQUNBLGFBQ0EsV0FDQSxXQUNBLFdBQ0EsV0FDQSxlQUNBLFVBQ0Esa0JBQ0Esb0JBQ0EsYUFDQSxVQUNBLGNBQ0EsWUFDQSxZQUVGQyxXQUFZLENBQUMsa0JBQ2JDLE9BQVEsQ0FDTix3RUFDQSxtR0FNU0MsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLENBQ0wsbUNBQ0Esa0JBQ0EsMENBQ0EsMkJBQ0Esa0NBQ0Esa0NBQ0Esd0NBQ0EsMkNBQ0EscUJBQ0EsNEJBQ0EsMkNBQ0EsdURBQ0EsNkJBQ0EseUJBQ0EsMEJBQ0EsK0JBQ0EsdUJBQ0EsdUZBQ0EseUJBQ0Esb0NBQ0Esb0JBQ0EsMEJBQ0EsOENBQ0EsMkJBQ0EsMEJBQ0EsNkJBQ0EsbUNBQ0Esd0NBQ0EsbUNBQ0EsMkJBQ0Esa0NBQ0EsdUJBQ0EsaUJBQ0EseUJBQ0EsOEJBQ0Esb0JBQ0EsMkJBQ0EsZUFDQSw2QkFDQSxpQkFDQSxhQUNBLGVBQ0Esc0JBQ0EsY0FDQSx5QkFDQSxvQkFDQSx1QkFFRkMsS0FBTSxXQUNOQyxZQUFhLDBDQUdqQkMsV0FBWSxDQUNWQyxRQUFTLENBQ1BKLE1BQU8sU0FDUEMsS0FBTSxT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 +"use strict";require("colors");var e=require("fs"),t=require("path"),o=require("https-proxy-agent"),r=require("prompts"),i=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),u=require("puppeteer"),d=require("jsdom"),h=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),y=require("express-rate-limit"),v="undefined"!=typeof document?document.currentScript:null;const b={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","parallel-coordinates","accessibility","boost-canvas","boost","data","data-tools","draggable-points","static-scale","broken-axis","heatmap","tilemap","tiledwebmap","timeline","treemap","treegraph","item-series","drilldown","histogram-bellcurve","bullet","funnel","funnel3d","geoheatmap","pyramid3d","networkgraph","overlapping-datalabels","pareto","pattern-fill","pictorial","price-indicator","sankey","arc-diagram","dependency-wheel","series-label","series-on-point","solid-gauge","sonification","streamgraph","sunburst","variable-pie","variwide","vector","venn","windbarb","wordcloud","xrange","no-data-to-display","drag-panes","debugger","dumbbell","lollipop","cylinder","organization","dotplot","marker-clusters","hollowcandlestick","heikinashi","flowmap","export-data","navigator","textpath"],indicators:["indicators-all"],custom:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js"]},w={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:b.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:b.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:b.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:b.custom,type:"string[]",description:"Additional custom scripts or dependencies to fetch."},forceFetch:{value:!1,type:"boolean",envLink:"HIGHCHARTS_FORCE_FETCH",description:"The flag to determine whether to refetch all scripts after each server rerun."},cachePath:{value:".cache",type:"string",envLink:"HIGHCHARTS_CACHE_PATH",description:"The path to the cache directory. It is used to store the Highcharts scripts and custom scripts."}},export:{infile:{value:!1,type:"string",description:"The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file."},instr:{value:!1,type:"string",description:"Input, provided in the form of a stringified JSON or SVG file, will override the --infile option."},options:{value:!1,type:"string",description:"An alias for the --instr option."},outfile:{value:!1,type:"string",description:"The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag."},type:{value:"png",type:"string",envLink:"EXPORT_TYPE",description:"The file export format. It can be jpeg, png, pdf, or svg."},constr:{value:"chart",type:"string",envLink:"EXPORT_CONSTR",description:"The constructor to use. Can be chart, stockChart, mapChart, or ganttChart."},defaultHeight:{value:400,type:"number",envLink:"EXPORT_DEFAULT_HEIGHT",description:"the default height of the exported chart. Used when no value is set."},defaultWidth:{value:600,type:"number",envLink:"EXPORT_DEFAULT_WIDTH",description:"The default width of the exported chart. Used when no value is set."},defaultScale:{value:1,type:"number",envLink:"EXPORT_DEFAULT_SCALE",description:"The default scale of the exported chart. Used when no value is set."},height:{value:!1,type:"number",description:"The height of the exported chart, overriding the option in the chart settings."},width:{value:!1,type:"number",description:"The width of the exported chart, overriding the option in the chart settings."},scale:{value:!1,type:"number",description:"The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0."},globalOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions."},themeOptions:{value:!1,type:"string",description:"Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions."},batch:{value:!1,type:"string",description:'Initiates a batch job with a string containing input/output pairs: "in=out;in=out;...".'},rasterizationTimeout:{value:1500,type:"number",envLink:"EXPORT_RASTERIZATION_TIMEOUT",description:"The duration in milliseconds to wait for rendering a webpage."}},customLogic:{allowCodeExecution:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_CODE_EXECUTION",description:"Controls whether the execution of arbitrary code is allowed during the exporting process."},allowFileResources:{value:!1,type:"boolean",envLink:"CUSTOM_LOGIC_ALLOW_FILE_RESOURCES",description:"Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server."},customCode:{value:!1,type:"string",description:"Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension."},callback:{value:!1,type:"string",description:"JavaScript code to run during construction. It can be a function or a filename with the .js extension."},resources:{value:!1,type:"string",description:"Additional resource in the form of a stringified JSON, which may contain files, js, and css sections."},loadConfig:{value:!1,type:"string",legacyName:"fromFile",description:"A file containing a pre-defined configuration to use."},createConfig:{value:!1,type:"string",description:"Enables setting options through a prompt and saving them in a provided config file."}},server:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},E={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:w.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:w.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:w.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:w.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:w.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:w.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:w.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${w.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${w.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:w.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:w.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:w.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:w.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:w.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:w.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:w.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:w.server.host.value},{type:"number",name:"port",message:"Server port",initial:w.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:w.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:w.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:w.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:w.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:w.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:w.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:w.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:w.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:w.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:w.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:w.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:w.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:w.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:w.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:w.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:w.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:w.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:w.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:w.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:w.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:w.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:w.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:w.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:w.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:w.pool.benchmarking.value}],logging:[{type:"number",name:"level",message:"The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)",initial:w.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with --toFile and --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:w.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:w.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:w.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:w.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:w.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:w.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:w.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:w.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:w.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:w.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:w.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:w.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:w.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:w.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:w.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:w.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:w.debug.debuggingPort.value}]},T=["options","globalOptions","themeOptions","resources","payload"],S={},O=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?O(r,`${t}.${o}`):(S[r.cliName||o]=`${t}.${o}`.substring(1),void 0!==r.legacyName&&(S[r.legacyName]=`${t}.${o}`.substring(1)))}}))};O(w),i.config();const x=e=>s.z.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),R=()=>s.z.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),L=e=>s.z.enum([...e,""]).transform((e=>""!==e?e:void 0)),_=()=>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=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),I=()=>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)),C=s.z.object({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:x(b.core),HIGHCHARTS_MODULE_SCRIPTS:x(b.modules),HIGHCHARTS_INDICATOR_SCRIPTS:x(b.indicators),HIGHCHARTS_FORCE_FETCH:R(),HIGHCHARTS_CACHE_PATH:_(),HIGHCHARTS_ADMIN_TOKEN:_(),EXPORT_TYPE:L(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:L(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:k(),EXPORT_DEFAULT_WIDTH:k(),EXPORT_DEFAULT_SCALE:k(),EXPORT_RASTERIZATION_TIMEOUT:I(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:R(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:R(),SERVER_ENABLE:R(),SERVER_HOST:_(),SERVER_PORT:k(),SERVER_BENCHMARKING:R(),SERVER_PROXY_HOST:_(),SERVER_PROXY_PORT:k(),SERVER_PROXY_TIMEOUT:I(),SERVER_RATE_LIMITING_ENABLE:R(),SERVER_RATE_LIMITING_MAX_REQUESTS:I(),SERVER_RATE_LIMITING_WINDOW:I(),SERVER_RATE_LIMITING_DELAY:I(),SERVER_RATE_LIMITING_TRUST_PROXY:R(),SERVER_RATE_LIMITING_SKIP_KEY:_(),SERVER_RATE_LIMITING_SKIP_TOKEN:_(),SERVER_SSL_ENABLE:R(),SERVER_SSL_FORCE:R(),SERVER_SSL_PORT:k(),SERVER_SSL_CERT_PATH:_(),POOL_MIN_WORKERS:I(),POOL_MAX_WORKERS:I(),POOL_WORK_LIMIT:k(),POOL_ACQUIRE_TIMEOUT:I(),POOL_CREATE_TIMEOUT:I(),POOL_DESTROY_TIMEOUT:I(),POOL_IDLE_TIMEOUT:I(),POOL_CREATE_RETRY_INTERVAL:I(),POOL_REAPER_INTERVAL:I(),POOL_BENCHMARKING:R(),POOL_RESOURCES_INTERVAL:I(),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:_(),LOGGING_DEST:_(),LOGGING_TO_CONSOLE:R(),LOGGING_TO_FILE:R(),UI_ENABLE:R(),UI_ROUTE:_(),OTHER_NODE_ENV:L(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:R(),OTHER_NO_LOGO:R(),OTHER_HARD_RESET_PAGE:R(),OTHER_BROWSER_SHELL_MODE:R(),OTHER_CONNECTION_OVER_PIPE:R(),DEBUG_ENABLE:R(),DEBUG_HEADLESS:R(),DEBUG_DEVTOOLS:R(),DEBUG_LISTEN_TO_CONSOLE:R(),DEBUG_DUMPIO:R(),DEBUG_SLOW_MO:I(),DEBUG_DEBUGGING_PORT:k()}).partial().parse(process.env),N=["red","yellow","blue","gray","green"];let P={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:N[0]},{title:"warning",color:N[1]},{title:"notice",color:N[2]},{title:"verbose",color:N[3]},{title:"benchmark",color:N[4]}],listeners:[]};const A=(t,o)=>{P.pathCreated||(!e.existsSync(P.dest)&&e.mkdirSync(P.dest),P.pathCreated=!0),e.appendFile(`${P.dest}${P.file}`,[o].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),P.toFile=!1)}))},H=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=P;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;P.listeners.forEach((e=>{e(s,o.join(" "))})),P.toConsole&&console.log.apply(void 0,[s.toString()[P.levelsDesc[t-1].color]].concat(o)),P.toFile&&A(o,s)},$=(e,t,o)=>{const r=o||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=[r,"\n",a];P.toConsole&&console.log.apply(void 0,[n.toString()[P.levelsDesc[e-1].color]].concat([r[N[e-1]],"\n",a])),P.listeners.forEach((e=>{e(n,l.join(" "))})),P.toFile&&A(l,n)},G=e=>{e>=0&&e<=P.levelsDesc.length&&(P.level=e)},F=(e,t)=>{if(P={...P,dest:e||P.dest,file:t||P.file,toFile:!0},0===P.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");P.dest.endsWith("/")||(P.dest+="/")},U=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:v&&"SCRIPT"===v.tagName.toUpperCase()&&v.src||new URL("index.cjs",document.baseURI).href)),D=async(e,t=0,...o)=>{try{return await e(...o)}catch(r){const i=2**t*1e3;if(++t>=6)throw r;return await new Promise((e=>setTimeout(e,i))),H(3,`[pool] Waited ${i}ms until next call for the resource of ID: ${o[0]}.`),D(e,t,...o)}},j=(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"},M=(t=!1,o)=>{const r=["js","css","files"];let i=t,s=!1;if(o&&t.endsWith(".json"))try{i=V(e.readFileSync(t,"utf8"))}catch(e){return $(2,e,"[cli] No resources found.")}else i=V(t),i&&!o&&delete i.files;for(const e in i)r.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):H(3,"[cli] No resources found.")};function V(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 q=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]=q(e[o]));return t},W=(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 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[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(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,o)=>{if(t&&"string"==typeof t)return(t=t.trim()).endsWith(".js")?!!o&&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,Q=(e,t,o=[])=>{const r=q(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]:Q(r[e],s,o);var i;return r};function Z(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?Z(i,s,`${o}.${r}`):(void 0!==s&&(i.value=s),i.envLink in C&&void 0!==C[i.envLink]&&(i.value=C[i.envLink]))}))}function ee(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:ee(r);return t}function te(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=te(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function oe(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?l:a)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}class re extends Error{constructor(e,t){super(),this.message=e,this.stackMessage=e,t&&(this.status=t)}setError(e){return this.error=e,e.name&&(this.name=e.name),!this.status&&e.statusCode&&(this.status=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,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),H(4,`[cache] Fetching script - ${e}.js`);const i=await oe(`${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 re(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`,500).setError(i);return H(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ae=async(t,r,i)=>{const s=t.version,n="latest"!==s&&s?`${s}/`:"",a=t.cdnURL||ie.cdnURL;H(3,`[cache] Updating cache version to Highcharts: ${n||"latest"}.`);const l={};try{return ie.sources=await(async(e,t,r,i,s)=>{let n;const a=i.host,l=i.port;if(a&&l)try{n=new o.HttpsProxyAgent({host:a,port:l})}catch(e){throw new re("[cache] Could not create a Proxy Agent.",500).setError(e)}const c=n?{agent:n,timeout:C.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>ne(`${e}`,c,s,!0))),...t.map((e=>ne(`${e}`,c,s))),...r.map((e=>ne(`${e}`,c)))];return(await Promise.all(p)).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,r,l),ie.hcVersion=se(ie),e.writeFileSync(i,ie.sources),l}catch(e){throw new re("[cache] Unable to update the local Highcharts cache.",500).setError(e)}},le=async o=>{const{highcharts:r,server:i}=o,s=ce();let n;const a=t.join(s,"manifest.json"),l=t.join(s,"sources.js");if(!e.existsSync(s)&&e.mkdirSync(s,{recursive:!0}),!e.existsSync(a)||r.forceFetch)H(3,"[cache] Fetching and caching Highcharts dependencies."),n=await ae(r,i.proxy,l);else{let t=!1;const o=JSON.parse(e.readFileSync(a));if(o.modules&&Array.isArray(o.modules)){const e={};o.modules.forEach((t=>e[t]=1)),o.modules=e}const{coreScripts:s,moduleScripts:c,indicatorScripts:p}=r,u=s.length+c.length+p.length;o.version!==r.version?(H(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),t=!0):Object.keys(o.modules||{}).length!==u?(H(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),t=!0):t=(c||[]).some((e=>{if(!o.modules[e])return H(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),t?n=await ae(r,i.proxy,l):(H(3,"[cache] Dependency cache is up to date, proceeding."),ie.sources=e.readFileSync(l,"utf8"),n=o.modules,ie.hcVersion=se(ie))}await(async(o,r)=>{const i={version:o.version,modules:r||{}};ie.activeManifest=i,H(3,"[cache] Writing a new manifest.");try{e.writeFileSync(t.join(ce(),"manifest.json"),JSON.stringify(i),"utf8")}catch(e){throw new re("[cache] Error writing the cache manifest.",400).setError(e)}})(r,n)},ce=()=>{const e=Y().highcharts.cachePath;return t.isAbsolute(e)?e:t.join(U,e)},pe=()=>ie.hcVersion;function ue(){Highcharts.animObject=function(){return{duration:0}}}async function de(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,u=JSON.parse(t.export.globalOptions);u&&s(u),Highcharts[t.export.constr||"chart"]("container",c,p);const d=r();for(const e in d)"function"!=typeof d[e]&&delete d[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const he=e.readFileSync(U+"/templates/template.html","utf8");let ge,me;async function fe(){try{H(3,"[browser] Restarting the browser connection."),ge&&!ge.connected&&(ge=await u.connect({browserWSEndpoint:me})),me=ge.wsEndpoint(),ge.on("disconnected",fe),H(3,"[browser] Browser reconnected successfully.")}catch(e){$(1,e,"[browser] Could not restore the browser connection, attempting to relaunch.");try{await ve()}catch(e){$(1,e,"[browser] Could not close the browser before relaunching (probably is already closed).")}await ye(Y().puppeteer.args||[]),H(3,"[browser] Browser relaunched successfully.")}}async function ye(e){const{debug:t,other:o}=Y(),{enable:r,...i}=t,s={headless:!o.browserShellMode||"shell",userDataDir:"./tmp/",args:e,pipe:C.OTHER_CONNECTION_OVER_PIPE,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...r&&i};if(!ge){let e=0;const t=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),ge=await u.launch(s);const t=await ge.pages();if(t)for(const e of t)await e.close();s.pipe||(me=ge.wsEndpoint(),ge.on("disconnected",fe))}catch(o){if($(1,o,"[browser] Failed to launch a browser instance."),!(e<25))throw o;H(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await t()}};try{await t(),"shell"===s.headless&&H(3,"[browser] Launched browser in shell mode."),r&&H(3,"[browser] Launched browser in debug mode.")}catch(e){throw new re("[browser] Maximum retries to open a browser instance reached.",500).setError(e)}if(!ge)throw new re("[browser] Cannot find a browser to open.",500)}return ge}async function ve(){ge&&ge.connected&&await ge.close(),ge=null,H(4,"[browser] Closed the browser.")}async function be(e){const t=(new Date).getTime();if(!ge||!ge.connected)throw new re("[browser] Browser is not yet connected.",500);if(e.page=await ge.newPage(),await e.page.setCacheEnabled(!1),await Ee(e.page),function(e){const{debug:t,pool:o}=Y();e.page.on("pageerror",(async t=>{await e.page.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

${t.toString()}`)})),t.enable&&t.listenToConsole&&e.page.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));!1===C.OTHER_CONNECTION_OVER_PIPE&&e.page.on("framedetached",(async t=>{const r=e.page.mainFrame();if(t===r&&r.detached&&e.workCount<=o.workLimit){H(3,`[browser] Pool resource [${e.id}] - Page's frame detached.`);try{D((async(e,t)=>{try{t.page.isClosed()||await t.page.close()}catch(t){H(3,`[browser] Pool resource [${e}] - Could not close the page with a detached frame.`)}await be(t)}),0,e.id,e)}catch(t){$(3,t,`[browser] Pool resource [${e.id}] - Could not create a new page.`),e.workCount=o.workLimit+1}}}))}(e),!e.page||e.page.isClosed())throw new re("The page is invalid or closed.",500);return H(3,`[pool] Pool resource [${e.id}] - Successfully created a worker, took ${(new Date).getTime()-t}ms.`),e}async function we(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){$(1,e,"[browser] Could not clear page's resources.")}}async function Ee(e){await e.setContent(he,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${ce()}/sources.js`}),await e.evaluate(ue)}const Te=async(e,t,o,r)=>e.evaluate(de,t,o,r);var Se=async(o,r,i)=>{let s=[];try{H(4,"[export] Determining export path.");const n=i.export,a=n?.options?.chart?.displayErrors&&ie.activeManifest.modules.debugger;let l;if(r.indexOf&&(r.indexOf("=0||r.indexOf("=0)){if(H(4,"[export] Treating as SVG."),"svg"===n.type)return r;l=!0,await o.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(r),{waitUntil:"domcontentloaded"})}else H(4,"[export] Treating as config."),n.strInj?await Te(o,{chart:{height:n.height,width:n.width}},i,a):(r.chart.height=n.height,r.chart.width=n.width,await Te(o,r,i,a));s=await async function(o,r){const i=[],s=r.customLogic.resources;if(s){const n=[];if(s.js&&n.push({content:s.js}),s.files)for(const t of s.files){const o=!t.startsWith("http");n.push(o?{content:e.readFileSync(t,"utf8")}:{url:t})}for(const e of n)try{i.push(await o.addScriptTag(e))}catch(e){$(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 o of e)o&&(o=o.replace("url(","").replace("@import","").replace(/"/g,"").replace(/'/g,"").replace(/;/,"").replace(/\)/g,"").trim(),o.startsWith("http")?a.push({url:o}):r.customLogic.allowFileResources&&a.push({path:t.join(U,o)}));a.push({content:s.css.replace(/@import\s*([^;]*);/g,"")||" "});for(const e of a)try{i.push(await o.addStyleTag(e))}catch(e){$(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return i}(o,i);const c=l?await o.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(n.scale)):await o.evaluate((()=>{const{chartHeight:e,chartWidth:t}=window.Highcharts.charts[0];return document.body.style.zoom=1,{chartHeight:e,chartWidth:t}})),p=Math.ceil(c.chartHeight||n.height),u=Math.ceil(c.chartWidth||n.width),{x:d,y:h}=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)}})))(o);let g;if(await o.setViewport({height:p,width:u,deviceScaleFactor:l?1:parseFloat(n.scale)}),"svg"===n.type)g=await(e=>e.$eval("#container svg:first-of-type",(e=>e.outerHTML)))(o);else if(["png","jpeg"].includes(n.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 re("Rasterization timeout",408))),i||1500)))]))(o,n.type,"base64",{width:u,height:p,x:d,y:h},n.rasterizationTimeout);else{if("pdf"!==n.type)throw new re(`[export] Unsupported output format ${n.type}.`,400);g=await(async(e,t,o,r,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:o,encoding:r}),new Promise(((e,t)=>setTimeout((()=>t(new re("Rasterization timeout",408))),i||1500)))])))(o,p,u,"base64",n.rasterizationTimeout)}return await we(o,s),g}catch(e){return await we(o,s),e}};const Oe=[],xe=e=>{Oe.push(e)},Re=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of Oe)clearInterval(e)};let Le=!1;const _e={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let ke={};const Ie={create:async()=>{try{const e={id:p.v4(),workCount:Math.round(Math.random()*(ke.workLimit/2))};return await be(e)}catch(e){throw new re("Error encountered when creating a new page.",500).setError(e)}},validate:async e=>{let t=!0;return ke.workLimit&&++e.workCount>ke.workLimit&&(H(3,`[pool] Pool resource [${e.id}] - Validation failed (exceeded the ${ke.workLimit} works limit).`),t=!1),e.page||(e.page.isClosed()&&H(3,`[pool] Pool resource [${e.id}] - Validation failed (page is closed or invalid).`),e.page.mainFrame().detached&&H(3,`[pool] Pool resource [${e.id}] - Validation failed (page's frame is detached).`),t=!1),t},destroy:async e=>{if(H(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page)try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){H(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`)}}},Ce=async e=>{if(ke=e&&e.pool?{...e.pool}:{},await ye(e.puppeteerArgs),H(3,`[pool] Initializing pool with workers: min ${ke.minWorkers}, max ${ke.maxWorkers}.`),Le)return H(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(ke.minWorkers)>parseInt(ke.maxWorkers)&&(ke.minWorkers=ke.maxWorkers);try{Le=new c.Pool({...Ie,min:parseInt(ke.minWorkers),max:parseInt(ke.maxWorkers),acquireTimeoutMillis:ke.acquireTimeout,createTimeoutMillis:ke.createTimeout,destroyTimeoutMillis:ke.destroyTimeout,idleTimeoutMillis:ke.idleTimeout,createRetryIntervalMillis:ke.createRetryInterval,reapIntervalMillis:ke.reaperInterval,propagateCreateError:!1}),Le.on("release",(async e=>{H(4,`[pool] Pool resource [${e.id}] - Releasing a worker.`),await async function(e,t=!1){try{e.page.isClosed()||(t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await Ee(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})))}catch(t){$(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=Y().pool.workLimit+1}}(e,!1)})),Le.on("destroySuccess",((e,t)=>{H(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const e=[];for(let t=0;t{Le.release(e)})),C.POOL_RESOURCES_INTERVAL&&xe((t=C.POOL_RESOURCES_INTERVAL,setInterval((async()=>{try{let e=Le.numUsed()+Le.numFree()+Le.numPendingCreates();for(;e++{let o;try{if(H(4,"[pool] Work received, starting to process."),++_e.exportAttempts,ke.benchmarking&&He(),!Le)throw new re("Work received, but pool has not been started.",500);const r=K();try{H(4,"[pool] Acquiring a worker handle."),o=await Le.acquire().promise,t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(H(4,"[pool] Acquired a worker handle."),!o.page)throw o.workCount=ke.workLimit+1,new re("Resolved worker page is invalid: the pool setup is wonky.",500);let i=(new Date).getTime();H(4,`[pool] Pool resource [${o.id}] - Starting work on this pool entry.`);const s=K(),n=await Se(o.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(o.workCount=ke.workLimit+1),new re((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&H(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Le.release(o);const a=(new Date).getTime()-i;return _e.timeSpent+=a,_e.spentAverage=_e.timeSpent/++_e.performedExports,H(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++_e.droppedExports,o&&Le.release(o),new re(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Le.min,max:Le.max,used:Le.numUsed(),available:Le.numFree(),allCreated:Le.numUsed()+Le.numFree(),pendingAcquires:Le.numPendingAcquires(),pendingCreates:Le.numPendingCreates(),pendingValidations:Le.numPendingValidations(),pendingDestroys:Le.pendingDestroys.length,absoluteAll:Le.numUsed()+Le.numFree()+Le.numPendingAcquires()+Le.numPendingCreates()+Le.numPendingValidations()+Le.pendingDestroys.length});function He(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:s,pendingCreates:n,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=Ae();H(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),H(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),H(5,`[pool] The number of used resources: ${o}.`),H(5,`[pool] The number of free resources: ${r}.`),H(5,`[pool] The number of all created (used and free) resources: ${i}.`),H(5,`[pool] The number of resources waiting to be acquired: ${s}.`),H(5,`[pool] The number of resources waiting to be created: ${n}.`),H(5,`[pool] The number of resources waiting to be validated: ${a}.`),H(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),H(5,`[pool] The number of all resources: ${c}.`)}var $e=Ae,Ge=()=>_e;let Fe=!1;const Ue=async(t,o)=>{H(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let o={};return e.svg?(o=q(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=Q(t,e,T),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(t,Y()),i=r.export;if(r.payload?.svg&&""!==r.payload.svg)try{H(4,"[chart] Attempting to export from a SVG input.");const e=Ve(function(e){const t=new d.JSDOM("").window;return h(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(r.payload.svg),r,o);return++_e.exportFromSvgAttempts,e}catch(e){return o(new re("[chart] Error loading SVG input.",400).setError(e))}if(i.infile&&i.infile.length)try{return H(4,"[chart] Attempting to export from an input file."),r.export.instr=e.readFileSync(i.infile,"utf8"),Ve(r.export.instr.trim(),r,o)}catch(e){return o(new re("[chart] Error loading input file.",400).setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return H(4,"[chart] Attempting to export from a raw input."),X(r.customLogic?.allowCodeExecution)?Me(r,o):"string"==typeof i.instr?Ve(i.instr.trim(),r,o):je(r,i.instr||i.options,o)}catch(e){return o(new re("[chart] Error loading raw input.",400).setError(e))}return o(new re("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))},De=e=>{const{chart:t,exporting:o}=e.export?.options||V(e.export?.instr),r=V(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},je=async(t,o,r,i)=>{let{export:s,customLogic:n}=t;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:Fe;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 o=e.readFileSync("resources.json","utf8");t.customLogic.resources=M(o,X(t.customLogic.allowFileResources))}catch(e){$(2,e,"[chart] Unable to load the default resources.json file.")}}else n=t.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return r(new re("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.",400));n.callback=!1,n.resources=!1,n.customCode=!1}if(o&&(o.chart=o.chart||{},o.exporting=o.exporting||{},o.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]={},$(2,e,`[chart] The '${t}' cannot be loaded.`)}})),n.allowCodeExecution)try{n.customCode=z(n.customCode,n.allowFileResources)}catch(e){$(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,$(2,e,"[chart] The 'callback' cannot be loaded.")}else n.callback=!1;t.export={...t.export,...De(t)};try{return r(!1,await Pe(s.strInj||o||i,t))}catch(e){return r(e)}},Me=(e,t)=>{try{let o,r=e.export.instr||e.export.options;return"string"!=typeof r&&(o=r=W(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,je(e,!1,t)}catch(o){return t(new re(`[chart] Malformed input detected for ${e.export?.requestId||"?"}. Please make sure that your JSON/JavaScript options are sent using the "options" attribute, and that if you're using SVG, it is unescaped.`,400).setError(o))}},Ve=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return H(4,"[chart] Parsing input as SVG."),je(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return r&&"object"==typeof r?je(t,r,o):o(new re("[chart] Invalid configuration provided - the options must be an object, not a string",400))}catch(e){return X(r)?Me(t,o):o(new re("[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.",400).setError(e))}},qe=(e,t,o,r)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,r(e)},We=(e,t,o,r)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;o.status(l).json({statusCode:l,message:n,stack:a})};var Be=(e,t)=>{const o="Too many requests, you have been rate limited. Please try again later.",r={max:t.maxRequests||30,window:t.window||1,delay:t.delay||0,trustProxy:t.trustProxy||!1,skipKey:t.skipKey||!1,skipToken:t.skipToken||!1};r.trustProxy&&e.enable("trust proxy");const i=y({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&&(H(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),H(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class Xe extends re{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=C.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new Xe("The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.",401);const r=e.get("hc-auth");if(!r||r!==o)throw new Xe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Xe("No new version supplied.",400);try{await(async e=>{const t=Y();t?.highcharts&&(t.highcharts.version=e),await le(t)})(i)}catch(e){throw new Xe(`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){o(e)}}));const Ke={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let Je=0;const Ye=[],Qe=[],Ze=(e,t,o,r)=>{let i=!0;const{id:s,uniqueId:n,type:a,body:l}=r;return e.some((e=>{if(e){let r=e(t,o,s,n,a,l);return void 0!==r&&!0!==r&&(i=r),!0}})),i},et=async(e,t,o)=>{try{const o=K(),i=p.v4().replace(/-/g,""),s=Y(),n=e.body,a=++Je;let l=j(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new Xe("The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).",400);let c=V(n.infile||n.options||n.data);if(!c&&!n.svg)throw H(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new Xe("No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.",400);let u=!1;if(u=Ze(Ye,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==u)return t.send(u);let d=!1;e.socket.on("close",(()=>{d=!0})),H(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const h={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:Fe,allowFileResources:!1,resources:V(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(h.export.instr=W(c,h.customLogic.allowCodeExecution));const g=Q(s,h);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 Xe("SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.",400);await Ue(g,((r,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&H(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),d)return H(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new Xe(`Unexpected return from chart generation. Please check your request data. For the request with ID ${i}, the result is ${c.result}.`,400);return l=c.options.export.type,Ze(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",Ke[l]||"image/png"),n.noDownload||t.attachment(`${e.params.filename||e.body.filename||"chart"}.${l||"png"}`),"svg"===l?t.send(c.result):t.send(Buffer.from(c.result,"base64"))):void 0}))}catch(e){o(e)}var r};const tt=JSON.parse(e.readFileSync(t.join(U,"package.json"))),ot=new Date,rt=[];function it(e){if(!e)return!1;xe(setInterval((()=>{const e=Ge(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;rt.push(t),rt.length>30&&rt.shift()}),6e4)),e.get("/health",((e,t)=>{const o=Ge(),r=rt.length,i=rt.reduce(((e,t)=>e+t),0)/rt.length;H(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ot,uptime:Math.floor(((new Date).getTime()-ot.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:pe(),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)||!rt.length?"Too early to report. No exports made yet. Please check back soon.":`Last ${r} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:o.exportFromSvgAttempts,jsonExportAttempts:o.performedExports-o.exportFromSvgAttempts})}))}const st=new Map,nt=m();nt.disable("x-powered-by"),nt.use(g({methods:["POST","GET","OPTIONS"]}));const at=f.memoryStorage(),lt=f({storage:at,limits:{fieldSize:52428800}});nt.use(m.json({limit:52428800})),nt.use(m.urlencoded({extended:!0,limit:52428800})),nt.use(lt.none());const ct=e=>{e.on("clientError",(e=>{$(1,e,`[server] Client error: ${e.message}`)})),e.on("error",(e=>{$(1,e,`[server] Server error: ${e.message}`)})),e.on("connection",(e=>{e.on("error",(e=>{$(1,e,`[server] Socket error: ${e.message}`)}))}))},pt=async o=>{try{if(!o.enable)return!1;if(!o.ssl.force){const e=a.createServer(nt);ct(e),e.listen(o.port,o.host),st.set(o.port,e),H(3,`[server] Started HTTP server on ${o.host}:${o.port}.`)}if(o.ssl.enable){let r,i;try{r=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.key"),"utf8"),i=await e.promises.readFile(t.posix.join(o.ssl.certPath,"server.crt"),"utf8")}catch(e){H(2,`[server] Unable to load key/certificate from the '${o.ssl.certPath}' path. Could not run secured layer server.`)}if(r&&i){const e=l.createServer({key:r,cert:i},nt);ct(e),e.listen(o.ssl.port,o.host),st.set(o.ssl.port,e),H(3,`[server] Started HTTPS server on ${o.host}:${o.ssl.port}.`)}}o.rateLimiting&&o.rateLimiting.enable&&![0,NaN].includes(o.rateLimiting.maxRequests)&&Be(nt,o.rateLimiting),nt.use(m.static(t.posix.join(U,"public"))),it(nt),(e=>{e.post("/",et),e.post("/:filename",et)})(nt),(e=>{!!e&&e.get("/",((e,o)=>{o.sendFile(t.join(U,"public","index.html"))}))})(nt),ze(nt),(e=>{e.use(qe),e.use(We)})(nt)}catch(e){throw new re("[server] Could not configure and start the server.",500).setError(e)}},ut=()=>{H(4,"[server] Closing all servers.");for(const[e,t]of st)t.close((()=>{st.delete(e),H(4,`[server] Closed server on port: ${e}.`)}))};var dt={startServer:pt,closeServers:ut,getServers:()=>st,enableRateLimiting:e=>Be(nt,e),getExpress:()=>m,getApp:()=>nt,use:(e,...t)=>{nt.use(e,...t)},get:(e,...t)=>{nt.get(e,...t)},post:(e,...t)=>{nt.post(e,...t)}};const ht=async e=>{(function(){if(!ge)throw new re("[browser] No valid browser has been created.",500);return ge})().removeAllListeners("disconnected"),await Promise.allSettled([Re(),ut(),Ne()]),process.exit(e)};var gt={server:dt,startServer:pt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,Fe=X(t),(e=>{for(const[t,o]of Object.entries(e))P[t]=o;G(e&&parseInt(e.level)),e&&e.dest&&e.toFile&&F(e.dest,e.file||"highcharts-export-server.log")})(e.logging),e.other.listenToProcessExits&&(H(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{H(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGTERM",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("SIGHUP",(async(e,t)=>{H(4,`The ${e} event with code: ${t}.`),await ht(0)})),process.on("uncaughtException",(async(e,t)=>{$(1,e,`The ${t} error.`),await ht(1)}))),await le(e),await Ce({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 Ue(t,(async(t,o)=>{if(t)throw t;const{outfile:r,type:i}=o.options.export;e.writeFileSync(r||`chart.${i}`,"svg"!==i?Buffer.from(o.result,"base64"):o.result),await Ne()}))},batchExport:async t=>{const o=[];for(let r of t.export.batch.split(";"))r=r.split("="),2===r.length&&o.push(Ue({...t,export:{...t.export,infile:r[0],outfile:r[1]}},((t,o)=>{if(t)throw t;e.writeFileSync(o.options.export.outfile,"svg"!==o.options.export.type?Buffer.from(o.result,"base64"):o.result)})));try{await Promise.all(o),await Ne()}catch(e){throw new re("[chart] Error encountered during batch export.").setError(e)}},startExport:Ue,initPool:Ce,killPool:Ne,setOptions:(t,o)=>(o?.length&&(J=function(t){const o=t.findIndex((e=>"loadConfig"===e.replace(/-/g,"")));if(o>-1&&t[o+1]){const r=t[o+1];try{if(r&&r.endsWith(".json"))return JSON.parse(e.readFileSync(r))}catch(e){$(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(o)),Z(w,J),J=ee(w),t&&(J=Q(J,t,T)),o?.length&&(J=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]=X(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(H(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&B();return e}(J,o,w)),J),shutdownCleanUp:ht,log:H,logWithStack:$,setLogLevel:G,enableFileLogging:F,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=S[o]?S[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.existsSync(t)&&(o=JSON.parse(e.readFileSync(t,"utf8")));const i=Object.keys(E).map((e=>({title:`${e} options`,value:e})));return r({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 r(a,{onSubmit:async(r,i)=>{if("moduleScripts"===r.name?(i=i.length?i.map((e=>r.choices[e])):r.choices,o[r.section][r.name]=i):o[r.section]=te(Object.assign({},o[r.section]||{}),r.name.split("."),r.choices?r.choices[i]:i),++n===a.length){try{await e.promises.writeFile(t,JSON.stringify(o,null,2),"utf8")}catch(e){$(1,e,`[config] An error occurred while creating the ${t} file.`)}return!0}}}),!0}})},printLogo:o=>{const r=JSON.parse(e.readFileSync(t.join(U,"package.json"))).version;o?console.log(`Starting Highcharts Export Server v${r}...`):console.log(e.readFileSync(U+"/msg/startup.msg").toString().bold.yellow,`v${r}\n`.bold)},printUsage:B};module.exports=gt; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9pbnRlcnZhbHMuanMiLCIuLi9saWIvcG9vbC5qcyIsIi4uL2xpYi9jaGFydC5qcyIsIi4uL2xpYi9zYW5pdGl6ZS5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vLyBQb3NzaWJsZSBuYW1lcyBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xuICBjb3JlOiBbJ2hpZ2hjaGFydHMnLCAnaGlnaGNoYXJ0cy1tb3JlJywgJ2hpZ2hjaGFydHMtM2QnXSxcbiAgbW9kdWxlczogW1xuICAgICdzdG9jaycsXG4gICAgJ21hcCcsXG4gICAgJ2dhbnR0JyxcbiAgICAnZXhwb3J0aW5nJyxcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxuICAgICdhY2Nlc3NpYmlsaXR5JyxcbiAgICAvLyAnYW5ub3RhdGlvbnMtYWR2YW5jZWQnLFxuICAgICdib29zdC1jYW52YXMnLFxuICAgICdib29zdCcsXG4gICAgJ2RhdGEnLFxuICAgICdkYXRhLXRvb2xzJyxcbiAgICAnZHJhZ2dhYmxlLXBvaW50cycsXG4gICAgJ3N0YXRpYy1zY2FsZScsXG4gICAgJ2Jyb2tlbi1heGlzJyxcbiAgICAnaGVhdG1hcCcsXG4gICAgJ3RpbGVtYXAnLFxuICAgICd0aWxlZHdlYm1hcCcsXG4gICAgJ3RpbWVsaW5lJyxcbiAgICAndHJlZW1hcCcsXG4gICAgJ3RyZWVncmFwaCcsXG4gICAgJ2l0ZW0tc2VyaWVzJyxcbiAgICAnZHJpbGxkb3duJyxcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXG4gICAgJ2J1bGxldCcsXG4gICAgJ2Z1bm5lbCcsXG4gICAgJ2Z1bm5lbDNkJyxcbiAgICAnZ2VvaGVhdG1hcCcsXG4gICAgJ3B5cmFtaWQzZCcsXG4gICAgJ25ldHdvcmtncmFwaCcsXG4gICAgJ292ZXJsYXBwaW5nLWRhdGFsYWJlbHMnLFxuICAgICdwYXJldG8nLFxuICAgICdwYXR0ZXJuLWZpbGwnLFxuICAgICdwaWN0b3JpYWwnLFxuICAgICdwcmljZS1pbmRpY2F0b3InLFxuICAgICdzYW5rZXknLFxuICAgICdhcmMtZGlhZ3JhbScsXG4gICAgJ2RlcGVuZGVuY3ktd2hlZWwnLFxuICAgICdzZXJpZXMtbGFiZWwnLFxuICAgICdzZXJpZXMtb24tcG9pbnQnLFxuICAgICdzb2xpZC1nYXVnZScsXG4gICAgJ3NvbmlmaWNhdGlvbicsXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcbiAgICAnc3RyZWFtZ3JhcGgnLFxuICAgICdzdW5idXJzdCcsXG4gICAgJ3ZhcmlhYmxlLXBpZScsXG4gICAgJ3Zhcml3aWRlJyxcbiAgICAndmVjdG9yJyxcbiAgICAndmVubicsXG4gICAgJ3dpbmRiYXJiJyxcbiAgICAnd29yZGNsb3VkJyxcbiAgICAneHJhbmdlJyxcbiAgICAnbm8tZGF0YS10by1kaXNwbGF5JyxcbiAgICAnZHJhZy1wYW5lcycsXG4gICAgJ2RlYnVnZ2VyJyxcbiAgICAnZHVtYmJlbGwnLFxuICAgICdsb2xsaXBvcCcsXG4gICAgJ2N5bGluZGVyJyxcbiAgICAnb3JnYW5pemF0aW9uJyxcbiAgICAnZG90cGxvdCcsXG4gICAgJ21hcmtlci1jbHVzdGVycycsXG4gICAgJ2hvbGxvd2NhbmRsZXN0aWNrJyxcbiAgICAnaGVpa2luYXNoaScsXG4gICAgJ2Zsb3dtYXAnLFxuICAgICdleHBvcnQtZGF0YScsXG4gICAgJ25hdmlnYXRvcicsXG4gICAgJ3RleHRwYXRoJ1xuICBdLFxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ10sXG4gIGN1c3RvbTogW1xuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQuanMvMi4zMC4xL21vbWVudC5taW4uanMnLFxuICAgICdodHRwczovL2NkbmpzLmNsb3VkZmxhcmUuY29tL2FqYXgvbGlicy9tb21lbnQtdGltZXpvbmUvMC41LjQ1L21vbWVudC10aW1lem9uZS13aXRoLWRhdGEubWluLmpzJ1xuICBdXG59O1xuXG4vLyBUaGlzIGlzIHRoZSBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIGFsbCBvcHRpb25zIGFuZCB0aGVpciBkZWZhdWx0IHZhbHVlcyxcbi8vIGFsc28gZnJvbSB0aGUgLmVudiBmaWxlIGlmIG9uZSBleGlzdHNcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xuICBwdXBwZXRlZXI6IHtcbiAgICBhcmdzOiB7XG4gICAgICB2YWx1ZTogW1xuICAgICAgICAnLS1hbGxvdy1ydW5uaW5nLWluc2VjdXJlLWNvbnRlbnQnLFxuICAgICAgICAnLS1hc2gtbm8tbnVkZ2VzJyxcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXG4gICAgICAgICctLWJsb2NrLW5ldy13ZWItY29udGVudHMnLFxuICAgICAgICAnLS1kaXNhYmxlLWFjY2VsZXJhdGVkLTJkLWNhbnZhcycsXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kLXRpbWVyLXRocm90dGxpbmcnLFxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmRpbmctb2NjbHVkZWQtd2luZG93cycsXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxuICAgICAgICAnLS1kaXNhYmxlLWNoZWNrZXItaW1hZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtY2xpZW50LXNpZGUtcGhpc2hpbmctZGV0ZWN0aW9uJyxcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxuICAgICAgICAnLS1kaXNhYmxlLWNvbXBvbmVudC11cGRhdGUnLFxuICAgICAgICAnLS1kaXNhYmxlLWRlZmF1bHQtYXBwcycsXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXG4gICAgICAgICctLWRpc2FibGUtZG9tYWluLXJlbGlhYmlsaXR5JyxcbiAgICAgICAgJy0tZGlzYWJsZS1leHRlbnNpb25zJyxcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXG4gICAgICAgICctLWRpc2FibGUtaGFuZy1tb25pdG9yJyxcbiAgICAgICAgJy0tZGlzYWJsZS1pcGMtZmxvb2RpbmctcHJvdGVjdGlvbicsXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXG4gICAgICAgICctLWRpc2FibGUtbm90aWZpY2F0aW9ucycsXG4gICAgICAgICctLWRpc2FibGUtb2ZmZXItc3RvcmUtdW5tYXNrZWQtd2FsbGV0LWNhcmRzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXG4gICAgICAgICctLWRpc2FibGUtcHJpbnQtcHJldmlldycsXG4gICAgICAgICctLWRpc2FibGUtcHJvbXB0LW9uLXJlcG9zdCcsXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXG4gICAgICAgICctLWRpc2FibGUtc2VhcmNoLWVuZ2luZS1jaG9pY2Utc2NyZWVuJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXNzaW9uLWNyYXNoZWQtYnViYmxlJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXG4gICAgICAgICctLWRpc2FibGUtc2l0ZS1pc29sYXRpb24tdHJpYWxzJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zcGVlY2gtYXBpJyxcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcbiAgICAgICAgJy0tZW5hYmxlLXVuc2FmZS13ZWJncHUnLFxuICAgICAgICAnLS1oaWRlLWNyYXNoLXJlc3RvcmUtYnViYmxlJyxcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcbiAgICAgICAgJy0tbWV0cmljcy1yZWNvcmRpbmctb25seScsXG4gICAgICAgICctLW11dGUtYXVkaW8nLFxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxuICAgICAgICAnLS1uby1maXJzdC1ydW4nLFxuICAgICAgICAnLS1uby1waW5ncycsXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxuICAgICAgICAnLS1uby1zdGFydHVwLXdpbmRvdycsXG4gICAgICAgICctLW5vLXp5Z290ZScsXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcbiAgICAgICAgJy0tcHJvY2Vzcy1wZXItdGFiJyxcbiAgICAgICAgJy0tdXNlLW1vY2sta2V5Y2hhaW4nXG4gICAgICBdLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQXJndW1lbnRzIGFycmF5IHRvIHNlbmQgdG8gUHVwcGV0ZWVyLidcbiAgICB9XG4gIH0sXG4gIGhpZ2hjaGFydHM6IHtcbiAgICB2ZXJzaW9uOiB7XG4gICAgICB2YWx1ZTogJ2xhdGVzdCcsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgSGlnaGNoYXJ0cyB2ZXJzaW9uIHRvIGJlIHVzZWQuJ1xuICAgIH0sXG4gICAgY2RuVVJMOiB7XG4gICAgICB2YWx1ZTogJ2h0dHBzOi8vY29kZS5oaWdoY2hhcnRzLmNvbS8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIENETiBVUkwgZm9yIEhpZ2hjaGFydHMgc2NyaXB0cyB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGNvcmVTY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmNvcmUsXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGNvcmUgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIG1vZHVsZVNjcmlwdHM6IHtcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMubW9kdWxlcyxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBtb2R1bGVzIG9mIEhpZ2hjaGFydHMgdG8gZmV0Y2guJ1xuICAgIH0sXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzLFxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGluZGljYXRvcnMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXG4gICAgfSxcbiAgICBjdXN0b21TY3JpcHRzOiB7XG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmN1c3RvbSxcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0FkZGl0aW9uYWwgY3VzdG9tIHNjcmlwdHMgb3IgZGVwZW5kZW5jaWVzIHRvIGZldGNoLidcbiAgICB9LFxuICAgIGZvcmNlRmV0Y2g6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGZsYWcgdG8gZGV0ZXJtaW5lIHdoZXRoZXIgdG8gcmVmZXRjaCBhbGwgc2NyaXB0cyBhZnRlciBlYWNoIHNlcnZlciByZXJ1bi4nXG4gICAgfSxcbiAgICBjYWNoZVBhdGg6IHtcbiAgICAgIHZhbHVlOiAnLmNhY2hlJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ0FDSEVfUEFUSCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xuICAgIH1cbiAgfSxcbiAgZXhwb3J0OiB7XG4gICAgaW5maWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGlucHV0IGZpbGUgc2hvdWxkIGluY2x1ZGUgYSBuYW1lIGFuZCBhIHR5cGUgKGpzb24gb3Igc3ZnKS4gSXQgbXVzdCBiZSBjb3JyZWN0bHkgZm9ybWF0dGVkIGFzIGEgSlNPTiBvciBTVkcgZmlsZS4nXG4gICAgfSxcbiAgICBpbnN0cjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0lucHV0LCBwcm92aWRlZCBpbiB0aGUgZm9ybSBvZiBhIHN0cmluZ2lmaWVkIEpTT04gb3IgU1ZHIGZpbGUsIHdpbGwgb3ZlcnJpZGUgdGhlIC0taW5maWxlIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQW4gYWxpYXMgZm9yIHRoZSAtLWluc3RyIG9wdGlvbi4nXG4gICAgfSxcbiAgICBvdXRmaWxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIG91dHB1dCBmaWxlbmFtZSBhbG9uZyB3aXRoIGEgdHlwZSAoanBlZywgcG5nLCBwZGYsIG9yIHN2ZykuIFRoaXMgd2lsbCBpZ25vcmUgdGhlIC0tdHlwZSBmbGFnLidcbiAgICB9LFxuICAgIHR5cGU6IHtcbiAgICAgIHZhbHVlOiAncG5nJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIGZpbGUgZXhwb3J0IGZvcm1hdC4gSXQgY2FuIGJlIGpwZWcsIHBuZywgcGRmLCBvciBzdmcuJ1xuICAgIH0sXG4gICAgY29uc3RyOiB7XG4gICAgICB2YWx1ZTogJ2NoYXJ0JyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgY29uc3RydWN0b3IgdG8gdXNlLiBDYW4gYmUgY2hhcnQsIHN0b2NrQ2hhcnQsIG1hcENoYXJ0LCBvciBnYW50dENoYXJ0LidcbiAgICB9LFxuICAgIGRlZmF1bHRIZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiA0MDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9IRUlHSFQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRXaWR0aDoge1xuICAgICAgdmFsdWU6IDYwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX1dJRFRIJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGRlZmF1bHQgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcbiAgICB9LFxuICAgIGRlZmF1bHRTY2FsZToge1xuICAgICAgdmFsdWU6IDEsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkZWZhdWx0IHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydC4gVXNlZCB3aGVuIG5vIHZhbHVlIGlzIHNldC4nXG4gICAgfSxcbiAgICBoZWlnaHQ6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4nXG4gICAgfSxcbiAgICB3aWR0aDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xuICAgIH0sXG4gICAgc2NhbGU6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLiBSYW5nZXMgYmV0d2VlbiAwLjEgYW5kIDUuMC4nXG4gICAgfSxcbiAgICBnbG9iYWxPcHRpb25zOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRWl0aGVyIGEgc3RyaW5naWZpZWQgSlNPTiBvciBhIGZpbGVuYW1lIGNvbnRhaW5pbmcgb3B0aW9ucyB0byBiZSBwYXNzZWQgaW50byB0aGUgSGlnaGNoYXJ0cy5zZXRPcHRpb25zLidcbiAgICB9LFxuICAgIHRoZW1lT3B0aW9uczoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIHRoZW1lIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXG4gICAgfSxcbiAgICBiYXRjaDoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0luaXRpYXRlcyBhIGJhdGNoIGpvYiB3aXRoIGEgc3RyaW5nIGNvbnRhaW5pbmcgaW5wdXQvb3V0cHV0IHBhaXJzOiBcImluPW91dDtpbj1vdXQ7Li4uXCIuJ1xuICAgIH0sXG4gICAgcmFzdGVyaXphdGlvblRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiAxNTAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXG4gICAgfVxuICB9LFxuICBjdXN0b21Mb2dpYzoge1xuICAgIGFsbG93Q29kZUV4ZWN1dGlvbjoge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWxsb3dGaWxlUmVzb3VyY2VzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnQ29udHJvbHMgdGhlIGFiaWxpdHkgdG8gaW5qZWN0IHJlc291cmNlcyBmcm9tIHRoZSBmaWxlc3lzdGVtLiBUaGlzIHNldHRpbmcgaGFzIG5vIGVmZmVjdCB3aGVuIHJ1bm5pbmcgYXMgYSBzZXJ2ZXIuJ1xuICAgIH0sXG4gICAgY3VzdG9tQ29kZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0N1c3RvbSBjb2RlIHRvIGV4ZWN1dGUgYmVmb3JlIGNoYXJ0IGluaXRpYWxpemF0aW9uLiBJdCBjYW4gYmUgYSBmdW5jdGlvbiwgY29kZSB3cmFwcGVkIHdpdGhpbiBhIGZ1bmN0aW9uLCBvciBhIGZpbGVuYW1lIHdpdGggdGhlIC5qcyBleHRlbnNpb24uJ1xuICAgIH0sXG4gICAgY2FsbGJhY2s6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdKYXZhU2NyaXB0IGNvZGUgdG8gcnVuIGR1cmluZyBjb25zdHJ1Y3Rpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXG4gICAgfSxcbiAgICByZXNvdXJjZXM6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdBZGRpdGlvbmFsIHJlc291cmNlIGluIHRoZSBmb3JtIG9mIGEgc3RyaW5naWZpZWQgSlNPTiwgd2hpY2ggbWF5IGNvbnRhaW4gZmlsZXMsIGpzLCBhbmQgY3NzIHNlY3Rpb25zLidcbiAgICB9LFxuICAgIGxvYWRDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnQSBmaWxlIGNvbnRhaW5pbmcgYSBwcmUtZGVmaW5lZCBjb25maWd1cmF0aW9uIHRvIHVzZS4nXG4gICAgfSxcbiAgICBjcmVhdGVDb25maWc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIHNldHRpbmcgb3B0aW9ucyB0aHJvdWdoIGEgcHJvbXB0IGFuZCBzYXZpbmcgdGhlbSBpbiBhIHByb3ZpZGVkIGNvbmZpZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHNlcnZlcjoge1xuICAgIGVuYWJsZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9FTkFCTEUnLFxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgc3RhcnRzIG9uIHRoZSBsb2NhbCBJUCBhZGRyZXNzIDAuMC4wLjAuJ1xuICAgIH0sXG4gICAgaG9zdDoge1xuICAgICAgdmFsdWU6ICcwLjAuMC4wJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9IT1NUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXG4gICAgfSxcbiAgICBwb3J0OiB7XG4gICAgICB2YWx1ZTogNzgwMSxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1NFUlZFUl9QT1JUJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXG4gICAgfSxcbiAgICBiZW5jaG1hcmtpbmc6IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfQkVOQ0hNQVJLSU5HJyxcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdJbmRpY2F0ZXMgd2hldGhlciB0byBkaXNwbGF5IHRoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBvZiBzcGVjaWZpYyBhY3Rpb25zIHRoYXQgb2NjdXIgb24gdGhlIHNlcnZlciB3aGlsZSBzZXJ2aW5nIGEgcmVxdWVzdC4nXG4gICAgfSxcbiAgICBwcm94eToge1xuICAgICAgaG9zdDoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1BST1hZX0hPU1QnLFxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH0sXG4gICAgICBwb3J0OiB7XG4gICAgICAgIHZhbHVlOiA4MDgwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcbiAgICAgICAgY2xpTmFtZTogJ3Byb3h5UG9ydCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UsIGlmIGl0IGV4aXN0cy4nXG4gICAgICB9LFxuICAgICAgdGltZW91dDoge1xuICAgICAgICB2YWx1ZTogNTAwMCxcbiAgICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUFJPWFlfVElNRU9VVCcsXG4gICAgICAgIGNsaU5hbWU6ICdwcm94eVRpbWVvdXQnLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcbiAgICAgIH1cbiAgICB9LFxuICAgIHJhdGVMaW1pdGluZzoge1xuICAgICAgZW5hYmxlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFJyxcbiAgICAgICAgY2xpTmFtZTogJ2VuYWJsZVJhdGVMaW1pdGluZycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcbiAgICAgIH0sXG4gICAgICBtYXhSZXF1ZXN0czoge1xuICAgICAgICB2YWx1ZTogMTAsXG4gICAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTJyxcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHJlcXVlc3RzIGFsbG93ZWQgaW4gb25lIG1pbnV0ZS4nXG4gICAgICB9LFxuICAgICAgd2luZG93OiB7XG4gICAgICAgIHZhbHVlOiAxLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHRpbWUgd2luZG93LCBpbiBtaW51dGVzLCBmb3IgdGhlIHJhdGUgbGltaXRpbmcuJ1xuICAgICAgfSxcbiAgICAgIGRlbGF5OiB7XG4gICAgICAgIHZhbHVlOiAwLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1RoZSBkZWxheSBkdXJhdGlvbiBmb3IgZWFjaCBzdWNjZXNzaXZlIHJlcXVlc3QgYmVmb3JlIHJlYWNoaW5nIHRoZSBtYXhpbXVtIGxpbWl0LidcbiAgICAgIH0sXG4gICAgICB0cnVzdFByb3h5OiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfVFJVU1RfUFJPWFknLFxuICAgICAgICBkZXNjcmlwdGlvbjogJ1NldCB0aGlzIHRvIHRydWUgaWYgdGhlIHNlcnZlciBpcyBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyLidcbiAgICAgIH0sXG4gICAgICBza2lwS2V5OiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWScsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xuICAgICAgfSxcbiAgICAgIHNraXBUb2tlbjoge1xuICAgICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTicsXG4gICAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50LidcbiAgICAgIH1cbiAgICB9LFxuICAgIHNzbDoge1xuICAgICAgZW5hYmxlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9FTkFCTEUnLFxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdFbmFibGVzIG9yIGRpc2FibGVzIHRoZSBTU0wgcHJvdG9jb2wuJ1xuICAgICAgfSxcbiAgICAgIGZvcmNlOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXG4gICAgICAgIGNsaU5hbWU6ICdzc2xGb3JjZScsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xPbmx5JyxcbiAgICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICAgJ1doZW4gc2V0IHRvIHRydWUsIHRoZSBzZXJ2ZXIgaXMgZm9yY2VkIHRvIHNlcnZlIG9ubHkgb3ZlciBIVFRQUy4nXG4gICAgICB9LFxuICAgICAgcG9ydDoge1xuICAgICAgICB2YWx1ZTogNDQzLFxuICAgICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXG4gICAgICAgIGNsaU5hbWU6ICdzc2xQb3J0JyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcG9ydCBvbiB3aGljaCB0byBydW4gdGhlIFNTTCBzZXJ2ZXIuJ1xuICAgICAgfSxcbiAgICAgIGNlcnRQYXRoOiB7XG4gICAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfU1NMX0NFUlRfUEFUSCcsXG4gICAgICAgIGxlZ2FjeU5hbWU6ICdzc2xQYXRoJyxcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcbiAgICAgIH1cbiAgICB9XG4gIH0sXG4gIHBvb2w6IHtcbiAgICBtaW5Xb3JrZXJzOiB7XG4gICAgICB2YWx1ZTogNCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfTUlOX1dPUktFUlMnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcbiAgICB9LFxuICAgIG1heFdvcmtlcnM6IHtcbiAgICAgIHZhbHVlOiA4LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9NQVhfV09SS0VSUycsXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBudW1iZXIgb2YgbWF4aW11bSBwb29sIHdvcmtlcnMgdG8gc3Bhd24uJ1xuICAgIH0sXG4gICAgd29ya0xpbWl0OiB7XG4gICAgICB2YWx1ZTogNDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgbnVtYmVyIG9mIHdvcmsgcGllY2VzIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyB0aGUgd29ya2VyIHByb2Nlc3MuJ1xuICAgIH0sXG4gICAgYWNxdWlyZVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9BQ1FVSVJFX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgY3JlYXRlVGltZW91dDoge1xuICAgICAgdmFsdWU6IDUwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0NSRUFURV9USU1FT1VUJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UuJ1xuICAgIH0sXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcbiAgICAgIHZhbHVlOiA1MDAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlLidcbiAgICB9LFxuICAgIGlkbGVUaW1lb3V0OiB7XG4gICAgICB2YWx1ZTogMzAwMDAsXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIGVudkxpbms6ICdQT09MX0lETEVfVElNRU9VVCcsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXG4gICAgfSxcbiAgICBjcmVhdGVSZXRyeUludGVydmFsOiB7XG4gICAgICB2YWx1ZTogMjAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBiZWZvcmUgcmV0cnlpbmcgdGhlIGNyZWF0ZSBwcm9jZXNzIGluIGNhc2Ugb2YgYSBmYWlsdXJlLidcbiAgICB9LFxuICAgIHJlYXBlckludGVydmFsOiB7XG4gICAgICB2YWx1ZTogMTAwMCxcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIGFmdGVyIHdoaWNoIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveSBpcyB0cmlnZ2VyZWQuJ1xuICAgIH0sXG4gICAgYmVuY2htYXJraW5nOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnUE9PTF9CRU5DSE1BUktJTkcnLFxuICAgICAgY2xpTmFtZTogJ3Bvb2xCZW5jaG1hcmtpbmcnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdJbmRpY2F0ZSB3aGV0aGVyIHRvIHNob3cgc3RhdGlzdGljcyBmb3IgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIG9yIG5vdC4nXG4gICAgfVxuICB9LFxuICBsb2dnaW5nOiB7XG4gICAgbGV2ZWw6IHtcbiAgICAgIHZhbHVlOiA0LFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19MRVZFTCcsXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbG9nZ2luZyBsZXZlbCB0byBiZSB1c2VkLidcbiAgICB9LFxuICAgIGZpbGU6IHtcbiAgICAgIHZhbHVlOiAnaGlnaGNoYXJ0cy1leHBvcnQtc2VydmVyLmxvZycsXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxuICAgICAgY2xpTmFtZTogJ2xvZ0ZpbGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgYGxvZ1RvRmlsZWAgYW5kIGBsb2dEZXN0YCBvcHRpb25zIGFsc28gbmVlZCB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXG4gICAgfSxcbiAgICBkZXN0OiB7XG4gICAgICB2YWx1ZTogJ2xvZy8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19ERVNUJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnVGhlIHBhdGggdG8gc3RvcmUgbG9nIGZpbGVzLiBUaGUgYGxvZ1RvRmlsZWAgb3B0aW9uIGFsc28gbmVlZHMgdG8gYmUgc2V0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcuJ1xuICAgIH0sXG4gICAgdG9Db25zb2xlOiB7XG4gICAgICB2YWx1ZTogdHJ1ZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX1RPX0NPTlNPTEUnLFxuICAgICAgY2xpTmFtZTogJ2xvZ1RvQ29uc29sZScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgc2hvd2luZyBsb2dzIGluIHRoZSBjb25zb2xlLidcbiAgICB9LFxuICAgIHRvRmlsZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnTE9HR0lOR19UT19GSUxFJyxcbiAgICAgIGNsaU5hbWU6ICdsb2dUb0ZpbGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdFbmFibGVzIG9yIGRpc2FibGVzIGNyZWF0aW9uIG9mIHRoZSBsb2cgZGlyZWN0b3J5IGFuZCBzYXZpbmcgdGhlIGxvZyBpbnRvIGEgLmxvZyBmaWxlLidcbiAgICB9XG4gIH0sXG4gIHVpOiB7XG4gICAgZW5hYmxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnVUlfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVVaScsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgZm9yIHRoZSBleHBvcnQgc2VydmVyLidcbiAgICB9LFxuICAgIHJvdXRlOiB7XG4gICAgICB2YWx1ZTogJy8nLFxuICAgICAgdHlwZTogJ3N0cmluZycsXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxuICAgICAgY2xpTmFtZTogJ3VpUm91dGUnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcbiAgICB9XG4gIH0sXG4gIG90aGVyOiB7XG4gICAgbm9kZUVudjoge1xuICAgICAgdmFsdWU6ICdwcm9kdWN0aW9uJyxcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxuICAgICAgZW52TGluazogJ09USEVSX05PREVfRU5WJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudC4nXG4gICAgfSxcbiAgICBsaXN0ZW5Ub1Byb2Nlc3NFeGl0czoge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFMnLFxuICAgICAgZGVzY3JpcHRpb246ICdEZWNpZGVzIHdoZXRoZXIgb3Igbm90IHRvIGF0dGFjaCBwcm9jZXNzLmV4aXQgaGFuZGxlcnMuJ1xuICAgIH0sXG4gICAgbm9Mb2dvOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9fTE9HTycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xuICAgIH0sXG4gICAgaGFyZFJlc2V0UGFnZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ09USEVSX0hBUkRfUkVTRVRfUEFHRScsXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xuICAgIH0sXG4gICAgYnJvd3NlclNoZWxsTW9kZToge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFJyxcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlLidcbiAgICB9XG4gIH0sXG4gIGRlYnVnOiB7XG4gICAgZW5hYmxlOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRU5BQkxFJyxcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3Nlci4nXG4gICAgfSxcbiAgICBoZWFkbGVzczoge1xuICAgICAgdmFsdWU6IHRydWUsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdDb250cm9scyB0aGUgbW9kZSBpbiB3aGljaCB0aGUgYnJvd3NlciBpcyBsYXVuY2hlZCB3aGVuIGluIHRoZSBkZWJ1ZyBtb2RlLidcbiAgICB9LFxuICAgIGRldnRvb2xzOiB7XG4gICAgICB2YWx1ZTogZmFsc2UsXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcbiAgICB9LFxuICAgIGxpc3RlblRvQ29uc29sZToge1xuICAgICAgdmFsdWU6IGZhbHNlLFxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxuICAgICAgZW52TGluazogJ0RFQlVHX0xJU1RFTl9UT19DT05TT0xFJyxcbiAgICAgIGRlc2NyaXB0aW9uOlxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBhIGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIHNlbnQgZnJvbSB0aGUgYnJvd3Nlci4nXG4gICAgfSxcbiAgICBkdW1waW86IHtcbiAgICAgIHZhbHVlOiBmYWxzZSxcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxuICAgICAgZGVzY3JpcHRpb246XG4gICAgICAgICdSZWRpcmVjdHMgYnJvd3NlciBwcm9jZXNzIHN0ZG91dCBhbmQgc3RkZXJyIHRvIHByb2Nlc3Muc3Rkb3V0IGFuZCBwcm9jZXNzLnN0ZGVyci4nXG4gICAgfSxcbiAgICBzbG93TW86IHtcbiAgICAgIHZhbHVlOiAwLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXG4gICAgICBkZXNjcmlwdGlvbjpcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcbiAgICB9LFxuICAgIGRlYnVnZ2luZ1BvcnQ6IHtcbiAgICAgIHZhbHVlOiA5MjIyLFxuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVCVUdHSU5HX1BPUlQnLFxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcbiAgICB9XG4gIH1cbn07XG5cbi8vIFRoZSBjb25maWcgZGVzY3JpcHRpb25zIG9iamVjdCBmb3IgdGhlIHByb21wdHMgZnVuY3Rpb25hbGl0eS4gSXQgY29udGFpbnNcbi8vIGluZm9ybWF0aW9uIGxpa2U6XG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcbi8vICogTmFtZSBvZiBhbiBvcHRpb25cbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXG4vLyAqIEluaXRpYWwgdmFsdWVcbmV4cG9ydCBjb25zdCBwcm9tcHRzQ29uZmlnID0ge1xuICBwdXBwZXRlZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbGlzdCcsXG4gICAgICBuYW1lOiAnYXJncycsXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnB1cHBldGVlci5hcmdzLnZhbHVlLmpvaW4oJywnKSxcbiAgICAgIHNlcGFyYXRvcjogJywnXG4gICAgfVxuICBdLFxuICBoaWdoY2hhcnRzOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMudmVyc2lvbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2NkblVSTCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNkblVSTC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBtb2R1bGUgc2NyaXB0cycsXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXG4gICAgICBuYW1lOiAnaW5kaWNhdG9yU2NyaXB0cycsXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuaW5kaWNhdG9yU2NyaXB0cy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ2xpc3QnLFxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jdXN0b21TY3JpcHRzLnZhbHVlLmpvaW4oJywnKSxcbiAgICAgIHNlcGFyYXRvcjogJywnXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSByZS1mZXRjaCB0aGUgc2NyaXB0cycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gdGhlIGNhY2hlIGRpcmVjdG9yeScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXG4gICAgfVxuICBdLFxuICBleHBvcnQ6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnc2VsZWN0JyxcbiAgICAgIG5hbWU6ICd0eXBlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LnR5cGUudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3NlbGVjdCcsXG4gICAgICBuYW1lOiAnY29uc3RyJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcbiAgICAgIGluaXRpYWw6IDAsXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxuICAgICAgbWluOiAwLjEsXG4gICAgICBtYXg6IDVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQucmFzdGVyaXphdGlvblRpbWVvdXQudmFsdWVcbiAgICB9XG4gIF0sXG4gIGN1c3RvbUxvZ2ljOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnYWxsb3dDb2RlRXhlY3V0aW9uJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdhbGxvd0ZpbGVSZXNvdXJjZXMnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxuICAgIH1cbiAgXSxcbiAgc2VydmVyOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdTdGFydHMgdGhlIHNlcnZlciBvbiAwLjAuMC4wJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ2hvc3QnLFxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBob3N0bmFtZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdwb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgcG9ydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBzZXJ2ZXIgYmVuY2htYXJraW5nJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgcmF0ZSBsaW1pdGluZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBtYXhpbXVtIHJlcXVlc3RzIGFsbG93ZWQgcGVyIG1pbnV0ZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxuICAgICAgbWVzc2FnZTogJ1RoZSByYXRlLWxpbWl0aW5nIHRpbWUgd2luZG93IGluIG1pbnV0ZXMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy50cnVzdFByb3h5JyxcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnNraXBLZXknLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuc2tpcEtleS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxuICAgICAgbWVzc2FnZTpcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFNTTCBwcm90b2NvbCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHNlcnZpbmcgb25seSBvdmVyIEhUVFBTJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxuICAgICAgbWVzc2FnZTogJ1NTTCBzZXJ2ZXIgcG9ydCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIHBhdGggdG8gZmluZCB0aGUgU1NMIGNlcnRpZmljYXRlL2tleScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcbiAgICB9XG4gIF0sXG4gIHBvb2w6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWluV29ya2Vycy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1heFdvcmtlcnMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIHBpZWNlcyBvZiB3b3JrIHRoYXQgY2FuIGJlIHBlcmZvcm1lZCBiZWZvcmUgcmVzdGFydGluZyBhIFB1cHBldGVlciBwcm9jZXNzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBhY3F1aXJpbmcgYSByZXNvdXJjZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGNyZWF0aW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBkZXN0cm95aW5nIGEgcmVzb3VyY2UnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgYWZ0ZXIgYW4gaWRsZSByZXNvdXJjZSBpcyBkZXN0cm95ZWQnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICdudW1iZXInLFxuICAgICAgbmFtZTogJ3JlYXBlckludGVydmFsJyxcbiAgICAgIG1lc3NhZ2U6XG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wucmVhcGVySW50ZXJ2YWwudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5iZW5jaG1hcmtpbmcudmFsdWVcbiAgICB9XG4gIF0sXG4gIGxvZ2dpbmc6IFtcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdsZXZlbCcsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5sZXZlbC52YWx1ZSxcbiAgICAgIHJvdW5kOiAwLFxuICAgICAgbWluOiAwLFxuICAgICAgbWF4OiA1XG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnZmlsZScsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCAtLXRvRmlsZSBhbmQgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmZpbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0ZXh0JyxcbiAgICAgIG5hbWU6ICdkZXN0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBhIGxvZyBmaWxlIHdoZW4gdGhlIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5kZXN0LnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICd0b0NvbnNvbGUnLFxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBsb2dnaW5nIHRvIHRoZSBjb25zb2xlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy50b0NvbnNvbGUudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ3RvRmlsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlcyBsb2dnaW5nIHRvIGEgZmlsZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcudG9GaWxlLnZhbHVlXG4gICAgfVxuICBdLFxuICB1aTogW1xuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2VuYWJsZScsXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RleHQnLFxuICAgICAgbmFtZTogJ3JvdXRlJyxcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxuICAgIH1cbiAgXSxcbiAgb3RoZXI6IFtcbiAgICB7XG4gICAgICB0eXBlOiAndGV4dCcsXG4gICAgICBuYW1lOiAnbm9kZUVudicsXG4gICAgICBtZXNzYWdlOiAnVGhlIHR5cGUgb2YgTm9kZS5qcyBlbnZpcm9ubWVudCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gZmFsc2UgdG8gc2tpcCBhdHRhY2hpbmcgcHJvY2Vzcy5leGl0IGhhbmRsZXJzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ25vTG9nbycsXG4gICAgICBtZXNzYWdlOiAnU2tpcCBwcmludGluZyB0aGUgbG9nbyBvbiBzdGFydHVwLiBSZXBsYWNlZCBieSBzaW1wbGUgdGV4dCcsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnaGFyZFJlc2V0UGFnZScsXG4gICAgICBtZXNzYWdlOiAnRGVjaWRlcyBpZiB0aGUgcGFnZSBjb250ZW50IHNob3VsZCBiZSByZXNldCBlbnRpcmVseScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcbiAgICB9LFxuICAgIHtcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxuICAgICAgbmFtZTogJ2Jyb3dzZXJTaGVsbE1vZGUnLFxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIGJyb3dzZXIgcnVucyBpbiB0aGUgc2hlbGwgbW9kZScsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmJyb3dzZXJTaGVsbE1vZGUudmFsdWVcbiAgICB9XG4gIF0sXG4gIGRlYnVnOiBbXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZW5hYmxlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXG4gICAgICBtZXNzYWdlOiAnVGhlIG1vZGUgc2V0dGluZyBmb3IgdGhlIGJyb3dzZXInLFxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5oZWFkbGVzcy52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ3RvZ2dsZScsXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBEZXZUb29scyBmb3IgdGhlIGhlYWRmdWwgYnJvd3NlcicsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRldnRvb2xzLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxuICAgICAgbWVzc2FnZTogJ1RoZSBldmVudCBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcubGlzdGVuVG9Db25zb2xlLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAndG9nZ2xlJyxcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxuICAgICAgbWVzc2FnZTogJ1JlZGlyZWN0cyB0aGUgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBOb2RlSlMgcHJvY2VzcycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmR1bXBpby52YWx1ZVxuICAgIH0sXG4gICAge1xuICAgICAgdHlwZTogJ251bWJlcicsXG4gICAgICBuYW1lOiAnc2xvd01vJyxcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgb3BlcmF0aW9ucyBzbG93IGRvd24gaW4gbWlsbGlzZWNvbmRzJyxcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuc2xvd01vLnZhbHVlXG4gICAgfSxcbiAgICB7XG4gICAgICB0eXBlOiAnbnVtYmVyJyxcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBudW1iZXIgZm9yIGRlYnVnZ2luZycsXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmRlYnVnZ2luZ1BvcnQudmFsdWVcbiAgICB9XG4gIF1cbn07XG5cbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcbmV4cG9ydCBjb25zdCBhYnNvbHV0ZVByb3BzID0gW1xuICAnb3B0aW9ucycsXG4gICdnbG9iYWxPcHRpb25zJyxcbiAgJ3RoZW1lT3B0aW9ucycsXG4gICdyZXNvdXJjZXMnLFxuICAncGF5bG9hZCdcbl07XG5cbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xuZXhwb3J0IGNvbnN0IG5lc3RlZEFyZ3MgPSB7fTtcblxuLyoqXG4gKiBSZWN1cnNpdmVseSBjcmVhdGVzIGEgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50cyBmcm9tIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJvcENoYWluIC0gVGhlIGN1cnJlbnQgY2hhaW4gb2YgbmVzdGVkIHByb3BlcnRpZXNcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXG4gKi9cbmNvbnN0IGNyZWF0ZU5lc3RlZEFyZ3MgPSAob2JqLCBwcm9wQ2hhaW4gPSAnJykgPT4ge1xuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xuICAgICAgY29uc3QgZW50cnkgPSBvYmpba107XG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgY3JlYXRlTmVzdGVkQXJncyhlbnRyeSwgYCR7cHJvcENoYWlufS4ke2t9YCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcbiAgICAgICAgbmVzdGVkQXJnc1tlbnRyeS5jbGlOYW1lIHx8IGtdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XG5cbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcbiAgICAgICAgaWYgKGVudHJ5LmxlZ2FjeU5hbWUgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfSk7XG59O1xuXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xuIiwiLyoqXG4gKiBAZmlsZW92ZXJ2aWV3XG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJ1xuICogbGlicmFyeS4gVGhlIHBhcnNlZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHRoZW4gZXhwb3J0ZWQgdG8gYmUgdXNlZFxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXG4gKlxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cbiAqIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lclxuICogZm9yIGVhY2ggb2YgdGhlIG9wdGlvbnMuXG4gKi9cblxuaW1wb3J0IGRvdGVudiBmcm9tICdkb3RlbnYnO1xuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XG5cbmltcG9ydCB7IHNjcmlwdHNOYW1lcyB9IGZyb20gJy4vc2NoZW1hcy9jb25maWcuanMnO1xuXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcbmRvdGVudi5jb25maWcoKTtcblxuLy8gT2JqZWN0IHdpdGggY3VzdG9tIHZhbGlkYXRvcnMgYW5kIHRyYW5zZm9ybWVycywgdG8gYXZvaWQgcmVwZXRpdGlvblxuLy8gaW4gdGhlIENvbmZpZyBvYmplY3RcbmNvbnN0IHYgPSB7XG4gIC8vIFNwbGl0cyBzdHJpbmcgdmFsdWUgaW50byBlbGVtZW50cyBpbiBhbiBhcnJheSwgdHJpbXMgZXZlcnkgZWxlbWVudCwgY2hlY2tzXG4gIC8vIGlmIGFuIGFycmF5IGlzIGNvcnJlY3QsIGlmIGl0IGlzIGVtcHR5LCBhbmQgaWYgaXQgaXMsIHJldHVybnMgdW5kZWZpbmVkXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cbiAgICAgICAgdmFsdWVcbiAgICAgICAgICAuc3BsaXQoJywnKVxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXG4gICAgICAgICAgLmZpbHRlcigodmFsdWUpID0+IGZpbHRlckFycmF5LmluY2x1ZGVzKHZhbHVlKSlcbiAgICAgIClcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcblxuICAvLyBBbGxvd3Mgb25seSB0cnVlLCBmYWxzZSBhbmQgY29ycmVjdGx5IHBhcnNlIHRoZSB2YWx1ZSB0byBib29sZWFuXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXG4gIGJvb2xlYW46ICgpID0+XG4gICAgelxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA9PT0gJ3RydWUnIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxuICAvLyBiZSB1bmRlZmluZWRcbiAgZW51bTogKHZhbHVlcykgPT5cbiAgICB6XG4gICAgICAuZW51bShbLi4udmFsdWVzLCAnJ10pXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gVHJpbXMgdGhlIHN0cmluZyB2YWx1ZSBhbmQgY2hlY2tzIGlmIGl0IGlzIGVtcHR5IG9yIGNvbnRhaW5zIHN0cmluZ2lmaWVkXG4gIC8vIHZhbHVlcyBzdWNoIGFzIGZhbHNlLCB1bmRlZmluZWQsIG51bGwsIE5hTiwgaWYgaXQgZG9lcywgcmV0dXJucyB1bmRlZmluZWRcbiAgc3RyaW5nOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxuICAgICAgICAgIHZhbHVlID09PSAnJyxcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIHBvc2l0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxuICAvLyBiZSB1bmRlZmluZWRcbiAgcG9zaXRpdmVOdW06ICgpID0+XG4gICAgelxuICAgICAgLnN0cmluZygpXG4gICAgICAudHJpbSgpXG4gICAgICAucmVmaW5lKFxuICAgICAgICAodmFsdWUpID0+XG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID4gMCksXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXG5cbiAgLy8gQWxsb3dzIG5vbi1uZWdhdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXG4gIG5vbk5lZ2F0aXZlTnVtOiAoKSA9PlxuICAgIHpcbiAgICAgIC5zdHJpbmcoKVxuICAgICAgLnRyaW0oKVxuICAgICAgLnJlZmluZShcbiAgICAgICAgKHZhbHVlKSA9PlxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwKSxcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICAgIH0pXG4gICAgICApXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcbn07XG5cbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XG4gIC8vIGhpZ2hjaGFydHNcbiAgSElHSENIQVJUU19WRVJTSU9OOiB6XG4gICAgLnN0cmluZygpXG4gICAgLnRyaW0oKVxuICAgIC5yZWZpbmUoXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxuICAgICAgKHZhbHVlKSA9PiAoe1xuICAgICAgICBtZXNzYWdlOiBgSElHSENIQVJUU19WRVJTSU9OIG11c3QgYmUgJ2xhdGVzdCcsIGEgbWFqb3IgdmVyc2lvbiwgb3IgaW4gdGhlIGZvcm0gWFguWVkuWlosIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxuICAgIC5zdHJpbmcoKVxuICAgIC50cmltKClcbiAgICAucmVmaW5lKFxuICAgICAgKHZhbHVlKSA9PlxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwczovLycpIHx8XG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxuICAgICAgICB2YWx1ZSA9PT0gJycsXG4gICAgICAodmFsdWUpID0+ICh7XG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXG4gICAgICB9KVxuICAgIClcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5jb3JlKSxcbiAgSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUzogdi5hcnJheShzY3JpcHRzTmFtZXMubW9kdWxlcyksXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcbiAgSElHSENIQVJUU19DQUNIRV9QQVRIOiB2LnN0cmluZygpLFxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxuXG4gIC8vIGV4cG9ydFxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcbiAgRVhQT1JUX0NPTlNUUjogdi5lbnVtKFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10pLFxuICBFWFBPUlRfREVGQVVMVF9IRUlHSFQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX0RFRkFVTFRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcbiAgRVhQT1JUX1JBU1RFUklaQVRJT05fVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxuXG4gIC8vIGN1c3RvbVxuICBDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT046IHYuYm9vbGVhbigpLFxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHNlcnZlclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX0hPU1Q6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9QT1JUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxuXG4gIC8vIHNlcnZlciBwcm94eVxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgU0VSVkVSX1BST1hZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcblxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xuICBTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEU6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHYuc3RyaW5nKCksXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU46IHYuc3RyaW5nKCksXG5cbiAgLy8gc2VydmVyIHNzbFxuICBTRVJWRVJfU1NMX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxuICBTRVJWRVJfU1NMX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcbiAgU0VSVkVSX1NTTF9DRVJUX1BBVEg6IHYuc3RyaW5nKCksXG5cbiAgLy8gcG9vbFxuICBQT09MX01JTl9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9XT1JLX0xJTUlUOiB2LnBvc2l0aXZlTnVtKCksXG4gIFBPT0xfQUNRVUlSRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9JRExFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgUE9PTF9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxuICBQT09MX1JFU09VUkNFU19JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxuXG4gIC8vIGxvZ2dlclxuICBMT0dHSU5HX0xFVkVMOiB6XG4gICAgLnN0cmluZygpXG4gICAgLnRyaW0oKVxuICAgIC5yZWZpbmUoXG4gICAgICAodmFsdWUpID0+XG4gICAgICAgIHZhbHVlID09PSAnJyB8fFxuICAgICAgICAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJlxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA8PSA1KSxcbiAgICAgICh2YWx1ZSkgPT4gKHtcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcbiAgICAgIH0pXG4gICAgKVxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcbiAgTE9HR0lOR19GSUxFOiB2LnN0cmluZygpLFxuICBMT0dHSU5HX0RFU1Q6IHYuc3RyaW5nKCksXG4gIExPR0dJTkdfVE9fQ09OU09MRTogdi5ib29sZWFuKCksXG4gIExPR0dJTkdfVE9fRklMRTogdi5ib29sZWFuKCksXG5cbiAgLy8gdWlcbiAgVUlfRU5BQkxFOiB2LmJvb2xlYW4oKSxcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXG5cbiAgLy8gb3RoZXJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxuICBPVEhFUl9OT19MT0dPOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcbiAgT1RIRVJfQ09OTkVDVElPTl9PVkVSX1BJUEU6IHYuYm9vbGVhbigpLFxuXG4gIC8vIGRlYnVnZ2VyXG4gIERFQlVHX0VOQUJMRTogdi5ib29sZWFuKCksXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcbiAgREVCVUdfREVWVE9PTFM6IHYuYm9vbGVhbigpLFxuICBERUJVR19MSVNURU5fVE9fQ09OU09MRTogdi5ib29sZWFuKCksXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXG4gIERFQlVHX1NMT1dfTU86IHYubm9uTmVnYXRpdmVOdW0oKSxcbiAgREVCVUdfREVCVUdHSU5HX1BPUlQ6IHYucG9zaXRpdmVOdW0oKVxufSk7XG5cbmV4cG9ydCBjb25zdCBlbnZzID0gQ29uZmlnLnBhcnRpYWwoKS5wYXJzZShwcm9jZXNzLmVudik7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgYXBwZW5kRmlsZSwgZXhpc3RzU3luYywgbWtkaXJTeW5jIH0gZnJvbSAnZnMnO1xuXG4vLyBUaGUgYXZhaWxhYmxlIGNvbG9yc1xuY29uc3QgY29sb3JzID0gWydyZWQnLCAneWVsbG93JywgJ2JsdWUnLCAnZ3JheScsICdncmVlbiddO1xuXG4vLyBUaGUgZGVmYXVsdCBsb2dnaW5nIGNvbmZpZ1xubGV0IGxvZ2dpbmcgPSB7XG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xuICB0b0NvbnNvbGU6IHRydWUsXG4gIHRvRmlsZTogZmFsc2UsXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcbiAgLy8gTG9nIGxldmVsc1xuICBsZXZlbHNEZXNjOiBbXG4gICAge1xuICAgICAgdGl0bGU6ICdlcnJvcicsXG4gICAgICBjb2xvcjogY29sb3JzWzBdXG4gICAgfSxcbiAgICB7XG4gICAgICB0aXRsZTogJ3dhcm5pbmcnLFxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICdub3RpY2UnLFxuICAgICAgY29sb3I6IGNvbG9yc1syXVxuICAgIH0sXG4gICAge1xuICAgICAgdGl0bGU6ICd2ZXJib3NlJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbM11cbiAgICB9LFxuICAgIHtcbiAgICAgIHRpdGxlOiAnYmVuY2htYXJrJyxcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cbiAgICB9XG4gIF0sXG4gIC8vIExvZyBsaXN0ZW5lcnNcbiAgbGlzdGVuZXJzOiBbXVxufTtcblxuLyoqXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXG4gKiB0aGUgbmVjZXNzYXJ5IGRpcmVjdG9yeSBzdHJ1Y3R1cmUgaWYgbm90IGFscmVhZHkgY3JlYXRlZCBhbmQgYXBwZW5kcyB0aGVcbiAqIGNvbnRlbnQsIGluY2x1ZGluZyBhbiBvcHRpb25hbCBwcmVmaXgsIHRvIHRoZSBzcGVjaWZpZWQgbG9nIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmdbXX0gdGV4dHMgLSBBbiBhcnJheSBvZiB0ZXh0cyB0byBiZSBsb2dnZWQuXG4gKiBAcGFyYW0ge3N0cmluZ30gcHJlZml4IC0gQW4gb3B0aW9uYWwgcHJlZml4IHRvIGJlIGFkZGVkIHRvIGVhY2ggbG9nIGVudHJ5LlxuICovXG5jb25zdCBsb2dUb0ZpbGUgPSAodGV4dHMsIHByZWZpeCkgPT4ge1xuICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcbiAgICAvLyBDcmVhdGUgaWYgZG9lcyBub3QgZXhpc3RcbiAgICAhZXhpc3RzU3luYyhsb2dnaW5nLmRlc3QpICYmIG1rZGlyU3luYyhsb2dnaW5nLmRlc3QpO1xuXG4gICAgLy8gV2Ugbm93IGFzc3VtZSB0aGUgcGF0aCBpcyBhdmFpbGFibGUsIGUuZy4gaXQncyB0aGUgcmVzcG9uc2liaWxpdHlcbiAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxuICAgIGxvZ2dpbmcucGF0aENyZWF0ZWQgPSB0cnVlO1xuICB9XG5cbiAgLy8gQWRkIHRoZSBjb250ZW50IHRvIGEgZmlsZVxuICBhcHBlbmRGaWxlKFxuICAgIGAke2xvZ2dpbmcuZGVzdH0ke2xvZ2dpbmcuZmlsZX1gLFxuICAgIFtwcmVmaXhdLmNvbmNhdCh0ZXh0cykuam9pbignICcpICsgJ1xcbicsXG4gICAgKGVycm9yKSA9PiB7XG4gICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgY29uc29sZS5sb2coYFtsb2dnZXJdIFVuYWJsZSB0byB3cml0ZSB0byBsb2cgZmlsZTogJHtlcnJvcn1gKTtcbiAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcbiAgICAgIH1cbiAgICB9XG4gICk7XG59O1xuXG4vKipcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXG4gKiBgbGV2ZWxgIHdpbGwgYmUgcGFzc2VkIGRpcmVjdGx5IHRvIGNvbnNvbGUubG9nLCBhbmQvb3Igd2lsbCBiZSBqb2luZWRcbiAqIGFuZCBhcHBlbmRlZCB0byB0aGUgbG9nIGZpbGUuXG4gKlxuICogQHBhcmFtIHthbnl9IGFyZ3MgLSBBbiBhcnJheSBvZiBhcmd1bWVudHMgd2hlcmUgdGhlIGZpcnN0IGlzIHRoZSBsb2cgbGV2ZWxcbiAqIGFuZCB0aGUgcmVzdCBhcmUgc3RyaW5ncyB0byBidWlsZCBhIG1lc3NhZ2Ugd2l0aC5cbiAqL1xuZXhwb3J0IGNvbnN0IGxvZyA9ICguLi5hcmdzKSA9PiB7XG4gIGNvbnN0IFtuZXdMZXZlbCwgLi4udGV4dHNdID0gYXJncztcblxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xuICBjb25zdCB7IGxldmVsc0Rlc2MsIGxldmVsIH0gPSBsb2dnaW5nO1xuXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlIG9yIGlzIGEgYmVuY2htYXJrIGxvZ1xuICBpZiAoXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcbiAgICAobmV3TGV2ZWwgPT09IDAgfHwgbmV3TGV2ZWwgPiBsZXZlbCB8fCBsZXZlbCA+IGxldmVsc0Rlc2MubGVuZ3RoKVxuICApIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xuXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XG5cbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xuICAgIGZuKHByZWZpeCwgdGV4dHMuam9pbignICcpKTtcbiAgfSk7XG5cbiAgLy8gTG9nIHRvIGNvbnNvbGVcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XG4gICAgY29uc29sZS5sb2cuYXBwbHkoXG4gICAgICB1bmRlZmluZWQsXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXG4gICAgKTtcbiAgfVxuXG4gIC8vIExvZyB0byBmaWxlXG4gIGlmIChsb2dnaW5nLnRvRmlsZSkge1xuICAgIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcbiAgfVxufTtcblxuLyoqXG4gKiBMb2dzIGFuIGVycm9yIG1lc3NhZ2Ugd2l0aCBpdHMgc3RhY2sgdHJhY2UuIE9wdGlvbmFsbHksIGEgY3VzdG9tIG1lc3NhZ2VcbiAqIGNhbiBiZSBwcm92aWRlZC5cbiAqXG4gKiBAcGFyYW0ge251bWJlcn0gbGV2ZWwgLSBUaGUgbG9nIGxldmVsLlxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbU1lc3NhZ2UgLSBBbiBvcHRpb25hbCBjdXN0b20gbWVzc2FnZSB0byBiZSBsb2dnZWQgYWxvbmdcbiAqIHdpdGggdGhlIGVycm9yLlxuICovXG5leHBvcnQgY29uc3QgbG9nV2l0aFN0YWNrID0gKG5ld0xldmVsLCBlcnJvciwgY3VzdG9tTWVzc2FnZSkgPT4ge1xuICAvLyBHZXQgdGhlIG1haW4gbWVzc2FnZVxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcblxuICAvLyBDdXJyZW50IGxvZ2dpbmcgb3B0aW9uc1xuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xuXG4gIC8vIENoZWNrIGlmIGxvZyBsZXZlbCBpcyB3aXRoaW4gYSBjb3JyZWN0IHJhbmdlXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxuICBjb25zdCBuZXdEYXRlID0gbmV3IERhdGUoKS50b1N0cmluZygpLnNwbGl0KCcoJylbMF0udHJpbSgpO1xuXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcbiAgY29uc3QgcHJlZml4ID0gYCR7bmV3RGF0ZX0gWyR7bGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLnRpdGxlfV0gLWA7XG5cbiAgLy8gSWYgdGhlIGN1c3RvbU1lc3NhZ2UgZXhpc3RzLCB3ZSB3YW50IHRvIGRpc3BsYXkgdGhlIHdob2xlIHN0YWNrIG1lc3NhZ2VcbiAgY29uc3Qgc3RhY2tNZXNzYWdlID1cbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcbiAgICAgID8gZXJyb3Iuc3RhY2tcbiAgICAgIDogZXJyb3Iuc3RhY2suc3BsaXQoJ1xcbicpLnNsaWNlKDEpLmpvaW4oJ1xcbicpO1xuXG4gIC8vIENvbWJpbmUgY3VzdG9tIG1lc3NhZ2Ugb3IgZXJyb3IgbWVzc2FnZSB3aXRoIGVycm9yIHN0YWNrIG1lc3NhZ2VcbiAgY29uc3QgdGV4dHMgPSBbbWFpbk1lc3NhZ2UsICdcXG4nLCBzdGFja01lc3NhZ2VdO1xuXG4gIC8vIExvZyB0byBjb25zb2xlXG4gIGlmIChsb2dnaW5nLnRvQ29uc29sZSkge1xuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxuICAgICAgdW5kZWZpbmVkLFxuICAgICAgW3ByZWZpeC50b1N0cmluZygpW2xvZ2dpbmcubGV2ZWxzRGVzY1tuZXdMZXZlbCAtIDFdLmNvbG9yXV0uY29uY2F0KFtcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxuICAgICAgICAnXFxuJyxcbiAgICAgICAgc3RhY2tNZXNzYWdlXG4gICAgICBdKVxuICAgICk7XG4gIH1cblxuICAvLyBDYWxsIGF2YWlsYWJsZSBsb2cgbGlzdGVuZXJzXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xuICB9KTtcblxuICAvLyBMb2cgdG8gZmlsZVxuICBpZiAobG9nZ2luZy50b0ZpbGUpIHtcbiAgICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XG4gIH1cbn07XG5cbi8qKlxuICogU2V0cyB0aGUgbG9nIGxldmVsIHRvIHRoZSBzcGVjaWZpZWQgdmFsdWUuIExvZyBsZXZlbHMgYXJlICgwID0gbm8gbG9nZ2luZyxcbiAqIDEgPSBlcnJvciwgMiA9IHdhcm5pbmcsIDMgPSBub3RpY2UsIDQgPSB2ZXJib3NlIG9yIDUgPSBiZW5jaG1hcmspXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IG5ld0xldmVsIC0gVGhlIG5ldyBsb2cgbGV2ZWwgdG8gYmUgc2V0LlxuICovXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcbiAgaWYgKG5ld0xldmVsID49IDAgJiYgbmV3TGV2ZWwgPD0gbG9nZ2luZy5sZXZlbHNEZXNjLmxlbmd0aCkge1xuICAgIGxvZ2dpbmcubGV2ZWwgPSBuZXdMZXZlbDtcbiAgfVxufTtcblxuLyoqXG4gKiBFbmFibGVzIGZpbGUgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgZGVzdGluYXRpb24gYW5kIGxvZyBmaWxlLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dGaWxlIC0gVGhlIGxvZyBmaWxlIG5hbWUuXG4gKi9cbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XG4gIC8vIFVwZGF0ZSBsb2dnaW5nIG9wdGlvbnNcbiAgbG9nZ2luZyA9IHtcbiAgICAuLi5sb2dnaW5nLFxuICAgIGRlc3Q6IGxvZ0Rlc3QgfHwgbG9nZ2luZy5kZXN0LFxuICAgIGZpbGU6IGxvZ0ZpbGUgfHwgbG9nZ2luZy5maWxlLFxuICAgIHRvRmlsZTogdHJ1ZVxuICB9O1xuXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIGxvZygxLCAnW2xvZ2dlcl0gRmlsZSBsb2dnaW5nIGluaXRpYWxpemF0aW9uOiBubyBwYXRoIHN1cHBsaWVkLicpO1xuICB9XG5cbiAgaWYgKCFsb2dnaW5nLmRlc3QuZW5kc1dpdGgoJy8nKSkge1xuICAgIGxvZ2dpbmcuZGVzdCArPSAnLyc7XG4gIH1cbn07XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgbG9nZ2luZyB3aXRoIHRoZSBzcGVjaWZpZWQgbG9nZ2luZyBjb25maWd1cmF0aW9uLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nT3B0aW9ucyAtIFRoZSBsb2dnaW5nIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICovXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZ09wdGlvbnMpID0+IHtcbiAgLy8gU2V0IGFsbCB0aGUgbG9nZ2luZyBvcHRpb25zIG9uIG91ciBsb2dnaW5nIG1vZHVsZSBvYmplY3RcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobG9nZ2luZ09wdGlvbnMpKSB7XG4gICAgbG9nZ2luZ1trZXldID0gdmFsdWU7XG4gIH1cblxuICAvLyBTZXQgdGhlIGxvZyBsZXZlbFxuICBzZXRMb2dMZXZlbChsb2dnaW5nT3B0aW9ucyAmJiBwYXJzZUludChsb2dnaW5nT3B0aW9ucy5sZXZlbCkpO1xuXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxuICBpZiAobG9nZ2luZ09wdGlvbnMgJiYgbG9nZ2luZ09wdGlvbnMuZGVzdCAmJiBsb2dnaW5nT3B0aW9ucy50b0ZpbGUpIHtcbiAgICBlbmFibGVGaWxlTG9nZ2luZyhcbiAgICAgIGxvZ2dpbmdPcHRpb25zLmRlc3QsXG4gICAgICBsb2dnaW5nT3B0aW9ucy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xuICAgICk7XG4gIH1cbn07XG5cbi8qKlxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cbiAqXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBmbiAtIFRoZSBsaXN0ZW5lciBmdW5jdGlvbiB0byBiZSBhZGRlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGxpc3RlbiA9IChmbikgPT4ge1xuICBsb2dnaW5nLmxpc3RlbmVycy5wdXNoKGZuKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgbG9nLFxuICBsb2dXaXRoU3RhY2ssXG4gIHNldExvZ0xldmVsLFxuICBlbmFibGVGaWxlTG9nZ2luZyxcbiAgaW5pdExvZ2dpbmcsXG4gIGxpc3RlblxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcblxuaW1wb3J0IHsgZGVmYXVsdENvbmZpZyB9IGZyb20gJy4uL2xpYi9zY2hlbWFzL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuY29uc3QgTUFYX0JBQ0tPRkZfQVRURU1QVFMgPSA2O1xuXG5leHBvcnQgY29uc3QgX19kaXJuYW1lID0gZmlsZVVSTFRvUGF0aChuZXcgVVJMKCcuLi8uJywgaW1wb3J0Lm1ldGEudXJsKSk7XG5cbi8qKlxuICogQ2xlYXJzIGFuZCBzdGFuZGFyZGl6ZXMgdGV4dCBieSByZXBsYWNpbmcgbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZVxuICogY2hhcmFjdGVycyB3aXRoIGEgc2luZ2xlIHNwYWNlIGFuZCB0cmltbWluZyBhbnkgbGVhZGluZyBvciB0cmFpbGluZ1xuICogd2hpdGVzcGFjZS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSBpbnB1dCB0ZXh0IHRvIGJlIGNsZWFyZWQuXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcbiAqIG11bHRpcGxlIGNvbnNlY3V0aXZlIHdoaXRlc3BhY2UgY2hhcmFjdGVycy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBbcmVwbGFjZXI9JyAnXSAtIFRoZSBzdHJpbmcgdXNlZCB0byByZXBsYWNlIG11bHRpcGxlXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY2xlYXJlZCBhbmQgc3RhbmRhcmRpemVkIHRleHQuXG4gKi9cbmV4cG9ydCBjb25zdCBjbGVhclRleHQgPSAodGV4dCwgcnVsZSA9IC9cXHNcXHMrL2csIHJlcGxhY2VyID0gJyAnKSA9PlxuICB0ZXh0LnJlcGxhY2VBbGwocnVsZSwgcmVwbGFjZXIpLnRyaW0oKTtcblxuLyoqXG4gKiBJbXBsZW1lbnRzIGFuIGV4cG9uZW50aWFsIGJhY2tvZmYgc3RyYXRlZ3kgZm9yIHJldHJ5aW5nIGEgZnVuY3Rpb24gdW50aWxcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXG4gKlxuICogQHBhcmFtIHtGdW5jdGlvbn0gZm4gLSBUaGUgZnVuY3Rpb24gdG8gYmUgcmV0cmllZC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxuICogQHBhcmFtIHsuLi5hbnl9IGFyZ3MgLSBBcmd1bWVudHMgdG8gYmUgcGFzc2VkIHRvIHRoZSBmdW5jdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxuICogaWYgc3VjY2Vzc2Z1bC5cbiAqXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXG4gKiBpcyByZWFjaGVkLlxuICovXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcbiAgdHJ5IHtcbiAgICAvLyBUcnkgdG8gY2FsbCB0aGUgZnVuY3Rpb25cbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gQ2FsY3VsYXRlIGRlbGF5IGluIG1zXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcblxuICAgIC8vIElmIHRoZSBhdHRlbXB0IGV4Y2VlZHMgdGhlIG1heGltdW0gYXR0ZW1wdHMgb2YgcmVhcGVhdCwgdGhyb3cgYW4gZXJyb3JcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XG4gICAgICB0aHJvdyBlcnJvcjtcbiAgICB9XG5cbiAgICAvLyBXYWl0IGdpdmVuIGFtb3VudCBvZiB0aW1lXG4gICAgYXdhaXQgbmV3IFByb21pc2UoKHJlc3BvbnNlKSA9PiBzZXRUaW1lb3V0KHJlc3BvbnNlLCBkZWxheUluTXMpKTtcbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtwb29sXSBXYWl0ZWQgJHtkZWxheUluTXN9bXMgdW50aWwgbmV4dCBjYWxsIGZvciB0aGUgcmVzb3VyY2Ugb2YgSUQ6ICR7YXJnc1swXX0uYFxuICAgICk7XG5cbiAgICAvLyBUcnkgYWdhaW5cbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XG4gIH1cbn07XG5cbi8qKlxuICogRml4ZXMgdGhlIGV4cG9ydCB0eXBlIGJhc2VkIG9uIE1JTUUgdHlwZXMgYW5kIGZpbGUgZXh0ZW5zaW9ucy5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIFRoZSBvcmlnaW5hbCBleHBvcnQgdHlwZS5cbiAqIEBwYXJhbSB7c3RyaW5nfSBvdXRmaWxlIC0gVGhlIGZpbGUgcGF0aCBvciBuYW1lLlxuICpcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNvcnJlY3RlZCBleHBvcnQgdHlwZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xuICAvLyBNSU1FIHR5cGVzXG4gIGNvbnN0IG1pbWVUeXBlcyA9IHtcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXG4gICAgJ2ltYWdlL2pwZWcnOiAnanBlZycsXG4gICAgJ2FwcGxpY2F0aW9uL3BkZic6ICdwZGYnLFxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcbiAgfTtcblxuICAvLyBGb3JtYXRzXG4gIGNvbnN0IGZvcm1hdHMgPSBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXTtcblxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcbiAgaWYgKG91dGZpbGUpIHtcbiAgICBjb25zdCBvdXRUeXBlID0gb3V0ZmlsZS5zcGxpdCgnLicpLnBvcCgpO1xuXG4gICAgaWYgKG91dFR5cGUgPT09ICdqcGcnKSB7XG4gICAgICB0eXBlID0gJ2pwZWcnO1xuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XG4gICAgICB0eXBlID0gb3V0VHlwZTtcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gYSBjb3JyZWN0IHR5cGVcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIGFuZCB2YWxpZGF0ZXMgcmVzb3VyY2VzIGZvciBleHBvcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcbiAqIGEgSlNPTiBvYmplY3QsIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBwYXRoIHRvIGEgSlNPTiBmaWxlLlxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBXaGV0aGVyIHRvIGFsbG93IGxvYWRpbmcgcmVzb3VyY2VzIGZyb21cbiAqIGZpbGVzLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R8dW5kZWZpbmVkfSAtIFRoZSBoYW5kbGVkIHJlc291cmNlcyBvciB1bmRlZmluZWQgaWYgbm8gdmFsaWRcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXG4gKi9cbmV4cG9ydCBjb25zdCBoYW5kbGVSZXNvdXJjZXMgPSAocmVzb3VyY2VzID0gZmFsc2UsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xuXG4gIGxldCBoYW5kbGVkUmVzb3VyY2VzID0gcmVzb3VyY2VzO1xuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xuXG4gIC8vIFRyeSB0byBsb2FkIHJlc291cmNlcyBmcm9tIGEgZmlsZVxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xuICAgIHRyeSB7XG4gICAgICBoYW5kbGVkUmVzb3VyY2VzID0gaXNDb3JyZWN0SlNPTihyZWFkRmlsZVN5bmMocmVzb3VyY2VzLCAndXRmOCcpKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjbGldIE5vIHJlc291cmNlcyBmb3VuZC5gKTtcbiAgICB9XG4gIH0gZWxzZSB7XG4gICAgLy8gVHJ5IHRvIGdldCBKU09OXG4gICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVzb3VyY2VzKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIGZpbGVzIHNlY3Rpb25cbiAgICBpZiAoaGFuZGxlZFJlc291cmNlcyAmJiAhYWxsb3dGaWxlUmVzb3VyY2VzKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcbiAgICB9XG4gIH1cblxuICAvLyBGaWx0ZXIgZnJvbSB1bm5lY2Vzc2FyeSBwcm9wZXJ0aWVzXG4gIGZvciAoY29uc3QgcHJvcE5hbWUgaW4gaGFuZGxlZFJlc291cmNlcykge1xuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xuICAgICAgZGVsZXRlIGhhbmRsZWRSZXNvdXJjZXNbcHJvcE5hbWVdO1xuICAgIH0gZWxzZSBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIC8vIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiBhbGxvd2VkIHByb3BlcnRpZXMgaXMgcHJlc2VudFxuICBpZiAoIWNvcnJlY3RSZXNvdXJjZXMpIHtcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XG4gIH1cblxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxuICBpZiAoaGFuZGxlZFJlc291cmNlcy5maWxlcykge1xuICAgIGhhbmRsZWRSZXNvdXJjZXMuZmlsZXMgPSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLm1hcCgoaXRlbSkgPT4gaXRlbS50cmltKCkpO1xuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcbiAgICB9XG4gIH1cblxuICAvLyBSZXR1cm4gcmVzb3VyY2VzXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xufTtcblxuLyoqXG4gKiBWYWxpZGF0ZXMgYW5kIHBhcnNlcyBKU09OIGRhdGEuIENoZWNrcyBpZiBwcm92aWRlZCBkYXRhIGlzIG9yIGNhblxuICogYmUgYSBjb3JyZWN0IEpTT04uIElmIGEgcHJpbWl0aXZlIGlzIHByb3ZpZGVkLCBpdCBpcyBzdHJpbmdpZmllZCBhbmQgcmV0dXJuZWQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSBkYXRhIC0gVGhlIEpTT04gZGF0YSB0byBiZSB2YWxpZGF0ZWQgYW5kIHBhcnNlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gdG9TdHJpbmcgLSBXaGV0aGVyIHRvIHJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXG4gKlxuICogQHJldHVybnMge09iamVjdHxzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgcGFyc2VkIEpTT04gb2JqZWN0LCBzdHJpbmdpZmllZCBKU09OLFxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGlzQ29ycmVjdEpTT04oZGF0YSwgdG9TdHJpbmcpIHtcbiAgdHJ5IHtcbiAgICAvLyBHZXQgdGhlIHN0cmluZyByZXByZXNlbnRhdGlvbiBpZiBub3QgYWxyZWFkeSBiZWZvcmUgcGFyc2luZ1xuICAgIGNvbnN0IHBhcnNlZERhdGEgPSBKU09OLnBhcnNlKFxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXG4gICAgKTtcblxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxuICAgIGlmICh0eXBlb2YgcGFyc2VkRGF0YSAhPT0gJ3N0cmluZycgJiYgdG9TdHJpbmcpIHtcbiAgICAgIHJldHVybiBKU09OLnN0cmluZ2lmeShwYXJzZWREYXRhKTtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm4gYSBKU09OXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrcyBpZiB0aGUgZ2l2ZW4gaXRlbSBpcyBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFRydWUgaWYgdGhlIGl0ZW0gaXMgYW4gb2JqZWN0LCBmYWxzZSBvdGhlcndpc2UuXG4gKi9cbmV4cG9ydCBjb25zdCBpc09iamVjdCA9IChpdGVtKSA9PlxuICB0eXBlb2YgaXRlbSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiYgaXRlbSAhPT0gbnVsbDtcblxuLyoqXG4gKiBDaGVja3MgaWYgdGhlIGdpdmVuIG9iamVjdCBpcyBlbXB0eS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gaXRlbSAtIFRoZSBvYmplY3QgdG8gYmUgY2hlY2tlZC5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGlzT2JqZWN0RW1wdHkgPSAoaXRlbSkgPT5cbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXG4gICFBcnJheS5pc0FycmF5KGl0ZW0pICYmXG4gIGl0ZW0gIT09IG51bGwgJiZcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xuXG4vKipcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGl0ZW0gLSBUaGUgc3RyaW5nIHRvIGJlIGNoZWNrZWQgZm9yIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwuXG4gKlxuICogQHJldHVybnMge2Jvb2xlYW59IC0gVHJ1ZSBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kLCBmYWxzZVxuICogb3RoZXJ3aXNlLlxuICovXG5leHBvcnQgY29uc3QgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCA9IChpdGVtKSA9PiB7XG4gIGNvbnN0IHJlZ2V4UGF0dGVybnMgPSBbXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEwXFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTI3XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiLyxcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxuICAgIC94bGluazpocmVmPVwiKD86aHR0cDpcXC9cXC98aHR0cHM6XFwvXFwvKT8xOTJcXC4xNjhcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFxiL1xuICBdO1xuXG4gIHJldHVybiByZWdleFBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChpdGVtKSk7XG59O1xuXG4vKipcbiAqIENyZWF0ZXMgYSBkZWVwIGNvcHkgb2YgdGhlIGdpdmVuIG9iamVjdCBvciBhcnJheS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdHxBcnJheX0gb2JqIC0gVGhlIG9iamVjdCBvciBhcnJheSB0byBiZSBkZWVwbHkgY29waWVkLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxuICovXG5leHBvcnQgY29uc3QgZGVlcENvcHkgPSAob2JqKSA9PiB7XG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcbiAgICByZXR1cm4gb2JqO1xuICB9XG5cbiAgY29uc3QgY29weSA9IEFycmF5LmlzQXJyYXkob2JqKSA/IFtdIDoge307XG5cbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XG4gICAgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIHtcbiAgICAgIGNvcHlba2V5XSA9IGRlZXBDb3B5KG9ialtrZXldKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gY29weTtcbn07XG5cbi8qKlxuICogQ29udmVydHMgdGhlIHByb3ZpZGVkIG9wdGlvbnMgb2JqZWN0IHRvIGEgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHdpdGggdGhlXG4gKiBvcHRpb24gdG8gcHJlc2VydmUgZnVuY3Rpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IHRvIGJlIGNvbnZlcnRlZCB0byBhIHN0cmluZy5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGdW5jdGlvbnMgLSBJZiBzZXQgdG8gdHJ1ZSwgZnVuY3Rpb25zIGFyZSBwcmVzZXJ2ZWRcbiAqIGluIHRoZSBvdXRwdXQuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgSlNPTi1mb3JtYXR0ZWQgc3RyaW5nIHJlcHJlc2VudGluZyB0aGUgb3B0aW9ucy5cbiAqL1xuZXhwb3J0IGNvbnN0IG9wdGlvbnNTdHJpbmdpZnkgPSAob3B0aW9ucywgYWxsb3dGdW5jdGlvbnMpID0+IHtcbiAgY29uc3QgcmVwbGFjZXJDYWxsYmFjayA9IChuYW1lLCB2YWx1ZSkgPT4ge1xuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICB2YWx1ZSA9IHZhbHVlLnRyaW0oKTtcblxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xuICAgICAgaWYgKFxuICAgICAgICAodmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24oJykgfHwgdmFsdWUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCcpKSAmJlxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXG4gICAgICApIHtcbiAgICAgICAgdmFsdWUgPSBhbGxvd0Z1bmN0aW9uc1xuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXG4gICAgICAgICAgOiB1bmRlZmluZWQ7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gJ2Z1bmN0aW9uJ1xuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcbiAgICAgIDogdmFsdWU7XG4gIH07XG5cbiAgLy8gU3RyaW5naWZ5IG9wdGlvbnMgYW5kIGlmIHJlcXVpcmVkLCByZXBsYWNlIHNwZWNpYWwgZnVuY3Rpb25zIG1hcmtzXG4gIHJldHVybiBKU09OLnN0cmluZ2lmeShvcHRpb25zLCByZXBsYWNlckNhbGxiYWNrKS5yZXBsYWNlQWxsKFxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXG4gICAgJydcbiAgKTtcbn07XG5cbi8qKlxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cbiAqXG4gKiBAcGFyYW0ge2Jvb2xlYW59IG5vTG9nbyAtIElmIHRydWUsIG9ubHkgcHJpbnRzIHZlcnNpb24gaW5mb3JtYXRpb24gd2l0aG91dFxuICogdGhlIGxvZ28uXG4gKi9cbmV4cG9ydCBjb25zdCBwcmludExvZ28gPSAobm9Mb2dvKSA9PiB7XG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXG4gIGNvbnN0IHBhY2thZ2VWZXJzaW9uID0gSlNPTi5wYXJzZShcbiAgICByZWFkRmlsZVN5bmMoam9pbihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSlcbiAgKS52ZXJzaW9uO1xuXG4gIC8vIFByaW50IHRleHQgb25seVxuICBpZiAobm9Mb2dvKSB7XG4gICAgY29uc29sZS5sb2coYFN0YXJ0aW5nIEhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlciB2JHtwYWNrYWdlVmVyc2lvbn0uLi5gKTtcbiAgICByZXR1cm47XG4gIH1cblxuICAvLyBQcmludCB0aGUgbG9nb1xuICBjb25zb2xlLmxvZyhcbiAgICByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy9tc2cvc3RhcnR1cC5tc2cnKS50b1N0cmluZygpLmJvbGQueWVsbG93LFxuICAgIGB2JHtwYWNrYWdlVmVyc2lvbn1cXG5gLmJvbGRcbiAgKTtcbn07XG5cbi8qKlxuICogUHJpbnRzIHRoZSB1c2FnZSBpbmZvcm1hdGlvbiBmb3IgQ0xJIGFyZ3VtZW50cy4gSWYgcmVxdWlyZWQsIGl0IGNhbiBsaXN0XG4gKiBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBwcmludFVzYWdlKCkge1xuICBjb25zdCBwYWQgPSA0ODtcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xuXG4gIC8vIERpc3BsYXkgcmVhZG1lIGluZm9ybWF0aW9uXG4gIGNvbnNvbGUubG9nKFxuICAgICdcXG5Vc2FnZSBvZiBDTEkgYXJndW1lbnRzOicuYm9sZCxcbiAgICAnXFxuLS0tLS0tJyxcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXG4gICk7XG5cbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKG9wdGlvbnMpKSB7XG4gICAgICAvLyBJZiBjYXRlZ29yeSBoYXMgbW9yZSBsZXZlbHMsIGdvIGZ1cnRoZXJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcbiAgICAgICAgY3ljbGVDYXRlZ29yaWVzKG9wdGlvbik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcbiAgICAgICAgICAoJzwnICsgb3B0aW9uLnR5cGUgKyAnPicpLmdyZWVuXG4gICAgICAgIH0gYDtcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xuICAgICAgICAgIGZvciAobGV0IGkgPSBkZXNjTmFtZS5sZW5ndGg7IGkgPCBwYWQ7IGkrKykge1xuICAgICAgICAgICAgZGVzY05hbWUgKz0gJy4nO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcbiAgICAgICAgY29uc29sZS5sb2coXG4gICAgICAgICAgZGVzY05hbWUsXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxuICAgICAgICAgIGBbRGVmYXVsdDogJHtvcHRpb24udmFsdWUudG9TdHJpbmcoKS5ib2xkfV1gLmJsdWVcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH07XG5cbiAgLy8gQ3ljbGUgdGhyb3VnaCBvcHRpb25zIG9mIGVhY2ggY2F0ZWdvcmllcyBhbmQgZGlzcGxheSB0aGUgdXNhZ2UgaW5mb1xuICBPYmplY3Qua2V5cyhkZWZhdWx0Q29uZmlnKS5mb3JFYWNoKChjYXRlZ29yeSkgPT4ge1xuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhjYXRlZ29yeSkpIHtcbiAgICAgIGNvbnNvbGUubG9nKGBcXG4ke2NhdGVnb3J5LnRvVXBwZXJDYXNlKCl9YC5yZWQpO1xuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcbiAgICB9XG4gIH0pO1xuICBjb25zb2xlLmxvZygnXFxuJyk7XG59XG5cbi8qKlxuICogUm91bmRzIGEgbnVtYmVyIHRvIHRoZSBzcGVjaWZpZWQgcHJlY2lzaW9uLlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cbiAqIEBwYXJhbSB7bnVtYmVyfSBwcmVjaXNpb24gLSBUaGUgbnVtYmVyIG9mIGRlY2ltYWwgcGxhY2VzIHRvIHJvdW5kIHRvLlxuICpcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxuICovXG5leHBvcnQgY29uc3Qgcm91bmROdW1iZXIgPSAodmFsdWUsIHByZWNpc2lvbiA9IDEpID0+IHtcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XG4gIHJldHVybiBNYXRoLnJvdW5kKCt2YWx1ZSAqIG11bHRpcGxpZXIpIC8gbXVsdGlwbGllcjtcbn07XG5cbi8qKlxuICogQ29udmVydHMgYSB2YWx1ZSB0byBhIGJvb2xlYW4uXG4gKlxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgdmFsdWUgdG8gYmUgY29udmVydGVkIHRvIGEgYm9vbGVhbi5cbiAqXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXG4gKi9cbmV4cG9ydCBjb25zdCB0b0Jvb2xlYW4gPSAoaXRlbSkgPT5cbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxuICAgID8gZmFsc2VcbiAgICA6ICEhaXRlbTtcblxuLyoqXG4gKiBXcmFwcyBjdXN0b20gY29kZSB0byBleGVjdXRlIGl0IHNhZmVseS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tQ29kZSAtIFRoZSBjdXN0b20gY29kZSB0byBiZSB3cmFwcGVkLlxuICogQHBhcmFtIHtib29sZWFufSBhbGxvd0ZpbGVSZXNvdXJjZXMgLSBGbGFnIHRvIGFsbG93IGxvYWRpbmcgY29kZSBmcm9tIGEgZmlsZS5cbiAqXG4gKiBAcmV0dXJucyB7c3RyaW5nfGJvb2xlYW59IC0gVGhlIHdyYXBwZWQgY3VzdG9tIGNvZGUgb3IgZmFsc2UgaWYgd3JhcHBpbmdcbiAqIGZhaWxzLlxuICovXG5leHBvcnQgY29uc3Qgd3JhcEFyb3VuZCA9IChjdXN0b21Db2RlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcbiAgaWYgKGN1c3RvbUNvZGUgJiYgdHlwZW9mIGN1c3RvbUNvZGUgPT09ICdzdHJpbmcnKSB7XG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xuXG4gICAgaWYgKGN1c3RvbUNvZGUuZW5kc1dpdGgoJy5qcycpKSB7XG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXG4gICAgICAgID8gd3JhcEFyb3VuZChyZWFkRmlsZVN5bmMoY3VzdG9tQ29kZSwgJ3V0ZjgnKSlcbiAgICAgICAgOiBmYWxzZTtcbiAgICB9IGVsc2UgaWYgKFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCdmdW5jdGlvbigpJykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnZnVuY3Rpb24gKCknKSB8fFxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcbiAgICAgIGN1c3RvbUNvZGUuc3RhcnRzV2l0aCgnKCkgPT4nKVxuICAgICkge1xuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XG4gICAgfVxuICAgIHJldHVybiBjdXN0b21Db2RlLnJlcGxhY2UoLzskLywgJycpO1xuICB9XG59O1xuXG4vKipcbiAqIFV0aWxpdHkgdG8gbWVhc3VyZSBlbGFwc2VkIHRpbWUgdXNpbmcgdGhlIE5vZGUuanMgcHJvY2Vzcy5ocnRpbWUoKSBtZXRob2QuXG4gKlxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXG4gKiBpbiBtaWxsaXNlY29uZHMuXG4gKi9cbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcbiAgY29uc3Qgc3RhcnQgPSBwcm9jZXNzLmhydGltZS5iaWdpbnQoKTtcbiAgcmV0dXJuICgpID0+IE51bWJlcihwcm9jZXNzLmhydGltZS5iaWdpbnQoKSAtIHN0YXJ0KSAvIDEwMDAwMDA7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIF9fZGlybmFtZSxcbiAgY2xlYXJUZXh0LFxuICBleHBCYWNrb2ZmLFxuICBmaXhUeXBlLFxuICBoYW5kbGVSZXNvdXJjZXMsXG4gIGlzQ29ycmVjdEpTT04sXG4gIGlzT2JqZWN0LFxuICBpc09iamVjdEVtcHR5LFxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxuICBvcHRpb25zU3RyaW5naWZ5LFxuICBwcmludExvZ28sXG4gIHByaW50VXNhZ2UsXG4gIHJvdW5kTnVtYmVyLFxuICB0b0Jvb2xlYW4sXG4gIHdyYXBBcm91bmQsXG4gIG1lYXN1cmVUaW1lXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IGV4aXN0c1N5bmMsIHJlYWRGaWxlU3luYywgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcblxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XG5cbmltcG9ydCB7XG4gIGFic29sdXRlUHJvcHMsXG4gIGRlZmF1bHRDb25maWcsXG4gIG5lc3RlZEFyZ3MsXG4gIHByb21wdHNDb25maWdcbn0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgZGVlcENvcHksIGlzT2JqZWN0LCBwcmludFVzYWdlLCB0b0Jvb2xlYW4gfSBmcm9tICcuL3V0aWxzLmpzJztcblxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XG5cbi8qKlxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBUaGUgZ2VuZXJhbCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldE9wdGlvbnMgPSAoKSA9PiBnZW5lcmFsT3B0aW9ucztcblxuLyoqXG4gKiBJbml0aWFsaXplcyBhbmQgc2V0cyB0aGUgZ2VuZXJhbCBvcHRpb25zIGZvciB0aGUgc2VydmVyIGluc3RhY2UsIGtlZXBpbmdcbiAqIHRoZSBwcmluY2lwbGUgb2YgdGhlIG9wdGlvbnMgbG9hZCBwcmlvcml0eS4gSXQgYWNjZXB0cyBvcHRpb25hbCB1c2VyT3B0aW9uc1xuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSB1c2VyT3B0aW9ucyAtIFVzZXItcHJvdmlkZWQgb3B0aW9ucyBmb3IgY3VzdG9taXphdGlvbi5cbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cbiAqIChDTEkgdXNhZ2UpLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXG4gKi9cbmV4cG9ydCBjb25zdCBzZXRPcHRpb25zID0gKHVzZXJPcHRpb25zLCBhcmdzKSA9PiB7XG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xuICAgIC8vIEdldCB0aGUgYWRkaXRpb25hbCBvcHRpb25zIGZyb20gdGhlIGN1c3RvbSBKU09OIGZpbGVcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xuICB9XG5cbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXG4gIHVwZGF0ZURlZmF1bHRDb25maWcoZGVmYXVsdENvbmZpZywgZ2VuZXJhbE9wdGlvbnMpO1xuXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxuICBnZW5lcmFsT3B0aW9ucyA9IGluaXRPcHRpb25zKGRlZmF1bHRDb25maWcpO1xuXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XG4gIGlmICh1c2VyT3B0aW9ucykge1xuICAgIC8vIE1lcmdlIHVzZXIgb3B0aW9uc1xuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXG4gICAgICB1c2VyT3B0aW9ucyxcbiAgICAgIGFic29sdXRlUHJvcHNcbiAgICApO1xuICB9XG5cbiAgLy8gT25seSBmb3IgdGhlIENMSSB1c2FnZVxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcbiAgICBnZW5lcmFsT3B0aW9ucyA9IHBhaXJBcmd1bWVudFZhbHVlKGdlbmVyYWxPcHRpb25zLCBhcmdzLCBkZWZhdWx0Q29uZmlnKTtcbiAgfVxuXG4gIC8vIFJldHVybiBmaW5hbCBnZW5lcmFsIG9wdGlvbnNcbiAgcmV0dXJuIGdlbmVyYWxPcHRpb25zO1xufTtcblxuLyoqXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXG4gKiB0aGUgY29uZmlndXJhdGlvbiB0byBhIGZpbGUuXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxib29sZWFuPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgdG8gdHJ1ZSBvbmNlIHRoZSBtYW51YWxcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IG1hbnVhbENvbmZpZyA9IGFzeW5jIChjb25maWdGaWxlTmFtZSkgPT4ge1xuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxuICBsZXQgY29uZmlnRmlsZSA9IHt9O1xuXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xuICBpZiAoZXhpc3RzU3luYyhjb25maWdGaWxlTmFtZSkpIHtcbiAgICBjb25maWdGaWxlID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMoY29uZmlnRmlsZU5hbWUsICd1dGY4JykpO1xuICB9XG5cbiAgLy8gUXVlc3Rpb24gYWJvdXQgYSBjb25maWd1cmF0aW9uIGNhdGVnb3J5XG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcbiAgICBsZXQgcXVlc3Rpb25zQ291bnRlciA9IDA7XG4gICAgbGV0IGFsbFF1ZXN0aW9ucyA9IFtdO1xuXG4gICAgLy8gQ3JlYXRlIGEgY29ycmVzcG9uZGluZyBwcm9wZXJ0eSBpbiB0aGUgbWFudWFsQ29uZmlnIG9iamVjdFxuICAgIGZvciAoY29uc3Qgc2VjdGlvbiBvZiBjYXRlZ29yaWVzKSB7XG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXG4gICAgICBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dID0gcHJvbXB0c0NvbmZpZ1tzZWN0aW9uXS5tYXAoKG9wdGlvbikgPT4gKHtcbiAgICAgICAgLi4ub3B0aW9uLFxuICAgICAgICBzZWN0aW9uXG4gICAgICB9KSk7XG5cbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xuICAgICAgYWxsUXVlc3Rpb25zID0gWy4uLmFsbFF1ZXN0aW9ucywgLi4ucHJvbXB0c0NvbmZpZ1tzZWN0aW9uXV07XG4gICAgfVxuXG4gICAgYXdhaXQgcHJvbXB0cyhhbGxRdWVzdGlvbnMsIHtcbiAgICAgIG9uU3VibWl0OiBhc3luYyAocHJvbXB0LCBhbnN3ZXIpID0+IHtcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXG4gICAgICAgIGlmIChwcm9tcHQubmFtZSA9PT0gJ21vZHVsZVNjcmlwdHMnKSB7XG4gICAgICAgICAgYW5zd2VyID0gYW5zd2VyLmxlbmd0aFxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXG4gICAgICAgICAgICA6IHByb21wdC5jaG9pY2VzO1xuXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNvbmZpZ0ZpbGVbcHJvbXB0LnNlY3Rpb25dID0gcmVjdXJzaXZlUHJvcHMoXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXG4gICAgICAgICAgICBwcm9tcHQubmFtZS5zcGxpdCgnLicpLFxuICAgICAgICAgICAgcHJvbXB0LmNob2ljZXMgPyBwcm9tcHQuY2hvaWNlc1thbnN3ZXJdIDogYW5zd2VyXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXdhaXQgZnNQcm9taXNlcy53cml0ZUZpbGUoXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxuICAgICAgICAgICAgICBKU09OLnN0cmluZ2lmeShjb25maWdGaWxlLCBudWxsLCAyKSxcbiAgICAgICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICAgICApO1xuICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgIGVycm9yLFxuICAgICAgICAgICAgICBgW2NvbmZpZ10gQW4gZXJyb3Igb2NjdXJyZWQgd2hpbGUgY3JlYXRpbmcgdGhlICR7Y29uZmlnRmlsZU5hbWV9IGZpbGUuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiB0cnVlO1xuICB9O1xuXG4gIC8vIEZpbmQgdGhlIGNhdGVnb3JpZXNcbiAgY29uc3QgY2hvaWNlcyA9IE9iamVjdC5rZXlzKHByb21wdHNDb25maWcpLm1hcCgoY2hvaWNlKSA9PiAoe1xuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxuICAgIHZhbHVlOiBjaG9pY2VcbiAgfSkpO1xuXG4gIC8vIENhdGVnb3J5IHByb21wdFxuICByZXR1cm4gcHJvbXB0cyhcbiAgICB7XG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxuICAgICAgbmFtZTogJ2NhdGVnb3J5JyxcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcbiAgICAgIGhpbnQ6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnJyxcbiAgICAgIGNob2ljZXNcbiAgICB9LFxuICAgIHsgb25TdWJtaXQgfVxuICApO1xufTtcblxuLyoqXG4gKiBNYXBzIG9sZC1zdHJ1Y3R1cmVkIChQaGFudG9tSlMpIG9wdGlvbnMgdG8gYSBuZXcgY29uZmlndXJhdGlvbiBmb3JtYXRcbiAqIChQdXBwZXRlZXIpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvbGRPcHRpb25zIC0gT2xkLXN0cnVjdHVyZWQgb3B0aW9ucyB0byBiZSBtYXBwZWQuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXG4gKiBtYXBwaW5nLlxuICovXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xuICBjb25zdCBuZXdPcHRpb25zID0ge307XG4gIC8vIEN5Y2xlIHRocm91Z2ggb2xkLXN0cnVjdHVyZWQgb3B0aW9uc1xuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nba2V5XSA/IG5lc3RlZEFyZ3Nba2V5XS5zcGxpdCgnLicpIDogW107XG5cbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoXG4gICAgICAob2JqLCBwcm9wLCBpbmRleCkgPT5cbiAgICAgICAgKG9ialtwcm9wXSA9XG4gICAgICAgICAgcHJvcGVydGllc0NoYWluLmxlbmd0aCAtIDEgPT09IGluZGV4ID8gdmFsdWUgOiBvYmpbcHJvcF0gfHwge30pLFxuICAgICAgbmV3T3B0aW9uc1xuICAgICk7XG4gIH1cbiAgcmV0dXJuIG5ld09wdGlvbnM7XG59O1xuXG4vKipcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPcmlnaW5hbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxuICogQHBhcmFtIHtBcnJheX0gYWJzb2x1dGVQcm9wcyAtIExpc3Qgb2YgcHJvcGVydGllcyB0aGF0IHNob3VsZFxuICogbm90IGJlIHJlY3Vyc2l2ZWx5IG1lcmdlZC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBNZXJnZWQgY29uZmlndXJhdGlvbiBvcHRpb25zLlxuICovXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xuICBjb25zdCBtZXJnZWRPcHRpb25zID0gZGVlcENvcHkob3B0aW9ucyk7XG5cbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcbiAgICBtZXJnZWRPcHRpb25zW2tleV0gPVxuICAgICAgaXNPYmplY3QodmFsdWUpICYmXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXG4gICAgICBtZXJnZWRPcHRpb25zW2tleV0gIT09IHVuZGVmaW5lZFxuICAgICAgICA/IG1lcmdlQ29uZmlnT3B0aW9ucyhtZXJnZWRPcHRpb25zW2tleV0sIHZhbHVlLCBhYnNvbHV0ZVByb3BzKVxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcbiAgICAgICAgICA/IHZhbHVlXG4gICAgICAgICAgOiBtZXJnZWRPcHRpb25zW2tleV07XG4gIH1cblxuICByZXR1cm4gbWVyZ2VkT3B0aW9ucztcbn07XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcbiAqIGFuZCBnZW5lcmFsT3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxuICogQHBhcmFtIHtPYmplY3R9IGdlbmVyYWxPcHRpb25zIC0gR2VuZXJhbCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxuICovXG5leHBvcnQgY29uc3QgaW5pdEV4cG9ydFNldHRpbmdzID0gKGV4cG9ydE9wdGlvbnMsIGdlbmVyYWxPcHRpb25zID0ge30pID0+IHtcbiAgbGV0IG9wdGlvbnMgPSB7fTtcblxuICBpZiAoZXhwb3J0T3B0aW9ucy5zdmcpIHtcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xuICAgIG9wdGlvbnMuZXhwb3J0LnR5cGUgPSBleHBvcnRPcHRpb25zLnR5cGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQudHlwZTtcbiAgICBvcHRpb25zLmV4cG9ydC5zY2FsZSA9IGV4cG9ydE9wdGlvbnMuc2NhbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQuc2NhbGU7XG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XG4gICAgICBleHBvcnRPcHRpb25zLm91dGZpbGUgfHwgZXhwb3J0T3B0aW9ucy5leHBvcnQub3V0ZmlsZTtcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXG4gICAgfTtcbiAgfSBlbHNlIHtcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxuICAgICAgZ2VuZXJhbE9wdGlvbnMsXG4gICAgICBleHBvcnRPcHRpb25zLFxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xuICAgICAgYWJzb2x1dGVQcm9wc1xuICAgICk7XG4gIH1cblxuICBvcHRpb25zLmV4cG9ydC5vdXRmaWxlID1cbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xuICByZXR1cm4gb3B0aW9ucztcbn07XG5cbi8qKlxuICogTG9hZHMgYWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGZyb20gYSBzcGVjaWZpZWQgZmlsZSB1c2luZ1xuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXG4gKlxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgdG8gY2hlY2sgZm9yXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBBZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb24gbG9hZGVkIGZyb20gdGhlIHNwZWNpZmllZCBmaWxlLFxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxuICovXG5mdW5jdGlvbiBsb2FkQ29uZmlnRmlsZShhcmdzKSB7XG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXG4gIGNvbnN0IGNvbmZpZ0luZGV4ID0gYXJncy5maW5kSW5kZXgoXG4gICAgKGFyZykgPT4gYXJnLnJlcGxhY2UoLy0vZywgJycpID09PSAnbG9hZENvbmZpZydcbiAgKTtcblxuICAvLyBDaGVjayBpZiB0aGUgLS1sb2FkQ29uZmlnIGhhcyBhIHZhbHVlXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xuICAgIGNvbnN0IGZpbGVOYW1lID0gYXJnc1tjb25maWdJbmRleCArIDFdO1xuICAgIHRyeSB7XG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcbiAgICAgIGlmIChmaWxlTmFtZSAmJiBmaWxlTmFtZS5lbmRzV2l0aCgnLmpzb24nKSkge1xuICAgICAgICAvLyBMb2FkIGFuIG9wdGlvbmFsIGN1c3RvbSBKU09OIGNvbmZpZyBmaWxlXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgIDIsXG4gICAgICAgIGVycm9yLFxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vIGFkZGl0aW9uYWwgb3B0aW9ucyB0byByZXR1cm5cbiAgcmV0dXJuIHt9O1xufVxuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3Qgd2l0aCB2YWx1ZXMgZnJvbSBhIGN1c3RvbSBvYmplY3RcbiAqIGFuZCBlbnZpcm9ubWVudCB2YXJpYWJsZXMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZ09iaiAtIFRoZSBkZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICogQHBhcmFtIHtPYmplY3R9IGN1c3RvbU9iaiAtIEN1c3RvbSBjb25maWd1cmF0aW9uIG9iamVjdCB0byBvdmVycmlkZSBkZWZhdWx0cy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcbiAqIGR1cmluZyByZWN1cnNpb24uXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcbiAgT2JqZWN0LmtleXMoY29uZmlnT2JqKS5mb3JFYWNoKChrZXkpID0+IHtcbiAgICBjb25zdCBlbnRyeSA9IGNvbmZpZ09ialtrZXldO1xuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xuXG4gICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYSBjdXN0b20gSlNPTiBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZW50cnkudmFsdWUgPSBjdXN0b21WYWx1ZTtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGFuIGVudiB2YXJpYWJsZSBleGlzdHMsIGl0IHRha2UgcHJlY2VkZW5jZVxuICAgICAgaWYgKGVudHJ5LmVudkxpbmsgaW4gZW52cyAmJiBlbnZzW2VudHJ5LmVudkxpbmtdICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgb3B0aW9ucyBvYmplY3QgYmFzZWQgb24gcHJvdmlkZWQgaXRlbXMsIHNldHRpbmcgdmFsdWVzIGZyb21cbiAqIG5lc3RlZCBwcm9wZXJ0aWVzIHJlY3Vyc2l2ZWx5LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtcyAtIENvbmZpZ3VyYXRpb24gaXRlbXMgdG8gYmUgdXNlZCBmb3IgaW5pdGlhbGl6aW5nXG4gKiBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEluaXRpYWxpemVkIG9wdGlvbnMgb2JqZWN0LlxuICovXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xuICBsZXQgb3B0aW9ucyA9IHt9O1xuICBmb3IgKGNvbnN0IFtuYW1lLCBpdGVtXSBvZiBPYmplY3QuZW50cmllcyhpdGVtcykpIHtcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXG4gICAgICA/IGl0ZW0udmFsdWVcbiAgICAgIDogaW5pdE9wdGlvbnMoaXRlbSk7XG4gIH1cbiAgcmV0dXJuIG9wdGlvbnM7XG59XG5cbi8qKlxuICogUGFpcnMgYXJndW1lbnQgdmFsdWVzIHdpdGggY29ycmVzcG9uZGluZyBvcHRpb25zIGluIHRoZSBjb25maWd1cmF0aW9uLFxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIG9iamVjdCB0byBiZSB1cGRhdGVkLlxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXG4gKiBvcHRpb25zLlxuICogQHBhcmFtIHtPYmplY3R9IGRlZmF1bHRDb25maWcgLSBEZWZhdWx0IGNvbmZpZ3VyYXRpb24gb2JqZWN0IGZvciByZWZlcmVuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvcHRpb25zIG9iamVjdC5cbiAqL1xuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xuICBsZXQgc2hvd1VzYWdlID0gZmFsc2U7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgYXJncy5sZW5ndGg7IGkrKykge1xuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XG5cbiAgICAvLyBGaW5kIHRoZSByaWdodCBwbGFjZSBmb3IgcHJvcGVydHkncyB2YWx1ZVxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxuICAgICAgPyBuZXN0ZWRBcmdzW29wdGlvbl0uc3BsaXQoJy4nKVxuICAgICAgOiBbXTtcblxuICAgIC8vIEdldCB0aGUgY29ycmVjdCB0eXBlIGZvciBDTEkgYXJncyB3aGljaCBhcmUgcGFzc2VkIGFzIHN0cmluZ3NcbiAgICBsZXQgYXJndW1lbnRUeXBlO1xuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcbiAgICAgICAgYXJndW1lbnRUeXBlID0gb2JqW3Byb3BdLnR5cGU7XG4gICAgICB9XG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xuICAgIH0sIGRlZmF1bHRDb25maWcpO1xuXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZSgob2JqLCBwcm9wLCBpbmRleCkgPT4ge1xuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcbiAgICAgICAgaWYgKHR5cGVvZiBvYmpbcHJvcF0gIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgaWYgKGFyZ3NbKytpXSkge1xuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IHRvQm9vbGVhbihhcmdzW2ldKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlID09PSAnbnVtYmVyJykge1xuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoYXJndW1lbnRUeXBlLmluZGV4T2YoJ10nKSA+PSAwKSB7XG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV0uc3BsaXQoJywnKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIG9ialtwcm9wXSA9IGFyZ3NbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgICAgMixcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIHNob3dVc2FnZSA9IHRydWU7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xuICAgIH0sIG9wdGlvbnMpO1xuICB9XG5cbiAgLy8gRGlzcGxheSB0aGUgdXNhZ2UgZm9yIHRoZSByZWZlcmVuY2UgaWYgbmVlZGVkXG4gIGlmIChzaG93VXNhZ2UpIHtcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xuICB9XG5cbiAgcmV0dXJuIG9wdGlvbnM7XG59XG5cbi8qKlxuICogUmVjdXJzaXZlbHkgdXBkYXRlcyBwcm9wZXJ0aWVzIGluIGFuIG9iamVjdCBiYXNlZCBvbiBuZXN0ZWQgbmFtZXMgYW5kIGFzc2lnbnNcbiAqIHRoZSBmaW5hbCB2YWx1ZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqZWN0VG9VcGRhdGUgLSBUaGUgb2JqZWN0IHRvIGJlIHVwZGF0ZWQuXG4gKiBAcGFyYW0ge0FycmF5fSBuZXN0ZWROYW1lcyAtIEFycmF5IG9mIG5lc3RlZCBwcm9wZXJ0eSBuYW1lcy5cbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9iamVjdCB3aXRoIGFzc2lnbmVkIHZhbHVlcy5cbiAqL1xuZnVuY3Rpb24gcmVjdXJzaXZlUHJvcHMob2JqZWN0VG9VcGRhdGUsIG5lc3RlZE5hbWVzLCB2YWx1ZSkge1xuICB3aGlsZSAobmVzdGVkTmFtZXMubGVuZ3RoID4gMSkge1xuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcblxuICAgIC8vIENyZWF0ZSBhIHByb3BlcnR5IGluIG9iamVjdCBpZiBpdCBkb2Vzbid0IGV4aXN0XG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xuICAgICAgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdID0ge307XG4gICAgfVxuXG4gICAgLy8gQ2FsbCBmdW5jdGlvbiBhZ2FpbiBpZiB0aGVyZSBzdGlsbCBuYW1lcyB0byBnb1xuICAgIG9iamVjdFRvVXBkYXRlW3Byb3BOYW1lXSA9IHJlY3Vyc2l2ZVByb3BzKFxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcbiAgICAgIG5lc3RlZE5hbWVzLFxuICAgICAgdmFsdWVcbiAgICApO1xuXG4gICAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xuICB9XG5cbiAgLy8gQXNzaWduIHRoZSBmaW5hbCB2YWx1ZVxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcbiAgcmV0dXJuIG9iamVjdFRvVXBkYXRlO1xufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGdldE9wdGlvbnMsXG4gIHNldE9wdGlvbnMsXG4gIG1hbnVhbENvbmZpZyxcbiAgbWFwVG9OZXdDb25maWcsXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcbiAgaW5pdEV4cG9ydFNldHRpbmdzXG59O1xuIiwiLyoqXG4gKiBUaGlzIG1vZHVsZSBleHBvcnRzIHR3byBmdW5jdGlvbnM6IGZldGNoIChmb3IgR0VUIHJlcXVlc3RzKSBhbmQgcG9zdCAoZm9yIFBPU1QgcmVxdWVzdHMpLlxuICovXG5cbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0IGh0dHBzIGZyb20gJ2h0dHBzJztcblxuLyoqXG4gKiBSZXR1cm5zIHRoZSBIVFRQIG9yIEhUVFBTIHByb3RvY29sIG1vZHVsZSBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgVVJMLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGRldGVybWluZSB0aGUgcHJvdG9jb2wuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cbiAqL1xuY29uc3QgZ2V0UHJvdG9jb2wgPSAodXJsKSA9PiAodXJsLnN0YXJ0c1dpdGgoJ2h0dHBzJykgPyBodHRwcyA6IGh0dHApO1xuXG4vKipcbiAqIEZldGNoZXMgZGF0YSBmcm9tIHRoZSBzcGVjaWZpZWQgVVJMIHVzaW5nIGVpdGhlciBIVFRQIG9yIEhUVFBTIHByb3RvY29sLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIGZldGNoIGRhdGEgZnJvbS5cbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3RcbiAqIHdpdGggYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxuICovXG5hc3luYyBmdW5jdGlvbiBmZXRjaCh1cmwsIHJlcXVlc3RPcHRpb25zID0ge30pIHtcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XG5cbiAgICBwcm90b2NvbFxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XG4gICAgICAgIGxldCBkYXRhID0gJyc7XG5cbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2RhdGEnLCAoY2h1bmspID0+IHtcbiAgICAgICAgICBkYXRhICs9IGNodW5rO1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBUaGUgd2hvbGUgcmVzcG9uc2UgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xuICAgICAgICAgIGlmICghZGF0YSkge1xuICAgICAgICAgICAgcmVqZWN0KCdOb3RoaW5nIHdhcyBmZXRjaGVkIGZyb20gdGhlIFVSTC4nKTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXMudGV4dCA9IGRhdGE7XG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcbiAgfSk7XG59XG5cbi8qKlxuICogU2VuZHMgYSBQT1NUIHJlcXVlc3QgdG8gdGhlIHNwZWNpZmllZCBVUkwgd2l0aCB0aGUgcHJvdmlkZWQgSlNPTiBib2R5IHVzaW5nXG4gKiBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gdXJsIC0gVGhlIFVSTCB0byBzZW5kIHRoZSBQT1NUIHJlcXVlc3QgdG8uXG4gKiBAcGFyYW0ge09iamVjdH0gYm9keSAtIFRoZSBKU09OIGJvZHkgdG8gaW5jbHVkZSBpbiB0aGUgUE9TVCByZXF1ZXN0XG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBIVFRQIHJlcXVlc3QgKG9wdGlvbmFsKS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxuICogYWRkZWQgJ3RleHQnIHByb3BlcnR5IG9yIHJlamVjdGluZyB3aXRoIGFuIGVycm9yLlxuICovXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgY29uc3QgcHJvdG9jb2wgPSBnZXRQcm90b2NvbCh1cmwpO1xuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcblxuICAgIC8vIFNldCBkZWZhdWx0IGhlYWRlcnMgYW5kIG1lcmdlIHdpdGggcmVxdWVzdE9wdGlvbnNcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcbiAgICAgIHtcbiAgICAgICAgbWV0aG9kOiAnUE9TVCcsXG4gICAgICAgIGhlYWRlcnM6IHtcbiAgICAgICAgICAnQ29udGVudC1UeXBlJzogJ2FwcGxpY2F0aW9uL2pzb24nLFxuICAgICAgICAgICdDb250ZW50LUxlbmd0aCc6IGRhdGEubGVuZ3RoXG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICByZXF1ZXN0T3B0aW9uc1xuICAgICk7XG5cbiAgICBjb25zdCByZXEgPSBwcm90b2NvbFxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XG4gICAgICAgIGxldCByZXNwb25zZURhdGEgPSAnJztcblxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xuICAgICAgICAgIHJlc3BvbnNlRGF0YSArPSBjaHVuaztcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcbiAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmVzLnRleHQgPSByZXNwb25zZURhdGE7XG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0pXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XG4gICAgICAgIHJlamVjdChlcnJvcik7XG4gICAgICB9KTtcblxuICAgIC8vIFdyaXRlIHRoZSByZXF1ZXN0IGJvZHkgYW5kIGVuZCB0aGUgcmVxdWVzdC5cbiAgICByZXEud3JpdGUoZGF0YSk7XG4gICAgcmVxLmVuZCgpO1xuICB9KTtcbn1cblxuZXhwb3J0IGRlZmF1bHQgZmV0Y2g7XG5leHBvcnQgeyBmZXRjaCwgcG9zdCB9O1xuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIC8qKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZVxuICAgKiBAcGFyYW0ge251bWJlcn0gW3N0YXR1c10gZGVzY3JpYmVzIHRoZSBzdGF0dXMgY29kZSAoNDAwLCA1MDAsIGV0Yy4pXG4gICAqL1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcbiAgICBzdXBlcigpO1xuXG4gICAgdGhpcy5tZXNzYWdlID0gbWVzc2FnZTtcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XG5cbiAgICBpZiAoc3RhdHVzKSB7XG4gICAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcbiAgICB9XG4gIH1cblxuICBzZXRFcnJvcihlcnJvcikge1xuICAgIHRoaXMuZXJyb3IgPSBlcnJvcjtcblxuICAgIGlmIChlcnJvci5uYW1lKSB7XG4gICAgICB0aGlzLm5hbWUgPSBlcnJvci5uYW1lO1xuICAgIH1cblxuICAgIGlmICghdGhpcy5zdGF0dXMgJiYgZXJyb3Iuc3RhdHVzQ29kZSkge1xuICAgICAgdGhpcy5zdGF0dXMgPSBlcnJvci5zdGF0dXNDb2RlO1xuICAgIH1cblxuICAgIGlmIChlcnJvci5zdGFjaykge1xuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xuICAgICAgdGhpcy5zdGFjayA9IGVycm9yLnN0YWNrO1xuICAgIH1cblxuICAgIHJldHVybiB0aGlzO1xuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cbi8vIFRoZSBjYWNoZSBpdHNlbGYgaXMgc3RvcmVkIGluIC5jYWNoZSwgYW5kIGlzIGNoZWNrZWQgYnkgdGhlIGNvbmZpZyBzeXN0ZW1cbi8vIGJlZm9yZSBzdGFydGluZyB0aGUgc2VydmljZVxuXG5pbXBvcnQgeyBleGlzdHNTeW5jLCBta2RpclN5bmMsIHJlYWRGaWxlU3luYywgd3JpdGVGaWxlU3luYyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IGlzQWJzb2x1dGUsIGpvaW4gfSBmcm9tICdwYXRoJztcblxuaW1wb3J0IHsgSHR0cHNQcm94eUFnZW50IH0gZnJvbSAnaHR0cHMtcHJveHktYWdlbnQnO1xuXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XG5pbXBvcnQgeyBmZXRjaCB9IGZyb20gJy4vZmV0Y2guanMnO1xuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbmNvbnN0IGNhY2hlID0ge1xuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcbiAgYWN0aXZlTWFuaWZlc3Q6IHt9LFxuICBzb3VyY2VzOiAnJyxcbiAgaGNWZXJzaW9uOiAnJ1xufTtcblxuLyoqXG4gKiBFeHRyYWN0cyBhbmQgY2FjaGVzIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gZnJvbSB0aGUgc291cmNlcyBzdHJpbmcuXG4gKlxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBleHRyYWN0VmVyc2lvbiA9IChjYWNoZSkgPT4ge1xuICByZXR1cm4gY2FjaGUuc291cmNlc1xuICAgIC5zdWJzdHJpbmcoMCwgY2FjaGUuc291cmNlcy5pbmRleE9mKCcqLycpKVxuICAgIC5yZXBsYWNlKCcvKicsICcnKVxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxuICAgIC5yZXBsYWNlKC9cXG4vZywgJycpXG4gICAgLnRyaW0oKTtcbn07XG5cbi8qKlxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXG4gKi9cbmV4cG9ydCBjb25zdCBleHRyYWN0TW9kdWxlTmFtZSA9IChzY3JpcHRQYXRoKSA9PiB7XG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXG4gICAgLyguKilcXC98KC4qKW1vZHVsZXNcXC98c3RvY2tcXC8oLiopaW5kaWNhdG9yc1xcL3xtYXBzXFwvKC4qKW1vZHVsZXNcXC8vZ2ksXG4gICAgJydcbiAgKTtcbn07XG5cbi8qKlxuICogU2F2ZXMgdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24gYW5kIGZldGNoZWQgbW9kdWxlcyB0byB0aGUgY2FjaGUgbWFuaWZlc3RcbiAqIGZpbGUuXG4gKlxuICogQHBhcmFtIHtvYmplY3R9IGNvbmZpZyAtIEhpZ2hjaGFydHMtcmVsYXRlZCBjb25maWd1cmF0aW9uIG9iamVjdC5cbiAqIEBwYXJhbSB7b2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB0aGF0IGNvbnRhaW5zIG1hcHBlZCBuYW1lcyBvZlxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIHdoaWxlIHdyaXRpbmdcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cbiAqL1xuZXhwb3J0IGNvbnN0IHNhdmVDb25maWdUb01hbmlmZXN0ID0gYXN5bmMgKGNvbmZpZywgZmV0Y2hlZE1vZHVsZXMpID0+IHtcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XG4gICAgdmVyc2lvbjogY29uZmlnLnZlcnNpb24sXG4gICAgbW9kdWxlczogZmV0Y2hlZE1vZHVsZXMgfHwge31cbiAgfTtcblxuICAvLyBVcGRhdGUgY2FjaGUgb2JqZWN0IHdpdGggdGhlIGN1cnJlbnQgbW9kdWxlc1xuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xuXG4gIGxvZygzLCAnW2NhY2hlXSBXcml0aW5nIGEgbmV3IG1hbmlmZXN0LicpO1xuICB0cnkge1xuICAgIHdyaXRlRmlsZVN5bmMoXG4gICAgICBqb2luKGdldENhY2hlUGF0aCgpLCAnbWFuaWZlc3QuanNvbicpLFxuICAgICAgSlNPTi5zdHJpbmdpZnkobmV3TWFuaWZlc3QpLFxuICAgICAgJ3V0ZjgnXG4gICAgKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW2NhY2hlXSBFcnJvciB3cml0aW5nIHRoZSBjYWNoZSBtYW5pZmVzdC4nLFxuICAgICAgNDAwXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogRmV0Y2hlcyBhIHNpbmdsZSBzY3JpcHQgYW5kIHVwZGF0ZXMgdGhlIGZldGNoZWRNb2R1bGVzIGFjY29yZGluZ2x5LlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cbiAqIEBwYXJhbSB7T2JqZWN0fSByZXF1ZXN0T3B0aW9ucyAtIEFkZGl0aW9uYWwgb3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50XG4gKiB0byB1c2UgZm9yIGEgcmVxdWVzdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cbiAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvdWxkVGhyb3dFcnJvciAtIEEgZmxhZyB0byBpbmRpY2F0ZSBpZiB0aGUgZXJyb3Igc2hvdWxkIGJlXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSB0ZXh0IHJlcHJlc2VudGF0aW9uXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhIHByb2JsZW0gd2l0aFxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGZldGNoQW5kUHJvY2Vzc1NjcmlwdCA9IGFzeW5jIChcbiAgc2NyaXB0LFxuICByZXF1ZXN0T3B0aW9ucyxcbiAgZmV0Y2hlZE1vZHVsZXMsXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxuKSA9PiB7XG4gIC8vIEdldCByaWQgb2YgdGhlIC5qcyBmcm9tIHRoZSBjdXN0b20gc3RyaW5nc1xuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xuICAgIHNjcmlwdCA9IHNjcmlwdC5zdWJzdHJpbmcoMCwgc2NyaXB0Lmxlbmd0aCAtIDMpO1xuICB9XG5cbiAgbG9nKDQsIGBbY2FjaGVdIEZldGNoaW5nIHNjcmlwdCAtICR7c2NyaXB0fS5qc2ApO1xuXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcbiAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaChgJHtzY3JpcHR9LmpzYCwgcmVxdWVzdE9wdGlvbnMpO1xuXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cbiAgaWYgKHJlc3BvbnNlLnN0YXR1c0NvZGUgPT09IDIwMCAmJiB0eXBlb2YgcmVzcG9uc2UudGV4dCA9PSAnc3RyaW5nJykge1xuICAgIGlmIChmZXRjaGVkTW9kdWxlcykge1xuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XG4gICAgICBmZXRjaGVkTW9kdWxlc1ttb2R1bGVOYW1lXSA9IDE7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3BvbnNlLnRleHQ7XG4gIH1cblxuICBpZiAoc2hvdWxkVGhyb3dFcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYCxcbiAgICAgIDUwMFxuICAgICkuc2V0RXJyb3IocmVzcG9uc2UpO1xuICB9IGVsc2Uge1xuICAgIGxvZyhcbiAgICAgIDIsXG4gICAgICBgW2NhY2hlXSBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uLmBcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuICcnO1xufTtcblxuLyoqXG4gKiBGZXRjaGVzIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tU2NyaXB0cyBmcm9tIHRoZSBnaXZlbiBDRE5zLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxuICogQHBhcmFtIHtzdHJpbmd9IG1vZHVsZVNjcmlwdHMgLSBBcnJheSBvZiBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gZmV0Y2guXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tU2NyaXB0cyAtIEFycmF5IG9mIGN1c3RvbSBzY3JpcHQgcGF0aHMgdG8gZmV0Y2hcbiAqIChmdWxsIFVSTHMpLlxuICogQHBhcmFtIHtvYmplY3R9IHByb3h5T3B0aW9ucyAtIE9wdGlvbnMgZm9yIHRoZSBwcm94eSBhZ2VudCB0byB1c2UgZm9yXG4gKiBhIHJlcXVlc3QuXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcbiAqIG1vZHVsZXMgaGF2ZSBiZWVuIGZldGNoZWQuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGZldGNoU2NyaXB0cyA9IGFzeW5jIChcbiAgY29yZVNjcmlwdHMsXG4gIG1vZHVsZVNjcmlwdHMsXG4gIGN1c3RvbVNjcmlwdHMsXG4gIHByb3h5T3B0aW9ucyxcbiAgZmV0Y2hlZE1vZHVsZXNcbikgPT4ge1xuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXG4gIGxldCBwcm94eUFnZW50O1xuICBjb25zdCBwcm94eUhvc3QgPSBwcm94eU9wdGlvbnMuaG9zdDtcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XG5cbiAgLy8gVHJ5IHRvIGNyZWF0ZSBhIFByb3h5IEFnZW50XG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XG4gICAgdHJ5IHtcbiAgICAgIHByb3h5QWdlbnQgPSBuZXcgSHR0cHNQcm94eUFnZW50KHtcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxuICAgICAgICBwb3J0OiBwcm94eVBvcnRcbiAgICAgIH0pO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdbY2FjaGVdIENvdWxkIG5vdCBjcmVhdGUgYSBQcm94eSBBZ2VudC4nLFxuICAgICAgICA1MDBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xuICBjb25zdCByZXF1ZXN0T3B0aW9ucyA9IHByb3h5QWdlbnRcbiAgICA/IHtcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXG4gICAgICAgIHRpbWVvdXQ6IGVudnMuU0VSVkVSX1BST1hZX1RJTUVPVVRcbiAgICAgIH1cbiAgICA6IHt9O1xuXG4gIGNvbnN0IGFsbEZldGNoUHJvbWlzZXMgPSBbXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcywgdHJ1ZSlcbiAgICApLFxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zLCBmZXRjaGVkTW9kdWxlcylcbiAgICApLFxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XG4gICAgICBmZXRjaEFuZFByb2Nlc3NTY3JpcHQoYCR7c2NyaXB0fWAsIHJlcXVlc3RPcHRpb25zKVxuICAgIClcbiAgXTtcblxuICBjb25zdCBmZXRjaGVkU2NyaXB0cyA9IGF3YWl0IFByb21pc2UuYWxsKGFsbEZldGNoUHJvbWlzZXMpO1xuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBsb2NhbCBjYWNoZSB3aXRoIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgdGhlaXIgdmVyc2lvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cbiAqIEBwYXJhbSB7c3RyaW5nfSBzb3VyY2VQYXRoIC0gVGhlIHBhdGggdG8gdGhlIHNvdXJjZSBmaWxlIGluIHRoZSBjYWNoZS5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcbiAqIHRoZSBmZXRjaGVkIG1vZHVsZXMuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xuICogdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcbiAgaGlnaGNoYXJ0c09wdGlvbnMsXG4gIHByb3h5T3B0aW9ucyxcbiAgc291cmNlUGF0aFxuKSA9PiB7XG4gIGNvbnN0IHZlcnNpb24gPSBoaWdoY2hhcnRzT3B0aW9ucy52ZXJzaW9uO1xuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcbiAgY29uc3QgY2RuVVJMID0gaGlnaGNoYXJ0c09wdGlvbnMuY2RuVVJMIHx8IGNhY2hlLmNkblVSTDtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW2NhY2hlXSBVcGRhdGluZyBjYWNoZSB2ZXJzaW9uIHRvIEhpZ2hjaGFydHM6ICR7aGNWZXJzaW9uIHx8ICdsYXRlc3QnfS5gXG4gICk7XG5cbiAgY29uc3QgZmV0Y2hlZE1vZHVsZXMgPSB7fTtcbiAgdHJ5IHtcbiAgICBjYWNoZS5zb3VyY2VzID0gYXdhaXQgZmV0Y2hTY3JpcHRzKFxuICAgICAgW1xuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcbiAgICAgIF0sXG4gICAgICBbXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxuICAgICAgICAgIG0gPT09ICdtYXAnXG4gICAgICAgICAgICA/IGAke2NkblVSTH1tYXBzLyR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcbiAgICAgICAgKSxcbiAgICAgICAgLi4uaGlnaGNoYXJ0c09wdGlvbnMuaW5kaWNhdG9yU2NyaXB0cy5tYXAoXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXG4gICAgICAgIClcbiAgICAgIF0sXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxuICAgICAgcHJveHlPcHRpb25zLFxuICAgICAgZmV0Y2hlZE1vZHVsZXNcbiAgICApO1xuXG4gICAgY2FjaGUuaGNWZXJzaW9uID0gZXh0cmFjdFZlcnNpb24oY2FjaGUpO1xuXG4gICAgLy8gU2F2ZSB0aGUgZmV0Y2hlZCBtb2R1bGVzIGludG8gY2FjaGVzJyBzb3VyY2UgSlNPTlxuICAgIHdyaXRlRmlsZVN5bmMoc291cmNlUGF0aCwgY2FjaGUuc291cmNlcyk7XG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJyxcbiAgICAgIDUwMFxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xuICB9XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcbiAqIHRoZSBjYWNoZSBmb3IgdGhlIG5ldyB2ZXJzaW9uLlxuICpcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTwob2JqZWN0fGJvb2xlYW4pPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZFxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXG4gKiBleGlzdHMuXG4gKi9cbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcbiAgY29uc3Qgb3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcbiAgaWYgKG9wdGlvbnM/LmhpZ2hjaGFydHMpIHtcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XG4gIH1cbiAgYXdhaXQgY2hlY2tBbmRVcGRhdGVDYWNoZShvcHRpb25zKTtcbn07XG5cbi8qKlxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcbiAqIGFuZCBsb2FkcyB0aGUgc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBjYWNoZSBpcyBjaGVja2VkXG4gKiBhbmQgdXBkYXRlZC5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIHRoZXJlIGlzIGFuIGlzc3VlIHVwZGF0aW5nXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNoZWNrQW5kVXBkYXRlQ2FjaGUgPSBhc3luYyAob3B0aW9ucykgPT4ge1xuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcblxuICBjb25zdCBjYWNoZVBhdGggPSBnZXRDYWNoZVBhdGgoKTtcblxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XG5cbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXG4gIGNvbnN0IG1hbmlmZXN0UGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnbWFuaWZlc3QuanNvbicpO1xuICBjb25zdCBzb3VyY2VQYXRoID0gam9pbihjYWNoZVBhdGgsICdzb3VyY2VzLmpzJyk7XG5cbiAgLy8gQ3JlYXRlIHRoZSBjYWNoZSBkZXN0aW5hdGlvbiBpZiBpdCBkb2Vzbid0IGV4aXN0IGFscmVhZHlcbiAgIWV4aXN0c1N5bmMoY2FjaGVQYXRoKSAmJiBta2RpclN5bmMoY2FjaGVQYXRoLCB7IHJlY3Vyc2l2ZTogdHJ1ZSB9KTtcblxuICAvLyBGZXRjaCBhbGwgdGhlIHNjcmlwdHMgZWl0aGVyIGlmIG1hbmlmZXN0Lmpzb24gZG9lcyBub3QgZXhpc3RcbiAgLy8gb3IgaWYgdGhlIGZvcmNlRmV0Y2ggb3B0aW9uIGlzIGVuYWJsZWRcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XG4gICAgbG9nKDMsICdbY2FjaGVdIEZldGNoaW5nIGFuZCBjYWNoaW5nIEhpZ2hjaGFydHMgZGVwZW5kZW5jaWVzLicpO1xuICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgfSBlbHNlIHtcbiAgICBsZXQgcmVxdWVzdFVwZGF0ZSA9IGZhbHNlO1xuXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxuICAgIGNvbnN0IG1hbmlmZXN0ID0gSlNPTi5wYXJzZShyZWFkRmlsZVN5bmMobWFuaWZlc3RQYXRoKSk7XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxuICAgIC8vIGl0IGVhc2llciB0byByZXNvbHZlIG1vZHVsZXMuXG4gICAgaWYgKG1hbmlmZXN0Lm1vZHVsZXMgJiYgQXJyYXkuaXNBcnJheShtYW5pZmVzdC5tb2R1bGVzKSkge1xuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzLmZvckVhY2goKG0pID0+IChtb2R1bGVNYXBbbV0gPSAxKSk7XG4gICAgICBtYW5pZmVzdC5tb2R1bGVzID0gbW9kdWxlTWFwO1xuICAgIH1cblxuICAgIGNvbnN0IHsgY29yZVNjcmlwdHMsIG1vZHVsZVNjcmlwdHMsIGluZGljYXRvclNjcmlwdHMgfSA9IGhpZ2hjaGFydHM7XG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cbiAgICAgIGNvcmVTY3JpcHRzLmxlbmd0aCArIG1vZHVsZVNjcmlwdHMubGVuZ3RoICsgaW5kaWNhdG9yU2NyaXB0cy5sZW5ndGg7XG5cbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXG4gICAgLy8gSWYgdGhlcmUgYXJlIGNoYW5nZXMsIGZldGNoIHJlcXVlc3RlZCBtb2R1bGVzIGFuZCBwcm9kdWN0cyxcbiAgICAvLyBhbmQgYmFrZSB0aGVtIGludG8gYSBnaWFudCBibG9iLiBTYXZlIHRoZSBibG9iLlxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMixcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcbiAgICAgICk7XG4gICAgICByZXF1ZXN0VXBkYXRlID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XG4gICAgICBsb2coXG4gICAgICAgIDIsXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXG4gICAgICApO1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENoZWNrIGVhY2ggbW9kdWxlLCBpZiBhbnl0aGluZyBpcyBtaXNzaW5nIHJlZmV0Y2ggZXZlcnl0aGluZ1xuICAgICAgcmVxdWVzdFVwZGF0ZSA9IChtb2R1bGVTY3JpcHRzIHx8IFtdKS5zb21lKChtb2R1bGVOYW1lKSA9PiB7XG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xuICAgICAgICAgIGxvZyhcbiAgICAgICAgICAgIDIsXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXG4gICAgICAgICAgKTtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKHJlcXVlc3RVcGRhdGUpIHtcbiAgICAgIGZldGNoZWRNb2R1bGVzID0gYXdhaXQgdXBkYXRlQ2FjaGUoaGlnaGNoYXJ0cywgc2VydmVyLnByb3h5LCBzb3VyY2VQYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbG9nKDMsICdbY2FjaGVdIERlcGVuZGVuY3kgY2FjaGUgaXMgdXAgdG8gZGF0ZSwgcHJvY2VlZGluZy4nKTtcblxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xuICAgICAgY2FjaGUuc291cmNlcyA9IHJlYWRGaWxlU3luYyhzb3VyY2VQYXRoLCAndXRmOCcpO1xuXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxuICAgICAgZmV0Y2hlZE1vZHVsZXMgPSBtYW5pZmVzdC5tb2R1bGVzO1xuXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gRmluYWxseSwgc2F2ZSB0aGUgbmV3IG1hbmlmZXN0LCB3aGljaCBpcyBiYXNpY2FsbHkgb3VyIGN1cnJlbnQgY29uZmlnXG4gIC8vIGluIGEgc2xpZ2h0bHkgZGlmZmVyZW50IGZvcm1hdFxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgdGhlIHBhdGggdG8gdGhlIGNhY2hlIGZvbGRlci5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBwYXRoIHRvIHRoZSBjYWNoZSBmb2xkZXIuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRDYWNoZVBhdGggPSAoKSA9PiB7XG4gIGNvbnN0IGNhY2hlUGF0aE9wdGlvbiA9IGdldE9wdGlvbnMoKS5oaWdoY2hhcnRzLmNhY2hlUGF0aDtcblxuICAvLyBpc3N1ZSAjNTYyOiBzdXBwb3J0IGZvciBhYnNvbHV0ZSBwYXRoc1xuICByZXR1cm4gaXNBYnNvbHV0ZShjYWNoZVBhdGhPcHRpb24pXG4gICAgPyBjYWNoZVBhdGhPcHRpb25cbiAgICA6IGpvaW4oX19kaXJuYW1lLCBjYWNoZVBhdGhPcHRpb24pO1xufTtcblxuZXhwb3J0IGNvbnN0IGdldENhY2hlID0gKCkgPT4gY2FjaGU7XG5cbmV4cG9ydCBjb25zdCBoaWdoY2hhcnRzID0gKCkgPT4gY2FjaGUuc291cmNlcztcblxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcbiAgZ2V0Q2FjaGVQYXRoLFxuICB1cGRhdGVWZXJzaW9uLFxuICBnZXRDYWNoZSxcbiAgaGlnaGNoYXJ0cyxcbiAgdmVyc2lvblxufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xuXG4vKipcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzZXR1cEhpZ2hjaGFydHMoKSB7XG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4geyBkdXJhdGlvbjogMCB9O1xuICB9O1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cbiAqXG4gKiBAcGFyYW0ge29iamVjdH0gY2hhcnRPcHRpb25zIC0gVGhlIG9wdGlvbnMgZm9yIHRoZSBIaWdoY2hhcnRzIGNoYXJ0LlxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGRpc3BsYXlFcnJvcnMgLSBBIGZsYWcgaW5kaWNhdGluZyB3aGV0aGVyIHRvIGRpc3BsYXkgZXJyb3JzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcbiAgLy8gRGlzcGxheSBlcnJvcnMgZmxhZyB0YWtlbiBmcm9tIGNoYXJ0IG9wdGlvbnMgbmFkIGRlYnVnZ2VyIG1vZHVsZVxuICB3aW5kb3cuX2Rpc3BsYXlFcnJvcnMgPSBkaXNwbGF5RXJyb3JzO1xuXG4gIC8vIEdldCByZXF1aXJlZCBmdW5jdGlvbnNcbiAgY29uc3QgeyBnZXRPcHRpb25zLCBtZXJnZSwgc2V0T3B0aW9ucywgd3JhcCB9ID0gSGlnaGNoYXJ0cztcblxuICAvLyBDcmVhdGUgYSBzZXBhcmF0ZSBvYmplY3QgZm9yIGEgcG90ZW50aWFsIHNldE9wdGlvbnMgdXNhZ2VzIGluIG9yZGVyIHRvXG4gIC8vIHByZXZlbnQgZnJvbSBwb2xsdXRpbmcgb3RoZXIgZXhwb3J0cyB0aGF0IGNhbiBoYXBwZW4gb24gdGhlIHNhbWUgcGFnZVxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XG5cbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcbiAgY29uc3QgY2hhcnQgPSB7XG4gICAgYW5pbWF0aW9uOiBmYWxzZVxuICB9O1xuXG4gIC8vIFdoZW4gc3RyYWlnaHQgaW5qZWN0LCB0aGUgc2l6ZSBpcyBzZXQgdGhyb3VnaCBDU1Mgb25seVxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XG4gICAgY2hhcnQuaGVpZ2h0ID0gY2hhcnRPcHRpb25zLmNoYXJ0LmhlaWdodDtcbiAgICBjaGFydC53aWR0aCA9IGNoYXJ0T3B0aW9ucy5jaGFydC53aWR0aDtcbiAgfVxuXG4gIC8vIE5PVEU6IElzIHRoaXMgdXNlZCBmb3IgYW55dGhpbmcgdXNlZnVsP1xuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xuICB3cmFwKEhpZ2hjaGFydHMuQ2hhcnQucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCB1c2VyT3B0aW9ucywgY2IpIHtcbiAgICAvLyBPdmVycmlkZSB1c2VyT3B0aW9ucyB3aXRoIGltYWdlIGZyaWVuZGx5IG9wdGlvbnNcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XG4gICAgICBleHBvcnRpbmc6IHtcbiAgICAgICAgZW5hYmxlZDogZmFsc2VcbiAgICAgIH0sXG4gICAgICBwbG90T3B0aW9uczoge1xuICAgICAgICBzZXJpZXM6IHtcbiAgICAgICAgICBsYWJlbDoge1xuICAgICAgICAgICAgZW5hYmxlZDogZmFsc2VcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICAvKiBFeHBlY3RzIHRvb2x0aXAgaW4gdXNlck9wdGlvbnMgd2hlbiBmb3JFeHBvcnQgaXMgdHJ1ZS5cbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxuICAgICAgICAqL1xuICAgICAgdG9vbHRpcDoge31cbiAgICB9KTtcblxuICAgICh1c2VyT3B0aW9ucy5zZXJpZXMgfHwgW10pLmZvckVhY2goZnVuY3Rpb24gKHNlcmllcykge1xuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xuICAgIH0pO1xuXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxuICAgIGlmICghd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlcikge1xuICAgICAgd2luZG93Lm9uSGlnaGNoYXJ0c1JlbmRlciA9IEhpZ2hjaGFydHMuYWRkRXZlbnQodGhpcywgJ3JlbmRlcicsICgpID0+IHtcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xuICAgICAgfSk7XG4gICAgfVxuXG4gICAgcHJvY2VlZC5hcHBseSh0aGlzLCBbdXNlck9wdGlvbnMsIGNiXSk7XG4gIH0pO1xuXG4gIHdyYXAoSGlnaGNoYXJ0cy5TZXJpZXMucHJvdG90eXBlLCAnaW5pdCcsIGZ1bmN0aW9uIChwcm9jZWVkLCBjaGFydCwgb3B0aW9ucykge1xuICAgIHByb2NlZWQuYXBwbHkodGhpcywgW2NoYXJ0LCBvcHRpb25zXSk7XG4gIH0pO1xuXG4gIC8vIEdldCB0aGUgdXNlciBvcHRpb25zXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXG4gICAgPyBuZXcgRnVuY3Rpb24oYHJldHVybiAke29wdGlvbnMuZXhwb3J0LnN0ckluan1gKSgpXG4gICAgOiBjaGFydE9wdGlvbnM7XG5cbiAgLy8gVHJpZ2dlciBjdXN0b20gY29kZVxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XG4gICAgbmV3IEZ1bmN0aW9uKCdvcHRpb25zJywgb3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSh1c2VyT3B0aW9ucyk7XG4gIH1cblxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcbiAgLy8gc2V0T3B0aW9ucyBmdW5jdGlvbiBhbmQgdXNlciBvcHRpb25zIHRvIGNyZWF0ZSB0aGUgZmluYWwgb3B0aW9ucyBvYmplY3RcbiAgY29uc3QgZmluYWxPcHRpb25zID0gbWVyZ2UoXG4gICAgZmFsc2UsXG4gICAgSlNPTi5wYXJzZShvcHRpb25zLmV4cG9ydC50aGVtZU9wdGlvbnMpLFxuICAgIHVzZXJPcHRpb25zLFxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcbiAgICB7IGNoYXJ0IH1cbiAgKTtcblxuICBjb25zdCBmaW5hbENhbGxiYWNrID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja1xuICAgID8gbmV3IEZ1bmN0aW9uKGByZXR1cm4gJHtvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrfWApKClcbiAgICA6IHVuZGVmaW5lZDtcblxuICAvLyBTZXQgdGhlIGdsb2JhbCBvcHRpb25zIGlmIGV4aXN0XG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xuICBpZiAoZ2xvYmFsT3B0aW9ucykge1xuICAgIHNldE9wdGlvbnMoZ2xvYmFsT3B0aW9ucyk7XG4gIH1cblxuICBIaWdoY2hhcnRzW29wdGlvbnMuZXhwb3J0LmNvbnN0ciB8fCAnY2hhcnQnXShcbiAgICAnY29udGFpbmVyJyxcbiAgICBmaW5hbE9wdGlvbnMsXG4gICAgZmluYWxDYWxsYmFja1xuICApO1xuXG4gIC8vIEdldCB0aGUgY3VycmVudCBnbG9iYWwgb3B0aW9uc1xuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcblxuICAvLyBDbGVhciBpdCBqdXN0IGluIGNhc2UgKGUuZy4gdGhlIHNldE9wdGlvbnMgd2FzIHVzZWQgaW4gdGhlIGN1c3RvbUNvZGUpXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xuICAgIGlmICh0eXBlb2YgZGVmYXVsdE9wdGlvbnNbcHJvcF0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgIGRlbGV0ZSBkZWZhdWx0T3B0aW9uc1twcm9wXTtcbiAgICB9XG4gIH1cblxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXG4gIHNldE9wdGlvbnMoSGlnaGNoYXJ0cy5zZXRPcHRpb25zT2JqKTtcblxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSB7fTtcbn1cbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyByZWFkRmlsZVN5bmMgfSBmcm9tICdmcyc7XG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcblxuaW1wb3J0IHB1cHBldGVlciBmcm9tICdwdXBwZXRlZXInO1xuXG5pbXBvcnQgeyBnZXRDYWNoZVBhdGggfSBmcm9tICcuL2NhY2hlLmpzJztcbmltcG9ydCB7IGdldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcbmltcG9ydCB7IHNldHVwSGlnaGNoYXJ0cyB9IGZyb20gJy4vaGlnaGNoYXJ0cy5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSwgZXhwQmFja29mZiB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vLyBHZXQgdGhlIHRlbXBsYXRlIGZvciB0aGUgcGFnZVxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsICd1dGY4Jyk7XG5cbi8vIFRvIHNhdmUgdGhlIGJyb3dzZXJcbmxldCBicm93c2VyO1xuXG4vLyBUbyBzYXZlIHRoZSBXZWJTb2NrZXQgZW5kcG9pbnQgaW4gY2FzZSBvZiBhIHN1ZGRlbiBkaXNjb25uZWN0XG5sZXQgd3NFbmRwb2ludDtcblxuLyoqXG4gKiBSZWNvbm5lY3RzIHRvIHRoZSBicm93c2VyIGluc3RhbmNlIHdoZW4gaXQgaXMgZGlzY29ubmVjdGVkLiBJZiB0aGUgY3VycmVudFxuICogYnJvd3NlciBjb25uZWN0aW9uIGlzIGxvc3QsIGl0IGF0dGVtcHRzIHRvIHJlY29ubmVjdCB1c2luZyB0aGUgcHJldmlvdXNcbiAqIFdlYlNvY2tldCBlbmRwb2ludC4gSWYgdGhlIHJlY29ubmVjdGlvbiBmYWlscywgaXQgd2lsbCB0cnkgdG8gY2xvc2UgdGhlXG4gKiBicm93c2VyIGFuZCByZWxhdW5jaCBhIG5ldyBpbnN0YW5jZS5cbiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVjb25uZWN0KCkge1xuICB0cnkge1xuICAgIC8vIFN0YXJ0IHRoZSByZWNvbm5lY3RpbmdcbiAgICBsb2coMywgYFticm93c2VyXSBSZXN0YXJ0aW5nIHRoZSBicm93c2VyIGNvbm5lY3Rpb24uYCk7XG5cbiAgICAvLyBUcnkgdG8gcmVjb25uZWN0IHRoZSBicm93c2VyXG4gICAgaWYgKGJyb3dzZXIgJiYgIWJyb3dzZXIuY29ubmVjdGVkKSB7XG4gICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmNvbm5lY3Qoe1xuICAgICAgICBicm93c2VyV1NFbmRwb2ludDogd3NFbmRwb2ludFxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gU2F2ZSBhIG5ldyBXZWJTb2NrZXQgZW5kcG9pbnRcbiAgICB3c0VuZHBvaW50ID0gYnJvd3Nlci53c0VuZHBvaW50KCk7XG5cbiAgICAvLyBBZGQgdGhlIHJlY29ubmVjdCBldmVudCBhZ2FpblxuICAgIGJyb3dzZXIub24oJ2Rpc2Nvbm5lY3RlZCcsIHJlY29ubmVjdCk7XG5cbiAgICAvLyBMb2cgdGhlIHN1Y2Nlc3MgbWVzc2FnZVxuICAgIGxvZygzLCBgW2Jyb3dzZXJdIEJyb3dzZXIgcmVjb25uZWN0ZWQgc3VjY2Vzc2Z1bGx5LmApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgIDEsXG4gICAgICBlcnJvcixcbiAgICAgICdbYnJvd3Nlcl0gQ291bGQgbm90IHJlc3RvcmUgdGhlIGJyb3dzZXIgY29ubmVjdGlvbiwgYXR0ZW1wdGluZyB0byByZWxhdW5jaC4nXG4gICAgKTtcblxuICAgIC8vIFRyeSB0byBjbG9zZSB0aGUgYnJvd3NlciBiZWZvcmUgcmVsYXVuY2hpbmdcbiAgICB0cnkge1xuICAgICAgYXdhaXQgY2xvc2UoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nV2l0aFN0YWNrKFxuICAgICAgICAxLFxuICAgICAgICBlcnJvcixcbiAgICAgICAgJ1ticm93c2VyXSBDb3VsZCBub3QgY2xvc2UgdGhlIGJyb3dzZXIgYmVmb3JlIHJlbGF1bmNoaW5nIChwcm9iYWJseSBpcyBhbHJlYWR5IGNsb3NlZCkuJ1xuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gcmVsYXVuY2ggdGhlIGJyb3dzZXJcbiAgICBhd2FpdCBjcmVhdGUoZ2V0T3B0aW9ucygpLnB1cHBldGVlci5hcmdzIHx8IFtdKTtcblxuICAgIC8vIExvZyB0aGUgc3VjY2VzcyBtZXNzYWdlXG4gICAgbG9nKDMsIGBbYnJvd3Nlcl0gQnJvd3NlciByZWxhdW5jaGVkIHN1Y2Nlc3NmdWxseS5gKTtcbiAgfVxufVxuXG4vKipcbiAqIFJldHJpZXZlcyB0aGUgZXhpc3RpbmcgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8b2JqZWN0Pn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUHVwcGV0ZWVyIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgbm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlblxuICogY3JlYXRlZC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldCgpIHtcbiAgaWYgKCFicm93c2VyKSB7XG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicsIDUwMCk7XG4gIH1cbiAgcmV0dXJuIGJyb3dzZXI7XG59XG5cbi8qKlxuICogQ3JlYXRlcyBhIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHNwZWNpZmllZCBhcmd1bWVudHMuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gcHVwcGV0ZWVyQXJncyAtIEFkZGl0aW9uYWwgYXJndW1lbnRzIGZvciBQdXBwZXRlZXIgbGF1bmNoLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXG4gKiBpbnN0YW5jZS5cbiAqXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXG4gKiBpbnN0YW5jZSBhcmUgcmVhY2hlZCwgb3IgaWYgbm8gYnJvd3NlciBpbnN0YW5jZSBpcyBmb3VuZCBhZnRlciByZXRyaWVzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcbiAgLy8gR2V0IGRlYnVnIGFuZCBvdGhlciBvcHRpb25zXG4gIGNvbnN0IHsgZGVidWcsIG90aGVyIH0gPSBnZXRPcHRpb25zKCk7XG5cbiAgLy8gR2V0IHRoZSBkZWJ1ZyBvcHRpb25zXG4gIGNvbnN0IHsgZW5hYmxlOiBlbmFibGVkRGVidWcsIC4uLmRlYnVnT3B0aW9ucyB9ID0gZGVidWc7XG5cbiAgY29uc3QgbGF1bmNoT3B0aW9ucyA9IHtcbiAgICBoZWFkbGVzczogb3RoZXIuYnJvd3NlclNoZWxsTW9kZSA/ICdzaGVsbCcgOiB0cnVlLFxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcbiAgICBhcmdzOiBwdXBwZXRlZXJBcmdzLFxuICAgIC8vIE11c3QgYmUgZGlzYWJsZWQgZm9yIGRlYnVnZ2luZyB0byB3b3JrXG4gICAgcGlwZTogZW52cy5PVEhFUl9DT05ORUNUSU9OX09WRVJfUElQRSxcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxuICAgIGhhbmRsZVNJR1RFUk06IGZhbHNlLFxuICAgIGhhbmRsZVNJR0hVUDogZmFsc2UsXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcbiAgICBkZWZhdWx0Vmlld3BvcnQ6IG51bGwsXG4gICAgLi4uKGVuYWJsZWREZWJ1ZyAmJiBkZWJ1Z09wdGlvbnMpXG4gIH07XG5cbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxuICBpZiAoIWJyb3dzZXIpIHtcbiAgICBsZXQgdHJ5Q291bnQgPSAwO1xuXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcbiAgICAgIHRyeSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbYnJvd3Nlcl0gQXR0ZW1wdGluZyB0byBnZXQgYSBicm93c2VyIGluc3RhbmNlICh0cnkgJHsrK3RyeUNvdW50fSkuYFxuICAgICAgICApO1xuXG4gICAgICAgIC8vIExhdW5jaCB0aGUgYnJvd3NlclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcblxuICAgICAgICAvLyBDbG9zZSB0aGUgaW5pdGlhbCBwYWdlcyBpZiBhbnkgZm91bmRcbiAgICAgICAgY29uc3QgcGFnZXMgPSBhd2FpdCBicm93c2VyLnBhZ2VzKCk7XG4gICAgICAgIGlmIChwYWdlcykge1xuICAgICAgICAgIGZvciAoY29uc3QgcGFnZSBvZiBwYWdlcykge1xuICAgICAgICAgICAgYXdhaXQgcGFnZS5jbG9zZSgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIE9ubHkgZm9yIHRoZSBXZWJTb2NrZXQgY29ubmVjdGlvblxuICAgICAgICBpZiAoIWxhdW5jaE9wdGlvbnMucGlwZSkge1xuICAgICAgICAgIC8vIFNhdmUgV2ViU29ja2V0IGVuZHBvaW50XG4gICAgICAgICAgd3NFbmRwb2ludCA9IGJyb3dzZXIud3NFbmRwb2ludCgpO1xuXG4gICAgICAgICAgLy8gQXR0YWNoIHRoZSBkaXNjb25uZWN0ZWQgZXZlbnRcbiAgICAgICAgICBicm93c2VyLm9uKCdkaXNjb25uZWN0ZWQnLCByZWNvbm5lY3QpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgMSxcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcbiAgICAgICAgKTtcblxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcbiAgICAgICAgaWYgKHRyeUNvdW50IDwgMjUpIHtcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcbiAgICAgICAgICBhd2FpdCBvcGVuKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IG9wZW4oKTtcblxuICAgICAgLy8gU2hlbGwgbW9kZSBpbmZvcm1cbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XG4gICAgICAgIGxvZygzLCBgW2Jyb3dzZXJdIExhdW5jaGVkIGJyb3dzZXIgaW4gc2hlbGwgbW9kZS5gKTtcbiAgICAgIH1cblxuICAgICAgLy8gRGVidWcgbW9kZSBpbmZvcm1cbiAgICAgIGlmIChlbmFibGVkRGVidWcpIHtcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdbYnJvd3Nlcl0gTWF4aW11bSByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyIGluc3RhbmNlIHJlYWNoZWQuJyxcbiAgICAgICAgNTAwXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICB9XG5cbiAgICBpZiAoIWJyb3dzZXIpIHtcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2Jyb3dzZXJdIENhbm5vdCBmaW5kIGEgYnJvd3NlciB0byBvcGVuLicsIDUwMCk7XG4gICAgfVxuICB9XG5cbiAgLy8gUmV0dXJuIGEgYnJvd3NlciBwcm9taXNlXG4gIHJldHVybiBicm93c2VyO1xufVxuXG4vKipcbiAqIENsb3NlcyB0aGUgUHVwcGV0ZWVyIGJyb3dzZXIgaW5zdGFuY2UgaWYgaXQgaXMgY29ubmVjdGVkLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcbiAqIGlzIGNsb3NlZC5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xuICAvLyBDbG9zZSB0aGUgYnJvd3NlciB3aGVuIGNvbm5lY3RlZFxuICBpZiAoYnJvd3NlciAmJiBicm93c2VyLmNvbm5lY3RlZCkge1xuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcbiAgfVxuICBicm93c2VyID0gbnVsbDtcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBuZXcgUHVwcGV0ZWVyIFBhZ2Ugd2l0aGluIGFuIGV4aXN0aW5nIGJyb3dzZXIgaW5zdGFuY2UuXG4gKlxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cbiAqXG4gKiBUaGUgZnVuY3Rpb24gY3JlYXRlcyBhIG5ldyBwYWdlLCBkaXNhYmxlcyBjYWNoaW5nLCBzZXRzIGNvbnRlbnQgdXNpbmdcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwb29sUmVzb3VyY2UgLSBUaGUgcG9vbCByZXNvdXJjZSB0aGF0IGNvbnRpYW5zIHBhZ2UgYW5kIGlkLlxuICpcbiAqIEByZXR1cm5zIHsoYm9vbGVhbnxvYmplY3QpfSBSZXR1cm5zIGZhbHNlIGlmIHRoZSBicm93c2VyIGluc3RhbmNlIGlzIG5vdFxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIG5ld1BhZ2UocG9vbFJlc291cmNlKSB7XG4gIGNvbnN0IHN0YXJ0RGF0ZSA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuXG4gIC8vIFRocm93IGFuIGVycm9yIGluIGNhc2Ugb2Ygbm8gY29ubmVjdGVkIGJyb3dzZXJcbiAgaWYgKCFicm93c2VyIHx8ICFicm93c2VyLmNvbm5lY3RlZCkge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW2Jyb3dzZXJdIEJyb3dzZXIgaXMgbm90IHlldCBjb25uZWN0ZWQuYCwgNTAwKTtcbiAgfVxuXG4gIC8vIENyZWF0ZSBhIHBhZ2VcbiAgcG9vbFJlc291cmNlLnBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcblxuICAvLyBEaXNhYmxlIGNhY2hlXG4gIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLnNldENhY2hlRW5hYmxlZChmYWxzZSk7XG5cbiAgLy8gU2V0IHRoZSBjb250ZW50XG4gIGF3YWl0IHNldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcblxuICAvLyBTZXQgcGFnZSBldmVudHNcbiAgc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UpO1xuXG4gIC8vIENoZWNrIGlmIHRoZSBwYWdlIGlzIGNvcnJlY3RseSBjcmVhdGVkXG4gIGlmICghcG9vbFJlc291cmNlLnBhZ2UgfHwgcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignVGhlIHBhZ2UgaXMgaW52YWxpZCBvciBjbG9zZWQuJywgNTAwKTtcbiAgfVxuXG4gIGxvZyhcbiAgICAzLFxuICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyLCB0b29rICR7XG4gICAgICBuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHN0YXJ0RGF0ZVxuICAgIH1tcy5gXG4gICk7XG5cbiAgLy8gUmV0dXJuIHRoZSByZXNvdXJjZSB3aXRoIGEgcmVhZHkgdG8gdXNlIHBhZ2VcbiAgcmV0dXJuIHBvb2xSZXNvdXJjZTtcbn1cblxuLyoqXG4gKiBDbGVhcnMgdGhlIGNvbnRlbnQgb2YgYSBQdXBwZXRlZXIgUGFnZSBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG1vZGUuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBwb29sIHJlc291cmNlIHRoYXQgY29udGlhbnMgcGFnZSBhbmQgaWQuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGhhcmRSZXNldCAtIEEgZmxhZyBpbmRpY2F0aW5nIHRoZSB0eXBlIG9mIGNsZWFyaW5nXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxuICogYW5kIHNjcmlwdHMuIElmIGZhbHNlLCBjbGVhcnMgdGhlIGJvZHkgY29udGVudCBieSBzZXR0aW5nIGEgcHJlZGVmaW5lZCBIVE1MXG4gKiBzdHJ1Y3R1cmUuXG4gKlxuICogQHRocm93cyB7RXJyb3J9IExvZ3MgdGhyb3duIGVycm9yIGlmIGNsZWFyaW5nIHRoZSBwYWdlIGNvbnRlbnQgZmFpbHMuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocG9vbFJlc291cmNlLCBoYXJkUmVzZXQgPSBmYWxzZSkge1xuICB0cnkge1xuICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgaWYgKGhhcmRSZXNldCkge1xuICAgICAgICAvLyBOYXZpZ2F0ZSB0byBhYm91dDpibGFua1xuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHtcbiAgICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xuICAgICAgICB9KTtcblxuICAgICAgICAvLyBTZXQgdGhlIGNvbnRlbnQgYW5kIGFuZCBzY3JpcHRzIGFnYWluXG4gICAgICAgIGF3YWl0IHNldFBhZ2VDb250ZW50KHBvb2xSZXNvdXJjZS5wYWdlKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIENsZWFyIGJvZHkgY29udGVudFxuICAgICAgICBhd2FpdCBwb29sUmVzb3VyY2UucGFnZS5ldmFsdWF0ZSgoKSA9PiB7XG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPVxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcbiAgICAgICAgfSk7XG4gICAgICB9XG4gICAgfVxuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGxvZ1dpdGhTdGFjayhcbiAgICAgIDIsXG4gICAgICBlcnJvcixcbiAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIENvbnRlbnQgb2YgdGhlIHBhZ2UgY291bGQgbm90IGJlIGNsZWFyZWQuYFxuICAgICk7XG4gICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcbiAgICBwb29sUmVzb3VyY2Uud29ya0NvdW50ID0gZ2V0T3B0aW9ucygpLnBvb2wud29ya0xpbWl0ICsgMTtcbiAgfVxufVxuXG4vKipcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxuICogb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcbiAqIGFkZGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBBbGwgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxBcnJheTxPYmplY3Q+Pn0gLSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBhcnJheSBvZiBpbmplY3RlZFxuICogcmVzb3VyY2VzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKSB7XG4gIC8vIEluamVjdGVkIHJlc291cmNlcyBhcnJheVxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xuXG4gIC8vIFVzZSByZXNvdXJjZXNcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XG4gIGlmIChyZXNvdXJjZXMpIHtcbiAgICBjb25zdCBpbmplY3RlZEpzID0gW107XG5cbiAgICAvLyBMb2FkIGN1c3RvbSBKUyBjb2RlXG4gICAgaWYgKHJlc291cmNlcy5qcykge1xuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmpzXG4gICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBMb2FkIHNjcmlwdHMgZnJvbSBhbGwgY3VzdG9tIGZpbGVzXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xuICAgICAgZm9yIChjb25zdCBmaWxlIG9mIHJlc291cmNlcy5maWxlcykge1xuICAgICAgICBjb25zdCBpc0xvY2FsID0gIWZpbGUuc3RhcnRzV2l0aCgnaHR0cCcpID8gdHJ1ZSA6IGZhbHNlO1xuXG4gICAgICAgIC8vIEFkZCBlYWNoIGN1c3RvbSBzY3JpcHQgZnJvbSByZXNvdXJjZXMnIGZpbGVzXG4gICAgICAgIGluamVjdGVkSnMucHVzaChcbiAgICAgICAgICBpc0xvY2FsXG4gICAgICAgICAgICA/IHtcbiAgICAgICAgICAgICAgICBjb250ZW50OiByZWFkRmlsZVN5bmMoZmlsZSwgJ3V0ZjgnKVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICA6IHtcbiAgICAgICAgICAgICAgICB1cmw6IGZpbGVcbiAgICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGZvciAoY29uc3QganNSZXNvdXJjZSBvZiBpbmplY3RlZEpzKSB7XG4gICAgICB0cnkge1xuICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU2NyaXB0VGFnKGpzUmVzb3VyY2UpKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xuICAgICAgfVxuICAgIH1cbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XG5cbiAgICAvLyBMb2FkIENTU1xuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XG4gICAgaWYgKHJlc291cmNlcy5jc3MpIHtcbiAgICAgIGxldCBjc3NJbXBvcnRzID0gcmVzb3VyY2VzLmNzcy5tYXRjaCgvQGltcG9ydFxccyooW147XSopOy9nKTtcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XG4gICAgICAgIC8vIEhhbmRsZSBjc3Mgc2VjdGlvblxuICAgICAgICBmb3IgKGxldCBjc3NJbXBvcnRQYXRoIG9mIGNzc0ltcG9ydHMpIHtcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xuICAgICAgICAgICAgY3NzSW1wb3J0UGF0aCA9IGNzc0ltcG9ydFBhdGhcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ3VybCgnLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoL1wiL2csICcnKVxuICAgICAgICAgICAgICAucmVwbGFjZSgvJy9nLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcbiAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcKS9nLCAnJylcbiAgICAgICAgICAgICAgLnRyaW0oKTtcblxuICAgICAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIGNzcyBmcm9tIHJlc291cmNlc1xuICAgICAgICAgICAgaWYgKGNzc0ltcG9ydFBhdGguc3RhcnRzV2l0aCgnaHR0cCcpKSB7XG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xuICAgICAgICAgICAgICAgIHVybDogY3NzSW1wb3J0UGF0aFxuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcbiAgICAgICAgICAgICAgaW5qZWN0ZWRDc3MucHVzaCh7XG4gICAgICAgICAgICAgICAgcGF0aDogcGF0aC5qb2luKF9fZGlybmFtZSwgY3NzSW1wb3J0UGF0aClcbiAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XG4gICAgICBpbmplY3RlZENzcy5wdXNoKHtcbiAgICAgICAgY29udGVudDogcmVzb3VyY2VzLmNzcy5yZXBsYWNlKC9AaW1wb3J0XFxzKihbXjtdKik7L2csICcnKSB8fCAnICdcbiAgICAgIH0pO1xuXG4gICAgICBmb3IgKGNvbnN0IGNzc1Jlc291cmNlIG9mIGluamVjdGVkQ3NzKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgaW5qZWN0ZWRSZXNvdXJjZXMucHVzaChhd2FpdCBwYWdlLmFkZFN0eWxlVGFnKGNzc1Jlc291cmNlKSk7XG4gICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xuICAgIH1cbiAgfVxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XG59XG5cbi8qKlxuICogQ2xlYXJzIG91dCBhbGwgc3RhdGUgc2V0IG9uIHRoZSBwYWdlIHdpdGggYWRkU2NyaXB0VGFnL2FkZFN0eWxlVGFnLiBSZW1vdmVzXG4gKiBpbmplY3RlZCByZXNvdXJjZXMgYW5kIHJlc2V0cyBDU1MgYW5kIHNjcmlwdCB0YWdzIG9uIHRoZSBwYWdlLiBBZGRpdGlvbmFsbHksXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZnJvbSB3aGljaCByZXNvdXJjZXMgd2lsbFxuICogYmUgY2xlYXJlZC5cbiAqIEBwYXJhbSB7QXJyYXk8T2JqZWN0Pn0gaW5qZWN0ZWRSZXNvdXJjZXMgLSBBcnJheSBvZiBpbmplY3RlZCByZXNvdXJjZXNcbiAqIHRvIGJlIGNsZWFyZWQuXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcbiAgdHJ5IHtcbiAgICBmb3IgKGNvbnN0IHJlc291cmNlIG9mIGluamVjdGVkUmVzb3VyY2VzKSB7XG4gICAgICBhd2FpdCByZXNvdXJjZS5kaXNwb3NlKCk7XG4gICAgfVxuXG4gICAgLy8gRGVzdHJveSBvbGQgY2hhcnRzIGFmdGVyIGV4cG9ydCBpcyBkb25lIGFuZCByZXNldCBhbGwgQ1NTIGFuZCBzY3JpcHQgdGFnc1xuICAgIGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgICAgLy8gV2UgYXJlIG5vdCBndWFyYW50ZWVkIHRoYXQgSGlnaGNoYXJ0cyBpcyBsb2FkZWQsIGUsZywgd2hlbiBkb2luZyBTVkdcbiAgICAgIC8vIGV4cG9ydHNcbiAgICAgIGlmICh0eXBlb2YgSGlnaGNoYXJ0cyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgIGNvbnN0IG9sZENoYXJ0cyA9IEhpZ2hjaGFydHMuY2hhcnRzO1xuXG4gICAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xuICAgICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcbiAgICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcbiAgICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xuICAgICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xuICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgIGNvbnN0IFsuLi5zY3JpcHRzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ3NjcmlwdCcpO1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICBjb25zdCBbLCAuLi5zdHlsZXNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc3R5bGUnKTtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgY29uc3QgWy4uLmxpbmtzVG9SZW1vdmVdID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoJ2xpbmsnKTtcblxuICAgICAgLy8gUmVtb3ZlIHRhZ3NcbiAgICAgIGZvciAoY29uc3QgZWxlbWVudCBvZiBbXG4gICAgICAgIC4uLnNjcmlwdHNUb1JlbW92ZSxcbiAgICAgICAgLi4uc3R5bGVzVG9SZW1vdmUsXG4gICAgICAgIC4uLmxpbmtzVG9SZW1vdmVcbiAgICAgIF0pIHtcbiAgICAgICAgZWxlbWVudC5yZW1vdmUoKTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbYnJvd3Nlcl0gQ291bGQgbm90IGNsZWFyIHBhZ2UncyByZXNvdXJjZXMuYCk7XG4gIH1cbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxuICogYW5kIGFkZGl0aW9uYWwgc2NyaXB0cy4gQWxzbywgc2V0cyB0aGUgcGFnZWVycm9yIGluIG9yZGVyIHRvIGNhdGNoXG4gKiBhbmQgZGlzcGxheSBlcnJvcnMgZnJvbSB0aGUgd2luZG93IGNvbnRleHQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZvciB3aGljaCB0aGUgY29udGVudFxuICogaXMgYmVpbmcgc2V0LlxuICovXG5hc3luYyBmdW5jdGlvbiBzZXRQYWdlQ29udGVudChwYWdlKSB7XG4gIGF3YWl0IHBhZ2Uuc2V0Q29udGVudCh0ZW1wbGF0ZSwgeyB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJyB9KTtcblxuICAvLyBBZGQgYWxsIHJlZ2lzdGVyZWQgSGlnY2hhcnRzIHNjcmlwdHMsIHF1aXRlIGRlbWFuZGluZ1xuICBhd2FpdCBwYWdlLmFkZFNjcmlwdFRhZyh7IHBhdGg6IGAke2dldENhY2hlUGF0aCgpfS9zb3VyY2VzLmpzYCB9KTtcblxuICAvLyBTZXQgdGhlIGluaXRpYWwgYW5pbU9iamVjdFxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKHNldHVwSGlnaGNoYXJ0cyk7XG59XG5cbi8qKlxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcG9vbFJlc291cmNlIC0gVGhlIHBvb2wgcmVzb3VyY2UgdGhhdCBjb250aWFucyBwYWdlIGFuZCBpZC5cbiAqL1xuZnVuY3Rpb24gc2V0UGFnZUV2ZW50cyhwb29sUmVzb3VyY2UpIHtcbiAgLy8gR2V0IGRlYnVnIG9wdGlvbnNcbiAgY29uc3QgeyBkZWJ1ZywgcG9vbCB9ID0gZ2V0T3B0aW9ucygpO1xuXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXG4gIHBvb2xSZXNvdXJjZS5wYWdlLm9uKCdwYWdlZXJyb3InLCBhc3luYyAoZXJyb3IpID0+IHtcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXG4gICAgLy8gb24gcGFnZSBlcnJvcnMuXG4gICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuJGV2YWwoXG4gICAgICAnI2NvbnRhaW5lcicsXG4gICAgICAoZWxlbWVudCwgZXJyb3JNZXNzYWdlKSA9PiB7XG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICBpZiAod2luZG93Ll9kaXNwbGF5RXJyb3JzKSB7XG4gICAgICAgICAgZWxlbWVudC5pbm5lckhUTUwgPSBlcnJvck1lc3NhZ2U7XG4gICAgICAgIH1cbiAgICAgIH0sXG4gICAgICBgPGgxPkNoYXJ0IGlucHV0IGRhdGEgZXJyb3I6IDwvaDE+JHtlcnJvci50b1N0cmluZygpfWBcbiAgICApO1xuICB9KTtcblxuICAvLyBTZXQgdGhlIGNvbnNvbGUgbGlzdGVuZXIsIGlmIG5lZWRlZFxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xuICAgIHBvb2xSZXNvdXJjZS5wYWdlLm9uKCdjb25zb2xlJywgKG1lc3NhZ2UpID0+IHtcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBBZGQgdGhlIGZyYW1lZGV0YWNoZWQgZXZlbnQgaWYgdGhlIGNvbm5lY3Rpb24gaXMgb3ZlciBXZWJTb2NrZXRcbiAgaWYgKGVudnMuT1RIRVJfQ09OTkVDVElPTl9PVkVSX1BJUEUgPT09IGZhbHNlKSB7XG4gICAgcG9vbFJlc291cmNlLnBhZ2Uub24oJ2ZyYW1lZGV0YWNoZWQnLCBhc3luYyAoZnJhbWUpID0+IHtcbiAgICAgIC8vIEdldCB0aGUgbWFpbiBmcmFtZVxuICAgICAgY29uc3QgbWFpbkZyYW1lID0gcG9vbFJlc291cmNlLnBhZ2UubWFpbkZyYW1lKCk7XG5cbiAgICAgIC8vIENoZWNrIGlmIGEgcGFnZSdzIGZyYW1lIGlzIGRldGFjaGVkIGFuZCByZXF1aXJlcyB0byBiZSByZWNyZWF0ZWRcbiAgICAgIGlmIChcbiAgICAgICAgZnJhbWUgPT09IG1haW5GcmFtZSAmJlxuICAgICAgICBtYWluRnJhbWUuZGV0YWNoZWQgJiZcbiAgICAgICAgcG9vbFJlc291cmNlLndvcmtDb3VudCA8PSBwb29sLndvcmtMaW1pdFxuICAgICAgKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICAzLFxuICAgICAgICAgIGBbYnJvd3Nlcl0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFBhZ2UncyBmcmFtZSBkZXRhY2hlZC5gXG4gICAgICAgICk7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgLy8gVHJ5IHRvIGNvbm5lY3QgdG8gYSBuZXcgcGFnZSB1c2luZyBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5XG4gICAgICAgICAgZXhwQmFja29mZihcbiAgICAgICAgICAgIGFzeW5jIChwb29sUmVzb3VyY2VJZCwgcG9vbFJlc291cmNlKSA9PiB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gVHJ5IHRvIGNsb3NlIHRoZSBwYWdlIHdpdGggYSBkZXRhY2hlZCBmcmFtZVxuICAgICAgICAgICAgICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgICAgICAgICAgICAgYXdhaXQgcG9vbFJlc291cmNlLnBhZ2UuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgbG9nKFxuICAgICAgICAgICAgICAgICAgMyxcbiAgICAgICAgICAgICAgICAgIGBbYnJvd3Nlcl0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2VJZH1dIC0gQ291bGQgbm90IGNsb3NlIHRoZSBwYWdlIHdpdGggYSBkZXRhY2hlZCBmcmFtZS5gXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgIC8vIFRyaWdnZXIgYSBwYWdlIGNyZWF0aW9uXG4gICAgICAgICAgICAgIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAwLFxuICAgICAgICAgICAgcG9vbFJlc291cmNlLmlkLFxuICAgICAgICAgICAgcG9vbFJlc291cmNlXG4gICAgICAgICAgKTtcbiAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgICAzLFxuICAgICAgICAgICAgZXJyb3IsXG4gICAgICAgICAgICBgW2Jyb3dzZXJdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBDb3VsZCBub3QgY3JlYXRlIGEgbmV3IHBhZ2UuYFxuICAgICAgICAgICk7XG5cbiAgICAgICAgICAvLyBTZXQgdGhlIGB3b3JrTGltaXRgIHRvIGV4Y2VlZGVkIGluIG9yZGVyIHRvIHJlY3JlYXRlIHRoZSByZXNvdXJjZVxuICAgICAgICAgIHBvb2xSZXNvdXJjZS53b3JrQ291bnQgPSBwb29sLndvcmtMaW1pdCArIDE7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGdldCxcbiAgY3JlYXRlLFxuICBjbG9zZSxcbiAgbmV3UGFnZSxcbiAgY2xlYXJQYWdlLFxuICBhZGRQYWdlUmVzb3VyY2VzLFxuICBjbGVhclBhZ2VSZXNvdXJjZXNcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgYWRkUGFnZVJlc291cmNlcywgY2xlYXJQYWdlUmVzb3VyY2VzIH0gZnJvbSAnLi9icm93c2VyLmpzJztcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyB0cmlnZ2VyRXhwb3J0IH0gZnJvbSAnLi9oaWdoY2hhcnRzLmpzJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4vbG9nZ2VyLmpzJztcblxuaW1wb3J0IHN2Z1RlbXBsYXRlIGZyb20gJy4vLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbi8qKlxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxuICogdGhlIGlkICdjaGFydC1jb250YWluZXInLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCBjb250YWluaW5nXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxuICovXG5jb25zdCBnZXRDbGlwUmVnaW9uID0gKHBhZ2UpID0+XG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xuICAgIGNvbnN0IHsgeCwgeSwgd2lkdGgsIGhlaWdodCB9ID0gZWxlbWVudC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICByZXR1cm4ge1xuICAgICAgeCxcbiAgICAgIHksXG4gICAgICB3aWR0aCxcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxuICAgIH07XG4gIH0pO1xuXG4vKipcbiAqIENyZWF0ZXMgYW4gaW1hZ2UgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBzY3JlZW5zaG90IGZ1bmN0aW9uYWxpdHkgd2l0aFxuICogc3BlY2lmaWVkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBJbWFnZSBlbmNvZGluZy5cbiAqIEBwYXJhbSB7T2JqZWN0fSBjbGlwIC0gQ2xpcHBpbmcgcmVnaW9uIGNvb3JkaW5hdGVzLlxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxuICogaW4gbWlsbGlzZWNvbmRzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXG4gKiB3aXRoIGFuIEV4cG9ydEVycm9yIGZvciB0aW1lb3V0LlxuICovXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XG4gIFByb21pc2UucmFjZShbXG4gICAgcGFnZS5zY3JlZW5zaG90KHtcbiAgICAgIHR5cGUsXG4gICAgICBlbmNvZGluZyxcbiAgICAgIGNsaXAsXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXG4gICAgICBmdWxsUGFnZTogZmFsc2UsXG4gICAgICBvcHRpbWl6ZUZvclNwZWVkOiB0cnVlLFxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxuXG4gICAgICAvLyAjNDQ3LCAjNDYzIC0gYWx3YXlzIHJlbmRlciBvbiBhIHRyYW5zcGFyZW50IHBhZ2UgaWYgdGhlIGV4cGVjdGVkIHR5cGVcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcbiAgICAgIG9taXRCYWNrZ3JvdW5kOiB0eXBlID09ICdwbmcnXG4gICAgfSksXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XG4gICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxuICAgICAgKVxuICAgIClcbiAgXSk7XG5cbi8qKlxuICogQ3JlYXRlcyBhIFBERiB1c2luZyBQdXBwZXRlZXIncyBwYWdlIHBkZiBmdW5jdGlvbmFsaXR5IHdpdGggc3BlY2lmaWVkXG4gKiBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXG4gKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBQREYgd2lkdGguXG4gKiBAcGFyYW0ge3N0cmluZ30gZW5jb2RpbmcgLSBQREYgZW5jb2RpbmcuXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8QnVmZmVyPn0gUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFBERiBidWZmZXIuXG4gKi9cbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcbiAgcGFnZSxcbiAgaGVpZ2h0LFxuICB3aWR0aCxcbiAgZW5jb2RpbmcsXG4gIHJhc3Rlcml6YXRpb25UaW1lb3V0XG4pID0+IHtcbiAgYXdhaXQgcGFnZS5lbXVsYXRlTWVkaWFUeXBlKCdzY3JlZW4nKTtcbiAgcmV0dXJuIFByb21pc2UucmFjZShbXG4gICAgcGFnZS5wZGYoe1xuICAgICAgLy8gVGhpcyB3aWxsIHJlbW92ZSBhbiBleHRyYSBlbXB0eSBwYWdlIGluIFBERiBleHBvcnRzXG4gICAgICBoZWlnaHQ6IGhlaWdodCArIDEsXG4gICAgICB3aWR0aCxcbiAgICAgIGVuY29kaW5nXG4gICAgfSksXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XG4gICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAoKSA9PiByZWplY3QobmV3IEV4cG9ydEVycm9yKCdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnLCA0MDgpKSxcbiAgICAgICAgcmFzdGVyaXphdGlvblRpbWVvdXQgfHwgMTUwMFxuICAgICAgKVxuICAgIClcbiAgXSk7XG59O1xuXG4vKipcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcbiAqIGluc2lkZSBhbiBlbGVtZW50IHdpdGggdGhlIGlkICdjb250YWluZXInLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZz59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBTVkcgc3RyaW5nLlxuICovXG5jb25zdCBjcmVhdGVTVkcgPSAocGFnZSkgPT5cbiAgcGFnZS4kZXZhbCgnI2NvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZScsIChlbGVtZW50KSA9PiBlbGVtZW50Lm91dGVySFRNTCk7XG5cbi8qKlxuICogU2V0cyB0aGUgc3BlY2lmaWVkIGNoYXJ0IGFuZCBvcHRpb25zIGFzIGNvbmZpZ3VyYXRpb24gaW50byB0aGUgdHJpZ2dlckV4cG9ydFxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHRoZSBjaGFydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxuICovXG5jb25zdCBzZXRBc0NvbmZpZyA9IGFzeW5jIChwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycykgPT5cbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XG5cbi8qKlxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zIGFuZCBjb25maWd1cmF0aW9uLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cbiAqIHRoZSBleHBvcnRlZCBkYXRhIG9yIHJlamVjdGluZyB3aXRoIGFuIEV4cG9ydEVycm9yLlxuICovXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcbiAgLy8gSW5qZWN0ZWQgcmVzb3VyY2VzIGFycmF5IChhZGRpdGlvbmFsIEpTIGFuZCBDU1MpXG4gIGxldCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xuXG4gIHRyeSB7XG4gICAgbG9nKDQsICdbZXhwb3J0XSBEZXRlcm1pbmluZyBleHBvcnQgcGF0aC4nKTtcblxuICAgIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcbiAgICBjb25zdCBkaXNwbGF5RXJyb3JzID1cbiAgICAgIGV4cG9ydE9wdGlvbnM/Lm9wdGlvbnM/LmNoYXJ0Py5kaXNwbGF5RXJyb3JzICYmXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XG5cbiAgICBsZXQgaXNTVkc7XG4gICAgaWYgKFxuICAgICAgY2hhcnQuaW5kZXhPZiAmJlxuICAgICAgKGNoYXJ0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8IGNoYXJ0LmluZGV4T2YoJzw/eG1sJykgPj0gMClcbiAgICApIHtcbiAgICAgIC8vIFNWRyBpbnB1dCBoYW5kbGluZ1xuICAgICAgbG9nKDQsICdbZXhwb3J0XSBUcmVhdGluZyBhcyBTVkcuJyk7XG5cbiAgICAgIC8vIElmIGlucHV0IGlzIGFsc28gU1ZHLCBqdXN0IHJldHVybiBpdFxuICAgICAgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3N2ZycpIHtcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xuICAgICAgfVxuXG4gICAgICBpc1NWRyA9IHRydWU7XG4gICAgICBhd2FpdCBwYWdlLnNldENvbnRlbnQoc3ZnVGVtcGxhdGUoY2hhcnQpLCB7XG4gICAgICAgIHdhaXRVbnRpbDogJ2RvbWNvbnRlbnRsb2FkZWQnXG4gICAgICB9KTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gSlNPTiBjb25maWcgaGFuZGxpbmdcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xuXG4gICAgICAvLyBOZWVkIHRvIHBlcmZvcm0gc3RyYWlnaHQgaW5qZWN0XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcbiAgICAgICAgLy8gSW5qZWN0aW9uIGJhc2VkIGNvbmZpZ3VyYXRpb24gZXhwb3J0XG4gICAgICAgIGF3YWl0IHNldEFzQ29uZmlnKFxuICAgICAgICAgIHBhZ2UsXG4gICAgICAgICAge1xuICAgICAgICAgICAgY2hhcnQ6IHtcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcbiAgICAgICAgICAgICAgd2lkdGg6IGV4cG9ydE9wdGlvbnMud2lkdGhcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9LFxuICAgICAgICAgIG9wdGlvbnMsXG4gICAgICAgICAgZGlzcGxheUVycm9yc1xuICAgICAgICApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gQmFzaWMgY29uZmlndXJhdGlvbiBleHBvcnRcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XG4gICAgICAgIGNoYXJ0LmNoYXJ0LndpZHRoID0gZXhwb3J0T3B0aW9ucy53aWR0aDtcblxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gS2VlcHMgdHJhY2sgb2YgYWxsIHJlc291cmNlcyBhZGRlZCBvbiB0aGUgcGFnZSB3aXRoIGFkZFhYWFRhZy4gZXRjXG4gICAgLy8gSXQncyBWSVRBTCB0aGF0IGFsbCBhZGRlZCByZXNvdXJjZXMgZW5kcyB1cCBoZXJlIHNvIHdlIGNhbiBjbGVhciB0aGluZ3NcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcbiAgICBpbmplY3RlZFJlc291cmNlcyA9IGF3YWl0IGFkZFBhZ2VSZXNvdXJjZXMocGFnZSwgb3B0aW9ucyk7XG5cbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XG4gICAgY29uc3Qgc2l6ZSA9IGlzU1ZHXG4gICAgICA/IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKHNjYWxlKSA9PiB7XG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXG4gICAgICAgICAgICAnI2NoYXJ0LWNvbnRhaW5lciBzdmc6Zmlyc3Qtb2YtdHlwZSdcbiAgICAgICAgICApO1xuXG4gICAgICAgICAgLy8gR2V0IHRoZSB2YWx1ZXMgY29ycmVjdGx5IHNjYWxlZFxuICAgICAgICAgIGNvbnN0IGNoYXJ0SGVpZ2h0ID0gc3ZnRWxlbWVudC5oZWlnaHQuYmFzZVZhbC52YWx1ZSAqIHNjYWxlO1xuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcblxuICAgICAgICAgIC8vIEluIGNhc2Ugb2YgU1ZHIHRoZSB6b29tIG11c3QgYmUgc2V0IGRpcmVjdGx5IGZvciBib2R5XG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXG4gICAgICAgICAgZG9jdW1lbnQuYm9keS5zdHlsZS56b29tID0gc2NhbGU7XG5cbiAgICAgICAgICAvLyBTZXQgdGhlIG1hcmdpbiB0byAwcHhcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xuXG4gICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxuICAgICAgICAgICAgY2hhcnRXaWR0aFxuICAgICAgICAgIH07XG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXG4gICAgICA6IGF3YWl0IHBhZ2UuZXZhbHVhdGUoKCkgPT4ge1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcblxuICAgICAgICAgIC8vIE5vIG5lZWQgZm9yIHN1Y2ggc2NhbGUgbWFuaXB1bGF0aW9uIGluIGNhc2Ugb2Ygb3RoZXIgdHlwZXMgb2YgZXhwb3J0c1xuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xuICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IDE7XG5cbiAgICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgY2hhcnRIZWlnaHQsXG4gICAgICAgICAgICBjaGFydFdpZHRoXG4gICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAvLyBTZXQgZmluYWwgaGVpZ2h0IGFuZCB3aWR0aCBmb3Igdmlld3BvcnRcbiAgICBjb25zdCB2aWV3cG9ydEhlaWdodCA9IE1hdGguY2VpbChzaXplLmNoYXJ0SGVpZ2h0IHx8IGV4cG9ydE9wdGlvbnMuaGVpZ2h0KTtcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcblxuICAgIC8vIEdldCB0aGUgY2xpcCByZWdpb24gZm9yIHRoZSBwYWdlXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xuXG4gICAgLy8gU2V0IHRoZSBmaW5hbCB2aWV3cG9ydCBub3cgdGhhdCB3ZSBoYXZlIHRoZSByZWFsIGhlaWdodFxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xuICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcbiAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcbiAgICB9KTtcblxuICAgIGxldCBkYXRhO1xuICAgIC8vIFJhc3Rlcml6YXRpb24gcHJvY2Vzc1xuICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XG4gICAgICAvLyBTVkdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVTVkcocGFnZSk7XG4gICAgfSBlbHNlIGlmIChbJ3BuZycsICdqcGVnJ10uaW5jbHVkZXMoZXhwb3J0T3B0aW9ucy50eXBlKSkge1xuICAgICAgLy8gUE5HIG9yIEpQRUdcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVJbWFnZShcbiAgICAgICAgcGFnZSxcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxuICAgICAgICAnYmFzZTY0JyxcbiAgICAgICAge1xuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxuICAgICAgICAgIGhlaWdodDogdmlld3BvcnRIZWlnaHQsXG4gICAgICAgICAgeCxcbiAgICAgICAgICB5XG4gICAgICAgIH0sXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcbiAgICAgICk7XG4gICAgfSBlbHNlIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdwZGYnKSB7XG4gICAgICAvLyBQREZcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXG4gICAgICAgIHBhZ2UsXG4gICAgICAgIHZpZXdwb3J0SGVpZ2h0LFxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxuICAgICAgICAnYmFzZTY0JyxcbiAgICAgICAgZXhwb3J0T3B0aW9ucy5yYXN0ZXJpemF0aW9uVGltZW91dFxuICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYCxcbiAgICAgICAgNDAwXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcbiAgICBhd2FpdCBjbGVhclBhZ2VSZXNvdXJjZXMocGFnZSwgaW5qZWN0ZWRSZXNvdXJjZXMpO1xuICAgIHJldHVybiBkYXRhO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XG4gICAgcmV0dXJuIGVycm9yO1xuICB9XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCBjc3NUZW1wbGF0ZSBmcm9tICcuL2Nzcy5qcyc7XG5cbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxuPCFET0NUWVBFIGh0bWw+XG48aHRtbCBsYW5nPSdlbi1VUyc+XG4gIDxoZWFkPlxuICAgIDxtZXRhIGh0dHAtZXF1aXY9XCJDb250ZW50LVR5cGVcIiBjb250ZW50PVwidGV4dC9odG1sOyBjaGFyc2V0PXV0Zi04XCI+XG4gICAgPHRpdGxlPkhpZ2hjaGFydHMgRXhwb3J0PC90aXRsZT5cbiAgPC9oZWFkPlxuICA8c3R5bGU+XG4gICAgJHtjc3NUZW1wbGF0ZSgpfVxuICA8L3N0eWxlPlxuICA8Ym9keT5cbiAgICA8ZGl2IGlkPVwiY2hhcnQtY29udGFpbmVyXCI+XG4gICAgICAke2NoYXJ0fVxuICAgIDwvZGl2PlxuICA8L2JvZHk+XG48L2h0bWw+XG5cbmA7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xuXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcbmNvbnN0IGludGVydmFsSWRzID0gW107XG5cbi8qKlxuICogQWRkcyBpZCBvZiBhIHNldEludGVydmFsIHRvIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cbiAqXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxuICovXG5leHBvcnQgY29uc3QgYWRkSW50ZXJ2YWwgPSAoaWQpID0+IHtcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XG59O1xuXG4vKipcbiAqIENsZWFycyBhbGwgb2Ygb25nb2luZyBpbnRlcnZhbHMgYnkgaWRzIGdhdGhlcmVkIGluIHRoZSBpbnRlcnZhbElkcyBhcnJheS5cbiAqL1xuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xuICBsb2coNCwgYFtzZXJ2ZXJdIENsZWFyaW5nIGFsbCByZWdpc3RlcmVkIGludGVydmFscy5gKTtcbiAgZm9yIChjb25zdCBpZCBvZiBpbnRlcnZhbElkcykge1xuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIGFkZEludGVydmFsLFxuICBjbGVhckFsbEludGVydmFsc1xufTtcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG5cbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxuXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcblxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxuXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cblxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxuXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5pbXBvcnQgeyBQb29sIH0gZnJvbSAndGFybic7XG5pbXBvcnQgeyB2NCBhcyB1dWlkIH0gZnJvbSAndXVpZCc7XG5cbmltcG9ydCB7XG4gIGNyZWF0ZSBhcyBjcmVhdGVCcm93c2VyLFxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXG4gIG5ld1BhZ2UsXG4gIGNsZWFyUGFnZVxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBtZWFzdXJlVGltZSB9IGZyb20gJy4vdXRpbHMuanMnO1xuXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vLyBUaGUgcG9vbCBpbnN0YW5jZVxubGV0IHBvb2wgPSBmYWxzZTtcblxuLy8gUG9vbCBzdGF0aXN0aWNzXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XG4gIHBlcmZvcm1lZEV4cG9ydHM6IDAsXG4gIGV4cG9ydEF0dGVtcHRzOiAwLFxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXG4gIHRpbWVTcGVudDogMCxcbiAgZHJvcHBlZEV4cG9ydHM6IDAsXG4gIHNwZW50QXZlcmFnZTogMFxufTtcblxubGV0IHBvb2xDb25maWcgPSB7fTtcblxuY29uc3QgZmFjdG9yeSA9IHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgd29ya2VyIHBhZ2UgZm9yIHRoZSBleHBvcnQgcG9vbC5cbiAgICpcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcbiAgICogYnJvd3NlciBwYWdlLCBhbmQgaW5pdGlhbCB3b3JrIGNvdW50LlxuICAgKlxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xuICAgKiBwYWdlLlxuICAgKi9cbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XG4gICAgdHJ5IHtcbiAgICAgIGNvbnN0IHBvb2xSZXNvdXJjZSA9IHtcbiAgICAgICAgaWQ6IHV1aWQoKSxcbiAgICAgICAgLy8gVHJ5IHRvIGRpc3RyaWJ1dGUgdGhlIGluaXRpYWwgd29yayBjb3VudFxuICAgICAgICB3b3JrQ291bnQ6IE1hdGgucm91bmQoTWF0aC5yYW5kb20oKSAqIChwb29sQ29uZmlnLndvcmtMaW1pdCAvIDIpKVxuICAgICAgfTtcblxuICAgICAgcmV0dXJuIGF3YWl0IG5ld1BhZ2UocG9vbFJlc291cmNlKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLicsXG4gICAgICAgIDUwMFxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgfVxuICB9LFxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZXMgYSB3b3JrZXIgcGFnZSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNoZWNraW5nIGlmIGl0IGhhcyBleGNlZWRlZFxuICAgKiB0aGUgd29yayBsaW1pdC5cbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZyB0aGVcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxuICAgKlxuICAgKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBSZXR1cm5zIHRydWUgaWYgdGhlIHdvcmtlciBpcyB2YWxpZCBhbmQgd2l0aGluXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXG4gICAqL1xuICB2YWxpZGF0ZTogYXN5bmMgKHBvb2xSZXNvdXJjZSkgPT4ge1xuICAgIGxldCB2YWxpZGF0ZWQgPSB0cnVlO1xuXG4gICAgLy8gQ2hlY2sgaWYgdGhlIGB3b3JrTGltaXRgIGlzIGV4Y2VlZGVkXG4gICAgaWYgKFxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcbiAgICAgICsrcG9vbFJlc291cmNlLndvcmtDb3VudCA+IHBvb2xDb25maWcud29ya0xpbWl0XG4gICAgKSB7XG4gICAgICBsb2coXG4gICAgICAgIDMsXG4gICAgICAgIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIFZhbGlkYXRpb24gZmFpbGVkIChleGNlZWRlZCB0aGUgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0gd29ya3MgbGltaXQpLmBcbiAgICAgICk7XG4gICAgICB2YWxpZGF0ZWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBDaGVjayBpZiB0aGUgYHBhZ2VgIGlzIG5vdCB2YWxpZFxuICAgIGlmICghcG9vbFJlc291cmNlLnBhZ2UpIHtcbiAgICAgIC8vIENoZWNrIGlmIHRoZSBgcGFnZWAgaXMgY2xvc2VkXG4gICAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UuaXNDbG9zZWQoKSkge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSBpcyBjbG9zZWQgb3IgaW52YWxpZCkuYFxuICAgICAgICApO1xuICAgICAgfVxuXG4gICAgICAvLyBDaGVjayBpZiB0aGUgYG1haW5GcmFtZWAgaXMgZGV0YWNoZWRcbiAgICAgIGlmIChwb29sUmVzb3VyY2UucGFnZS5tYWluRnJhbWUoKS5kZXRhY2hlZCkge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBWYWxpZGF0aW9uIGZhaWxlZCAocGFnZSdzIGZyYW1lIGlzIGRldGFjaGVkKS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgICB2YWxpZGF0ZWQgPSBmYWxzZTtcbiAgICB9XG5cbiAgICByZXR1cm4gdmFsaWRhdGVkO1xuICB9LFxuXG4gIC8qKlxuICAgKiBEZXN0cm95cyBhIHdvcmtlciBlbnRyeSBpbiB0aGUgZXhwb3J0IHBvb2wsIGNsb3NpbmcgaXRzIGFzc29jaWF0ZWQgcGFnZS5cbiAgICpcbiAgICogQHBhcmFtIHtPYmplY3R9IHBvb2xSZXNvdXJjZSAtIFRoZSBoYW5kbGUgdG8gdGhlIHdvcmtlciwgY29udGFpbmluZ1xuICAgKiB0aGUgd29ya2VyJ3MgSUQgYW5kIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UuXG4gICAqL1xuICBkZXN0cm95OiBhc3luYyAocG9vbFJlc291cmNlKSA9PiB7XG4gICAgbG9nKDMsIGBbcG9vbF0gUG9vbCByZXNvdXJjZSBbJHtwb29sUmVzb3VyY2UuaWR9XSAtIERlc3Ryb3lpbmcgYSB3b3JrZXIuYCk7XG5cbiAgICBpZiAocG9vbFJlc291cmNlLnBhZ2UpIHtcbiAgICAgIHRyeSB7XG4gICAgICAgIC8vIFJlbW92ZSBhbGwgYXR0YWNoZWQgZXZlbnQgbGlzdGVuZXJzIGZyb20gdGhlIHJlc291cmNlXG4gICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygncGFnZWVycm9yJyk7XG4gICAgICAgIHBvb2xSZXNvdXJjZS5wYWdlLnJlbW92ZUFsbExpc3RlbmVycygnY29uc29sZScpO1xuICAgICAgICBwb29sUmVzb3VyY2UucGFnZS5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2ZyYW1lZGV0YWNoZWQnKTtcblxuICAgICAgICAvLyBXZSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXG4gICAgICAgIGF3YWl0IHBvb2xSZXNvdXJjZS5wYWdlLmNsb3NlKCk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2coXG4gICAgICAgICAgMyxcbiAgICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cG9vbFJlc291cmNlLmlkfV0gLSBQYWdlIGNvdWxkIG5vdCBiZSBjbG9zZWQgdXBvbiBkZXN0cm95aW5nLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn07XG5cbi8qKlxuICogSW5pdGlhbGl6ZXMgdGhlIGV4cG9ydCBwb29sIHdpdGggdGhlIHByb3ZpZGVkIGNvbmZpZ3VyYXRpb24sIGNyZWF0aW5nXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnIC0gQ29uZmlndXJhdGlvbiBvcHRpb25zIGZvciB0aGUgZXhwb3J0IHBvb2wgYWxvbmdcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxuICovXG5leHBvcnQgY29uc3QgaW5pdFBvb2wgPSBhc3luYyAoY29uZmlnKSA9PiB7XG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXG4gIHBvb2xDb25maWcgPSBjb25maWcgJiYgY29uZmlnLnBvb2wgPyB7IC4uLmNvbmZpZy5wb29sIH0gOiB7fTtcblxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcbiAgYXdhaXQgY3JlYXRlQnJvd3Nlcihjb25maWcucHVwcGV0ZWVyQXJncyk7XG5cbiAgbG9nKFxuICAgIDMsXG4gICAgYFtwb29sXSBJbml0aWFsaXppbmcgcG9vbCB3aXRoIHdvcmtlcnM6IG1pbiAke3Bvb2xDb25maWcubWluV29ya2Vyc30sIG1heCAke3Bvb2xDb25maWcubWF4V29ya2Vyc30uYFxuICApO1xuXG4gIGlmIChwb29sKSB7XG4gICAgcmV0dXJuIGxvZyhcbiAgICAgIDQsXG4gICAgICAnW3Bvb2xdIEFscmVhZHkgaW5pdGlhbGl6ZWQsIHBsZWFzZSBraWxsIGl0IGJlZm9yZSBjcmVhdGluZyBhIG5ldyBvbmUuJ1xuICAgICk7XG4gIH1cblxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcbiAgICBwb29sQ29uZmlnLm1pbldvcmtlcnMgPSBwb29sQ29uZmlnLm1heFdvcmtlcnM7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIENyZWF0ZSBhIHBvb2wgYWxvbmcgd2l0aCBhIG1pbmltYWwgbnVtYmVyIG9mIHJlc291cmNlc1xuICAgIHBvb2wgPSBuZXcgUG9vbCh7XG4gICAgICAvLyBHZXQgdGhlIGNyZWF0ZS92YWxpZGF0ZS9kZXN0cm95L2xvZyBmdW5jdGlvbnNcbiAgICAgIC4uLmZhY3RvcnksXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXG4gICAgICBtYXg6IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycyksXG4gICAgICBhY3F1aXJlVGltZW91dE1pbGxpczogcG9vbENvbmZpZy5hY3F1aXJlVGltZW91dCxcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcbiAgICAgIGRlc3Ryb3lUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmRlc3Ryb3lUaW1lb3V0LFxuICAgICAgaWRsZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuaWRsZVRpbWVvdXQsXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXG4gICAgICByZWFwSW50ZXJ2YWxNaWxsaXM6IHBvb2xDb25maWcucmVhcGVySW50ZXJ2YWwsXG4gICAgICBwcm9wYWdhdGVDcmVhdGVFcnJvcjogZmFsc2VcbiAgICB9KTtcblxuICAgIC8vIFNldCBldmVudHNcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XG4gICAgICBsb2coNCwgYFtwb29sXSBQb29sIHJlc291cmNlIFske3Jlc291cmNlLmlkfV0gLSBSZWxlYXNpbmcgYSB3b3JrZXIuYCk7XG4gICAgICBhd2FpdCBjbGVhclBhZ2UocmVzb3VyY2UsIGZhbHNlKTtcbiAgICB9KTtcblxuICAgIHBvb2wub24oJ2Rlc3Ryb3lTdWNjZXNzJywgKF9ldmVudElkLCByZXNvdXJjZSkgPT4ge1xuICAgICAgbG9nKFxuICAgICAgICA0LFxuICAgICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7cmVzb3VyY2UuaWR9XSAtIERlc3Ryb3llZCBhIHdvcmtlciBzdWNjZXNzZnVsbHkuYFxuICAgICAgKTtcbiAgICAgIHJlc291cmNlLnBhZ2UgPSBudWxsO1xuICAgIH0pO1xuXG4gICAgY29uc3QgaW5pdGlhbFJlc291cmNlcyA9IFtdO1xuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IHBvb2xDb25maWcubWluV29ya2VyczsgaSsrKSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XG4gICAgICAgIGluaXRpYWxSZXNvdXJjZXMucHVzaChyZXNvdXJjZSk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIGluaXRpYWwgbnVtYmVyIG9mIHJlc291cmNlcyBiYWNrIHRvIHRoZSBwb29sXG4gICAgaW5pdGlhbFJlc291cmNlcy5mb3JFYWNoKChyZXNvdXJjZSkgPT4ge1xuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcbiAgICB9KTtcblxuICAgIC8vIEluaXQgdGhlIGludGVydmFsIGZvciBjaGVja2luZyBpZiB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGV4aXN0XG4gICAgaWYgKGVudnMuUE9PTF9SRVNPVVJDRVNfSU5URVJWQUwpIHtcbiAgICAgIC8vIFJlZ2lzdGVyIGludGVydmFsIGZvciB0aGUgbGF0ZXIgY2xlYXJpbmdcbiAgICAgIGFkZEludGVydmFsKF9jaGVja2luZ1Jlc291cmNlc0ludGVydmFsKGVudnMuUE9PTF9SRVNPVVJDRVNfSU5URVJWQUwpKTtcbiAgICB9XG5cbiAgICBsb2coXG4gICAgICAzLFxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcbiAgICApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSB0aGUgcG9vbCBvZiB3b3JrZXJzLicsXG4gICAgICA1MDBcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBLaWxscyBhbGwgd29ya2VycyBpbiB0aGUgcG9vbCwgZGVzdHJveXMgdGhlIHBvb2wsIGFuZCBjbG9zZXMgdGhlIGJyb3dzZXJcbiAqIGluc3RhbmNlLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyBhZnRlciB0aGUgd29ya2VycyBhcmVcbiAqIGtpbGxlZCwgdGhlIHBvb2wgaXMgZGVzdHJveWVkLCBhbmQgdGhlIGJyb3dzZXIgaXMgY2xvc2VkLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24ga2lsbFBvb2woKSB7XG4gIGxvZygzLCAnW3Bvb2xdIEtpbGxpbmcgcG9vbCB3aXRoIGFsbCB3b3JrZXJzIGFuZCBjbG9zaW5nIGJyb3dzZXIuJyk7XG5cbiAgLy8gSWYgc3RpbGwgYWxpdmUsIGRlc3Ryb3kgdGhlIHBvb2wgb2YgcGFnZXMgYmVmb3JlIGNsb3NpbmcgYSBicm93c2VyXG4gIGlmIChwb29sKSB7XG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xuICAgIGZvciAoY29uc3Qgd29ya2VyIG9mIHBvb2wudXNlZCkge1xuICAgICAgcG9vbC5yZWxlYXNlKHdvcmtlci5yZXNvdXJjZSk7XG4gICAgfVxuXG4gICAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgcG9vbFxuICAgIHBvb2wucmVtb3ZlQWxsTGlzdGVuZXJzKCdyZWxlYXNlJyk7XG4gICAgcG9vbC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Rlc3Ryb3lTdWNjZXNzJyk7XG4gICAgcG9vbC5yZW1vdmVBbGxMaXN0ZW5lcnMoJ2Rlc3Ryb3lGYWlsJyk7XG5cbiAgICAvLyBEZXN0cm95IHRoZSBwb29sIGlmIGl0IGlzIHN0aWxsIGF2YWlsYWJsZVxuICAgIGlmICghcG9vbC5kZXN0cm95ZWQpIHtcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xuICAgICAgbG9nKDQsICdbYnJvd3Nlcl0gRGVzdHJveWVkIHRoZSBwb29sIG9mIHJlc291cmNlcy4nKTtcbiAgICB9XG4gICAgcG9vbCA9IG51bGw7XG4gIH1cblxuICAvLyBDbG9zZSB0aGUgYnJvd3NlciBpbnN0YW5jZVxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzZXMgdGhlIGV4cG9ydCB3b3JrIHVzaW5nIGEgd29ya2VyIGZyb20gdGhlIHBvb2wuIEFjcXVpcmVzIGEgd29ya2VyXG4gKiBoYW5kbGUgZnJvbSB0aGUgcG9vbCwgcGVyZm9ybXMgdGhlIGV4cG9ydCB1c2luZyBwdXBwZXRlZXIsIGFuZCByZWxlYXNlc1xuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gY2hhcnQgLSBUaGUgY2hhcnQgZGF0YSBvciBjb25maWd1cmF0aW9uIHRvIGJlIGV4cG9ydGVkLlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSBleHBvcnQgcmVzdWx0YW5kXG4gKiBvcHRpb25zLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBJZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nIHRoZSBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3RXb3JrID0gYXN5bmMgKGNoYXJ0LCBvcHRpb25zKSA9PiB7XG4gIGxldCB3b3JrZXJIYW5kbGU7XG5cbiAgdHJ5IHtcbiAgICBsb2coNCwgJ1twb29sXSBXb3JrIHJlY2VpdmVkLCBzdGFydGluZyB0byBwcm9jZXNzLicpO1xuXG4gICAgKytzdGF0cy5leHBvcnRBdHRlbXB0cztcbiAgICBpZiAocG9vbENvbmZpZy5iZW5jaG1hcmtpbmcpIHtcbiAgICAgIGdldFBvb2xJbmZvKCk7XG4gICAgfVxuXG4gICAgaWYgKCFwb29sKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdXb3JrIHJlY2VpdmVkLCBidXQgcG9vbCBoYXMgbm90IGJlZW4gc3RhcnRlZC4nLFxuICAgICAgICA1MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XG4gICAgY29uc3QgYWNxdWlyZUNvdW50ZXIgPSBtZWFzdXJlVGltZSgpO1xuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xuICAgICAgd29ya2VySGFuZGxlID0gYXdhaXQgcG9vbC5hY3F1aXJlKCkucHJvbWlzZTtcblxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXG4gICAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICA1LFxuICAgICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcbiAgICAgICAgICBgQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlOiAke2FjcXVpcmVDb3VudGVyKCl9bXMuYFxuICAgICAgICApO1xuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXG4gICAgICAgICAgOiAnJykgK1xuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXG4gICAgICApLnNldEVycm9yKGVycm9yKTtcbiAgICB9XG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xuXG4gICAgaWYgKCF3b3JrZXJIYW5kbGUucGFnZSkge1xuICAgICAgLy8gU2V0IHRoZSBgd29ya0xpbWl0YCB0byBleGNlZWRlZCBpbiBvcmRlciB0byByZWNyZWF0ZSB0aGUgcmVzb3VyY2VcbiAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBwb29sQ29uZmlnLndvcmtMaW1pdCArIDE7XG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nLFxuICAgICAgICA1MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxuICAgIGxldCB3b3JrU3RhcnQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcblxuICAgIGxvZyhcbiAgICAgIDQsXG4gICAgICBgW3Bvb2xdIFBvb2wgcmVzb3VyY2UgWyR7d29ya2VySGFuZGxlLmlkfV0gLSBTdGFydGluZyB3b3JrIG9uIHRoaXMgcG9vbCBlbnRyeS5gXG4gICAgKTtcblxuICAgIC8vIFBlcmZvcm0gYW4gZXhwb3J0IG9uIGEgcHVwcGV0ZWVyIGxldmVsXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcHVwcGV0ZWVyRXhwb3J0KHdvcmtlckhhbmRsZS5wYWdlLCBjaGFydCwgb3B0aW9ucyk7XG5cbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXG4gICAgaWYgKHJlc3VsdCBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICBpZiAocmVzdWx0Lm1lc3NhZ2UgPT09ICdSYXN0ZXJpemF0aW9uIHRpbWVvdXQnKSB7XG4gICAgICAgIC8vIFNldCB0aGUgYHdvcmtMaW1pdGAgdG8gZXhjZWVkZWQgaW4gb3JkZXIgdG8gcmVjcmVhdGUgdGhlIHJlc291cmNlXG4gICAgICAgIHdvcmtlckhhbmRsZS53b3JrQ291bnQgPSBwb29sQ29uZmlnLndvcmtMaW1pdCArIDE7XG4gICAgICB9XG5cbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgKG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICApLnNldEVycm9yKHJlc3VsdCk7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgdGhlIFB1cHBldGVlciBleHBvcnQgdGltZVxuICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgNSxcbiAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcbiAgICAgICAgICA6ICdbYmVuY2htYXJrXScsXG4gICAgICAgIGBFeHBvcnRlZCBhIGNoYXJ0IHN1Y2Vzc2Z1bGx5OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXG4gICAgICApO1xuICAgIH1cblxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcbiAgICBwb29sLnJlbGVhc2Uod29ya2VySGFuZGxlKTtcblxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcbiAgICAvLyBpbiB0dXJuIGlzIHVzZWQgYnkgdGhlIC9oZWFsdGggcm91dGUuXG4gICAgY29uc3Qgd29ya0VuZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xuICAgIHN0YXRzLnRpbWVTcGVudCArPSBleHBvcnRUaW1lO1xuICAgIHN0YXRzLnNwZW50QXZlcmFnZSA9IHN0YXRzLnRpbWVTcGVudCAvICsrc3RhdHMucGVyZm9ybWVkRXhwb3J0cztcblxuICAgIGxvZyg0LCBgW3Bvb2xdIFdvcmsgY29tcGxldGVkIGluICR7ZXhwb3J0VGltZX0gbXMuYCk7XG5cbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcbiAgICByZXR1cm4ge1xuICAgICAgcmVzdWx0LFxuICAgICAgb3B0aW9uc1xuICAgIH07XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcblxuICAgIGlmICh3b3JrZXJIYW5kbGUpIHtcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xuICAgIH1cblxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcbiAgICAgIGVycm9yXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnQgcG9vbCBpbnN0YW5jZS5cbiAqXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcbiAqIGlmIHRoZSBwb29sIGhhcyBub3QgYmVlbiBjcmVhdGVkLlxuICovXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XG5cbi8qKlxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXG4gKiB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmUgcmVxdWVzdHMuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldFBvb2xJbmZvSlNPTiA9ICgpID0+ICh7XG4gIG1pbjogcG9vbC5taW4sXG4gIG1heDogcG9vbC5tYXgsXG4gIHVzZWQ6IHBvb2wubnVtVXNlZCgpLFxuICBhdmFpbGFibGU6IHBvb2wubnVtRnJlZSgpLFxuICBhbGxDcmVhdGVkOiBwb29sLm51bVVzZWQoKSArIHBvb2wubnVtRnJlZSgpLFxuICBwZW5kaW5nQWNxdWlyZXM6IHBvb2wubnVtUGVuZGluZ0FjcXVpcmVzKCksXG4gIHBlbmRpbmdDcmVhdGVzOiBwb29sLm51bVBlbmRpbmdDcmVhdGVzKCksXG4gIHBlbmRpbmdWYWxpZGF0aW9uczogcG9vbC5udW1QZW5kaW5nVmFsaWRhdGlvbnMoKSxcbiAgcGVuZGluZ0Rlc3Ryb3lzOiBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGgsXG4gIGFic29sdXRlQWxsOlxuICAgIHBvb2wubnVtVXNlZCgpICtcbiAgICBwb29sLm51bUZyZWUoKSArXG4gICAgcG9vbC5udW1QZW5kaW5nQWNxdWlyZXMoKSArXG4gICAgcG9vbC5udW1QZW5kaW5nQ3JlYXRlcygpICtcbiAgICBwb29sLm51bVBlbmRpbmdWYWxpZGF0aW9ucygpICtcbiAgICBwb29sLnBlbmRpbmdEZXN0cm95cy5sZW5ndGhcbn0pO1xuXG4vKipcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxuICogYW5kIG1heGltdW0gd29ya2VycywgYXZhaWxhYmxlIHdvcmtlcnMsIHdvcmtlcnMgaW4gdXNlLCBhbmQgcGVuZGluZyBhY3F1aXJlXG4gKiByZXF1ZXN0cy5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdldFBvb2xJbmZvKCkge1xuICBjb25zdCB7XG4gICAgbWluLFxuICAgIG1heCxcbiAgICB1c2VkLFxuICAgIGF2YWlsYWJsZSxcbiAgICBhbGxDcmVhdGVkLFxuICAgIHBlbmRpbmdBY3F1aXJlcyxcbiAgICBwZW5kaW5nQ3JlYXRlcyxcbiAgICBwZW5kaW5nVmFsaWRhdGlvbnMsXG4gICAgcGVuZGluZ0Rlc3Ryb3lzLFxuICAgIGFic29sdXRlQWxsXG4gIH0gPSBnZXRQb29sSW5mb0pTT04oKTtcblxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttYXh9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHVzZWQgcmVzb3VyY2VzOiAke3VzZWR9LmApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGZyZWUgcmVzb3VyY2VzOiAke2F2YWlsYWJsZX0uYCk7XG4gIGxvZyhcbiAgICA1LFxuICAgIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCAodXNlZCBhbmQgZnJlZSkgcmVzb3VyY2VzOiAke2FsbENyZWF0ZWR9LmBcbiAgKTtcbiAgbG9nKFxuICAgIDUsXG4gICAgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmdBY3F1aXJlc30uYFxuICApO1xuICBsb2coXG4gICAgNSxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgY3JlYXRlZDogJHtwZW5kaW5nQ3JlYXRlc30uYFxuICApO1xuICBsb2coXG4gICAgNSxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgdmFsaWRhdGVkOiAke3BlbmRpbmdWYWxpZGF0aW9uc30uYFxuICApO1xuICBsb2coXG4gICAgNSxcbiAgICBgW3Bvb2xdIFRoZSBudW1iZXIgb2YgcmVzb3VyY2VzIHdhaXRpbmcgdG8gYmUgZGVzdHJveWVkOiAke3BlbmRpbmdEZXN0cm95c30uYFxuICApO1xuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFsbCByZXNvdXJjZXM6ICR7YWJzb2x1dGVBbGx9LmApO1xufVxuXG4vKipcbiAqIFBlcmlvZGljYWxseSBjaGVja3MgYW5kIGVuc3VyZXMgdGhlIG1pbmltdW0gbnVtYmVyIG9mIHJlc291cmNlcyBpbiB0aGUgcG9vbC5cbiAqIElmIHRoZSB0b3RhbCBudW1iZXIgb2YgdXNlZCwgZnJlZSBhbmQgYWJvdXQgdG8gYmUgY3JlYXRlZCByZXNvdXJjZXMgZmFsbHNcbiAqIGJlbG93IHRoZSBtaW5pbXVtIHNldCB3aXRoIHRoZSBgcG9vbC5taW5gLCBpdCBjcmVhdGVzIGFkZGl0aW9uYWwgcmVzb3VyY2VzIHRvXG4gKiBtZWV0IHRoZSBtaW5pbXVtIHJlcXVpcmVtZW50LlxuICpcbiAqIEBwYXJhbSB7bnVtYmVyfSByZXNvdXJjZUNoZWNrSW50ZXJ2YWwgLSBUaGUgaW50ZXJ2YWwsIGluIG1pbGxpc2Vjb25kcywgYXRcbiAqIHdoaWNoIHRoZSBwb29sIHJlc291cmNlcyBhcmUgY2hlY2tlZC5cbiAqXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IC0gUmV0dXJucyBhIHRpbWVyIElEIHRoYXQgY2FuIGJlIHVzZWQgdG8gY2xlYXIgdGhlXG4gKiBpbnRlcnZhbCBsYXRlci5cbiAqL1xuZnVuY3Rpb24gX2NoZWNraW5nUmVzb3VyY2VzSW50ZXJ2YWwocmVzb3VyY2VDaGVja0ludGVydmFsKSB7XG4gIC8vIFNldCB0aGUgaW50ZXJ2YWwgZm9yIGNoZWNraW5nIHRoZSBudW1iZXIgb2YgcG9vbCByZXNvdXJjZXNcbiAgcmV0dXJuIHNldEludGVydmFsKGFzeW5jICgpID0+IHtcbiAgICB0cnkge1xuICAgICAgLy8gR2V0IHRoZSBjdXJyZW50IG51bWJlciBvZiByZXNvdXJjZXNcbiAgICAgIGxldCBjdXJyZW50TnVtYmVyID1cbiAgICAgICAgcG9vbC5udW1Vc2VkKCkgKyBwb29sLm51bUZyZWUoKSArIHBvb2wubnVtUGVuZGluZ0NyZWF0ZXMoKTtcblxuICAgICAgLy8gQ3JlYXRlIG1pc3NpbmcgcmVzb3VyY2VzXG4gICAgICB3aGlsZSAoY3VycmVudE51bWJlcisrIDwgcG9vbC5taW4pIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAvLyBFeHBsaWNpdGx5IGNyZWF0aW5nIGEgcmVzb3VyY2VcbiAgICAgICAgICBhd2FpdCBwb29sLl9kb0NyZWF0ZSgpO1xuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIGEgbWlzc2luZyByZXNvdXJjZS4nKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgIDEsXG4gICAgICAgIGVycm9yLFxuICAgICAgICBgW3Bvb2xdIFNvbWV0aGluZyB3ZW50IHdyb25nIHdoZW4gdHJ5aW5nIHRvIGNyZWF0ZSBtaXNzaW5nIHJlc291cmNlcy5gXG4gICAgICApO1xuICAgIH1cbiAgfSwgcmVzb3VyY2VDaGVja0ludGVydmFsKTtcbn1cblxuZXhwb3J0IGRlZmF1bHQge1xuICBpbml0UG9vbCxcbiAga2lsbFBvb2wsXG4gIHBvc3RXb3JrLFxuICBnZXRQb29sLFxuICBnZXRQb29sSW5mbyxcbiAgZ2V0UG9vbEluZm9KU09OLFxuICBnZXRTdGF0czogKCkgPT4gc3RhdHNcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuXG5pbXBvcnQgeyBnZXRPcHRpb25zLCBpbml0RXhwb3J0U2V0dGluZ3MgfSBmcm9tICcuL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGtpbGxQb29sLCBwb3N0V29yaywgc3RhdHMgfSBmcm9tICcuL3Bvb2wuanMnO1xuaW1wb3J0IHtcbiAgZml4VHlwZSxcbiAgaGFuZGxlUmVzb3VyY2VzLFxuICBpc0NvcnJlY3RKU09OLFxuICBvcHRpb25zU3RyaW5naWZ5LFxuICByb3VuZE51bWJlcixcbiAgdG9Cb29sZWFuLFxuICB3cmFwQXJvdW5kXG59IGZyb20gJy4vdXRpbHMuanMnO1xuaW1wb3J0IHsgc2FuaXRpemUgfSBmcm9tICcuL3Nhbml0aXplLmpzJztcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XG5cbmxldCBhbGxvd0NvZGVFeGVjdXRpb24gPSBmYWxzZTtcblxuLyoqXG4gKiBTdGFydHMgYW4gZXhwb3J0IHByb2Nlc3MuIFRoZSBgc2V0dGluZ3NgIGNvbnRhaW5zIGZpbmFsIG9wdGlvbnMgZ2F0aGVyZWRcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xuICogY2FsbGVkIHdoZW4gdGhlIGV4cG9ydCBpcyBjb21wbGV0ZWQsIHdpdGggYW4gZXJyb3Igb2JqZWN0IGFzIHRoZSBmaXJzdFxuICogYXJndW1lbnQgYW5kIHRoZSBzZWNvbmQgY29udGFpbmluZyB0aGUgYmFzZTY0IHJlc3ByZXNlbnRhdGlvbiBvZiBhIGNoYXJ0LlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXR0aW5ncyAtIFRoZSBzZXR0aW5ncyBvYmplY3QgY29udGFpbmluZyBleHBvcnRcbiAqIGNvbmZpZ3VyYXRpb24uXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cbiAqIGZpbmFsaXppbmcgd29yayBvciB1cG9uIGVycm9yIG9jY3VyYW5jZSBvZiB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuXG4gKlxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXG4gKiBpdCBjb21tdW5pY2F0ZXMgcmVzdWx0cyB2aWEgdGhlIGVuZENhbGxiYWNrLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XG4gIC8vIFN0YXJ0aW5nIGV4cG9ydGluZyBwcm9jZXNzIG1lc3NhZ2VcbiAgbG9nKDQsICdbY2hhcnRdIFN0YXJ0aW5nIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy4nKTtcblxuICAvLyBJbml0aWFsaXplIG9wdGlvbnNcbiAgY29uc3Qgb3B0aW9ucyA9IGluaXRFeHBvcnRTZXR0aW5ncyhzZXR0aW5ncywgZ2V0T3B0aW9ucygpKTtcblxuICAvLyBHZXQgdGhlIGV4cG9ydCBvcHRpb25zXG4gIGNvbnN0IGV4cG9ydE9wdGlvbnMgPSBvcHRpb25zLmV4cG9ydDtcblxuICAvLyBJZiBTVkcgaXMgYW4gaW5wdXQgKGFyZ3VtZW50IGNhbiBiZSBzZW50IG9ubHkgYnkgdGhlIHJlcXVlc3QpXG4gIGlmIChvcHRpb25zLnBheWxvYWQ/LnN2ZyAmJiBvcHRpb25zLnBheWxvYWQuc3ZnICE9PSAnJykge1xuICAgIHRyeSB7XG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIFNWRyBpbnB1dC4nKTtcblxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXG4gICAgICAgIHNhbml0aXplKG9wdGlvbnMucGF5bG9hZC5zdmcpLCAvLyAjMjA5XG4gICAgICAgIG9wdGlvbnMsXG4gICAgICAgIGVuZENhbGxiYWNrXG4gICAgICApO1xuXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcbiAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgU1ZHIGlucHV0LicsIDQwMCkuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIEV4cG9ydCB1c2luZyBvcHRpb25zIGZyb20gdGhlIGZpbGVcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xuICAgIC8vIFRyeSB0byByZWFkIHRoZSBmaWxlIHRvIGdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uXG4gICAgdHJ5IHtcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XG4gICAgICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zLmluZmlsZSwgJ3V0ZjgnKTtcbiAgICAgIHJldHVybiBleHBvcnRBc1N0cmluZyhvcHRpb25zLmV4cG9ydC5pbnN0ci50cmltKCksIG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBpbnB1dCBmaWxlLicsIDQwMCkuc2V0RXJyb3IoXG4gICAgICAgICAgZXJyb3JcbiAgICAgICAgKVxuICAgICAgKTtcbiAgICB9XG4gIH1cblxuICAvLyBFeHBvcnQgd2l0aCBvcHRpb25zIGZyb20gdGhlIHJhdyByZXByZXNlbnRhdGlvblxuICBpZiAoXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XG4gICAgKGV4cG9ydE9wdGlvbnMub3B0aW9ucyAmJiBleHBvcnRPcHRpb25zLm9wdGlvbnMgIT09ICcnKVxuICApIHtcbiAgICB0cnkge1xuICAgICAgbG9nKDQsICdbY2hhcnRdIEF0dGVtcHRpbmcgdG8gZXhwb3J0IGZyb20gYSByYXcgaW5wdXQuJyk7XG5cbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXG4gICAgICBpZiAodG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvbikpIHtcbiAgICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgICAgfVxuXG4gICAgICAvLyBFaXRoZXIgdHJ5IHRvIHBhcnNlIHRvIEpTT04gZmlyc3Qgb3IgZG8gdGhlIGRpcmVjdCBleHBvcnRcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcbiAgICAgICAgPyBleHBvcnRBc1N0cmluZyhleHBvcnRPcHRpb25zLmluc3RyLnRyaW0oKSwgb3B0aW9ucywgZW5kQ2FsbGJhY2spXG4gICAgICAgIDogZG9FeHBvcnQoXG4gICAgICAgICAgICBvcHRpb25zLFxuICAgICAgICAgICAgZXhwb3J0T3B0aW9ucy5pbnN0ciB8fCBleHBvcnRPcHRpb25zLm9wdGlvbnMsXG4gICAgICAgICAgICBlbmRDYWxsYmFja1xuICAgICAgICAgICk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicsIDQwMCkuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIC8vIE5vIGlucHV0IHNwZWNpZmllZCwgcGFzcyBhbiBlcnJvciBtZXNzYWdlIHRvIHRoZSBjYWxsYmFja1xuICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgbmV3IEV4cG9ydEVycm9yKFxuICAgICAgYFtjaGFydF0gTm8gdmFsaWQgaW5wdXQgc3BlY2lmaWVkLiBDaGVjayBpZiBhdCBsZWFzdCBvbmUgb2YgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzIGlzIGNvcnJlY3RseSBzZXQ6ICdpbmZpbGUnLCAnaW5zdHInLCAnb3B0aW9ucycsIG9yICdzdmcnLmAsXG4gICAgICA0MDBcbiAgICApXG4gICk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBhIGJhdGNoIGV4cG9ydCBwcm9jZXNzIGZvciBtdWx0aXBsZSBjaGFydHMgYmFzZWQgb24gdGhlIGluZm9ybWF0aW9uXG4gKiBpbiB0aGUgYmF0Y2ggb3B0aW9uLiBUaGUgYmF0Y2ggaXMgYSBzdHJpbmcgaW4gdGhlIGZvbGxvd2luZyBmb3JtYXQ6XG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgYmF0Y2ggZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBiYXRjaCBleHBvcnRcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZ1xuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cbiAqL1xuZXhwb3J0IGNvbnN0IGJhdGNoRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcblxuICAvLyBTcGxpdCBhbmQgcGFpciB0aGUgLS1iYXRjaCBhcmd1bWVudHNcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XG4gICAgcGFpciA9IHBhaXIuc3BsaXQoJz0nKTtcbiAgICBpZiAocGFpci5sZW5ndGggPT09IDIpIHtcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXG4gICAgICAgIHN0YXJ0RXhwb3J0KFxuICAgICAgICAgIHtcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXG4gICAgICAgICAgICBleHBvcnQ6IHtcbiAgICAgICAgICAgICAgLi4ub3B0aW9ucy5leHBvcnQsXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcbiAgICAgICAgICAgICAgb3V0ZmlsZTogcGFpclsxXVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0sXG4gICAgICAgICAgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgICAgICAgICAvLyBUaHJvdyBhbiBlcnJvclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBTYXZlIHRoZSBiYXNlNjQgZnJvbSBhIGJ1ZmZlciB0byBhIGNvcnJlY3QgaW1hZ2UgZmlsZVxuICAgICAgICAgICAgd3JpdGVGaWxlU3luYyhcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxuICAgICAgICAgICAgICBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGUgIT09ICdzdmcnXG4gICAgICAgICAgICAgICAgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxuICAgICAgICAgICAgKTtcbiAgICAgICAgICB9XG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuICB9XG5cbiAgdHJ5IHtcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxuICAgIGF3YWl0IFByb21pc2UuYWxsKGJhdGNoRnVuY3Rpb25zKTtcblxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAnW2NoYXJ0XSBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgYmF0Y2ggZXhwb3J0LidcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBTdGFydHMgYSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcbiAqIGEgc2luZ2xlIGV4cG9ydC5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxuICogcHJvY2VzcyBpcyBjb21wbGV0ZWQuXG4gKlxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXG4gKiB0aGUgc2luZ2xlIGV4cG9ydCBwcm9jZXNzLlxuICovXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcbiAgLy8gVXNlIGluc3RyIG9yIGl0cyBhbGlhcywgb3B0aW9uc1xuICBvcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnMuZXhwb3J0Lmluc3RyIHx8IG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnM7XG5cbiAgLy8gUGVyZm9ybSBhbiBleHBvcnRcbiAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgYXN5bmMgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcbiAgICBpZiAoZXJyb3IpIHtcbiAgICAgIHRocm93IGVycm9yO1xuICAgIH1cblxuICAgIGNvbnN0IHsgb3V0ZmlsZSwgdHlwZSB9ID0gaW5mby5vcHRpb25zLmV4cG9ydDtcblxuICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXG4gICAgd3JpdGVGaWxlU3luYyhcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxuICAgICAgdHlwZSAhPT0gJ3N2ZycgPyBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ2Jhc2U2NCcpIDogaW5mby5yZXN1bHRcbiAgICApO1xuXG4gICAgLy8gS2lsbCBwb29sIGFuZCBjbG9zZSBicm93c2VyIGFmdGVyIGZpbmlzaGluZyBzaW5nbGUgZXhwb3J0XG4gICAgYXdhaXQga2lsbFBvb2woKTtcbiAgfSk7XG59O1xuXG4vKipcbiAqIERldGVybWluZXMgdGhlIHNpemUgYW5kIHNjYWxlIGZvciBjaGFydCBleHBvcnQgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogY2hhcnQgZXhwb3J0LlxuICpcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXG4gKiBhbmQgc2NhbGUgZm9yIHRoZSBjaGFydCBleHBvcnQuXG4gKi9cbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcbiAgY29uc3QgeyBjaGFydCwgZXhwb3J0aW5nIH0gPVxuICAgIG9wdGlvbnMuZXhwb3J0Py5vcHRpb25zIHx8IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmluc3RyKTtcblxuICAvLyBTZWUgaWYgZ2xvYmFsT3B0aW9ucyBob2xkcyBjaGFydCBvciBleHBvcnRpbmcgc2l6ZVxuICBjb25zdCBnbG9iYWxPcHRpb25zID0gaXNDb3JyZWN0SlNPTihvcHRpb25zLmV4cG9ydD8uZ2xvYmFsT3B0aW9ucyk7XG5cbiAgLy8gU2VjdXJlIHNjYWxlIHZhbHVlXG4gIGxldCBzY2FsZSA9XG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XG4gICAgZXhwb3J0aW5nPy5zY2FsZSB8fFxuICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc2NhbGUgfHxcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XG4gICAgMTtcblxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXG4gIHNjYWxlID0gTWF0aC5tYXgoMC4xLCBNYXRoLm1pbihzY2FsZSwgNS4wKSk7XG5cbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xuICBzY2FsZSA9IHJvdW5kTnVtYmVyKHNjYWxlLCAyKTtcblxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXG4gIGNvbnN0IHNpemUgPSB7XG4gICAgaGVpZ2h0OlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxuICAgICAgZXhwb3J0aW5nPy5zb3VyY2VIZWlnaHQgfHxcbiAgICAgIGNoYXJ0Py5oZWlnaHQgfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XG4gICAgICBnbG9iYWxPcHRpb25zPy5jaGFydD8uaGVpZ2h0IHx8XG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdEhlaWdodCB8fFxuICAgICAgNDAwLFxuICAgIHdpZHRoOlxuICAgICAgb3B0aW9ucy5leHBvcnQ/LndpZHRoIHx8XG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XG4gICAgICBjaGFydD8ud2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlV2lkdGggfHxcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRXaWR0aCB8fFxuICAgICAgNjAwLFxuICAgIHNjYWxlXG4gIH07XG5cbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcbiAgZm9yIChsZXQgW3BhcmFtLCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMoc2l6ZSkpIHtcbiAgICBzaXplW3BhcmFtXSA9XG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xuICB9XG4gIHJldHVybiBzaXplO1xufTtcblxuLyoqXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxuICogQHBhcmFtIHtPYmplY3R9IGNoYXJ0SnNvbiAtIFRoZSBKU09OIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBjaGFydC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB1cG9uXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxuICogQHBhcmFtIHtzdHJpbmd9IHN2ZyAtIFRoZSBTVkcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xuICogaXMgY29tcGxldGVkLlxuICovXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcbiAgbGV0IHsgZXhwb3J0OiBleHBvcnRPcHRpb25zLCBjdXN0b21Mb2dpYzogY3VzdG9tTG9naWNPcHRpb25zIH0gPSBvcHRpb25zO1xuXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XG4gICAgdHlwZW9mIGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24gPT09ICdib29sZWFuJ1xuICAgICAgPyBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuICBpZiAoIWN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcbiAgfSBlbHNlIGlmIChhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQpIHtcbiAgICBpZiAodHlwZW9mIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID09PSAnc3RyaW5nJykge1xuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcbiAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyxcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxuICAgICAgKTtcbiAgICB9IGVsc2UgaWYgKCFvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzb3VyY2VzID0gcmVhZEZpbGVTeW5jKCdyZXNvdXJjZXMuanNvbicsICd1dGY4Jyk7XG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWMucmVzb3VyY2VzID0gaGFuZGxlUmVzb3VyY2VzKFxuICAgICAgICAgIHJlc291cmNlcyxcbiAgICAgICAgICB0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpXG4gICAgICAgICk7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBsb2dXaXRoU3RhY2soXG4gICAgICAgICAgMixcbiAgICAgICAgICBlcnJvcixcbiAgICAgICAgICBgW2NoYXJ0XSBVbmFibGUgdG8gbG9hZCB0aGUgZGVmYXVsdCByZXNvdXJjZXMuanNvbiBmaWxlLmBcbiAgICAgICAgKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBJZiB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcgaXNuJ3Qgc2V0LCB3ZSBzaG91bGQgcmVmdXNlIHRoZSB1c2FnZVxuICAvLyBvZiBjYWxsYmFjaywgcmVzb3VyY2VzLCBhbmQgY3VzdG9tIGNvZGUuIEFkZGl0aW9uYWxseSwgdGhlIHdvcmtlciB3aWxsXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXG4gIC8vIG9wdGlvbiwgdGhlbiB3ZSBzaG91bGQgdGFrZSBhIGxvb2sgYXQgdGhlIG92ZXJhbGwgcG9vbCBvcHRpb24uXG4gIGlmICghYWxsb3dDb2RlRXhlY3V0aW9uU2NvcGVkICYmIGN1c3RvbUxvZ2ljT3B0aW9ucykge1xuICAgIGlmIChcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyB8fFxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcbiAgICApIHtcbiAgICAgIC8vIFNlbmQgYmFjayBhIGZyaWVuZGx5IG1lc3NhZ2Ugc2F5aW5nIHRoYXQgdGhlIGV4cG9ydGVyIGRvZXMgbm90IHN1cHBvcnRcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmAsXG4gICAgICAgICAgNDAwXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMucmVzb3VyY2VzID0gZmFsc2U7XG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcbiAgfVxuXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXG4gIGlmIChjaGFydEpzb24pIHtcbiAgICBjaGFydEpzb24uY2hhcnQgPSBjaGFydEpzb24uY2hhcnQgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XG4gICAgY2hhcnRKc29uLmV4cG9ydGluZy5lbmFibGVkID0gZmFsc2U7XG4gIH1cblxuICBleHBvcnRPcHRpb25zLmNvbnN0ciA9IGV4cG9ydE9wdGlvbnMuY29uc3RyIHx8ICdjaGFydCc7XG4gIGV4cG9ydE9wdGlvbnMudHlwZSA9IGZpeFR5cGUoZXhwb3J0T3B0aW9ucy50eXBlLCBleHBvcnRPcHRpb25zLm91dGZpbGUpO1xuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xuICAgIGV4cG9ydE9wdGlvbnMud2lkdGggPSBmYWxzZTtcbiAgfVxuXG4gIC8vIFByZXBhcmUgZ2xvYmFsIGFuZCB0aGVtZSBvcHRpb25zXG4gIFsnZ2xvYmFsT3B0aW9ucycsICd0aGVtZU9wdGlvbnMnXS5mb3JFYWNoKChvcHRpb25zTmFtZSkgPT4ge1xuICAgIHRyeSB7XG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucyAmJiBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSkge1xuICAgICAgICBpZiAoXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLmVuZHNXaXRoKCcuanNvbicpXG4gICAgICAgICkge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIHJlYWRGaWxlU3luYyhleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSwgJ3V0ZjgnKSxcbiAgICAgICAgICAgIHRydWVcbiAgICAgICAgICApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxuICAgICAgICAgICAgdHJ1ZVxuICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcbiAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtjaGFydF0gVGhlICcke29wdGlvbnNOYW1lfScgY2Fubm90IGJlIGxvYWRlZC5gKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIFByZXBhcmUgdGhlIGN1c3RvbUNvZGVcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcbiAgICB0cnkge1xuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSB3cmFwQXJvdW5kKFxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlc1xuICAgICAgKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJ2N1c3RvbUNvZGUnIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgfVxuICB9XG5cbiAgLy8gR2V0IHRoZSBjYWxsYmFja1xuICBpZiAoXG4gICAgY3VzdG9tTG9naWNPcHRpb25zICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrICYmXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXG4gICkge1xuICAgIC8vIFRoZSBhbGxvd0ZpbGVSZXNvdXJjZXMgaXMgYWx3YXlzIHNldCB0byBmYWxzZSBmb3IgSFRUUCByZXF1ZXN0cyB0byBhdm9pZFxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcbiAgICBpZiAoY3VzdG9tTG9naWNPcHRpb25zLmFsbG93RmlsZVJlc291cmNlcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxuICAgICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayxcbiAgICAgICAgICAndXRmOCdcbiAgICAgICAgKTtcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xuICAgIH1cbiAgfVxuXG4gIC8vIFNpemUgc2VhcmNoXG4gIG9wdGlvbnMuZXhwb3J0ID0ge1xuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxuICAgIC4uLmZpbmRDaGFydFNpemUob3B0aW9ucylcbiAgfTtcblxuICAvLyBQb3N0IHRoZSB3b3JrIHRvIHRoZSBwb29sXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXG4gICAgICBleHBvcnRPcHRpb25zLnN0ckluaiB8fCBjaGFydEpzb24gfHwgc3ZnLFxuICAgICAgb3B0aW9uc1xuICAgICk7XG4gICAgcmV0dXJuIGVuZENhbGxiYWNrKGZhbHNlLCByZXN1bHQpO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XG4gIH1cbn07XG5cbi8qKlxuICogUGVyZm9ybXMgYSBkaXJlY3QgaW5qZWN0IG9mIG9wdGlvbnMgYmVmb3JlIGV4cG9ydC4gVGhlIGZ1bmN0aW9uIGF0dGVtcHRzXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcbiAqIGVuc3VyaW5nIGEgY2xlYW4gYW5kIGZvcm1hdHRlZCBpbnB1dC4gVGhlIHJlc3VsdGluZyBzdHJpbmcgaXMgc2F2ZWQgYXNcbiAqIGEgXCJzdHJpZ2h0IGluamVjdFwiIHN0cmluZyBpbiB0aGUgZXhwb3J0IG9wdGlvbnMuIEl0IHRoZW4gaW52b2tlcyB0aGVcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cbiAqXG4gKiBJTVBPUlRBTlQ6IERhbmdlcm91cyBhbmQgbXVzdCBiZSB1c2VkIGRlbGliZXJhdGVseSBieSBzb21lb25lIHdobyBzZXRzIHVwXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBleHBvcnQgb3B0aW9ucyBjb250YWluaW5nIHRoZSBpbnB1dFxuICogdG8gYmUgaW5qZWN0ZWQuXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkXG4gKiBhdCB0aGUgZW5kIG9mIHRoZSBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHtQcm9taXNlfSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyB3aXRoIHRoZSByZXN1bHQgb2YgdGhlIGV4cG9ydFxuICogb3BlcmF0aW9uIG9yIHJlamVjdHMgd2l0aCBhbiBlcnJvciBpZiBhbnkgaXNzdWVzIG9jY3VyIGR1cmluZyB0aGUgcHJvY2Vzcy5cbiAqL1xuY29uc3QgZG9TdHJhaWdodEluamVjdCA9IChvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICB0cnkge1xuICAgIGxldCBzdHJJbmo7XG4gICAgbGV0IGluc3RyID0gb3B0aW9ucy5leHBvcnQuaW5zdHIgfHwgb3B0aW9ucy5leHBvcnQub3B0aW9ucztcblxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBUcnkgdG8gc3RyaW5naWZ5IG9wdGlvbnNcbiAgICAgIHN0ckluaiA9IGluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcbiAgICAgICAgaW5zdHIsXG4gICAgICAgIG9wdGlvbnMuY3VzdG9tTG9naWM/LmFsbG93Q29kZUV4ZWN1dGlvblxuICAgICAgKTtcbiAgICB9XG4gICAgc3RySW5qID0gaW5zdHIucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJycpLnRyaW0oKTtcblxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcbiAgICBpZiAoc3RySW5qW3N0ckluai5sZW5ndGggLSAxXSA9PT0gJzsnKSB7XG4gICAgICBzdHJJbmogPSBzdHJJbmouc3Vic3RyaW5nKDAsIHN0ckluai5sZW5ndGggLSAxKTtcbiAgICB9XG5cbiAgICAvLyBTYXZlIGFzIHN0cmlnaHQgaW5qZWN0IHN0cmluZ1xuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrKTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgIGBbY2hhcnRdIE1hbGZvcm1lZCBpbnB1dCBkZXRlY3RlZCBmb3IgJHtvcHRpb25zLmV4cG9ydD8ucmVxdWVzdElkIHx8ICc/J30uIFBsZWFzZSBtYWtlIHN1cmUgdGhhdCB5b3VyIEpTT04vSmF2YVNjcmlwdCBvcHRpb25zIGFyZSBzZW50IHVzaW5nIHRoZSBcIm9wdGlvbnNcIiBhdHRyaWJ1dGUsIGFuZCB0aGF0IGlmIHlvdSdyZSB1c2luZyBTVkcsIGl0IGlzIHVuZXNjYXBlZC5gLFxuICAgICAgICA0MDBcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpXG4gICAgKTtcbiAgfVxufTtcblxuLyoqXG4gKiBFeHBvcnRzIGEgc3RyaW5nIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcHRpb25zIGFuZCBpbnZva2VzIGFuIGVuZCBjYWxsYmFjay5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gc3RyaW5nVG9FeHBvcnQgLSBUaGUgc3RyaW5nIGNvbnRlbnQgdG8gYmUgZXhwb3J0ZWQuXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEV4cG9ydCBvcHRpb25zLCBpbmNsdWRpbmcgY3VzdG9tTG9naWMgd2l0aFxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIENhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWQgYXQgdGhlIGVuZFxuICogb2YgdGhlIGV4cG9ydCBwcm9jZXNzLlxuICpcbiAqIEByZXR1cm5zIHthbnl9IFJlc3VsdCBvZiB0aGUgZXhwb3J0IHByb2Nlc3Mgb3IgYW4gZXJyb3IgaWYgZW5jb3VudGVyZWQuXG4gKi9cbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xuICBjb25zdCB7IGFsbG93Q29kZUV4ZWN1dGlvbiB9ID0gb3B0aW9ucy5jdXN0b21Mb2dpYztcblxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcbiAgaWYgKFxuICAgIHN0cmluZ1RvRXhwb3J0LmluZGV4T2YoJzxzdmcnKSA+PSAwIHx8XG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXG4gICkge1xuICAgIGxvZyg0LCAnW2NoYXJ0XSBQYXJzaW5nIGlucHV0IGFzIFNWRy4nKTtcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XG4gIH1cblxuICB0cnkge1xuICAgIC8vIFRyeSB0byBwYXJzZSB0byBKU09OIGFuZCBjYWxsIHRoZSBkb0V4cG9ydCBmdW5jdGlvblxuICAgIGNvbnN0IGNoYXJ0SlNPTiA9IEpTT04ucGFyc2Uoc3RyaW5nVG9FeHBvcnQucmVwbGFjZUFsbCgvXFx0fFxcbnxcXHIvZywgJyAnKSk7XG5cbiAgICBpZiAoIWNoYXJ0SlNPTiB8fCB0eXBlb2YgY2hhcnRKU09OICE9PSAnb2JqZWN0Jykge1xuICAgICAgcmV0dXJuIGVuZENhbGxiYWNrKFxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXG4gICAgICAgICAgJ1tjaGFydF0gSW52YWxpZCBjb25maWd1cmF0aW9uIHByb3ZpZGVkIC0gdGhlIG9wdGlvbnMgbXVzdCBiZSBhbiBvYmplY3QsIG5vdCBhIHN0cmluZycsXG4gICAgICAgICAgNDAwXG4gICAgICAgIClcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gSWYgYSBjb3JyZWN0IEpTT04sIGRvIHRoZSBleHBvcnRcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgLy8gTm90IGEgdmFsaWQgSlNPTlxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xuICAgICAgcmV0dXJuIGRvU3RyYWlnaHRJbmplY3Qob3B0aW9ucywgZW5kQ2FsbGJhY2spO1xuICAgIH0gZWxzZSB7XG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXG4gICAgICAgIG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLicsXG4gICAgICAgICAgNDAwXG4gICAgICAgICkuc2V0RXJyb3IoZXJyb3IpXG4gICAgICApO1xuICAgIH1cbiAgfVxufTtcblxuLyoqXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXG4gKlxuICogQHJldHVybnMge2FueX0gVGhlIHZhbHVlIG9mIGFsbG93Q29kZUV4ZWN1dGlvbi5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEFsbG93Q29kZUV4ZWN1dGlvbiA9ICgpID0+IGFsbG93Q29kZUV4ZWN1dGlvbjtcblxuLyoqXG4gKiBTZXRzIHRoZSBjb2RlIGV4ZWN1dGlvbiBwZXJtaXNzaW9uIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBib29sZWFuIHZhbHVlLlxuICpcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXG4gKiB0byBhbGxvd0NvZGVFeGVjdXRpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcbiAgYWxsb3dDb2RlRXhlY3V0aW9uID0gdG9Cb29sZWFuKHZhbHVlKTtcbn07XG5cbmV4cG9ydCBkZWZhdWx0IHtcbiAgYmF0Y2hFeHBvcnQsXG4gIHNpbmdsZUV4cG9ydCxcbiAgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXG4gIHN0YXJ0RXhwb3J0LFxuICBmaW5kQ2hhcnRTaXplXG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbi8qKlxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcbiAqIHRvIHByZXZlbnQgWFNTIGF0dGFja3MgKHdpdGggdGhlIERPTVB1cmlmeSBsaWJyYXJ5KS5cbiAqKi9cblxuaW1wb3J0IHsgSlNET00gfSBmcm9tICdqc2RvbSc7XG5pbXBvcnQgRE9NUHVyaWZ5IGZyb20gJ2RvbXB1cmlmeSc7XG5cbi8qKlxuICogU2FuaXRpemVzIGEgZ2l2ZW4gSFRNTCBzdHJpbmcgYnkgcmVtb3ZpbmcgPHNjcmlwdD4gdGFncy5cbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXG4gKiBvY2N1cnJlbmNlcyBvZiA8c2NyaXB0Pi4uLjwvc2NyaXB0PiB0YWdzIGFuZCBhbnkgY29udGVudCB3aXRoaW4gdGhlbS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cbiAqIEByZXR1cm5zIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTCBzdHJpbmcuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xuICBjb25zdCB3aW5kb3cgPSBuZXcgSlNET00oJycpLndpbmRvdztcbiAgY29uc3QgcHVyaWZ5ID0gRE9NUHVyaWZ5KHdpbmRvdyk7XG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xufVxuXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcbiIsImltcG9ydCB7IGVudnMgfSBmcm9tICcuLi9lbnZzLmpzJztcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5cbi8qKlxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXG4gKlxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXMgLSBUaGUgRXhwcmVzcyByZXNwb25zZSBvYmplY3QuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cbiAqL1xuY29uc3QgbG9nRXJyb3JNaWRkbGV3YXJlID0gKGVycm9yLCByZXEsIHJlcywgbmV4dCkgPT4ge1xuICAvLyBEaXNwbGF5IHRoZSBlcnJvciB3aXRoIHN0YWNrIGluIGEgY29ycmVjdCBmb3JtYXRcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcblxuICAvLyBEZWxldGUgdGhlIHN0YWNrIGZvciB0aGUgZW52aXJvbm1lbnQgb3RoZXIgdGhhbiB0aGUgZGV2ZWxvcG1lbnRcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcbiAgICBkZWxldGUgZXJyb3Iuc3RhY2s7XG4gIH1cblxuICAvLyBDYWxsIHRoZSByZXR1cm5FcnJvck1pZGRsZXdhcmVcbiAgbmV4dChlcnJvcik7XG59O1xuXG4vKipcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cbiAqXG4gKiBAcGFyYW0ge0Vycm9yfSBlcnJvciAtIFRoZSBlcnJvciBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IG5leHQgLSBUaGUgbmV4dCBtaWRkbGV3YXJlIGZ1bmN0aW9uLlxuICovXG5jb25zdCByZXR1cm5FcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XG4gIC8vIEdhdGhlciBhbGwgcmVxdWllZCBpbmZvcm1hdGlvbiBmb3IgdGhlIHJlc3BvbnNlXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcbiAgY29uc3Qgc3RhdHVzQ29kZSA9IHN0Q29kZSB8fCBzdGF0dXMgfHwgNTAwO1xuXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXG4gIHJlcy5zdGF0dXMoc3RhdHVzQ29kZSkuanNvbih7IHN0YXR1c0NvZGUsIG1lc3NhZ2UsIHN0YWNrIH0pO1xufTtcblxuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT4ge1xuICAvLyBBZGQgbG9nIGVycm9yIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xuXG4gIC8vIEFkZCBzZXQgc3RhdHVzIGFuZCByZXR1cm4gZXJyb3IgbWlkZGxld2FyZVxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XG59O1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCByYXRlTGltaXQgZnJvbSAnZXhwcmVzcy1yYXRlLWxpbWl0JztcblxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcblxuLyoqXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXG4gKlxuICogQHBhcmFtIHtFeHByZXNzfSBhcHAgLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IChhcHAsIGxpbWl0Q29uZmlnKSA9PiB7XG4gIGNvbnN0IG1zZyA9XG4gICAgJ1RvbyBtYW55IHJlcXVlc3RzLCB5b3UgaGF2ZSBiZWVuIHJhdGUgbGltaXRlZC4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlci4nO1xuXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcbiAgY29uc3QgcmF0ZU9wdGlvbnMgPSB7XG4gICAgbWF4OiBsaW1pdENvbmZpZy5tYXhSZXF1ZXN0cyB8fCAzMCxcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxuICAgIGRlbGF5OiBsaW1pdENvbmZpZy5kZWxheSB8fCAwLFxuICAgIHRydXN0UHJveHk6IGxpbWl0Q29uZmlnLnRydXN0UHJveHkgfHwgZmFsc2UsXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcbiAgICBza2lwVG9rZW46IGxpbWl0Q29uZmlnLnNraXBUb2tlbiB8fCBmYWxzZVxuICB9O1xuXG4gIC8vIFNldCBpZiBiZWhpbmQgYSBwcm94eVxuICBpZiAocmF0ZU9wdGlvbnMudHJ1c3RQcm94eSkge1xuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XG4gIH1cblxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXG4gIGNvbnN0IGxpbWl0ZXIgPSByYXRlTGltaXQoe1xuICAgIHdpbmRvd01zOiByYXRlT3B0aW9ucy53aW5kb3cgKiA2MCAqIDEwMDAsXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXG4gICAgbWF4OiByYXRlT3B0aW9ucy5tYXgsXG4gICAgLy8gRGlzYWJsZSBkZWxheWluZywgZnVsbCBzcGVlZCB1bnRpbCB0aGUgbWF4IGxpbWl0IGlzIHJlYWNoZWRcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcbiAgICBoYW5kbGVyOiAocmVxdWVzdCwgcmVzcG9uc2UpID0+IHtcbiAgICAgIHJlc3BvbnNlLmZvcm1hdCh7XG4gICAgICAgIGpzb246ICgpID0+IHtcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKHsgbWVzc2FnZTogbXNnIH0pO1xuICAgICAgICB9LFxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XG4gICAgICAgICAgcmVzcG9uc2Uuc3RhdHVzKDQyOSkuc2VuZChtc2cpO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9LFxuICAgIHNraXA6IChyZXF1ZXN0KSA9PiB7XG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxuICAgICAgaWYgKFxuICAgICAgICByYXRlT3B0aW9ucy5za2lwS2V5ICE9PSBmYWxzZSAmJlxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXG4gICAgICAgIHJlcXVlc3QucXVlcnkua2V5ID09PSByYXRlT3B0aW9ucy5za2lwS2V5ICYmXG4gICAgICAgIHJlcXVlc3QucXVlcnkuYWNjZXNzX3Rva2VuID09PSByYXRlT3B0aW9ucy5za2lwVG9rZW5cbiAgICAgICkge1xuICAgICAgICBsb2coNCwgJ1tyYXRlIGxpbWl0aW5nXSBTa2lwcGluZyByYXRlIGxpbWl0ZXIuJyk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gVXNlIGEgbGltaXRlciBhcyBhIG1pZGRsZXdhcmVcbiAgYXBwLnVzZShsaW1pdGVyKTtcblxuICBsb2coXG4gICAgMyxcbiAgICBgW3JhdGUgbGltaXRpbmddIEVuYWJsZWQgcmF0ZSBsaW1pdGluZyB3aXRoICR7cmF0ZU9wdGlvbnMubWF4fSByZXF1ZXN0cyBwZXIgJHtyYXRlT3B0aW9ucy53aW5kb3d9IG1pbnV0ZSBmb3IgZWFjaCBJUCwgdHJ1c3RpbmcgcHJveHk6ICR7cmF0ZU9wdGlvbnMudHJ1c3RQcm94eX0uYFxuICApO1xufTtcbiIsImltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL0V4cG9ydEVycm9yLmpzJztcblxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlLCBzdGF0dXMpIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcbiAgfVxuXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcbiAgICB0aGlzLnN0YXR1cyA9IHN0YXR1cztcbiAgICByZXR1cm4gdGhpcztcbiAgfVxufVxuXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgdXBkYXRlVmVyc2lvbiwgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcbmltcG9ydCB7IGVudnMgfSBmcm9tICcuLi8uLi9lbnZzLmpzJztcblxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcblxuLyoqXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcbiAqIHRoZSBIaWdoY2hhcnRzIHZlcnNpb24gb24gdGhlIHNlcnZlci5cbiAqXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcbiAqL1xuZXhwb3J0IGRlZmF1bHQgKGFwcCkgPT5cbiAgIWFwcFxuICAgID8gZmFsc2VcbiAgICA6IGFwcC5wb3N0KFxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcbiAgICAgICAgYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XG4gICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XG5cbiAgICAgICAgICAgIC8vIENoZWNrIHRoZSBleGlzdGVuY2Ugb2YgdGhlIHRva2VuXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICAgICAgICAgJ1RoZSBzZXJ2ZXIgaXMgbm90IGNvbmZpZ3VyZWQgdG8gcGVyZm9ybSBydW4tdGltZSB2ZXJzaW9uIGNoYW5nZXM6IEhJR0hDSEFSVFNfQURNSU5fVE9LRU4gaXMgbm90IHNldC4nLFxuICAgICAgICAgICAgICAgIDQwMVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDaGVjayBpZiB0aGUgaGMtYXV0aCBoZWFkZXIgY29udGFpbiBhIGNvcnJlY3QgdG9rZW5cbiAgICAgICAgICAgIGNvbnN0IHRva2VuID0gcmVxdWVzdC5nZXQoJ2hjLWF1dGgnKTtcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICAgICAgICAnSW52YWxpZCBvciBtaXNzaW5nIHRva2VuOiBTZXQgdGhlIHRva2VuIGluIHRoZSBoYy1hdXRoIGhlYWRlci4nLFxuICAgICAgICAgICAgICAgIDQwMVxuICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBDb21wYXJlIHZlcnNpb25zXG4gICAgICAgICAgICBjb25zdCBuZXdWZXJzaW9uID0gcmVxdWVzdC5wYXJhbXMubmV3VmVyc2lvbjtcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXG4gICAgICAgICAgICAgICAgICBlcnJvci5zdGF0dXNDb2RlXG4gICAgICAgICAgICAgICAgKS5zZXRFcnJvcihlcnJvcik7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBTdWNjZXNzXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xuICAgICAgICAgICAgICAgIHN0YXR1c0NvZGU6IDIwMCxcbiAgICAgICAgICAgICAgICB2ZXJzaW9uOiB2ZXJzaW9uKCksXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXG4gICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcignTm8gbmV3IHZlcnNpb24gc3VwcGxpZWQuJywgNDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICAgICAgbmV4dChlcnJvcik7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICApO1xuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcblxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXG5cbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxuXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXG5cbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxuXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXG5cbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbmltcG9ydCB7IHY0IGFzIHV1aWQgfSBmcm9tICd1dWlkJztcblxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcbmltcG9ydCB7IGdldE9wdGlvbnMsIG1lcmdlQ29uZmlnT3B0aW9ucyB9IGZyb20gJy4uLy4uL2NvbmZpZy5qcyc7XG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuLi8uLi9sb2dnZXIuanMnO1xuaW1wb3J0IHtcbiAgZml4VHlwZSxcbiAgaXNDb3JyZWN0SlNPTixcbiAgaXNPYmplY3RFbXB0eSxcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcbiAgb3B0aW9uc1N0cmluZ2lmeSxcbiAgbWVhc3VyZVRpbWVcbn0gZnJvbSAnLi4vLi4vdXRpbHMuanMnO1xuXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xuXG4vLyBSZXZlcnNlZCBNSU1FIHR5cGVzXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XG4gIHBuZzogJ2ltYWdlL3BuZycsXG4gIGpwZWc6ICdpbWFnZS9qcGVnJyxcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcbiAgcGRmOiAnYXBwbGljYXRpb24vcGRmJyxcbiAgc3ZnOiAnaW1hZ2Uvc3ZnK3htbCdcbn07XG5cbi8vIFRoZSByZXF1ZXN0cyBjb3VudGVyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcblxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGJlZm9yZSBhIHJlcXVlc3RcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcblxuLy8gVGhlIGFycmF5IG9mIGNhbGxiYWNrcyB0byBjYWxsIGFmdGVyIGEgcmVxdWVzdFxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XG5cbi8qKlxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcbiAqIGN1c3RvbWl6YXRpb24gb2YgcmVxdWVzdCBoYW5kbGluZy5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xuICogdG8gYmUgZXhlY3V0ZWQuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cbiAqIEBwYXJhbSB7T2JqZWN0fSBkYXRhIC0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgcGFyYW1ldGVycyBsaWtlIGlkLCB1bmlxdWVJZCxcbiAqIHR5cGUsIGFuZCBib2R5LlxuICpcbiAqIEByZXR1cm5zIHtib29sZWFufSAtIFJldHVybnMgYSBib29sZWFuIGluZGljYXRpbmcgdGhlIG92ZXJhbGwgcmVzdWx0XG4gKiBvZiB0aGUgY2FsbGJhY2sgaW52b2NhdGlvbnMuXG4gKi9cbmNvbnN0IGRvQ2FsbGJhY2tzID0gKGNhbGxiYWNrcywgcmVxdWVzdCwgcmVzcG9uc2UsIGRhdGEpID0+IHtcbiAgbGV0IHJlc3VsdCA9IHRydWU7XG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xuXG4gIGNhbGxiYWNrcy5zb21lKChjYWxsYmFjaykgPT4ge1xuICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgbGV0IGNhbGxSZXNwb25zZSA9IGNhbGxiYWNrKHJlcXVlc3QsIHJlc3BvbnNlLCBpZCwgdW5pcXVlSWQsIHR5cGUsIGJvZHkpO1xuXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XG4gICAgICAgIHJlc3VsdCA9IGNhbGxSZXNwb25zZTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxuICpcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXF1ZXN0fSByZXF1ZXN0IC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXG4gKlxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcbiAqIGlzIGNvbXBsZXRlLlxuICovXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XG4gIHRyeSB7XG4gICAgLy8gU3RhcnQgY291bnRpbmcgdGltZVxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcblxuICAgIC8vIENyZWF0ZSBhIHVuaXF1ZSBJRCBmb3IgYSByZXF1ZXN0XG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XG5cbiAgICAvLyBHZXQgdGhlIGN1cnJlbnQgc2VydmVyJ3MgZ2VuZXJhbCBvcHRpb25zXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XG5cbiAgICBjb25zdCBib2R5ID0gcmVxdWVzdC5ib2R5O1xuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XG5cbiAgICBsZXQgdHlwZSA9IGZpeFR5cGUoYm9keS50eXBlKTtcblxuICAgIC8vIFRocm93ICdCYWQgUmVxdWVzdCcgaWYgdGhlcmUncyBubyBib2R5XG4gICAgaWYgKCFib2R5IHx8IGlzT2JqZWN0RW1wdHkoYm9keSkpIHtcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXG4gICAgICAgICdUaGUgcmVxdWVzdCBib2R5IGlzIHJlcXVpcmVkLiBQbGVhc2UgZW5zdXJlIHRoYXQgeW91ciBDb250ZW50LVR5cGUgaGVhZGVyIGlzIGNvcnJlY3QgKGFjY2VwdGVkIHR5cGVzIGFyZSBhcHBsaWNhdGlvbi9qc29uIGFuZCBtdWx0aXBhcnQvZm9ybS1kYXRhKS4nLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxuICAgIGxldCBpbnN0ciA9IGlzQ29ycmVjdEpTT04oYm9keS5pbmZpbGUgfHwgYm9keS5vcHRpb25zIHx8IGJvZHkuZGF0YSk7XG5cbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XG4gICAgaWYgKCFpbnN0ciAmJiAhYm9keS5zdmcpIHtcbiAgICAgIGxvZyhcbiAgICAgICAgMixcbiAgICAgICAgYFRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gZnJvbSAke1xuICAgICAgICAgIHJlcXVlc3QuaGVhZGVyc1sneC1mb3J3YXJkZWQtZm9yJ10gfHwgcmVxdWVzdC5jb25uZWN0aW9uLnJlbW90ZUFkZHJlc3NcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXG4gICAgICApO1xuXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICBcIk5vIGNvcnJlY3QgY2hhcnQgZGF0YSBmb3VuZC4gRW5zdXJlIHRoYXQgeW91IGFyZSB1c2luZyBlaXRoZXIgYXBwbGljYXRpb24vanNvbiBvciBtdWx0aXBhcnQvZm9ybS1kYXRhIGhlYWRlcnMuIElmIHNlbmRpbmcgSlNPTiwgbWFrZSBzdXJlIHRoZSBjaGFydCBkYXRhIGlzIGluIHRoZSAnaW5maWxlJywgJ29wdGlvbnMnLCBvciAnZGF0YScgYXR0cmlidXRlLiBJZiBzZW5kaW5nIFNWRywgZW5zdXJlIGl0IGlzIGluIHRoZSAnc3ZnJyBhdHRyaWJ1dGUuXCIsXG4gICAgICAgIDQwMFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XG5cbiAgICAvLyBDYWxsIHRoZSBiZWZvcmUgcmVxdWVzdCBmdW5jdGlvbnNcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xuICAgICAgaWQsXG4gICAgICB1bmlxdWVJZCxcbiAgICAgIHR5cGUsXG4gICAgICBib2R5XG4gICAgfSk7XG5cbiAgICAvLyBCbG9jayB0aGUgcmVxdWVzdCBpZiBvbmUgb2YgYSBjYWxsYmFja3MgZmFpbGVkXG4gICAgaWYgKGNhbGxSZXNwb25zZSAhPT0gdHJ1ZSkge1xuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcbiAgICB9XG5cbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcblxuICAgIC8vIEluIGNhc2UgdGhlIGNvbm5lY3Rpb24gaXMgY2xvc2VkLCBmb3JjZSB0byBhYm9ydCBmdXJ0aGVyIGFjdGlvbnNcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XG4gICAgICBjb25uZWN0aW9uQWJvcnRlZCA9IHRydWU7XG4gICAgfSk7XG5cbiAgICBsb2coNCwgYFtleHBvcnRdIEdvdCBhbiBpbmNvbWluZyBIVFRQIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfS5gKTtcblxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XG5cbiAgICAvLyBHYXRoZXIgYW5kIG9yZ2FuaXplIG9wdGlvbnMgZnJvbSB0aGUgcGF5bG9hZFxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xuICAgICAgZXhwb3J0OiB7XG4gICAgICAgIGluc3RyLFxuICAgICAgICB0eXBlLFxuICAgICAgICBjb25zdHI6IGJvZHkuY29uc3RyWzBdLnRvTG93ZXJDYXNlKCkgKyBib2R5LmNvbnN0ci5zdWJzdHIoMSksXG4gICAgICAgIGhlaWdodDogYm9keS5oZWlnaHQsXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxuICAgICAgICBzY2FsZTogYm9keS5zY2FsZSB8fCBkZWZhdWx0T3B0aW9ucy5leHBvcnQuc2NhbGUsXG4gICAgICAgIGdsb2JhbE9wdGlvbnM6IGlzQ29ycmVjdEpTT04oYm9keS5nbG9iYWxPcHRpb25zLCB0cnVlKSxcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxuICAgICAgfSxcbiAgICAgIGN1c3RvbUxvZ2ljOiB7XG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXG4gICAgICAgIGFsbG93RmlsZVJlc291cmNlczogZmFsc2UsXG4gICAgICAgIHJlc291cmNlczogaXNDb3JyZWN0SlNPTihib2R5LnJlc291cmNlcywgdHJ1ZSksXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxuICAgICAgICBjdXN0b21Db2RlOiBib2R5LmN1c3RvbUNvZGVcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgaWYgKGluc3RyKSB7XG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcbiAgICAgIHJlcXVlc3RPcHRpb25zLmV4cG9ydC5pbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXG4gICAgICAgIGluc3RyLFxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gTWVyZ2UgdGhlIHJlcXVlc3Qgb3B0aW9ucyBpbnRvIGRlZmF1bHQgb25lc1xuICAgIGNvbnN0IG9wdGlvbnMgPSBtZXJnZUNvbmZpZ09wdGlvbnMoZGVmYXVsdE9wdGlvbnMsIHJlcXVlc3RPcHRpb25zKTtcblxuICAgIC8vIFNhdmUgdGhlIEpTT04gaWYgZXhpc3RzXG4gICAgb3B0aW9ucy5leHBvcnQub3B0aW9ucyA9IGluc3RyO1xuXG4gICAgLy8gTGFzdGx5LCBhZGQgdGhlIHNlcnZlciBzcGVjaWZpYyBhcmd1bWVudHMgaW50byBvcHRpb25zIGFzIHBheWxvYWRcbiAgICBvcHRpb25zLnBheWxvYWQgPSB7XG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxuICAgICAgYjY0OiBib2R5LmI2NCB8fCBmYWxzZSxcbiAgICAgIG5vRG93bmxvYWQ6IGJvZHkubm9Eb3dubG9hZCB8fCBmYWxzZSxcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcbiAgICB9O1xuXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xuICAgIGlmIChib2R5LnN2ZyAmJiBpc1ByaXZhdGVSYW5nZVVybEZvdW5kKG9wdGlvbnMucGF5bG9hZC5zdmcpKSB7XG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxuICAgICAgICA0MDBcbiAgICAgICk7XG4gICAgfVxuXG4gICAgLy8gU3RhcnQgdGhlIGV4cG9ydCBwcm9jZXNzXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XG4gICAgICAvLyBSZW1vdmUgdGhlIGNsb3NlIGV2ZW50IGZyb20gdGhlIHNvY2tldFxuICAgICAgcmVxdWVzdC5zb2NrZXQucmVtb3ZlQWxsTGlzdGVuZXJzKCdjbG9zZScpO1xuXG4gICAgICAvLyBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3NcbiAgICAgIGlmIChkZWZhdWx0T3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XG4gICAgICAgIGxvZyhcbiAgICAgICAgICA1LFxuICAgICAgICAgIGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0gLSBBZnRlciB0aGUgd2hvbGUgZXhwb3J0aW5nIHByb2Nlc3M6ICR7c3RvcENvdW50ZXIoKX1tcy5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcbiAgICAgIGlmIChjb25uZWN0aW9uQWJvcnRlZCkge1xuICAgICAgICByZXR1cm4gbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFtleHBvcnRdIFRoZSBjbGllbnQgY2xvc2VkIHRoZSBjb25uZWN0aW9uIGJlZm9yZSB0aGUgY2hhcnQgZmluaXNoZWQgcHJvY2Vzc2luZy5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIElmIGVycm9yLCBsb2cgaXQgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcbiAgICAgIGlmIChlcnJvcikge1xuICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgIH1cblxuICAgICAgLy8gSWYgZGF0YSBpcyBtaXNzaW5nLCBsb2cgdGhlIG1lc3NhZ2UgYW5kIHNlbmQgaXQgdG8gdGhlIGVycm9yIG1pZGRsZXdhcmVcbiAgICAgIGlmICghaW5mbyB8fCAhaW5mby5yZXN1bHQpIHtcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcbiAgICAgICAgICBgVW5leHBlY3RlZCByZXR1cm4gZnJvbSBjaGFydCBnZW5lcmF0aW9uLiBQbGVhc2UgY2hlY2sgeW91ciByZXF1ZXN0IGRhdGEuIEZvciB0aGUgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LCB0aGUgcmVzdWx0IGlzICR7aW5mby5yZXN1bHR9LmAsXG4gICAgICAgICAgNDAwXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcbiAgICAgIHR5cGUgPSBpbmZvLm9wdGlvbnMuZXhwb3J0LnR5cGU7XG5cbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xuICAgICAgZG9DYWxsYmFja3MoYWZ0ZXJSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwgeyBpZCwgYm9keTogaW5mby5yZXN1bHQgfSk7XG5cbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xuICAgICAgICAvLyBJZiBvbmx5IGJhc2U2NCBpcyByZXF1aXJlZCwgcmV0dXJuIGl0XG4gICAgICAgIGlmIChib2R5LmI2NCkge1xuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXG4gICAgICAgICAgaWYgKHR5cGUgPT09ICdwZGYnIHx8IHR5cGUgPT0gJ3N2ZycpIHtcbiAgICAgICAgICAgIHJldHVybiByZXNwb25zZS5zZW5kKFxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcbiAgICAgICAgICAgICk7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gU2V0IGNvcnJlY3QgY29udGVudCB0eXBlXG4gICAgICAgIHJlc3BvbnNlLmhlYWRlcignQ29udGVudC1UeXBlJywgcmV2ZXJzZWRNaW1lW3R5cGVdIHx8ICdpbWFnZS9wbmcnKTtcblxuICAgICAgICAvLyBEZWNpZGUgd2hldGhlciB0byBkb3dubG9hZCBvciBub3QgY2hhcnQgZmlsZVxuICAgICAgICBpZiAoIWJvZHkubm9Eb3dubG9hZCkge1xuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXG4gICAgICAgICAgICBgJHtyZXF1ZXN0LnBhcmFtcy5maWxlbmFtZSB8fCByZXF1ZXN0LmJvZHkuZmlsZW5hbWUgfHwgJ2NoYXJ0J30uJHtcbiAgICAgICAgICAgICAgdHlwZSB8fCAncG5nJ1xuICAgICAgICAgICAgfWBcbiAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSWYgU1ZHLCByZXR1cm4gcGxhaW4gY29udGVudFxuICAgICAgICByZXR1cm4gdHlwZSA9PT0gJ3N2ZydcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXG4gICAgICAgICAgOiByZXNwb25zZS5zZW5kKEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykpO1xuICAgICAgfVxuICAgIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIG5leHQoZXJyb3IpO1xuICB9XG59O1xuXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XG4gIC8qKlxuICAgKiBBZGRzIHRoZSBQT1NUIC8gYSByb3V0ZSBmb3IgaGFuZGxpbmcgUE9TVCByZXF1ZXN0cyBhdCB0aGUgcm9vdCBlbmRwb2ludC5cbiAgICovXG4gIGFwcC5wb3N0KCcvJywgZXhwb3J0SGFuZGxlcik7XG5cbiAgLyoqXG4gICAqIEFkZHMgdGhlIFBPU1QgLzpmaWxlbmFtZSBhIHJvdXRlIGZvciBoYW5kbGluZyBQT1NUIHJlcXVlc3RzIHdpdGhcbiAgICogYSBzcGVjaWZpZWQgZmlsZW5hbWUgcGFyYW1ldGVyLlxuICAgKi9cbiAgYXBwLnBvc3QoJy86ZmlsZW5hbWUnLCBleHBvcnRIYW5kbGVyKTtcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcbmltcG9ydCB7IGxvZyB9IGZyb20gJy4uLy4uL2xvZ2dlci5qcyc7XG5cbmltcG9ydCB7IHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XG5pbXBvcnQgeyBhZGRJbnRlcnZhbCB9IGZyb20gJy4uLy4uL2ludGVydmFscy5qcyc7XG5pbXBvcnQgcG9vbCBmcm9tICcuLi8uLi9wb29sLmpzJztcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcblxuY29uc3QgcGtnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKHBhdGhlcihfX2Rpcm5hbWUsICdwYWNrYWdlLmpzb24nKSkpO1xuXG5jb25zdCBzZXJ2ZXJTdGFydFRpbWUgPSBuZXcgRGF0ZSgpO1xuXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcbmNvbnN0IHJlY29yZEludGVydmFsID0gNjAgKiAxMDAwOyAvLyByZWNvcmQgZXZlcnkgbWludXRlXG5jb25zdCB3aW5kb3dTaXplID0gMzA7IC8vIDMwIG1pbnV0ZXNcblxuLyoqXG4gKiBDYWxjdWxhdGVzIG1vdmluZyBhdmVyYWdlIGluZGljYXRvciBiYXNlZCBvbiB0aGUgZGF0YSBmcm9tIHRoZSBzdWNjZXNzUmF0ZXNcbiAqIGFycmF5LlxuICpcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gQSBtb3ZpbmcgYXZlcmFnZSBmb3Igc3VjY2VzcyByYXRpbyBvZiB0aGUgc2VydmVyIGV4cG9ydHMuXG4gKi9cbmZ1bmN0aW9uIGNhbGN1bGF0ZU1vdmluZ0F2ZXJhZ2UoKSB7XG4gIGNvbnN0IHN1bSA9IHN1Y2Nlc3NSYXRlcy5yZWR1Y2UoKGEsIGIpID0+IGEgKyBiLCAwKTtcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XG59XG5cbi8qKlxuICogU3RhcnRzIHRoZSBpbnRlcnZhbCByZXNwb25zaWJsZSBmb3IgY2FsY3VsYXRpbmcgY3VycmVudCBzdWNjZXNzIHJhdGUgcmF0aW9cbiAqIGFuZCBnYXRoZXJzXG4gKlxuICogQHJldHVybnMge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxuICovXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XG4gIHNldEludGVydmFsKCgpID0+IHtcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxuICAgICAgc3RhdHMuZXhwb3J0QXR0ZW1wdHMgPT09IDBcbiAgICAgICAgPyAxXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XG5cbiAgICBzdWNjZXNzUmF0ZXMucHVzaChzdWNjZXNzUmF0aW8pO1xuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xuICAgICAgc3VjY2Vzc1JhdGVzLnNoaWZ0KCk7XG4gICAgfVxuICB9LCByZWNvcmRJbnRlcnZhbCk7XG5cbi8qKlxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXG4gKiB3aGljaCBvdXRwdXQgYmFzaWMgc3RhdHMgZm9yIHRoZSBzZXJ2ZXIuXG4gKi9cbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcbiAgaWYgKCFhcHApIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICAvLyBTdGFydCBwcm9jZXNzaW5nIHN1Y2Nlc3MgcmF0ZSByYXRpbyBpbnRlcnZhbCBhbmQgc2F2ZSBpdHMgaWQgdG8gdGhlIGFycmF5XG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXG4gIGFkZEludGVydmFsKHN0YXJ0U3VjY2Vzc1JhdGUoKSk7XG5cbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcbiAgICBjb25zdCBzdGF0cyA9IHBvb2wuZ2V0U3RhdHMoKTtcbiAgICBjb25zdCBwZXJpb2QgPSBzdWNjZXNzUmF0ZXMubGVuZ3RoO1xuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XG5cbiAgICBsb2coNCwgJ1toZWFsdGguanNdIEdFVCAvaGVhbHRoIFsyMDBdIC0gcmV0dXJuaW5nIHNlcnZlciBoZWFsdGguJyk7XG5cbiAgICByZXMuc2VuZCh7XG4gICAgICBzdGF0dXM6ICdPSycsXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxuICAgICAgdXB0aW1lOlxuICAgICAgICBNYXRoLmZsb29yKFxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXG4gICAgICAgICkgKyAnIG1pbnV0ZXMnLFxuICAgICAgdmVyc2lvbjogcGtnRmlsZS52ZXJzaW9uLFxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IHZlcnNpb24oKSxcbiAgICAgIGF2ZXJhZ2VQcm9jZXNzaW5nVGltZTogc3RhdHMuc3BlbnRBdmVyYWdlLFxuICAgICAgcGVyZm9ybWVkRXhwb3J0czogc3RhdHMucGVyZm9ybWVkRXhwb3J0cyxcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxuICAgICAgZXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEF0dGVtcHRzLFxuICAgICAgc3VjZXNzUmF0aW86IChzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC8gc3RhdHMuZXhwb3J0QXR0ZW1wdHMpICogMTAwLFxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxuICAgICAgcG9vbDogcG9vbC5nZXRQb29sSW5mb0pTT04oKSxcblxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcbiAgICAgIHBlcmlvZCxcbiAgICAgIG1vdmluZ0F2ZXJhZ2UsXG4gICAgICBtZXNzYWdlOlxuICAgICAgICBpc05hTihtb3ZpbmdBdmVyYWdlKSB8fCAhc3VjY2Vzc1JhdGVzLmxlbmd0aFxuICAgICAgICAgID8gJ1RvbyBlYXJseSB0byByZXBvcnQuIE5vIGV4cG9ydHMgbWFkZSB5ZXQuIFBsZWFzZSBjaGVjayBiYWNrIHNvb24uJ1xuICAgICAgICAgIDogYExhc3QgJHtwZXJpb2R9IG1pbnV0ZXMgaGFkIGEgc3VjY2VzcyByYXRlIG9mICR7bW92aW5nQXZlcmFnZS50b0ZpeGVkKDIpfSUuYCxcblxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcbiAgICAgIHN2Z0V4cG9ydEF0dGVtcHRzOiBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHMsXG4gICAgICBqc29uRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLSBzdGF0cy5leHBvcnRGcm9tU3ZnQXR0ZW1wdHNcbiAgICB9KTtcbiAgfSk7XG59XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgcHJvbWlzZXMgYXMgZnNQcm9taXNlcyB9IGZyb20gJ2ZzJztcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XG5cbmltcG9ydCBjb3JzIGZyb20gJ2NvcnMnO1xuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XG5pbXBvcnQgaHR0cCBmcm9tICdodHRwJztcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XG5cbmltcG9ydCBlcnJvckhhbmRsZXIgZnJvbSAnLi9lcnJvci5qcyc7XG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi91dGlscy5qcyc7XG5cbmltcG9ydCB2U3dpdGNoUm91dGUgZnJvbSAnLi9yb3V0ZXMvY2hhbmdlX2hjX3ZlcnNpb24uanMnO1xuaW1wb3J0IGV4cG9ydFJvdXRlcyBmcm9tICcuL3JvdXRlcy9leHBvcnQuanMnO1xuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XG5pbXBvcnQgdWlSb3V0ZSBmcm9tICcuL3JvdXRlcy91aS5qcyc7XG5cbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xuXG4vLyBBcnJheSBvZiBhbiBhY3RpdmUgc2VydmVyc1xuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcblxuLy8gQ3JlYXRlIGV4cHJlc3MgYXBwXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbi8vIERpc2FibGUgdGhlIFgtUG93ZXJlZC1CeSBoZWFkZXJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcblxuLy8gRW5hYmxlIENPUlMgc3VwcG9ydFxuYXBwLnVzZShcbiAgY29ycyh7XG4gICAgbWV0aG9kczogWydQT1NUJywgJ0dFVCcsICdPUFRJT05TJ11cbiAgfSlcbik7XG5cbi8vIEVuYWJsZSBwYXJzaW5nIG9mIGZvcm0gZGF0YSAoZmlsZXMpIHdpdGggTXVsdGVyIHBhY2thZ2VcbmNvbnN0IHN0b3JhZ2UgPSBtdWx0ZXIubWVtb3J5U3RvcmFnZSgpO1xuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcbiAgc3RvcmFnZSxcbiAgbGltaXRzOiB7XG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XG4gIH1cbn0pO1xuXG4vLyBFbmFibGUgYm9keSBwYXJzZXJcbmFwcC51c2UoZXhwcmVzcy5qc29uKHsgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xuXG4vLyBVc2Ugb25seSBub24tZmlsZSBtdWx0aXBhcnQgZm9ybSBmaWVsZHNcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XG5cbi8qKlxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtodHRwLlNlcnZlcn0gc2VydmVyIC0gVGhlIEhUVFAvSFRUUFMgc2VydmVyIGluc3RhbmNlLlxuICovXG5jb25zdCBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzID0gKHNlcnZlcikgPT4ge1xuICBzZXJ2ZXIub24oJ2NsaWVudEVycm9yJywgKGVycm9yKSA9PiB7XG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XG4gIH0pO1xuXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBbc2VydmVyXSBTZXJ2ZXIgZXJyb3I6ICR7ZXJyb3IubWVzc2FnZX1gKTtcbiAgfSk7XG5cbiAgc2VydmVyLm9uKCdjb25uZWN0aW9uJywgKHNvY2tldCkgPT4ge1xuICAgIHNvY2tldC5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xuICAgIH0pO1xuICB9KTtcbn07XG5cbi8qKlxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcbiAqIG9iamVjdCBjb250YWlucyBhbGwgc2VydmVyIHJlbGF0ZWQgcHJvcGVydGllcyAoc2VlIHRoZSBgc2VydmVyYCBzZWN0aW9uXG4gKiBpbiB0aGUgYGxpYi9zY2hlbWFzL2NvbmZpZy5qc2AgZmlsZSBmb3IgYSByZWZlcmVuY2UpLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBzZXJ2ZXJDb25maWcgLSBUaGUgc2VydmVyIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxuICpcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXG4gKiBhbmQgc3RhcnRlZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xuICB0cnkge1xuICAgIC8vIFN0b3AgaWYgbm90IGVuYWJsZWRcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvLyBMaXN0ZW4gSFRUUCBzZXJ2ZXJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5zc2wuZm9yY2UpIHtcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxuICAgICAgY29uc3QgaHR0cFNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGFwcCk7XG5cbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcbiAgICAgIGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMoaHR0cFNlcnZlcik7XG5cbiAgICAgIC8vIExpc3RlblxuICAgICAgaHR0cFNlcnZlci5saXN0ZW4oc2VydmVyQ29uZmlnLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcblxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLnNldChzZXJ2ZXJDb25maWcucG9ydCwgaHR0cFNlcnZlcik7XG5cbiAgICAgIGxvZyhcbiAgICAgICAgMyxcbiAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUCBzZXJ2ZXIgb24gJHtzZXJ2ZXJDb25maWcuaG9zdH06JHtzZXJ2ZXJDb25maWcucG9ydH0uYFxuICAgICAgKTtcbiAgICB9XG5cbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXG4gICAgaWYgKHNlcnZlckNvbmZpZy5zc2wuZW5hYmxlKSB7XG4gICAgICAvLyBTZXQgdXAgYW4gU1NMIHNlcnZlciBhbHNvXG4gICAgICBsZXQga2V5LCBjZXJ0O1xuXG4gICAgICB0cnkge1xuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcbiAgICAgICAga2V5ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcbiAgICAgICAgICBwb3NpeC5qb2luKHNlcnZlckNvbmZpZy5zc2wuY2VydFBhdGgsICdzZXJ2ZXIua2V5JyksXG4gICAgICAgICAgJ3V0ZjgnXG4gICAgICAgICk7XG5cbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcbiAgICAgICAgY2VydCA9IGF3YWl0IGZzUHJvbWlzZXMucmVhZEZpbGUoXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmNydCcpLFxuICAgICAgICAgICd1dGY4J1xuICAgICAgICApO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgbG9nKFxuICAgICAgICAgIDIsXG4gICAgICAgICAgYFtzZXJ2ZXJdIFVuYWJsZSB0byBsb2FkIGtleS9jZXJ0aWZpY2F0ZSBmcm9tIHRoZSAnJHtzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRofScgcGF0aC4gQ291bGQgbm90IHJ1biBzZWN1cmVkIGxheWVyIHNlcnZlci5gXG4gICAgICAgICk7XG4gICAgICB9XG5cbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xuICAgICAgICAvLyBNYWluIHNlcnZlciBpbnN0YW5jZSAoSFRUUFMpXG4gICAgICAgIGNvbnN0IGh0dHBzU2VydmVyID0gaHR0cHMuY3JlYXRlU2VydmVyKHsga2V5LCBjZXJ0IH0sIGFwcCk7XG5cbiAgICAgICAgLy8gQXR0YWNoIGVycm9yIGhhbmRsZXJzIGFuZCBsaXN0ZW4gdG8gdGhlIHNlcnZlclxuICAgICAgICBhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzKGh0dHBzU2VydmVyKTtcblxuICAgICAgICAvLyBMaXN0ZW5cbiAgICAgICAgaHR0cHNTZXJ2ZXIubGlzdGVuKHNlcnZlckNvbmZpZy5zc2wucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xuXG4gICAgICAgIC8vIFNhdmUgdGhlIHJlZmVyZW5jZSB0byBIVFRQUyBzZXJ2ZXJcbiAgICAgICAgYWN0aXZlU2VydmVycy5zZXQoc2VydmVyQ29uZmlnLnNzbC5wb3J0LCBodHRwc1NlcnZlcik7XG5cbiAgICAgICAgbG9nKFxuICAgICAgICAgIDMsXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gRW5hYmxlIHRoZSByYXRlIGxpbWl0ZXIgaWYgY29uZmlnIHNheXMgc29cbiAgICBpZiAoXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nICYmXG4gICAgICBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nLmVuYWJsZSAmJlxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXG4gICAgKSB7XG4gICAgICByYXRlTGltaXQoYXBwLCBzZXJ2ZXJDb25maWcucmF0ZUxpbWl0aW5nKTtcbiAgICB9XG5cbiAgICAvLyBTZXQgdXAgc3RhdGljIGZvbGRlcidzIHJvdXRlXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XG5cbiAgICAvLyBTZXQgdXAgcm91dGVzXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcbiAgICBleHBvcnRSb3V0ZXMoYXBwKTtcbiAgICB1aVJvdXRlKGFwcCk7XG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XG5cbiAgICAvLyBTZXQgdXAgY2VudHJhbGl6ZWQgZXJyb3IgaGFuZGxlclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLicsXG4gICAgICA1MDBcbiAgICApLnNldEVycm9yKGVycm9yKTtcbiAgfVxufTtcblxuLyoqXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgY2xvc2VTZXJ2ZXJzID0gKCkgPT4ge1xuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XG4gIGZvciAoY29uc3QgW3BvcnQsIHNlcnZlcl0gb2YgYWN0aXZlU2VydmVycykge1xuICAgIHNlcnZlci5jbG9zZSgoKSA9PiB7XG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcbiAgICAgIGxvZyg0LCBgW3NlcnZlcl0gQ2xvc2VkIHNlcnZlciBvbiBwb3J0OiAke3BvcnR9LmApO1xuICAgIH0pO1xuICB9XG59O1xuXG4vKipcbiAqIEdldCBhbGwgc2VydmVycyBhc3NvY2lhdGVkIHdpdGggRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxuICovXG5leHBvcnQgY29uc3QgZ2V0U2VydmVycyA9ICgpID0+IGFjdGl2ZVNlcnZlcnM7XG5cbi8qKlxuICogRW5hYmxlIHJhdGUgbGltaXRpbmcgZm9yIHRoZSBzZXJ2ZXIuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGxpbWl0Q29uZmlnIC0gQ29uZmlndXJhdGlvbiBvYmplY3QgZm9yIHJhdGUgbGltaXRpbmcuXG4gKi9cbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcblxuLyoqXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBpbnN0YW5jZS5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldEV4cHJlc3MgPSAoKSA9PiBleHByZXNzO1xuXG4vKipcbiAqIEdldCB0aGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKlxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXG4gKi9cbmV4cG9ydCBjb25zdCBnZXRBcHAgPSAoKSA9PiBhcHA7XG5cbi8qKlxuICogQXBwbHkgbWlkZGxld2FyZShzKSB0byBhIHNwZWNpZmljIHBhdGguXG4gKlxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcGF0aCB0byB3aGljaCB0aGUgbWlkZGxld2FyZShzKSBzaG91bGQgYmUgYXBwbGllZC5cbiAqIEBwYXJhbSB7Li4uRnVuY3Rpb259IG1pZGRsZXdhcmVzIC0gVGhlIG1pZGRsZXdhcmUgZnVuY3Rpb25zIHRvIGJlIGFwcGxpZWQuXG4gKi9cbmV4cG9ydCBjb25zdCB1c2UgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnVzZShwYXRoLCAuLi5taWRkbGV3YXJlcyk7XG59O1xuXG4vKipcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IGdldCA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcbn07XG5cbi8qKlxuICogU2V0IHVwIGEgcm91dGUgd2l0aCBQT1NUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cbiAqXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cbiAqL1xuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcbiAgYXBwLnBvc3QocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBzdGFydFNlcnZlcixcbiAgY2xvc2VTZXJ2ZXJzLFxuICBnZXRTZXJ2ZXJzLFxuICBlbmFibGVSYXRlTGltaXRpbmcsXG4gIGdldEV4cHJlc3MsXG4gIGdldEFwcCxcbiAgdXNlLFxuICBnZXQsXG4gIHBvc3Rcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xuXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuLi8uLi91dGlscy5qcyc7XG5cbi8qKlxuICogQWRkcyB0aGUgR0VUIC8gcm91dGUgZm9yIGEgVUkgd2hlbiBlbmFibGVkIG9uIHRoZSBleHBvcnQgc2VydmVyLlxuICovXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxuICAhYXBwXG4gICAgPyBmYWxzZVxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xuICAgICAgICByZXNwb25zZS5zZW5kRmlsZShqb2luKF9fZGlybmFtZSwgJ3B1YmxpYycsICdpbmRleC5odG1sJykpO1xuICAgICAgfSk7XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0IHsgY2xlYXJBbGxJbnRlcnZhbHMgfSBmcm9tICcuL2ludGVydmFscy5qcyc7XG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBjbG9zZVNlcnZlcnMgfSBmcm9tICcuL3NlcnZlci9zZXJ2ZXIuanMnO1xuaW1wb3J0IHsgZ2V0IGFzIGdldEJyb3dzZXIgfSBmcm9tICcuL2Jyb3dzZXIuanMnO1xuXG4vKipcbiAqIENsZWFuIHVwIGZ1bmN0aW9uIHRvIHRyaWdnZXIgYmVmb3JlIGVuZGluZyBwcm9jZXNzIGZvciB0aGUgZ3JhY2VmdWwgc2h1dGRvd24uXG4gKlxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXG4gKi9cbmV4cG9ydCBjb25zdCBzaHV0ZG93bkNsZWFuVXAgPSBhc3luYyAoZXhpdENvZGUpID0+IHtcbiAgLy8gUmVtb3ZlIGFsbCBhdHRhY2hlZCBldmVudCBsaXN0ZW5lcnMgZnJvbSB0aGUgYnJvd3NlclxuICBnZXRCcm93c2VyKCkucmVtb3ZlQWxsTGlzdGVuZXJzKCdkaXNjb25uZWN0ZWQnKTtcblxuICAvLyBBd2FpdCBmcmVlaW5nIGFsbCByZXNvdXJjZXNcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcbiAgICAvLyBDbGVhciBhbGwgb25nb2luZyBpbnRlcnZhbHNcbiAgICBjbGVhckFsbEludGVydmFscygpLFxuXG4gICAgLy8gR2V0IGF2YWlsYWJsZSBzZXJ2ZXIgaW5zdGFuY2VzIChIVFRQL0hUVFBTKSBhbmQgY2xvc2UgdGhlbVxuICAgIGNsb3NlU2VydmVycygpLFxuXG4gICAgLy8gQ2xvc2UgcG9vbCBhbG9uZyB3aXRoIGl0cyB3b3JrZXJzIGFuZCB0aGUgYnJvd3NlciBpbnN0YW5jZSwgaWYgZXhpc3RzXG4gICAga2lsbFBvb2woKVxuICBdKTtcblxuICAvLyBFeGl0IHByb2Nlc3Mgd2l0aCBhIGNvcnJlY3QgY29kZVxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xufTtcblxuZXhwb3J0IGRlZmF1bHQge1xuICBzaHV0ZG93bkNsZWFuVXBcbn07XG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxuXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcblxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XG5cbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cblxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXG5cblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cblxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuaW1wb3J0ICdjb2xvcnMnO1xuXG5pbXBvcnQgeyBjaGVja0FuZFVwZGF0ZUNhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XG5pbXBvcnQge1xuICBiYXRjaEV4cG9ydCxcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxuICBzaW5nbGVFeHBvcnQsXG4gIHN0YXJ0RXhwb3J0XG59IGZyb20gJy4vY2hhcnQuanMnO1xuaW1wb3J0IHsgbWFwVG9OZXdDb25maWcsIG1hbnVhbENvbmZpZywgc2V0T3B0aW9ucyB9IGZyb20gJy4vY29uZmlnLmpzJztcbmltcG9ydCB7XG4gIGluaXRMb2dnaW5nLFxuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcbmltcG9ydCB7IGluaXRQb29sLCBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XG5pbXBvcnQgeyBzaHV0ZG93bkNsZWFuVXAgfSBmcm9tICcuL3Jlc291cmNlX3JlbGVhc2UuanMnO1xuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XG5pbXBvcnQgeyBwcmludExvZ28sIHByaW50VXNhZ2UgfSBmcm9tICcuL3V0aWxzLmpzJztcblxuLyoqXG4gKiBBdHRhY2hlcyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2VzcywgZW5zdXJpbmcgcHJvcGVyIGNsZWFudXAgb2YgcmVzb3VyY2VzXG4gKiBhbmQgdGVybWluYXRpb24gb24gZXhpdCBzaWduYWxzLiBIYW5kbGVzICdleGl0JywgJ1NJR0lOVCcsICdTSUdURVJNJywgYW5kXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cbiAqL1xuY29uc3QgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMgPSAoKSA9PiB7XG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcblxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ2V4aXQnXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgUHJvY2VzcyBleGl0ZWQgd2l0aCBjb2RlICR7Y29kZX0uYCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSU5UJ1xuICBwcm9jZXNzLm9uKCdTSUdJTlQnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdURVJNJ1xuICBwcm9jZXNzLm9uKCdTSUdURVJNJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMCk7XG4gIH0pO1xuXG4gIC8vIEhhbmRsZXIgZm9yIHRoZSAnU0lHSFVQJ1xuICBwcm9jZXNzLm9uKCdTSUdIVVAnLCBhc3luYyAobmFtZSwgY29kZSkgPT4ge1xuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcbiAgfSk7XG5cbiAgLy8gSGFuZGxlciBmb3IgdGhlICd1bmNhdWdodEV4Y2VwdGlvbidcbiAgcHJvY2Vzcy5vbigndW5jYXVnaHRFeGNlcHRpb24nLCBhc3luYyAoZXJyb3IsIG5hbWUpID0+IHtcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcbiAgICBhd2FpdCBzaHV0ZG93bkNsZWFuVXAoMSk7XG4gIH0pO1xufTtcblxuLyoqXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcbiAqIGNhY2hlIGFuZCBzb3VyY2VzLCBhbmQgaW5pdGlhbGl6aW5nIHRoZSBwb29sIG9mIHJlc291cmNlcyBoYXBwZW4gZHVyaW5nXG4gKiB0aGlzIHN0YWdlLiBGdW5jdGlvbiB0aGF0IGlzIHJlcXVpcmVkIHRvIGJlIGNhbGxlZCBiZWZvcmUgdHJ5aW5nIHRvIGV4cG9ydCBjaGFydHMgb3Igc2V0dGluZyBhIHNlcnZlci4gVGhlIGBvcHRpb25zYCBpcyBhbiBvYmplY3QgdGhhdCBjb250YWlucyBhbGwgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIEFsbCBleHBvcnQgb3B0aW9ucy5cbiAqXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cbiAqL1xuY29uc3QgaW5pdEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXG4gIHNldEFsbG93Q29kZUV4ZWN1dGlvbihcbiAgICBvcHRpb25zLmN1c3RvbUxvZ2ljICYmIG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uXG4gICk7XG5cbiAgLy8gSW5pdCB0aGUgbG9nZ2luZ1xuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xuXG4gIC8vIEF0dGFjaCBwcm9jZXNzJyBleGl0IGxpc3RlbmVyc1xuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xuICAgIGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzKCk7XG4gIH1cblxuICAvLyBDaGVjayBpZiBjYWNoZSBuZWVkcyB0byBiZSB1cGRhdGVkXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XG5cbiAgLy8gSW5pdCB0aGUgcG9vbFxuICBhd2FpdCBpbml0UG9vbCh7XG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcbiAgICAgIG1pbldvcmtlcnM6IDEsXG4gICAgICBtYXhXb3JrZXJzOiAxXG4gICAgfSxcbiAgICBwdXBwZXRlZXJBcmdzOiBvcHRpb25zLnB1cHBldGVlci5hcmdzIHx8IFtdXG4gIH0pO1xuXG4gIC8vIFJldHVybiB1cGRhdGVkIG9wdGlvbnNcbiAgcmV0dXJuIG9wdGlvbnM7XG59O1xuXG5leHBvcnQgZGVmYXVsdCB7XG4gIC8vIFNlcnZlclxuICBzZXJ2ZXIsXG4gIHN0YXJ0U2VydmVyLFxuXG4gIC8vIEV4cG9ydGluZ1xuICBpbml0RXhwb3J0LFxuICBzaW5nbGVFeHBvcnQsXG4gIGJhdGNoRXhwb3J0LFxuICBzdGFydEV4cG9ydCxcblxuICAvLyBQb29sXG4gIGluaXRQb29sLFxuICBraWxsUG9vbCxcblxuICAvLyBPdGhlclxuICBzZXRPcHRpb25zLFxuICBzaHV0ZG93bkNsZWFuVXAsXG5cbiAgLy8gTG9nc1xuICBsb2csXG4gIGxvZ1dpdGhTdGFjayxcbiAgc2V0TG9nTGV2ZWwsXG4gIGVuYWJsZUZpbGVMb2dnaW5nLFxuXG4gIC8vIFV0aWxzXG4gIG1hcFRvTmV3Q29uZmlnLFxuICBtYW51YWxDb25maWcsXG4gIHByaW50TG9nbyxcbiAgcHJpbnRVc2FnZVxufTtcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJjdXN0b20iLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInRvQ29uc29sZSIsInRvRmlsZSIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiUE9PTF9SRVNPVVJDRVNfSU5URVJWQUwiLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiTE9HR0lOR19UT19DT05TT0xFIiwiTE9HR0lOR19UT19GSUxFIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIk9USEVSX0JST1dTRVJfU0hFTExfTU9ERSIsIk9USEVSX0NPTk5FQ1RJT05fT1ZFUl9QSVBFIiwiREVCVUdfRU5BQkxFIiwiREVCVUdfSEVBRExFU1MiLCJERUJVR19ERVZUT09MUyIsIkRFQlVHX0xJU1RFTl9UT19DT05TT0xFIiwiREVCVUdfRFVNUElPIiwiREVCVUdfU0xPV19NTyIsIkRFQlVHX0RFQlVHR0lOR19QT1JUIiwicGFydGlhbCIsInBhcnNlIiwicHJvY2VzcyIsImVudiIsImNvbG9ycyIsInBhdGhDcmVhdGVkIiwibGV2ZWxzRGVzYyIsInRpdGxlIiwiY29sb3IiLCJsaXN0ZW5lcnMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJ0YWdOYW1lIiwidG9VcHBlckNhc2UiLCJzcmMiLCJiYXNlVVJJIiwiZXhwQmFja29mZiIsImFzeW5jIiwiYXR0ZW1wdCIsImRlbGF5SW5NcyIsIlByb21pc2UiLCJyZXNwb25zZSIsInNldFRpbWVvdXQiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5Iiwia2V5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwib3B0aW9uIiwiZW50cmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwicmVkIiwidG9Cb29sZWFuIiwid3JhcEFyb3VuZCIsInJlcGxhY2UiLCJtZWFzdXJlVGltZSIsInN0YXJ0IiwiaHJ0aW1lIiwiYmlnaW50IiwiTnVtYmVyIiwiZ2VuZXJhbE9wdGlvbnMiLCJnZXRPcHRpb25zIiwibWVyZ2VDb25maWdPcHRpb25zIiwibmV3T3B0aW9ucyIsIm1lcmdlZE9wdGlvbnMiLCJ1cGRhdGVEZWZhdWx0Q29uZmlnIiwiY29uZmlnT2JqIiwiY3VzdG9tT2JqIiwiY3VzdG9tVmFsdWUiLCJpbml0T3B0aW9ucyIsIml0ZW1zIiwicmVjdXJzaXZlUHJvcHMiLCJvYmplY3RUb1VwZGF0ZSIsIm5lc3RlZE5hbWVzIiwic2hpZnQiLCJhc3NpZ24iLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwicmVzb2x2ZSIsInJlamVjdCIsInByb3RvY29sIiwiaHR0cHMiLCJodHRwIiwiZ2V0UHJvdG9jb2wiLCJnZXQiLCJyZXMiLCJvbiIsImNodW5rIiwidGV4dCIsIkV4cG9ydEVycm9yIiwiRXJyb3IiLCJjb25zdHJ1Y3RvciIsInN0YXR1cyIsInN1cGVyIiwidGhpcyIsInNldEVycm9yIiwic3RhdHVzQ29kZSIsImNhY2hlIiwiYWN0aXZlTWFuaWZlc3QiLCJzb3VyY2VzIiwiaGNWZXJzaW9uIiwiZXh0cmFjdFZlcnNpb24iLCJpbmRleE9mIiwiZmV0Y2hBbmRQcm9jZXNzU2NyaXB0Iiwic2NyaXB0IiwiZmV0Y2hlZE1vZHVsZXMiLCJzaG91bGRUaHJvd0Vycm9yIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsImdldENhY2hlUGF0aCIsIm1hbmlmZXN0UGF0aCIsInJlY3Vyc2l2ZSIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImNhY2hlUGF0aE9wdGlvbiIsImlzQWJzb2x1dGUiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiY2hhcnQiLCJhbmltYXRpb24iLCJzdHJJbmoiLCJpc1JlbmRlckNvbXBsZXRlIiwiQ2hhcnQiLCJwcm9jZWVkIiwidXNlck9wdGlvbnMiLCJjYiIsImV4cG9ydGluZyIsImVuYWJsZWQiLCJwbG90T3B0aW9ucyIsInNlcmllcyIsImxhYmVsIiwidG9vbHRpcCIsIm9uSGlnaGNoYXJ0c1JlbmRlciIsImFkZEV2ZW50IiwiU2VyaWVzIiwiRnVuY3Rpb24iLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwid3NFbmRwb2ludCIsInJlY29ubmVjdCIsImNvbm5lY3RlZCIsImNvbm5lY3QiLCJicm93c2VyV1NFbmRwb2ludCIsImNsb3NlIiwiY3JlYXRlIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImRlYnVnT3B0aW9ucyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsInBpcGUiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwicGFnZXMiLCJwYWdlIiwibmV3UGFnZSIsInBvb2xSZXNvdXJjZSIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsImlubmVySFRNTCIsImZyYW1lIiwibWFpbkZyYW1lIiwiZGV0YWNoZWQiLCJ3b3JrQ291bnQiLCJpZCIsInBvb2xSZXNvdXJjZUlkIiwiaXNDbG9zZWQiLCJzZXRQYWdlRXZlbnRzIiwiY2xlYXJQYWdlUmVzb3VyY2VzIiwiaW5qZWN0ZWRSZXNvdXJjZXMiLCJyZXNvdXJjZSIsImRpc3Bvc2UiLCJldmFsdWF0ZSIsIm9sZENoYXJ0cyIsImNoYXJ0cyIsIm9sZENoYXJ0IiwiZGVzdHJveSIsInNjcmlwdHNUb1JlbW92ZSIsImdldEVsZW1lbnRzQnlUYWdOYW1lIiwic3R5bGVzVG9SZW1vdmUiLCJsaW5rc1RvUmVtb3ZlIiwicmVtb3ZlIiwic2V0Q29udGVudCIsIndhaXRVbnRpbCIsImFkZFNjcmlwdFRhZyIsInBhdGgiLCJzZXRBc0NvbmZpZyIsInB1cHBldGVlckV4cG9ydCIsImV4cG9ydE9wdGlvbnMiLCJkZWJ1Z2dlciIsImlzU1ZHIiwic3ZnVGVtcGxhdGUiLCJpbmplY3RlZEpzIiwianMiLCJwdXNoIiwiY29udGVudCIsImlzTG9jYWwiLCJqc1Jlc291cmNlIiwiaW5qZWN0ZWRDc3MiLCJjc3MiLCJjc3NJbXBvcnRzIiwibWF0Y2giLCJjc3NJbXBvcnRQYXRoIiwiY3NzUmVzb3VyY2UiLCJhZGRTdHlsZVRhZyIsImFkZFBhZ2VSZXNvdXJjZXMiLCJzaXplIiwic3ZnRWxlbWVudCIsInF1ZXJ5U2VsZWN0b3IiLCJjaGFydEhlaWdodCIsImJhc2VWYWwiLCJjaGFydFdpZHRoIiwiYm9keSIsInN0eWxlIiwiem9vbSIsIm1hcmdpbiIsInZpZXdwb3J0SGVpZ2h0IiwiTWF0aCIsImNlaWwiLCJ2aWV3cG9ydFdpZHRoIiwieCIsInkiLCJnZXRCb3VuZGluZ0NsaWVudFJlY3QiLCJ0cnVuYyIsImdldENsaXBSZWdpb24iLCJzZXRWaWV3cG9ydCIsImRldmljZVNjYWxlRmFjdG9yIiwib3V0ZXJIVE1MIiwiY3JlYXRlU1ZHIiwiZW5jb2RpbmciLCJjbGlwIiwicmFjZSIsInNjcmVlbnNob3QiLCJjYXB0dXJlQmV5b25kVmlld3BvcnQiLCJmdWxsUGFnZSIsIm9wdGltaXplRm9yU3BlZWQiLCJxdWFsaXR5Iiwib21pdEJhY2tncm91bmQiLCJfcmVzb2x2ZSIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsImludGVydmFsSWRzIiwiYWRkSW50ZXJ2YWwiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJzdGF0cyIsInBlcmZvcm1lZEV4cG9ydHMiLCJleHBvcnRBdHRlbXB0cyIsImV4cG9ydEZyb21TdmdBdHRlbXB0cyIsInRpbWVTcGVudCIsImRyb3BwZWRFeHBvcnRzIiwic3BlbnRBdmVyYWdlIiwicG9vbENvbmZpZyIsImZhY3RvcnkiLCJ1dWlkIiwicmFuZG9tIiwidmFsaWRhdGUiLCJ2YWxpZGF0ZWQiLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJpbml0UG9vbCIsImNyZWF0ZUJyb3dzZXIiLCJwYXJzZUludCIsIlBvb2wiLCJhY3F1aXJlVGltZW91dE1pbGxpcyIsImNyZWF0ZVRpbWVvdXRNaWxsaXMiLCJkZXN0cm95VGltZW91dE1pbGxpcyIsImlkbGVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlUmV0cnlJbnRlcnZhbE1pbGxpcyIsInJlYXBJbnRlcnZhbE1pbGxpcyIsInByb3BhZ2F0ZUNyZWF0ZUVycm9yIiwiaGFyZFJlc2V0IiwiZ290byIsImNsZWFyUGFnZSIsIl9ldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsInJlc291cmNlQ2hlY2tJbnRlcnZhbCIsInNldEludGVydmFsIiwiY3VycmVudE51bWJlciIsIm51bVVzZWQiLCJudW1GcmVlIiwibnVtUGVuZGluZ0NyZWF0ZXMiLCJfZG9DcmVhdGUiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsIndvcmtlckhhbmRsZSIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJhdmFpbGFibGUiLCJhbGxDcmVhdGVkIiwicGVuZGluZ0FjcXVpcmVzIiwibnVtUGVuZGluZ0FjcXVpcmVzIiwicGVuZGluZ0NyZWF0ZXMiLCJwZW5kaW5nVmFsaWRhdGlvbnMiLCJudW1QZW5kaW5nVmFsaWRhdGlvbnMiLCJwZW5kaW5nRGVzdHJveXMiLCJhYnNvbHV0ZUFsbCIsInBvb2wkMSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiQUREX1RBR1MiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInZTd2l0Y2hSb3V0ZSIsInBvc3QiLCJhZG1pblRva2VuIiwidG9rZW4iLCJuZXdWZXJzaW9uIiwicGFyYW1zIiwidXBkYXRlVmVyc2lvbiIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzdWNjZXNzUmF0aW8iLCJfIiwicGVyaW9kIiwibW92aW5nQXZlcmFnZSIsInJlZHVjZSIsImEiLCJiIiwiYm9vdFRpbWUiLCJ1cHRpbWUiLCJmbG9vciIsImhpZ2hjaGFydHNWZXJzaW9uIiwiYXZlcmFnZVByb2Nlc3NpbmdUaW1lIiwiZmFpbGVkRXhwb3J0cyIsInN1Y2Vzc1JhdGlvIiwidG9GaXhlZCIsInN2Z0V4cG9ydEF0dGVtcHRzIiwianNvbkV4cG9ydEF0dGVtcHRzIiwiYWN0aXZlU2VydmVycyIsIk1hcCIsImV4cHJlc3MiLCJkaXNhYmxlIiwiY29ycyIsIm1ldGhvZHMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwiZXhwb3J0Um91dGVzIiwic2VuZEZpbGUiLCJ1aVJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImVuYWJsZVJhdGVMaW1pdGluZyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiZ2V0QnJvd3NlciIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwibG9nZ2luZ09wdGlvbnMiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSx1QkFDQSxnQkFFQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVBQ0EseUJBQ0EsU0FDQSxlQUNBLFlBQ0Esa0JBQ0EsU0FDQSxjQUNBLG1CQUNBLGVBQ0Esa0JBQ0EsY0FDQSxlQUVBLGNBQ0EsV0FDQSxlQUNBLFdBQ0EsU0FDQSxPQUNBLFdBQ0EsWUFDQSxTQUNBLHFCQUNBLGFBQ0EsV0FDQSxXQUNBLFdBQ0EsV0FDQSxlQUNBLFVBQ0Esa0JBQ0Esb0JBQ0EsYUFDQSxVQUNBLGNBQ0EsWUFDQSxZQUVGQyxXQUFZLENBQUMsa0JBQ2JDLE9BQVEsQ0FDTix3RUFDQSxtR0FNU0MsRUFBZ0IsQ0FDM0JDLFVBQVcsQ0FDVEMsS0FBTSxDQUNKQyxNQUFPLENBQ0wsbUNBQ0Esa0JBQ0EsMENBQ0EsMkJBQ0Esa0NBQ0Esa0NBQ0Esd0NBQ0EsMkNBQ0EscUJBQ0EsNEJBQ0EsMkNBQ0EsdURBQ0EsNkJBQ0EseUJBQ0EsMEJBQ0EsK0JBQ0EsdUJBQ0EsdUZBQ0EseUJBQ0Esb0NBQ0Esb0JBQ0EsMEJBQ0EsOENBQ0EsMkJBQ0EsMEJBQ0EsNkJBQ0EsbUNBQ0Esd0NBQ0EsbUNBQ0EsMkJBQ0Esa0NBQ0EsdUJBQ0EsaUJBQ0EseUJBQ0EsOEJBQ0Esb0JBQ0EsMkJBQ0EsZUFDQSw2QkFDQSxpQkFDQSxhQUNBLGVBQ0Esc0JBQ0EsY0FDQSx5QkFDQSxvQkFDQSx1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 diff --git a/dist/index.esm.js b/dist/index.esm.js index 1801a237..3b243f94 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 O={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"]},R={puppeteer:{args:{value:["--allow-running-insecure-content","--ash-no-nudges","--autoplay-policy=user-gesture-required","--block-new-web-contents","--disable-accelerated-2d-canvas","--disable-background-networking","--disable-background-timer-throttling","--disable-backgrounding-occluded-windows","--disable-breakpad","--disable-checker-imaging","--disable-client-side-phishing-detection","--disable-component-extensions-with-background-pages","--disable-component-update","--disable-default-apps","--disable-dev-shm-usage","--disable-domain-reliability","--disable-extensions","--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP","--disable-hang-monitor","--disable-ipc-flooding-protection","--disable-logging","--disable-notifications","--disable-offer-store-unmasked-wallet-cards","--disable-popup-blocking","--disable-print-preview","--disable-prompt-on-repost","--disable-renderer-backgrounding","--disable-search-engine-choice-screen","--disable-session-crashed-bubble","--disable-setuid-sandbox","--disable-site-isolation-trials","--disable-speech-api","--disable-sync","--enable-unsafe-webgpu","--hide-crash-restore-bubble","--hide-scrollbars","--metrics-recording-only","--mute-audio","--no-default-browser-check","--no-first-run","--no-pings","--no-sandbox","--no-startup-window","--no-zygote","--password-store=basic","--process-per-tab","--use-mock-keychain"],type:"string[]",description:"Arguments array to send to Puppeteer."}},highcharts:{version:{value:"latest",type:"string",envLink:"HIGHCHARTS_VERSION",description:"The Highcharts version to be used."},cdnURL:{value:"https://code.highcharts.com/",type:"string",envLink:"HIGHCHARTS_CDN_URL",description:"The CDN URL for Highcharts scripts to be used."},coreScripts:{value:O.core,type:"string[]",envLink:"HIGHCHARTS_CORE_SCRIPTS",description:"The core Highcharts scripts to fetch."},moduleScripts:{value:O.modules,type:"string[]",envLink:"HIGHCHARTS_MODULE_SCRIPTS",description:"The modules of Highcharts to fetch."},indicatorScripts:{value:O.indicators,type:"string[]",envLink:"HIGHCHARTS_INDICATOR_SCRIPTS",description:"The indicators of Highcharts to fetch."},customScripts:{value:O.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:{enable:{value:!1,type:"boolean",envLink:"SERVER_ENABLE",cliName:"enableServer",description:"When set to true, the server starts on the local IP address 0.0.0.0."},host:{value:"0.0.0.0",type:"string",envLink:"SERVER_HOST",description:"The hostname of the server. Additionally, it starts a server on the provided hostname."},port:{value:7801,type:"number",envLink:"SERVER_PORT",description:"The server port when enabled."},benchmarking:{value:!1,type:"boolean",envLink:"SERVER_BENCHMARKING",cliName:"serverBenchmarking",description:"Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request."},proxy:{host:{value:!1,type:"string",envLink:"SERVER_PROXY_HOST",cliName:"proxyHost",description:"The host of the proxy server to use, if it exists."},port:{value:8080,type:"number",envLink:"SERVER_PROXY_PORT",cliName:"proxyPort",description:"The port of the proxy server to use, if it exists."},timeout:{value:5e3,type:"number",envLink:"SERVER_PROXY_TIMEOUT",cliName:"proxyTimeout",description:"The timeout for the proxy server to use, if it exists."}},rateLimiting:{enable:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_ENABLE",cliName:"enableRateLimiting",description:"Enables rate limiting for the server."},maxRequests:{value:10,type:"number",envLink:"SERVER_RATE_LIMITING_MAX_REQUESTS",legacyName:"rateLimit",description:"The maximum number of requests allowed in one minute."},window:{value:1,type:"number",envLink:"SERVER_RATE_LIMITING_WINDOW",description:"The time window, in minutes, for the rate limiting."},delay:{value:0,type:"number",envLink:"SERVER_RATE_LIMITING_DELAY",description:"The delay duration for each successive request before reaching the maximum limit."},trustProxy:{value:!1,type:"boolean",envLink:"SERVER_RATE_LIMITING_TRUST_PROXY",description:"Set this to true if the server is behind a load balancer."},skipKey:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_KEY",description:"Allows bypassing the rate limiter and should be provided with the skipToken argument."},skipToken:{value:!1,type:"string",envLink:"SERVER_RATE_LIMITING_SKIP_TOKEN",description:"Allows bypassing the rate limiter and should be provided with the skipKey argument."}},ssl:{enable:{value:!1,type:"boolean",envLink:"SERVER_SSL_ENABLE",cliName:"enableSsl",description:"Enables or disables the SSL protocol."},force:{value:!1,type:"boolean",envLink:"SERVER_SSL_FORCE",cliName:"sslForce",legacyName:"sslOnly",description:"When set to true, the server is forced to serve only over HTTPS."},port:{value:443,type:"number",envLink:"SERVER_SSL_PORT",cliName:"sslPort",description:"The port on which to run the SSL server."},certPath:{value:!1,type:"string",envLink:"SERVER_SSL_CERT_PATH",legacyName:"sslPath",description:"The path to the SSL certificate/key file."}}},pool:{minWorkers:{value:4,type:"number",envLink:"POOL_MIN_WORKERS",description:"The number of minimum and initial pool workers to spawn."},maxWorkers:{value:8,type:"number",envLink:"POOL_MAX_WORKERS",legacyName:"workers",description:"The number of maximum pool workers to spawn."},workLimit:{value:40,type:"number",envLink:"POOL_WORK_LIMIT",description:"The number of work pieces that can be performed before restarting the worker process."},acquireTimeout:{value:5e3,type:"number",envLink:"POOL_ACQUIRE_TIMEOUT",description:"The duration, in milliseconds, to wait for acquiring a resource."},createTimeout:{value:5e3,type:"number",envLink:"POOL_CREATE_TIMEOUT",description:"The duration, in milliseconds, to wait for creating a resource."},destroyTimeout:{value:5e3,type:"number",envLink:"POOL_DESTROY_TIMEOUT",description:"The duration, in milliseconds, to wait for destroying a resource."},idleTimeout:{value:3e4,type:"number",envLink:"POOL_IDLE_TIMEOUT",description:"The duration, in milliseconds, after which an idle resource is destroyed."},createRetryInterval:{value:200,type:"number",envLink:"POOL_CREATE_RETRY_INTERVAL",description:"The duration, in milliseconds, to wait before retrying the create process in case of a failure."},reaperInterval:{value:1e3,type:"number",envLink:"POOL_REAPER_INTERVAL",description:"The duration, in milliseconds, after which the check for idle resources to destroy is triggered."},benchmarking:{value:!1,type:"boolean",envLink:"POOL_BENCHMARKING",cliName:"poolBenchmarking",description:"Indicate whether to show statistics for the pool of resources or not."}},logging:{level:{value:4,type:"number",envLink:"LOGGING_LEVEL",cliName:"logLevel",description:"The logging level to be used."},file:{value:"highcharts-export-server.log",type:"string",envLink:"LOGGING_FILE",cliName:"logFile",description:"The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. The `logToFile` option also needs to be set to enable file logging."},toConsole:{value:!0,type:"boolean",envLink:"LOGGING_TO_CONSOLE",cliName:"logToConsole",description:"Enables or disables showing logs in the console."},toFile:{value:!0,type:"boolean",envLink:"LOGGING_TO_FILE",cliName:"logToFile",description:"Enables or disables creation of the log directory and saving the log into a .log file."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},L={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:R.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:R.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:R.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:R.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:R.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:R.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:R.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:R.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:R.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${R.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${R.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:R.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:R.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:R.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:R.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:R.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:R.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:R.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:R.server.host.value},{type:"number",name:"port",message:"Server port",initial:R.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:R.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:R.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:R.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:R.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:R.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:R.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:R.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:R.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:R.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:R.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:R.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:R.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:R.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:R.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:R.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:R.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:R.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:R.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:R.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:R.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:R.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:R.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:R.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:R.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:R.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:R.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:R.logging.file.value},{type:"text",name:"dest",message:"The path to a log file when the file logging is enabled",initial:R.logging.dest.value},{type:"toggle",name:"toConsole",message:"Enable logging to the console",initial:R.logging.toConsole.value},{type:"toggle",name:"toFile",message:"Enables logging to a file",initial:R.logging.toFile.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:R.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:R.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:R.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:R.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:R.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:R.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:R.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:R.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:R.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:R.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:R.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:R.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:R.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:R.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((o=>{if(!["puppeteer","highcharts"].includes(o)){const r=e[o];void 0===r.value?I(r,`${t}.${o}`):(k[r.cliName||o]=`${t}.${o}`.substring(1),void 0!==r.legacyName&&(k[r.legacyName]=`${t}.${o}`.substring(1)))}}))};I(R),h.config();const C=e=>u.string().transform((t=>t.split(",").map((e=>e.trim())).filter((t=>e.includes(t))))).transform((e=>e.length?e:void 0)),N=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),A=e=>u.enum([...e,""]).transform((e=>""!==e?e:void 0)),P=()=>u.string().trim().refine((e=>!["false","undefined","null","NaN"].includes(e)||""===e),(e=>({message:`The string contains forbidden values, received '${e}'`}))).transform((e=>""!==e?e:void 0)),H=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>0),(e=>({message:`The value must be numeric and positive, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),$=()=>u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0),(e=>({message:`The value must be numeric and non-negative, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),G=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(O.core),HIGHCHARTS_MODULE_SCRIPTS:C(O.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(O.indicators),HIGHCHARTS_FORCE_FETCH:N(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:A(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:A(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:N(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:N(),SERVER_ENABLE:N(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:N(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:N(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:N(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:N(),SERVER_SSL_FORCE:N(),SERVER_SSL_PORT:H(),SERVER_SSL_CERT_PATH:P(),POOL_MIN_WORKERS:$(),POOL_MAX_WORKERS:$(),POOL_WORK_LIMIT:H(),POOL_ACQUIRE_TIMEOUT:$(),POOL_CREATE_TIMEOUT:$(),POOL_DESTROY_TIMEOUT:$(),POOL_IDLE_TIMEOUT:$(),POOL_CREATE_RETRY_INTERVAL:$(),POOL_REAPER_INTERVAL:$(),POOL_BENCHMARKING:N(),LOGGING_LEVEL:u.string().trim().refine((e=>""===e||!isNaN(parseFloat(e))&&parseFloat(e)>=0&&parseFloat(e)<=5),(e=>({message:`Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${e}'`}))).transform((e=>""!==e?parseFloat(e):void 0)),LOGGING_FILE:P(),LOGGING_DEST:P(),LOGGING_TO_CONSOLE:N(),LOGGING_TO_FILE:N(),UI_ENABLE:N(),UI_ROUTE:P(),OTHER_NODE_ENV:A(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:N(),OTHER_NO_LOGO:N(),OTHER_HARD_RESET_PAGE:N(),OTHER_BROWSER_SHELL_MODE:N(),DEBUG_ENABLE:N(),DEBUG_HEADLESS:N(),DEBUG_DEVTOOLS:N(),DEBUG_LISTEN_TO_CONSOLE:N(),DEBUG_DUMPIO:N(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),D=["red","yellow","blue","gray","green"];let U={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:D[0]},{title:"warning",color:D[1]},{title:"notice",color:D[2]},{title:"verbose",color:D[3]},{title:"benchmark",color:D[4]}],listeners:[]};const j=(r,i)=>{U.pathCreated||(!e(U.dest)&&t(U.dest),U.pathCreated=!0),o(`${U.dest}${U.file}`,[i].concat(r).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),U.toFile=!1)}))},M=(...e)=>{const[t,...o]=e,{levelsDesc:r,level:i}=U;if(5!==t&&(0===t||t>i||i>r.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${r[t-1].title}] -`;U.listeners.forEach((e=>{e(s,o.join(" "))})),U.toConsole&&console.log.apply(void 0,[s.toString()[U.levelsDesc[t-1].color]].concat(o)),U.toFile&&j(o,s)},F=(e,t,o)=>{const r=o||t.message,{level:i,levelsDesc:s}=U;if(0===e||e>i||i>s.length)return;const n=`${(new Date).toString().split("(")[0].trim()} [${s[e-1].title}] -`,a=t.message!==t.stackMessage||void 0===t.stackMessage?t.stack:t.stack.split("\n").slice(1).join("\n"),l=[r,"\n",a];U.toConsole&&console.log.apply(void 0,[n.toString()[U.levelsDesc[e-1].color]].concat([r[D[e-1]],"\n",a])),U.listeners.forEach((e=>{e(n,l.join(" "))})),U.toFile&&j(l,n)},W=e=>{e>=0&&e<=U.levelsDesc.length&&(U.level=e)},V=(e,t)=>{if(U={...U,dest:e||U.dest,file:t||U.file,toFile:!0},0===U.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");U.dest.endsWith("/")||(U.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(e,t)=>{const o=["png","jpeg","pdf","svg"];if(t){const r=t.split(".").pop();"jpg"===r?e="jpeg":o.includes(r)&&e!==r&&(e=r)}return{"image/png":"png","image/jpeg":"jpeg","application/pdf":"pdf","image/svg+xml":"svg"}[e]||o.find((t=>t===e))||"png"},X=(e=!1,t)=>{const o=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(r(e,"utf8"))}catch(e){return F(2,e,"[cli] No resources found.")}else i=K(e),i&&!t&&delete i.files;for(const e in i)o.includes(e)?s||(s=!0):delete i[e];return s?(i.files&&(i.files=i.files.map((e=>e.trim())),(!i.files||i.files.length<=0)&&delete i.files),i):M(3,"[cli] No resources found.")};function K(e,t){try{const o=JSON.parse("string"!=typeof e?JSON.stringify(e):e);return"string"!=typeof o&&t?JSON.stringify(o):o}catch{return!1}}const 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},z=(e,t)=>JSON.stringify(e,((e,o)=>("string"==typeof o&&((o=o.trim()).startsWith("function(")||o.startsWith("function ("))&&o.endsWith("}")&&(o=t?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:void 0),"function"==typeof o?`EXP_FUN${(o+"").replaceAll(/\n|\t|\r/g," ")}EXP_FUN`:o))).replaceAll(/"EXP_FUN|EXP_FUN"/g,"");function Y(){console.log("\nUsage of CLI arguments:".bold,"\n------",`\nFor more detailed information, visit the readme at: ${"https://github.com/highcharts/node-export-server#readme".bold.yellow}.`);const e=t=>{for(const[o,r]of Object.entries(t))if(Object.prototype.hasOwnProperty.call(r,"value")){let e=` --${r.cliName||o} ${("<"+r.type+">").green} `;if(e.length<48)for(let t=e.length;t<48;t++)e+=".";console.log(e,r.description,`[Default: ${r.value.toString().bold}]`.blue)}else e(r)};Object.keys(R).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(R[t]))})),console.log("\n")}const Q=e=>!["false","undefined","null","NaN","0",""].includes(e)&&!!e,Z=(e,t)=>{if(e&&"string"==typeof e)return(e=e.trim()).endsWith(".js")?!!t&&Z(r(e,"utf8")):e.startsWith("function()")||e.startsWith("function ()")||e.startsWith("()=>")||e.startsWith("() =>")?`(${e})()`:e.replace(/;$/,"")},ee=()=>{const e=process.hrtime.bigint();return()=>Number(process.hrtime.bigint()-e)/1e6};let te={};const oe=()=>te,re=(e,t,o=[])=>{const r=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]:re(r[e],s,o);var i;return r};function ie(e,t={},o=""){Object.keys(e).forEach((r=>{const i=e[r],s=t&&t[r];void 0===i.value?ie(i,s,`${o}.${r}`):(void 0!==s&&(i.value=s),i.envLink in G&&void 0!==G[i.envLink]&&(i.value=G[i.envLink]))}))}function se(e){let t={};for(const[o,r]of Object.entries(e))t[o]=Object.prototype.hasOwnProperty.call(r,"value")?r.value:se(r);return t}function ne(e,t,o){for(;t.length>1;){const r=t.shift();return Object.prototype.hasOwnProperty.call(e,r)||(e[r]={}),e[r]=ne(Object.assign({},e[r]),t,o),e}return e[t[0]]=o,e}async function ae(e,t={}){return new Promise(((o,r)=>{const i=(e=>e.startsWith("https")?m:g)(e);i.get(e,t,(e=>{let t="";e.on("data",(e=>{t+=e})),e.on("end",(()=>{t||r("Nothing was fetched from the URL."),e.text=t,o(e)}))})).on("error",(e=>{r(e)}))}))}class le extends Error{constructor(e){super(),this.message=e,this.stackMessage=e}setError(e){return this.error=e,e.name&&(this.name=e.name),e.statusCode&&(this.statusCode=e.statusCode),e.stack&&(this.stackMessage=e.message,this.stack=e.stack),this}}const ce={cdnURL:"https://code.highcharts.com/",activeManifest:{},sources:"",hcVersion:""},pe=e=>e.sources.substring(0,e.sources.indexOf("*/")).replace("/*","").replace("*/","").replace(/\n/g,"").trim(),he=async(e,t,o,r=!1)=>{e.endsWith(".js")&&(e=e.substring(0,e.length-3)),M(4,`[cache] Fetching script - ${e}.js`);const i=await ae(`${e}.js`,t);if(200===i.statusCode&&"string"==typeof i.text){if(o){o[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(r)throw new le(`Could not fetch the ${e}.js. The script might not exist in the requested version (status code: ${i.statusCode}).`).setError(i);return M(2,`[cache] Could not fetch the ${e}.js. The script might not exist in the requested version.`),""},ue=async(e,t,o)=>{const r=e.version,i="latest"!==r&&r?`${r}/`:"",n=e.cdnURL||ce.cdnURL;M(3,`[cache] Updating cache version to Highcharts: ${i||"latest"}.`);const a={};try{return ce.sources=await(async(e,t,o,r,i)=>{let s;const n=r.host,a=r.port;if(n&&a)try{s=new c({host:n,port:a})}catch(e){throw new le("[cache] Could not create a Proxy Agent.").setError(e)}const l=s?{agent:s,timeout:G.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...o.map((e=>he(`${e}`,l)))];return(await Promise.all(p)).join(";\n")})([...e.coreScripts.map((e=>`${n}${i}${e}`))],[...e.moduleScripts.map((e=>"map"===e?`${n}maps/${i}modules/${e}`:`${n}${i}modules/${e}`)),...e.indicatorScripts.map((e=>`${n}stock/${i}indicators/${e}`))],e.customScripts,t,a),ce.hcVersion=pe(ce),s(o,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async o=>{const{highcharts:i,server:n}=o,l=a(q,i.cachePath);let c;const p=a(l,"manifest.json"),h=a(l,"sources.js");if(!e(l)&&t(l),!e(p)||i.forceFetch)M(3,"[cache] Fetching and caching Highcharts dependencies."),c=await ue(i,n.proxy,h);else{let e=!1;const t=JSON.parse(r(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:o,moduleScripts:s,indicatorScripts:a}=i,l=o.length+s.length+a.length;t.version!==i.version?(M(2,"[cache] A Highcharts version mismatch in the cache, need to re-fetch."),e=!0):Object.keys(t.modules||{}).length!==l?(M(2,"[cache] The cache and the requested modules do not match, need to re-fetch."),e=!0):e=(s||[]).some((e=>{if(!t.modules[e])return M(2,`[cache] The ${e} is missing in the cache, need to re-fetch.`),!0})),e?c=await ue(i,n.proxy,h):(M(3,"[cache] Dependency cache is up to date, proceeding."),ce.sources=r(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const o={version:e.version,modules:t||{}};ce.activeManifest=o,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(o),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,oe().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(e,t,o){window._displayErrors=o;const{getOptions:r,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},r()),t.customLogic.customCode&&new Function(t.customLogic.customCode)();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,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),Highcharts[t.export.constr||"chart"]("container",c,p);const u=r();for(const e in u)"function"!=typeof u[e]&&delete u[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const ye=r(q+"/templates/template.html","utf8");let be;async function we(){if(!be)return!1;const e=await be.newPage();return await e.setCacheEnabled(!1),await Te(e),function(e){const{debug:t}=oe();t.enable&&t.listenToConsole&&e.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));e.on("pageerror",(async t=>{await e.$eval("#container",((e,t)=>{window._displayErrors&&(e.innerHTML=t)}),`

Chart input data error:

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

Chart input data error:

${t.toString()}`)})),t.enable&&t.listenToConsole&&e.page.on("console",(e=>{console.log(`[debug] ${e.text()}`)}));!1===D.OTHER_CONNECTION_OVER_PIPE&&e.page.on("framedetached",(async t=>{const r=e.page.mainFrame();if(t===r&&r.detached&&e.workCount<=o.workLimit){M(3,`[browser] Pool resource [${e.id}] - Page's frame detached.`);try{X((async(e,t)=>{try{t.page.isClosed()||await t.page.close()}catch(t){M(3,`[browser] Pool resource [${e}] - Could not close the page with a detached frame.`)}await Re(t)}),0,e.id,e)}catch(t){V(3,t,`[browser] Pool resource [${e.id}] - Could not create a new page.`),e.workCount=o.workLimit+1}}}))}(e),!e.page||e.page.isClosed())throw new pe("The page is invalid or closed.",500);return M(3,`[pool] Pool resource [${e.id}] - Successfully created a worker, took ${(new Date).getTime()-t}ms.`),e}async function xe(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(1,e,"[browser] Could not clear page's resources.")}}async function _e(e){await e.setContent(we,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${fe()}/sources.js`}),await e.evaluate(ye)}const ke=async(e,t,o,r)=>e.evaluate(be,t,o,r);var Ie=async(e,t,o)=>{let i=[];try{M(4,"[export] Determining export path.");const s=o.export,a=s?.options?.chart?.displayErrors&&ue.activeManifest.modules.debugger;let l;if(t.indexOf&&(t.indexOf("=0||t.indexOf("=0)){if(M(4,"[export] Treating as SVG."),"svg"===s.type)return t;l=!0,await e.setContent((e=>`\n\n\n \n \n Highcharts Export\n \n \n \n
\n ${e}\n
\n \n\n\n`)(t),{waitUntil:"domcontentloaded"})}else M(4,"[export] Treating as config."),s.strInj?await ke(e,{chart:{height:s.height,width:s.width}},o,a):(t.chart.height=s.height,t.chart.width=s.width,await ke(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.ceil(c.chartHeight||s.height),u=Math.ceil(c.chartWidth||s.width),{x:h,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:u,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 pe("Rasterization timeout",408))),i||1500)))]))(e,s.type,"base64",{width:u,height:p,x:h,y:d},s.rasterizationTimeout);else{if("pdf"!==s.type)throw new pe(`[export] Unsupported output format ${s.type}.`,400);g=await(async(e,t,o,r,i)=>(await e.emulateMediaType("screen"),Promise.race([e.pdf({height:t+1,width:o,encoding:r}),new Promise(((e,t)=>setTimeout((()=>t(new pe("Rasterization timeout",408))),i||1500)))])))(e,p,u,"base64",s.rasterizationTimeout)}return await xe(e,i),g}catch(t){return await xe(e,i),t}};const Ce=[],Ne=e=>{Ce.push(e)},Pe=()=>{M(4,"[server] Clearing all registered intervals.");for(const e of Ce)clearInterval(e)};let Ae=!1;const He={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let $e={};const Ge={create:async()=>{try{const e={id:y(),workCount:Math.round(Math.random()*($e.workLimit/2))};return await Re(e)}catch(e){throw new pe("Error encountered when creating a new page.",500).setError(e)}},validate:async e=>{let t=!0;return $e.workLimit&&++e.workCount>$e.workLimit&&(M(3,`[pool] Pool resource [${e.id}] - Validation failed (exceeded the ${$e.workLimit} works limit).`),t=!1),e.page||(e.page.isClosed()&&M(3,`[pool] Pool resource [${e.id}] - Validation failed (page is closed or invalid).`),e.page.mainFrame().detached&&M(3,`[pool] Pool resource [${e.id}] - Validation failed (page's frame is detached).`),t=!1),t},destroy:async e=>{if(M(3,`[pool] Pool resource [${e.id}] - Destroying a worker.`),e.page)try{e.page.removeAllListeners("pageerror"),e.page.removeAllListeners("console"),e.page.removeAllListeners("framedetached"),await e.page.close()}catch(t){M(3,`[pool] Pool resource [${e.id}] - Page could not be closed upon destroying.`)}}},De=async e=>{if($e=e&&e.pool?{...e.pool}:{},await Oe(e.puppeteerArgs),M(3,`[pool] Initializing pool with workers: min ${$e.minWorkers}, max ${$e.maxWorkers}.`),Ae)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt($e.minWorkers)>parseInt($e.maxWorkers)&&($e.minWorkers=$e.maxWorkers);try{Ae=new v({...Ge,min:parseInt($e.minWorkers),max:parseInt($e.maxWorkers),acquireTimeoutMillis:$e.acquireTimeout,createTimeoutMillis:$e.createTimeout,destroyTimeoutMillis:$e.destroyTimeout,idleTimeoutMillis:$e.idleTimeout,createRetryIntervalMillis:$e.createRetryInterval,reapIntervalMillis:$e.reaperInterval,propagateCreateError:!1}),Ae.on("release",(async e=>{M(4,`[pool] Pool resource [${e.id}] - Releasing a worker.`),await async function(e,t=!1){try{e.page.isClosed()||(t?(await e.page.goto("about:blank",{waitUntil:"domcontentloaded"}),await _e(e.page)):await e.page.evaluate((()=>{document.body.innerHTML='
'})))}catch(t){V(2,t,`[pool] Pool resource [${e.id}] - Content of the page could not be cleared.`),e.workCount=ie().pool.workLimit+1}}(e,!1)})),Ae.on("destroySuccess",((e,t)=>{M(4,`[pool] Pool resource [${t.id}] - Destroyed a worker successfully.`),t.page=null}));const e=[];for(let t=0;t<$e.minWorkers;t++)try{const t=await Ae.acquire().promise;e.push(t)}catch(e){V(2,e,"[pool] Could not create an initial resource.")}e.forEach((e=>{Ae.release(e)})),D.POOL_RESOURCES_INTERVAL&&Ne((t=D.POOL_RESOURCES_INTERVAL,setInterval((async()=>{try{let e=Ae.numUsed()+Ae.numFree()+Ae.numPendingCreates();for(;e++{let o;try{if(M(4,"[pool] Work received, starting to process."),++He.exportAttempts,$e.benchmarking&&Me(),!Ae)throw new pe("Work received, but pool has not been started.",500);const r=oe();try{M(4,"[pool] Acquiring a worker handle."),o=await Ae.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${r()}ms.`)}catch(e){throw new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${r()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!o.page)throw o.workCount=$e.workLimit+1,new pe("Resolved worker page is invalid: the pool setup is wonky.",500);let i=(new Date).getTime();M(4,`[pool] Pool resource [${o.id}] - Starting work on this pool entry.`);const s=oe(),n=await Ie(o.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(o.workCount=$e.workLimit+1),new pe((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered during export: ${s()}ms.`).setError(n);t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Exported a chart sucessfully: ${s()}ms.`),Ae.release(o);const a=(new Date).getTime()-i;return He.timeSpent+=a,He.spentAverage=He.timeSpent/++He.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++He.droppedExports,o&&Ae.release(o),new pe(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Fe=()=>({min:Ae.min,max:Ae.max,used:Ae.numUsed(),available:Ae.numFree(),allCreated:Ae.numUsed()+Ae.numFree(),pendingAcquires:Ae.numPendingAcquires(),pendingCreates:Ae.numPendingCreates(),pendingValidations:Ae.numPendingValidations(),pendingDestroys:Ae.pendingDestroys.length,absoluteAll:Ae.numUsed()+Ae.numFree()+Ae.numPendingAcquires()+Ae.numPendingCreates()+Ae.numPendingValidations()+Ae.pendingDestroys.length});function Me(){const{min:e,max:t,used:o,available:r,allCreated:i,pendingAcquires:s,pendingCreates:n,pendingValidations:a,pendingDestroys:l,absoluteAll:c}=Fe();M(5,`[pool] The minimum number of resources allowed by pool: ${e}.`),M(5,`[pool] The maximum number of resources allowed by pool: ${t}.`),M(5,`[pool] The number of used resources: ${o}.`),M(5,`[pool] The number of free resources: ${r}.`),M(5,`[pool] The number of all created (used and free) resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`),M(5,`[pool] The number of resources waiting to be created: ${n}.`),M(5,`[pool] The number of resources waiting to be validated: ${a}.`),M(5,`[pool] The number of resources waiting to be destroyed: ${l}.`),M(5,`[pool] The number of all resources: ${c}.`)}var Ve=Fe,We=()=>He;let qe=!1;const Be=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const o=((e,t={})=>{let o={};return e.svg?(o=Y(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=se(t,e,k),o.export.outfile=o.export?.outfile||`chart.${o.export?.type||"png"}`,o})(e,ie()),i=o.export;if(o.payload?.svg&&""!==o.payload.svg)try{M(4,"[chart] Attempting to export from a SVG input.");const e=ze(function(e){const t=new w("").window;return E(t).sanitize(e,{ADD_TAGS:["foreignObject"]})}(o.payload.svg),o,t);return++He.exportFromSvgAttempts,e}catch(e){return t(new pe("[chart] Error loading SVG input.",400).setError(e))}if(i.infile&&i.infile.length)try{return M(4,"[chart] Attempting to export from an input file."),o.export.instr=r(i.infile,"utf8"),ze(o.export.instr.trim(),o,t)}catch(e){return t(new pe("[chart] Error loading input file.",400).setError(e))}if(i.instr&&""!==i.instr||i.options&&""!==i.options)try{return M(4,"[chart] Attempting to export from a raw input."),ee(o.customLogic?.allowCodeExecution)?Je(o,t):"string"==typeof i.instr?ze(i.instr.trim(),o,t):Ke(o,i.instr||i.options,t)}catch(e){return t(new pe("[chart] Error loading raw input.",400).setError(e))}return t(new pe("[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.",400))},Xe=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},Ke=async(e,t,o,i)=>{let{export:s,customLogic:n}=e;const a="boolean"==typeof n.allowCodeExecution?n.allowCodeExecution:qe;if(n){if(a)if("string"==typeof e.customLogic.resources)e.customLogic.resources=J(e.customLogic.resources,ee(e.customLogic.allowFileResources));else if(!e.customLogic.resources)try{const t=r("resources.json","utf8");e.customLogic.resources=J(t,ee(e.customLogic.allowFileResources))}catch(e){V(2,e,"[chart] Unable to load the default resources.json file.")}}else n=e.customLogic={};if(!a&&n){if(n.callback||n.resources||n.customCode)return o(new pe("[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.",400));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=K(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=te(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,...Xe(e)};try{return o(!1,await je(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=Q(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,Ke(e,!1,t)}catch(o){return t(new pe(`[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.`,400).setError(o))}},ze=(e,t,o)=>{const{allowCodeExecution:r}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ke(t,!1,o,e);try{const r=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return r&&"object"==typeof r?Ke(t,r,o):o(new pe("[chart] Invalid configuration provided - the options must be an object, not a string",400))}catch(e){return ee(r)?Je(t,o):o(new pe("[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.",400).setError(e))}},Ye=(e,t,o,r)=>{V(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,r(e)},Qe=(e,t,o,r)=>{const{statusCode:i,status:s,message:n,stack:a}=e,l=i||s||500;o.status(l).json({statusCode:l,message:n,stack:a})};var Ze=(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=L({windowMs:60*r.window*1e3,max:r.max,delayMs:r.delay,handler:(e,t)=>{t.format({json:()=>{t.status(429).send({message:o})},default:()=>{t.status(429).send(o)}})},skip:e=>!1!==r.skipKey&&!1!==r.skipToken&&e.query.key===r.skipKey&&e.query.access_token===r.skipToken&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${r.max} requests per ${r.window} minute for each IP, trusting proxy: ${r.trustProxy}.`)};class et extends pe{constructor(e,t){super(e),this.status=this.statusCode=t}setStatus(e){return this.status=e,this}}var tt=e=>!!e&&e.post("/version/change/:newVersion",(async(e,t,o)=>{try{const o=D.HIGHCHARTS_ADMIN_TOKEN;if(!o||!o.length)throw new et("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 et("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new et("No new version supplied.",400);try{await(async e=>{const t=ie();t?.highcharts&&(t.highcharts.version=e),await me(t)})(i)}catch(e){throw new et(`Version change: ${e.message}`,e.statusCode).setError(e)}t.status(200).send({statusCode:200,version:ve(),message:`Successfully updated Highcharts to version: ${i}.`})}catch(e){o(e)}}));const ot={png:"image/png",jpeg:"image/jpeg",gif:"image/gif",pdf:"application/pdf",svg:"image/svg+xml"};let rt=0;const it=[],st=[],nt=(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},at=async(e,t,o)=>{try{const o=oe(),i=y().replace(/-/g,""),s=ie(),n=e.body,a=++rt;let l=K(n.type);if(!n||"object"==typeof(r=n)&&!Array.isArray(r)&&null!==r&&0===Object.keys(r).length)throw new et("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 M(2,`The request with ID ${i} from ${e.headers["x-forwarded-for"]||e.connection.remoteAddress} was incorrect. Payload received: ${JSON.stringify(n)}.`),new et("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=nt(it,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==p)return t.send(p);let u=!1;e.socket.on("close",(()=>{u=!0})),M(4,`[export] Got an incoming HTTP request with ID ${i}.`),n.constr="string"==typeof n.constr&&n.constr||"chart";const h={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:qe,allowFileResources:!1,resources:z(n.resources,!0),callback:n.callback,customCode:n.customCode}};c&&(h.export.instr=Q(c,h.customLogic.allowCodeExecution));const d=se(s,h);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 et("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 Be(d,((r,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${o()}ms.`),u)return M(3,"[export] The client closed the connection before the chart finished processing.");if(r)throw r;if(!c||!c.result)throw new et(`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,nt(st,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",ot[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 lt=JSON.parse(r(a(B,"package.json"))),ct=new Date,pt=[];function ut(e){if(!e)return!1;Ne(setInterval((()=>{const e=We(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;pt.push(t),pt.length>30&&pt.shift()}),6e4)),e.get("/health",((e,t)=>{const o=We(),r=pt.length,i=pt.reduce(((e,t)=>e+t),0)/pt.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:ct,uptime:Math.floor(((new Date).getTime()-ct.getTime())/1e3/60)+" minutes",version:lt.version,highchartsVersion:ve(),averageProcessingTime:o.spentAverage,performedExports:o.performedExports,failedExports:o.droppedExports,exportAttempts:o.exportAttempts,sucessRatio:o.performedExports/o.exportAttempts*100,pool:Ve(),period:r,movingAverage:i,message:isNaN(i)||!pt.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 ht=new Map,dt=S();dt.disable("x-powered-by"),dt.use(T({methods:["POST","GET","OPTIONS"]}));const gt=O.memoryStorage(),mt=O({storage:gt,limits:{fieldSize:52428800}});dt.use(S.json({limit:52428800})),dt.use(S.urlencoded({extended:!0,limit:52428800})),dt.use(mt.none());const ft=e=>{e.on("clientError",(e=>{V(1,e,`[server] Client error: ${e.message}`)})),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}`)}))}))},vt=async e=>{try{if(!e.enable)return!1;if(!e.ssl.force){const t=m.createServer(dt);ft(t),t.listen(e.port,e.host),ht.set(e.port,t),M(3,`[server] Started HTTP server on ${e.host}:${e.port}.`)}if(e.ssl.enable){let t,o;try{t=await i.readFile(c.join(e.ssl.certPath,"server.key"),"utf8"),o=await i.readFile(c.join(e.ssl.certPath,"server.crt"),"utf8")}catch(t){M(2,`[server] Unable to load key/certificate from the '${e.ssl.certPath}' path. Could not run secured layer server.`)}if(t&&o){const r=f.createServer({key:t,cert:o},dt);ft(r),r.listen(e.ssl.port,e.host),ht.set(e.ssl.port,r),M(3,`[server] Started HTTPS server on ${e.host}:${e.ssl.port}.`)}}e.rateLimiting&&e.rateLimiting.enable&&![0,NaN].includes(e.rateLimiting.maxRequests)&&Ze(dt,e.rateLimiting),dt.use(S.static(c.join(B,"public"))),ut(dt),(e=>{e.post("/",at),e.post("/:filename",at)})(dt),(e=>{!!e&&e.get("/",((e,t)=>{t.sendFile(a(B,"public","index.html"))}))})(dt),tt(dt),(e=>{e.use(Ye),e.use(Qe)})(dt)}catch(e){throw new pe("[server] Could not configure and start the server.",500).setError(e)}},yt=()=>{M(4,"[server] Closing all servers.");for(const[e,t]of ht)t.close((()=>{ht.delete(e),M(4,`[server] Closed server on port: ${e}.`)}))};var bt={startServer:vt,closeServers:yt,getServers:()=>ht,enableRateLimiting:e=>Ze(dt,e),getExpress:()=>S,getApp:()=>dt,use:(e,...t)=>{dt.use(e,...t)},get:(e,...t)=>{dt.get(e,...t)},post:(e,...t)=>{dt.post(e,...t)}};const wt=async e=>{(function(){if(!Ee)throw new pe("[browser] No valid browser has been created.",500);return Ee})().removeAllListeners("disconnected"),await Promise.allSettled([Pe(),yt(),Ue()]),process.exit(e)};var Et={server:bt,startServer:vt,initExport:async e=>{var t;return t=e.customLogic&&e.customLogic.allowCodeExecution,qe=ee(t),(e=>{for(const[t,o]of Object.entries(e))j[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&&(M(3,"[process] Attaching exit listeners to the process."),process.on("exit",(e=>{M(4,`Process exited with code ${e}.`)})),process.on("SIGINT",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("SIGTERM",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("SIGHUP",(async(e,t)=>{M(4,`The ${e} event with code: ${t}.`),await wt(0)})),process.on("uncaughtException",(async(e,t)=>{V(1,e,`The ${t} error.`),await wt(1)}))),await me(e),await De({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 Be(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 Ue()}))},batchExport:async e=>{const t=[];for(let o of e.export.batch.split(";"))o=o.split("="),2===o.length&&t.push(Be({...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 Ue()}catch(e){throw new pe("[chart] Error encountered during batch export.").setError(e)}},startExport:Be,initPool:De,killPool:Ue,setOptions:(e,t)=>(t?.length&&(re=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)),ne(x,re),re=ae(x),e&&(re=se(re,e,k)),t?.length&&(re=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]=ee(t[i]):"number"===a?e[o]=+t[i]:a.indexOf("]")>=0?e[o]=t[i].split(","):e[o]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),r=!0)),e[o])),e)}r&&Z();return e}(re,t,x)),re),shutdownCleanUp:wt,log:M,logWithStack:V,setLogLevel:W,enableFileLogging:q,mapToNewConfig:e=>{const t={};for(const[o,r]of Object.entries(e)){const e=I[o]?I[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(_).map((e=>({title:`${e} options`,value:e})));return u({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)_[e]=_[e].map((t=>({...t,section:e}))),n=[...n,..._[e]];return await u(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]=le(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{Et as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index 3423b1a2..045a5571 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":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Possible names for Highcharts scripts\nexport const scriptsNames = {\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n modules: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'parallel-coordinates',\n 'accessibility',\n // 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'data-tools',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'tiledwebmap',\n 'timeline',\n 'treemap',\n 'treegraph',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'geoheatmap',\n 'pyramid3d',\n 'networkgraph',\n 'overlapping-datalabels',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'series-on-point',\n 'solid-gauge',\n 'sonification',\n // 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi',\n 'flowmap',\n 'export-data',\n 'navigator',\n 'textpath'\n ],\n indicators: ['indicators-all'],\n custom: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\n ]\n};\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [\n '--allow-running-insecure-content',\n '--ash-no-nudges',\n '--autoplay-policy=user-gesture-required',\n '--block-new-web-contents',\n '--disable-accelerated-2d-canvas',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-checker-imaging',\n '--disable-client-side-phishing-detection',\n '--disable-component-extensions-with-background-pages',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-logging',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-search-engine-choice-screen',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-site-isolation-trials',\n '--disable-speech-api',\n '--disable-sync',\n '--enable-unsafe-webgpu',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-startup-window',\n '--no-zygote',\n '--password-store=basic',\n '--process-per-tab',\n '--use-mock-keychain'\n ],\n type: 'string[]',\n description: 'Arguments array to send to Puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n type: 'string',\n envLink: 'HIGHCHARTS_VERSION',\n description: 'The Highcharts version to be used.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n type: 'string',\n envLink: 'HIGHCHARTS_CDN_URL',\n description: 'The CDN URL for Highcharts scripts to be used.'\n },\n coreScripts: {\n value: scriptsNames.core,\n type: 'string[]',\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n description: 'The core Highcharts scripts to fetch.'\n },\n moduleScripts: {\n value: scriptsNames.modules,\n type: 'string[]',\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\n description: 'The modules of Highcharts to fetch.'\n },\n indicatorScripts: {\n value: scriptsNames.indicators,\n type: 'string[]',\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\n description: 'The indicators of Highcharts to fetch.'\n },\n customScripts: {\n value: scriptsNames.custom,\n type: 'string[]',\n description: 'Additional custom scripts or dependencies to fetch.'\n },\n forceFetch: {\n value: false,\n type: 'boolean',\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n description:\n 'The flag to determine whether to refetch all scripts after each server rerun.'\n },\n cachePath: {\n value: '.cache',\n type: 'string',\n envLink: 'HIGHCHARTS_CACHE_PATH',\n description:\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\n },\n type: {\n value: 'png',\n type: 'string',\n envLink: 'EXPORT_TYPE',\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\n },\n constr: {\n value: 'chart',\n type: 'string',\n envLink: 'EXPORT_CONSTR',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\n },\n defaultHeight: {\n value: 400,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n description:\n 'the default height of the exported chart. Used when no value is set.'\n },\n defaultWidth: {\n value: 600,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_WIDTH',\n description:\n 'The default width of the exported chart. Used when no value is set.'\n },\n defaultScale: {\n value: 1,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_SCALE',\n description:\n 'The default scale of the exported chart. Used when no value is set.'\n },\n height: {\n value: false,\n type: 'number',\n description:\n 'The height of the exported chart, overriding the option in the chart settings.'\n },\n width: {\n value: false,\n type: 'number',\n description:\n 'The width of the exported chart, overriding the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description:\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\n },\n rasterizationTimeout: {\n value: 1500,\n type: 'number',\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\n description:\n 'The duration in milliseconds to wait for rendering a webpage.'\n }\n },\n customLogic: {\n allowCodeExecution: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\n description:\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\n },\n allowFileResources: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\n description:\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description:\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n legacyName: 'fromFile',\n description: 'A file containing a pre-defined configuration to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Enables setting options through a prompt and saving them in a provided config file.'\n }\n },\n server: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_ENABLE',\n cliName: 'enableServer',\n description:\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\n },\n host: {\n value: '0.0.0.0',\n type: 'string',\n envLink: 'SERVER_HOST',\n description:\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\n },\n port: {\n value: 7801,\n type: 'number',\n envLink: 'SERVER_PORT',\n description: 'The server port when enabled.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_BENCHMARKING',\n cliName: 'serverBenchmarking',\n description:\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\n },\n proxy: {\n host: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_HOST',\n cliName: 'proxyHost',\n description: 'The host of the proxy server to use, if it exists.'\n },\n port: {\n value: 8080,\n type: 'number',\n envLink: 'SERVER_PROXY_PORT',\n cliName: 'proxyPort',\n description: 'The port of the proxy server to use, if it exists.'\n },\n timeout: {\n value: 5000,\n type: 'number',\n envLink: 'SERVER_PROXY_TIMEOUT',\n cliName: 'proxyTimeout',\n description: 'The timeout for the proxy server to use, if it exists.'\n }\n },\n rateLimiting: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting for the server.'\n },\n maxRequests: {\n value: 10,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\n legacyName: 'rateLimit',\n description: 'The maximum number of requests allowed in one minute.'\n },\n window: {\n value: 1,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\n description: 'The time window, in minutes, for the rate limiting.'\n },\n delay: {\n value: 0,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_DELAY',\n description:\n 'The delay duration for each successive request before reaching the maximum limit.'\n },\n trustProxy: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\n description: 'Set this to true if the server is behind a load balancer.'\n },\n skipKey: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\n },\n skipToken: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\n }\n },\n ssl: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_ENABLE',\n cliName: 'enableSsl',\n description: 'Enables or disables the SSL protocol.'\n },\n force: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_FORCE',\n cliName: 'sslForce',\n legacyName: 'sslOnly',\n description:\n 'When set to true, the server is forced to serve only over HTTPS.'\n },\n port: {\n value: 443,\n type: 'number',\n envLink: 'SERVER_SSL_PORT',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n value: false,\n type: 'string',\n envLink: 'SERVER_SSL_CERT_PATH',\n legacyName: 'sslPath',\n description: 'The path to the SSL certificate/key file.'\n }\n }\n },\n pool: {\n minWorkers: {\n value: 4,\n type: 'number',\n envLink: 'POOL_MIN_WORKERS',\n description: 'The number of minimum and initial pool workers to spawn.'\n },\n maxWorkers: {\n value: 8,\n type: 'number',\n envLink: 'POOL_MAX_WORKERS',\n legacyName: 'workers',\n description: 'The number of maximum pool workers to spawn.'\n },\n workLimit: {\n value: 40,\n type: 'number',\n envLink: 'POOL_WORK_LIMIT',\n description:\n 'The number of work pieces that can be performed before restarting the worker process.'\n },\n acquireTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_ACQUIRE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for acquiring a resource.'\n },\n createTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_CREATE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for creating a resource.'\n },\n destroyTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_DESTROY_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for destroying a resource.'\n },\n idleTimeout: {\n value: 30000,\n type: 'number',\n envLink: 'POOL_IDLE_TIMEOUT',\n description:\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\n },\n createRetryInterval: {\n value: 200,\n type: 'number',\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\n description:\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\n },\n reaperInterval: {\n value: 1000,\n type: 'number',\n envLink: 'POOL_REAPER_INTERVAL',\n description:\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'POOL_BENCHMARKING',\n cliName: 'poolBenchmarking',\n description:\n 'Indicate whether to show statistics for the pool of resources or not.'\n }\n },\n logging: {\n level: {\n value: 4,\n type: 'number',\n envLink: 'LOGGING_LEVEL',\n cliName: 'logLevel',\n description: 'The logging level to be used.'\n },\n file: {\n value: 'highcharts-export-server.log',\n type: 'string',\n envLink: 'LOGGING_FILE',\n cliName: 'logFile',\n description:\n 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.'\n },\n dest: {\n value: 'log/',\n type: 'string',\n envLink: 'LOGGING_DEST',\n cliName: 'logDest',\n description:\n 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.'\n },\n toConsole: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_CONSOLE',\n cliName: 'logToConsole',\n description: 'Enables or disables showing logs in the console.'\n },\n toFile: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_FILE',\n cliName: 'logToFile',\n description:\n 'Enables or disables creation of the log directory and saving the log into a .log file.'\n }\n },\n ui: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'UI_ENABLE',\n cliName: 'enableUi',\n description:\n 'Enables or disables the user interface (UI) for the export server.'\n },\n route: {\n value: '/',\n type: 'string',\n envLink: 'UI_ROUTE',\n cliName: 'uiRoute',\n description:\n 'The endpoint route to which the user interface (UI) should be attached.'\n }\n },\n other: {\n nodeEnv: {\n value: 'production',\n type: 'string',\n envLink: 'OTHER_NODE_ENV',\n description: 'The type of Node.js environment.'\n },\n listenToProcessExits: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\n description: 'Decides whether or not to attach process.exit handlers.'\n },\n noLogo: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_NO_LOGO',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n },\n hardResetPage: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_HARD_RESET_PAGE',\n description: 'Decides if the page content should be reset entirely.'\n },\n browserShellMode: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_BROWSER_SHELL_MODE',\n description: 'Decides if the browser runs in the shell mode.'\n }\n },\n debug: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_ENABLE',\n cliName: 'enableDebug',\n description: 'Enables or disables debug mode for the underlying browser.'\n },\n headless: {\n value: true,\n type: 'boolean',\n envLink: 'DEBUG_HEADLESS',\n description:\n 'Controls the mode in which the browser is launched when in the debug mode.'\n },\n devtools: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DEVTOOLS',\n description:\n 'Decides whether to enable DevTools when the browser is in a headful state.'\n },\n listenToConsole: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\n description:\n 'Decides whether to enable a listener for console messages sent from the browser.'\n },\n dumpio: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DUMPIO',\n description:\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\n },\n slowMo: {\n value: 0,\n type: 'number',\n envLink: 'DEBUG_SLOW_MO',\n description:\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\n },\n debuggingPort: {\n value: 9222,\n type: 'number',\n envLink: 'DEBUG_DEBUGGING_PORT',\n description: 'Specifies the debugging port.'\n }\n }\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The URL of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'coreScripts',\n message: 'Available core scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.coreScripts.value\n },\n {\n type: 'multiselect',\n name: 'moduleScripts',\n message: 'Available module scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.moduleScripts.value\n },\n {\n type: 'multiselect',\n name: 'indicatorScripts',\n message: 'Available indicator scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.indicatorScripts.value\n },\n {\n type: 'list',\n name: 'customScripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.customScripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Force re-fetch the scripts',\n initial: defaultConfig.highcharts.forceFetch.value\n },\n {\n type: 'text',\n name: 'cachePath',\n message: 'The path to the cache directory',\n initial: defaultConfig.highcharts.cachePath.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default export file type',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n },\n {\n type: 'number',\n name: 'rasterizationTimeout',\n message: 'The rendering webpage timeout in milliseconds',\n initial: defaultConfig.export.rasterizationTimeout.value\n }\n ],\n customLogic: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Enable execution of custom code',\n initial: defaultConfig.customLogic.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Enable file resources',\n initial: defaultConfig.customLogic.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts the server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'Server hostname',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'Server port',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable server benchmarking',\n initial: defaultConfig.server.benchmarking.value\n },\n {\n type: 'text',\n name: 'proxy.host',\n message: 'The host of the proxy server to use',\n initial: defaultConfig.server.proxy.host.value\n },\n {\n type: 'number',\n name: 'proxy.port',\n message: 'The port of the proxy server to use',\n initial: defaultConfig.server.proxy.port.value\n },\n {\n type: 'number',\n name: 'proxy.timeout',\n message: 'The timeout for the proxy server to use',\n initial: defaultConfig.server.proxy.timeout.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'The maximum requests allowed per minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The rate-limiting time window in minutes',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The delay for each successive request before reaching the maximum',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force serving only over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'SSL server port',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'The path to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'minWorkers',\n message: 'The initial number of workers to spawn',\n initial: defaultConfig.pool.minWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The maximum number of workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a Puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'number',\n name: 'createTimeout',\n message: 'The number of milliseconds to wait for creating a resource',\n initial: defaultConfig.pool.createTimeout.value\n },\n {\n type: 'number',\n name: 'destroyTimeout',\n message: 'The number of milliseconds to wait for destroying a resource',\n initial: defaultConfig.pool.destroyTimeout.value\n },\n {\n type: 'number',\n name: 'idleTimeout',\n message: 'The number of milliseconds after an idle resource is destroyed',\n initial: defaultConfig.pool.idleTimeout.value\n },\n {\n type: 'number',\n name: 'createRetryInterval',\n message:\n 'The retry interval in milliseconds after a create process fails',\n initial: defaultConfig.pool.createRetryInterval.value\n },\n {\n type: 'number',\n name: 'reaperInterval',\n message:\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\n initial: defaultConfig.pool.reaperInterval.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable benchmarking for a resource pool',\n initial: defaultConfig.pool.benchmarking.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 5\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A log file name. Set with --toFile and --logDest to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'The path to a log file when the file logging is enabled',\n initial: defaultConfig.logging.dest.value\n },\n {\n type: 'toggle',\n name: 'toConsole',\n message: 'Enable logging to the console',\n initial: defaultConfig.logging.toConsole.value\n },\n {\n type: 'toggle',\n name: 'toFile',\n message: 'Enables logging to a file',\n initial: defaultConfig.logging.toFile.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'text',\n name: 'nodeEnv',\n message: 'The type of Node.js environment',\n initial: defaultConfig.other.nodeEnv.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false to skip attaching process.exit handlers',\n initial: defaultConfig.other.listenToProcessExits.value\n },\n {\n type: 'toggle',\n name: 'noLogo',\n message: 'Skip printing the logo on startup. Replaced by simple text',\n initial: defaultConfig.other.noLogo.value\n },\n {\n type: 'toggle',\n name: 'hardResetPage',\n message: 'Decides if the page content should be reset entirely',\n initial: defaultConfig.other.hardResetPage.value\n },\n {\n type: 'toggle',\n name: 'browserShellMode',\n message: 'Decides if the browser runs in the shell mode',\n initial: defaultConfig.other.browserShellMode.value\n }\n ],\n debug: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enables debug mode for the browser instance',\n initial: defaultConfig.debug.enable.value\n },\n {\n type: 'toggle',\n name: 'headless',\n message: 'The mode setting for the browser',\n initial: defaultConfig.debug.headless.value\n },\n {\n type: 'toggle',\n name: 'devtools',\n message: 'The DevTools for the headful browser',\n initial: defaultConfig.debug.devtools.value\n },\n {\n type: 'toggle',\n name: 'listenToConsole',\n message: 'The event listener for console messages from the browser',\n initial: defaultConfig.debug.listenToConsole.value\n },\n {\n type: 'toggle',\n name: 'dumpio',\n message: 'Redirects the browser stdout and stderr to NodeJS process',\n initial: defaultConfig.debug.dumpio.value\n },\n {\n type: 'number',\n name: 'slowMo',\n message: 'Puppeteer operations slow down in milliseconds',\n initial: defaultConfig.debug.slowMo.value\n },\n {\n type: 'number',\n name: 'debuggingPort',\n message: 'The port number for debugging',\n initial: defaultConfig.debug.debuggingPort.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Recursively creates a chain of nested arguments from an object.\n *\n * @param {Object} obj - The object containing nested arguments.\n * @param {string} propChain - The current chain of nested properties\n * (used internally during recursion).\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n\n // Support for the legacy, PhantomJS properties names\n if (entry.legacyName !== undefined) {\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\n }\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/**\n * @fileoverview\n * This file is responsible for parsing the environment variables with the 'zod'\n * library. The parsed environment variables are then exported to be used\n * in the application as \"envs\". We should not use process.env directly\n * in the application as these would not be parsed properly.\n *\n * The environment variables are parsed and validated only once when\n * the application starts. We should write a custom validator or a transformer\n * for each of the options.\n */\n\nimport dotenv from 'dotenv';\nimport { z } from 'zod';\n\nimport { scriptsNames } from './schemas/config.js';\n\n// Load .env into environment variables\ndotenv.config();\n\n// Object with custom validators and transformers, to avoid repetition\n// in the Config object\nconst v = {\n // Splits string value into elements in an array, trims every element, checks\n // if an array is correct, if it is empty, and if it is, returns undefined\n array: (filterArray) =>\n z\n .string()\n .transform((value) =>\n value\n .split(',')\n .map((value) => value.trim())\n .filter((value) => filterArray.includes(value))\n )\n .transform((value) => (value.length ? value : undefined)),\n\n // Allows only true, false and correctly parse the value to boolean\n // or no value in which case the returned value will be undefined\n boolean: () =>\n z\n .enum(['true', 'false', ''])\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\n\n // Allows passed values or no value in which case the returned value will\n // be undefined\n enum: (values) =>\n z\n .enum([...values, ''])\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Trims the string value and checks if it is empty or contains stringified\n // values such as false, undefined, null, NaN, if it does, returns undefined\n string: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\n value === '',\n (value) => ({\n message: `The string contains forbidden values, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Allows positive numbers or no value in which case the returned value will\n // be undefined\n positiveNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\n (value) => ({\n message: `The value must be numeric and positive, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n\n // Allows non-negative numbers or no value in which case the returned value\n // will be undefined\n nonNegativeNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\n (value) => ({\n message: `The value must be numeric and non-negative, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\n};\n\nexport const Config = z.object({\n // highcharts\n HIGHCHARTS_VERSION: z\n .string()\n .trim()\n .refine(\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\n (value) => ({\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CDN_URL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value.startsWith('https://') ||\n value.startsWith('http://') ||\n value === '',\n (value) => ({\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\n HIGHCHARTS_CACHE_PATH: v.string(),\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\n\n // export\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\n\n // custom\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\n\n // server\n SERVER_ENABLE: v.boolean(),\n SERVER_HOST: v.string(),\n SERVER_PORT: v.positiveNum(),\n SERVER_BENCHMARKING: v.boolean(),\n\n // server proxy\n SERVER_PROXY_HOST: v.string(),\n SERVER_PROXY_PORT: v.positiveNum(),\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\n\n // server rate limiting\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\n\n // server ssl\n SERVER_SSL_ENABLE: v.boolean(),\n SERVER_SSL_FORCE: v.boolean(),\n SERVER_SSL_PORT: v.positiveNum(),\n SERVER_SSL_CERT_PATH: v.string(),\n\n // pool\n POOL_MIN_WORKERS: v.nonNegativeNum(),\n POOL_MAX_WORKERS: v.nonNegativeNum(),\n POOL_WORK_LIMIT: v.positiveNum(),\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\n POOL_BENCHMARKING: v.boolean(),\n\n // logger\n LOGGING_LEVEL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' ||\n (!isNaN(parseFloat(value)) &&\n parseFloat(value) >= 0 &&\n parseFloat(value) <= 5),\n (value) => ({\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n LOGGING_FILE: v.string(),\n LOGGING_DEST: v.string(),\n LOGGING_TO_CONSOLE: v.boolean(),\n LOGGING_TO_FILE: v.boolean(),\n\n // ui\n UI_ENABLE: v.boolean(),\n UI_ROUTE: v.string(),\n\n // other\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\n OTHER_NO_LOGO: v.boolean(),\n OTHER_HARD_RESET_PAGE: v.boolean(),\n OTHER_BROWSER_SHELL_MODE: v.boolean(),\n\n // debugger\n DEBUG_ENABLE: v.boolean(),\n DEBUG_HEADLESS: v.boolean(),\n DEBUG_DEVTOOLS: v.boolean(),\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\n DEBUG_DUMPIO: v.boolean(),\n DEBUG_SLOW_MO: v.nonNegativeNum(),\n DEBUG_DEBUGGING_PORT: v.positiveNum()\n});\n\nexport const envs = Config.partial().parse(process.env);\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { appendFile, existsSync, mkdirSync } from 'fs';\n\n// The available colors\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\n\n// The default logging config\nlet logging = {\n // Flags for logging status\n toConsole: true,\n toFile: false,\n pathCreated: false,\n // Log levels\n levelsDesc: [\n {\n title: 'error',\n color: colors[0]\n },\n {\n title: 'warning',\n color: colors[1]\n },\n {\n title: 'notice',\n color: colors[2]\n },\n {\n title: 'verbose',\n color: colors[3]\n },\n {\n title: 'benchmark',\n color: colors[4]\n }\n ],\n // Log listeners\n listeners: []\n};\n\n/**\n * Logs the provided texts to a file, if file logging is enabled. It creates\n * the necessary directory structure if not already created and appends the\n * content, including an optional prefix, to the specified log file.\n *\n * @param {string[]} texts - An array of texts to be logged.\n * @param {string} prefix - An optional prefix to be added to each log entry.\n */\nconst logToFile = (texts, prefix) => {\n if (!logging.pathCreated) {\n // Create if does not exist\n !existsSync(logging.dest) && mkdirSync(logging.dest);\n\n // We now assume the path is available, e.g. it's the responsibility\n // of the user to create the path with the correct access rights.\n logging.pathCreated = true;\n }\n\n // Add the content to a file\n appendFile(\n `${logging.dest}${logging.file}`,\n [prefix].concat(texts).join(' ') + '\\n',\n (error) => {\n if (error) {\n console.log(`[logger] Unable to write to log file: ${error}`);\n logging.toFile = false;\n }\n }\n );\n};\n\n/**\n * Logs a message. Accepts a variable amount of arguments. Arguments after\n * `level` will be passed directly to console.log, and/or will be joined\n * and appended to the log file.\n *\n * @param {any} args - An array of arguments where the first is the log level\n * and the rest are strings to build a message with.\n */\nexport const log = (...args) => {\n const [newLevel, ...texts] = args;\n\n // Current logging options\n const { levelsDesc, level } = logging;\n\n // Check if log level is within a correct range or is a benchmark log\n if (\n newLevel !== 5 &&\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\n ) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\n );\n }\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Logs an error message with its stack trace. Optionally, a custom message\n * can be provided.\n *\n * @param {number} level - The log level.\n * @param {Error} error - The error object.\n * @param {string} customMessage - An optional custom message to be logged along\n * with the error.\n */\nexport const logWithStack = (newLevel, error, customMessage) => {\n // Get the main message\n const mainMessage = customMessage || error.message;\n\n // Current logging options\n const { level, levelsDesc } = logging;\n\n // Check if log level is within a correct range\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\n return;\n }\n\n // Get rid of the GMT text information\n const newDate = new Date().toString().split('(')[0].trim();\n\n // Create a message's prefix\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\n\n // If the customMessage exists, we want to display the whole stack message\n const stackMessage =\n error.message !== error.stackMessage || error.stackMessage === undefined\n ? error.stack\n : error.stack.split('\\n').slice(1).join('\\n');\n\n // Combine custom message or error message with error stack message\n const texts = [mainMessage, '\\n', stackMessage];\n\n // Log to console\n if (logging.toConsole) {\n console.log.apply(\n undefined,\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\n mainMessage[colors[newLevel - 1]],\n '\\n',\n stackMessage\n ])\n );\n }\n\n // Call available log listeners\n logging.listeners.forEach((fn) => {\n fn(prefix, texts.join(' '));\n });\n\n // Log to file\n if (logging.toFile) {\n logToFile(texts, prefix);\n }\n};\n\n/**\n * Sets the log level to the specified value. Log levels are (0 = no logging,\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\n *\n * @param {number} newLevel - The new log level to be set.\n */\nexport const setLogLevel = (newLevel) => {\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\n logging.level = newLevel;\n }\n};\n\n/**\n * Enables file logging with the specified destination and log file.\n *\n * @param {string} logDest - The destination path for log files.\n * @param {string} logFile - The log file name.\n */\nexport const enableFileLogging = (logDest, logFile) => {\n // Update logging options\n logging = {\n ...logging,\n dest: logDest || logging.dest,\n file: logFile || logging.file,\n toFile: true\n };\n\n if (logging.dest.length === 0) {\n return log(1, '[logger] File logging initialization: no path supplied.');\n }\n\n if (!logging.dest.endsWith('/')) {\n logging.dest += '/';\n }\n};\n\n/**\n * Initializes logging with the specified logging configuration.\n *\n * @param {Object} loggingOptions - The logging configuration object.\n */\nexport const initLogging = (loggingOptions) => {\n // Set all the logging options on our logging module object\n for (const [key, value] of Object.entries(loggingOptions)) {\n logging[key] = value;\n }\n\n // Set the log level\n setLogLevel(loggingOptions && parseInt(loggingOptions.level));\n\n // Set the log file path and name\n if (loggingOptions && loggingOptions.dest && loggingOptions.toFile) {\n enableFileLogging(\n loggingOptions.dest,\n loggingOptions.file || 'highcharts-export-server.log'\n );\n }\n};\n\n/**\n * Adds a listener function to the logging system.\n *\n * @param {function} fn - The listener function to be added.\n */\nexport const listen = (fn) => {\n logging.listeners.push(fn);\n};\n\nexport default {\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n initLogging,\n listen\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport { join } from 'path';\nimport { fileURLToPath } from 'url';\n\nimport { defaultConfig } from '../lib/schemas/config.js';\nimport { log, logWithStack } from './logger.js';\n\nconst MAX_BACKOFF_ATTEMPTS = 6;\n\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\n\n/**\n * Clears and standardizes text by replacing multiple consecutive whitespace\n * characters with a single space and trimming any leading or trailing\n * whitespace.\n *\n * @param {string} text - The input text to be cleared.\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\n * multiple consecutive whitespace characters.\n * @param {string} [replacer=' '] - The string used to replace multiple\n * consecutive whitespace characters.\n *\n * @returns {string} - The cleared and standardized text.\n */\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\n text.replaceAll(rule, replacer).trim();\n\n/**\n * Implements an exponential backoff strategy for retrying a function until\n * a certain number of attempts are reached.\n *\n * @param {Function} fn - The function to be retried.\n * @param {number} [attempt=0] - The current attempt number.\n * @param {...any} args - Arguments to be passed to the function.\n *\n * @returns {Promise} - A promise that resolves to the result of the function\n * if successful.\n *\n * @throws {Error} - Throws an error if the maximum number of attempts\n * is reached.\n */\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\n try {\n // Try to call the function\n return await fn(...args);\n } catch (error) {\n // Calculate delay in ms\n const delayInMs = 2 ** attempt * 1000;\n\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\n throw error;\n }\n\n // Wait given amount of time\n await new Promise((response) => setTimeout(response, delayInMs));\n log(\n 3,\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\n );\n\n // Try again\n return expBackoff(fn, attempt, ...args);\n }\n};\n\n/**\n * Fixes the export type based on MIME types and file extensions.\n *\n * @param {string} type - The original export type.\n * @param {string} outfile - The file path or name.\n *\n * @returns {string} - The corrected export type.\n */\nexport const fixType = (type, outfile) => {\n // MIME types\n const mimeTypes = {\n 'image/png': 'png',\n 'image/jpeg': 'jpeg',\n 'application/pdf': 'pdf',\n 'image/svg+xml': 'svg'\n };\n\n // Formats\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\n\n // Check if type and outfile's extensions are the same\n if (outfile) {\n const outType = outfile.split('.').pop();\n\n if (outType === 'jpg') {\n type = 'jpeg';\n } else if (formats.includes(outType) && type !== outType) {\n type = outType;\n }\n }\n\n // Return a correct type\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\n};\n\n/**\n * Handles and validates resources for export.\n *\n * @param {Object|string} resources - The resources to be handled. Can be either\n * a JSON object, stringified JSON or a path to a JSON file.\n * @param {boolean} allowFileResources - Whether to allow loading resources from\n * files.\n *\n * @returns {Object|undefined} - The handled resources or undefined if no valid\n * resources are found.\n */\nexport const handleResources = (resources = false, allowFileResources) => {\n const allowedProps = ['js', 'css', 'files'];\n\n let handledResources = resources;\n let correctResources = false;\n\n // Try to load resources from a file\n if (allowFileResources && resources.endsWith('.json')) {\n try {\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\n } catch (error) {\n return logWithStack(2, error, `[cli] No resources found.`);\n }\n } else {\n // Try to get JSON\n handledResources = isCorrectJSON(resources);\n\n // Get rid of the files section\n if (handledResources && !allowFileResources) {\n delete handledResources.files;\n }\n }\n\n // Filter from unnecessary properties\n for (const propName in handledResources) {\n if (!allowedProps.includes(propName)) {\n delete handledResources[propName];\n } else if (!correctResources) {\n correctResources = true;\n }\n }\n\n // Check if at least one of allowed properties is present\n if (!correctResources) {\n return log(3, `[cli] No resources found.`);\n }\n\n // Handle files section\n if (handledResources.files) {\n handledResources.files = handledResources.files.map((item) => item.trim());\n if (!handledResources.files || handledResources.files.length <= 0) {\n delete handledResources.files;\n }\n }\n\n // Return resources\n return handledResources;\n};\n\n/**\n * Validates and parses JSON data. Checks if provided data is or can\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\n *\n * @param {Object|string} data - The JSON data to be validated and parsed.\n * @param {boolean} toString - Whether to return a stringified representation\n * of the parsed JSON.\n *\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\n * or false if validation fails.\n */\nexport function isCorrectJSON(data, toString) {\n try {\n // Get the string representation if not already before parsing\n const parsedData = JSON.parse(\n typeof data !== 'string' ? JSON.stringify(data) : data\n );\n\n // Return a stringified representation of a JSON if required\n if (typeof parsedData !== 'string' && toString) {\n return JSON.stringify(parsedData);\n }\n\n // Return a JSON\n return parsedData;\n } catch {\n return false;\n }\n}\n\n/**\n * Checks if the given item is an object.\n *\n * @param {any} item - The item to be checked.\n *\n * @returns {boolean} - True if the item is an object, false otherwise.\n */\nexport const isObject = (item) =>\n typeof item === 'object' && !Array.isArray(item) && item !== null;\n\n/**\n * Checks if the given object is empty.\n *\n * @param {Object} item - The object to be checked.\n *\n * @returns {boolean} - True if the object is empty, false otherwise.\n */\nexport const isObjectEmpty = (item) =>\n typeof item === 'object' &&\n !Array.isArray(item) &&\n item !== null &&\n Object.keys(item).length === 0;\n\n/**\n * Checks if a private IP range URL is found in the given string.\n *\n * @param {string} item - The string to be checked for a private IP range URL.\n *\n * @returns {boolean} - True if a private IP range URL is found, false\n * otherwise.\n */\nexport const isPrivateRangeUrlFound = (item) => {\n const regexPatterns = [\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\n ];\n\n return regexPatterns.some((pattern) => pattern.test(item));\n};\n\n/**\n * Creates a deep copy of the given object or array.\n *\n * @param {Object|Array} obj - The object or array to be deeply copied.\n *\n * @returns {Object|Array} - The deep copy of the provided object or array.\n */\nexport const deepCopy = (obj) => {\n if (obj === null || typeof obj !== 'object') {\n return obj;\n }\n\n const copy = Array.isArray(obj) ? [] : {};\n\n for (const key in obj) {\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\n copy[key] = deepCopy(obj[key]);\n }\n }\n\n return copy;\n};\n\n/**\n * Converts the provided options object to a JSON-formatted string with the\n * option to preserve functions.\n *\n * @param {Object} options - The options object to be converted to a string.\n * @param {boolean} allowFunctions - If set to true, functions are preserved\n * in the output.\n *\n * @returns {string} - The JSON-formatted string representing the options.\n */\nexport const optionsStringify = (options, allowFunctions) => {\n const replacerCallback = (name, value) => {\n if (typeof value === 'string') {\n value = value.trim();\n\n // If allowFunctions is set to true, preserve functions\n if (\n (value.startsWith('function(') || value.startsWith('function (')) &&\n value.endsWith('}')\n ) {\n value = allowFunctions\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : undefined;\n }\n }\n\n return typeof value === 'function'\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\n : value;\n };\n\n // Stringify options and if required, replace special functions marks\n return JSON.stringify(options, replacerCallback).replaceAll(\n /\"EXP_FUN|EXP_FUN\"/g,\n ''\n );\n};\n\n/**\n * Prints the Highcharts Export Server logo and version information.\n *\n * @param {boolean} noLogo - If true, only prints version information without\n * the logo.\n */\nexport const printLogo = (noLogo) => {\n // Get package version either from env or from package.json\n const packageVersion = JSON.parse(\n readFileSync(join(__dirname, 'package.json'))\n ).version;\n\n // Print text only\n if (noLogo) {\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\n return;\n }\n\n // Print the logo\n console.log(\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\n `v${packageVersion}\\n`.bold\n );\n};\n\n/**\n * Prints the usage information for CLI arguments. If required, it can list\n * properties recursively\n */\nexport function printUsage() {\n const pad = 48;\n const readme = 'https://github.com/highcharts/node-export-server#readme';\n\n // Display readme information\n console.log(\n '\\nUsage of CLI arguments:'.bold,\n '\\n------',\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\n );\n\n const cycleCategories = (options) => {\n for (const [name, option] of Object.entries(options)) {\n // If category has more levels, go further\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\n cycleCategories(option);\n } else {\n let descName = ` --${option.cliName || name} ${\n ('<' + option.type + '>').green\n } `;\n if (descName.length < pad) {\n for (let i = descName.length; i < pad; i++) {\n descName += '.';\n }\n }\n\n // Display correctly aligned messages\n console.log(\n descName,\n option.description,\n `[Default: ${option.value.toString().bold}]`.blue\n );\n }\n }\n };\n\n // Cycle through options of each categories and display the usage info\n Object.keys(defaultConfig).forEach((category) => {\n // Only puppeteer and highcharts categories cannot be configured through CLI\n if (!['puppeteer', 'highcharts'].includes(category)) {\n console.log(`\\n${category.toUpperCase()}`.red);\n cycleCategories(defaultConfig[category]);\n }\n });\n console.log('\\n');\n}\n\n/**\n * Rounds a number to the specified precision.\n *\n * @param {number} value - The number to be rounded.\n * @param {number} precision - The number of decimal places to round to.\n *\n * @returns {number} - The rounded number.\n */\nexport const roundNumber = (value, precision = 1) => {\n const multiplier = Math.pow(10, precision || 0);\n return Math.round(+value * multiplier) / multiplier;\n};\n\n/**\n * Converts a value to a boolean.\n *\n * @param {any} item - The value to be converted to a boolean.\n *\n * @returns {boolean} - The boolean representation of the input value.\n */\nexport const toBoolean = (item) =>\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\n ? false\n : !!item;\n\n/**\n * Wraps custom code to execute it safely.\n *\n * @param {string} customCode - The custom code to be wrapped.\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\n *\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\n * fails.\n */\nexport const wrapAround = (customCode, allowFileResources) => {\n if (customCode && typeof customCode === 'string') {\n customCode = customCode.trim();\n\n if (customCode.endsWith('.js')) {\n return allowFileResources\n ? wrapAround(readFileSync(customCode, 'utf8'))\n : false;\n } else if (\n customCode.startsWith('function()') ||\n customCode.startsWith('function ()') ||\n customCode.startsWith('()=>') ||\n customCode.startsWith('() =>')\n ) {\n return `(${customCode})()`;\n }\n return customCode.replace(/;$/, '');\n }\n};\n\n/**\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\n *\n * @returns {function(): number} - A function to calculate the elapsed time\n * in milliseconds.\n */\nexport const measureTime = () => {\n const start = process.hrtime.bigint();\n return () => Number(process.hrtime.bigint() - start) / 1000000;\n};\n\nexport default {\n __dirname,\n clearText,\n expBackoff,\n fixType,\n handleResources,\n isCorrectJSON,\n isObject,\n isObjectEmpty,\n isPrivateRangeUrlFound,\n optionsStringify,\n printLogo,\n printUsage,\n roundNumber,\n toBoolean,\n wrapAround,\n measureTime\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\n\nimport prompts from 'prompts';\n\nimport {\n absoluteProps,\n defaultConfig,\n nestedArgs,\n promptsConfig\n} from './schemas/config.js';\nimport { envs } from './envs.js';\nimport { log, logWithStack } from './logger.js';\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\n\nlet generalOptions = {};\n\n/**\n * Retrieves and returns the general options for the export process.\n *\n * @returns {Object} The general options object.\n */\nexport const getOptions = () => generalOptions;\n\n/**\n * Initializes and sets the general options for the server instace, keeping\n * the principle of the options load priority. It accepts optional userOptions\n * and args from the CLI.\n *\n * @param {Object} userOptions - User-provided options for customization.\n * @param {Array} args - Command-line arguments for additional configuration\n * (CLI usage).\n *\n * @returns {Object} The updated general options object.\n */\nexport const setOptions = (userOptions, args) => {\n // Only for the CLI usage\n if (args?.length) {\n // Get the additional options from the custom JSON file\n generalOptions = loadConfigFile(args);\n }\n\n // Update the default config with a correct option values\n updateDefaultConfig(defaultConfig, generalOptions);\n\n // Set values for server's options and returns them\n generalOptions = initOptions(defaultConfig);\n\n // Apply user options if there are any\n if (userOptions) {\n // Merge user options\n generalOptions = mergeConfigOptions(\n generalOptions,\n userOptions,\n absoluteProps\n );\n }\n\n // Only for the CLI usage\n if (args?.length) {\n // Pair provided arguments\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\n }\n\n // Return final general options\n return generalOptions;\n};\n\n/**\n * Allows manual configuration based on specified prompts and saves\n * the configuration to a file.\n *\n * @param {string} configFileName - The name of the configuration file.\n *\n * @returns {Promise} A Promise that resolves to true once the manual\n * configuration is completed and saved.\n */\nexport const manualConfig = async (configFileName) => {\n // Prepare a config object\n let configFile = {};\n\n // Check if provided config file exists\n if (existsSync(configFileName)) {\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\n }\n\n // Question about a configuration category\n const onSubmit = async (p, categories) => {\n let questionsCounter = 0;\n let allQuestions = [];\n\n // Create a corresponding property in the manualConfig object\n for (const section of categories) {\n // Mark each option with a section\n promptsConfig[section] = promptsConfig[section].map((option) => ({\n ...option,\n section\n }));\n\n // Collect the questions\n allQuestions = [...allQuestions, ...promptsConfig[section]];\n }\n\n await prompts(allQuestions, {\n onSubmit: async (prompt, answer) => {\n // Get the default module scripts\n if (prompt.name === 'moduleScripts') {\n answer = answer.length\n ? answer.map((module) => prompt.choices[module])\n : prompt.choices;\n\n configFile[prompt.section][prompt.name] = answer;\n } else {\n configFile[prompt.section] = recursiveProps(\n Object.assign({}, configFile[prompt.section] || {}),\n prompt.name.split('.'),\n prompt.choices ? prompt.choices[answer] : answer\n );\n }\n\n if (++questionsCounter === allQuestions.length) {\n try {\n await fsPromises.writeFile(\n configFileName,\n JSON.stringify(configFile, null, 2),\n 'utf8'\n );\n } catch (error) {\n logWithStack(\n 1,\n error,\n `[config] An error occurred while creating the ${configFileName} file.`\n );\n }\n return true;\n }\n }\n });\n\n return true;\n };\n\n // Find the categories\n const choices = Object.keys(promptsConfig).map((choice) => ({\n title: `${choice} options`,\n value: choice\n }));\n\n // Category prompt\n return prompts(\n {\n type: 'multiselect',\n name: 'category',\n message: 'Which category do you want to configure?',\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\n instructions: '',\n choices\n },\n { onSubmit }\n );\n};\n\n/**\n * Maps old-structured (PhantomJS) options to a new configuration format\n * (Puppeteer).\n *\n * @param {Object} oldOptions - Old-structured options to be mapped.\n *\n * @returns {Object} New options structured based on the defined nestedArgs\n * mapping.\n */\nexport const mapToNewConfig = (oldOptions) => {\n const newOptions = {};\n // Cycle through old-structured options\n for (const [key, value] of Object.entries(oldOptions)) {\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\n\n // Populate object in correct properties levels\n propertiesChain.reduce(\n (obj, prop, index) =>\n (obj[prop] =\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\n newOptions\n );\n }\n return newOptions;\n};\n\n/**\n * Merges two sets of configuration options, considering absolute properties.\n *\n * @param {Object} options - Original configuration options.\n * @param {Object} newOptions - New configuration options to be merged.\n * @param {Array} absoluteProps - List of properties that should\n * not be recursively merged.\n *\n * @returns {Object} Merged configuration options.\n */\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\n const mergedOptions = deepCopy(options);\n\n for (const [key, value] of Object.entries(newOptions)) {\n mergedOptions[key] =\n isObject(value) &&\n !absoluteProps.includes(key) &&\n mergedOptions[key] !== undefined\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\n : value !== undefined\n ? value\n : mergedOptions[key];\n }\n\n return mergedOptions;\n};\n\n/**\n * Initializes export settings based on provided exportOptions\n * and generalOptions.\n *\n * @param {Object} exportOptions - Options specific to the export process.\n * @param {Object} generalOptions - General configuration options.\n *\n * @returns {Object} Initialized export settings.\n */\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\n let options = {};\n\n if (exportOptions.svg) {\n options = deepCopy(generalOptions);\n options.export.type = exportOptions.type || exportOptions.export.type;\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\n options.export.outfile =\n exportOptions.outfile || exportOptions.export.outfile;\n options.payload = {\n svg: exportOptions.svg\n };\n } else {\n options = mergeConfigOptions(\n generalOptions,\n exportOptions,\n // Omit going down recursively with the belows\n absoluteProps\n );\n }\n\n options.export.outfile =\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\n return options;\n};\n\n/**\n * Loads additional configuration from a specified file using\n * the --loadConfig option.\n *\n * @param {Array} args - Command-line arguments to check for\n * the --loadConfig option.\n *\n * @returns {Object} Additional configuration loaded from the specified file,\n * or an empty object if not found or invalid.\n */\nfunction loadConfigFile(args) {\n // Check if the --loadConfig option was used\n const configIndex = args.findIndex(\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\n );\n\n // Check if the --loadConfig has a value\n if (configIndex > -1 && args[configIndex + 1]) {\n const fileName = args[configIndex + 1];\n try {\n // Check if an additional config file is a correct JSON file\n if (fileName && fileName.endsWith('.json')) {\n // Load an optional custom JSON config file\n return JSON.parse(readFileSync(fileName));\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[config] Unable to load the configuration from the ${fileName} file.`\n );\n }\n }\n\n // No additional options to return\n return {};\n}\n\n/**\n * Updates the default configuration object with values from a custom object\n * and environment variables.\n *\n * @param {Object} configObj - The default configuration object.\n * @param {Object} customObj - Custom configuration object to override defaults.\n * @param {string} propChain - Property chain for tracking nested properties\n * during recursion.\n */\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\n Object.keys(configObj).forEach((key) => {\n const entry = configObj[key];\n const customValue = customObj && customObj[key];\n\n if (typeof entry.value === 'undefined') {\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\n } else {\n // If a value from a custom JSON exists, it take precedence\n if (customValue !== undefined) {\n entry.value = customValue;\n }\n\n // If a value from an env variable exists, it take precedence\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\n entry.value = envs[entry.envLink];\n }\n }\n });\n}\n\n/**\n * Initializes options object based on provided items, setting values from\n * nested properties recursively.\n *\n * @param {Object} items - Configuration items to be used for initializing\n * options.\n *\n * @returns {Object} Initialized options object.\n */\nfunction initOptions(items) {\n let options = {};\n for (const [name, item] of Object.entries(items)) {\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\n ? item.value\n : initOptions(item);\n }\n return options;\n}\n\n/**\n * Pairs argument values with corresponding options in the configuration,\n * updating the options object.\n *\n * @param {Object} options - Configuration options object to be updated.\n * @param {Array} args - Command-line arguments containing values for specific\n * options.\n * @param {Object} defaultConfig - Default configuration object for reference.\n *\n * @returns {Object} Updated options object.\n */\nfunction pairArgumentValue(options, args, defaultConfig) {\n let showUsage = false;\n for (let i = 0; i < args.length; i++) {\n const option = args[i].replace(/-/g, '');\n\n // Find the right place for property's value\n const propertiesChain = nestedArgs[option]\n ? nestedArgs[option].split('.')\n : [];\n\n // Get the correct type for CLI args which are passed as strings\n let argumentType;\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n argumentType = obj[prop].type;\n }\n return obj[prop];\n }, defaultConfig);\n\n propertiesChain.reduce((obj, prop, index) => {\n if (propertiesChain.length - 1 === index) {\n // Finds an option and set a corresponding value\n if (typeof obj[prop] !== 'undefined') {\n if (args[++i]) {\n if (argumentType === 'boolean') {\n obj[prop] = toBoolean(args[i]);\n } else if (argumentType === 'number') {\n obj[prop] = +args[i];\n } else if (argumentType.indexOf(']') >= 0) {\n obj[prop] = args[i].split(',');\n } else {\n obj[prop] = args[i];\n }\n } else {\n log(\n 2,\n `[config] Missing value for the '${option}' argument. Using the default value.`\n );\n showUsage = true;\n }\n }\n }\n return obj[prop];\n }, options);\n }\n\n // Display the usage for the reference if needed\n if (showUsage) {\n printUsage(defaultConfig);\n }\n\n return options;\n}\n\n/**\n * Recursively updates properties in an object based on nested names and assigns\n * the final value.\n *\n * @param {Object} objectToUpdate - The object to be updated.\n * @param {Array} nestedNames - Array of nested property names.\n * @param {any} value - The final value to be assigned.\n *\n * @returns {Object} Updated object with assigned values.\n */\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\n while (nestedNames.length > 1) {\n const propName = nestedNames.shift();\n\n // Create a property in object if it doesn't exist\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\n objectToUpdate[propName] = {};\n }\n\n // Call function again if there still names to go\n objectToUpdate[propName] = recursiveProps(\n Object.assign({}, objectToUpdate[propName]),\n nestedNames,\n value\n );\n\n return objectToUpdate;\n }\n\n // Assign the final value\n objectToUpdate[nestedNames[0]] = value;\n return objectToUpdate;\n}\n\nexport default {\n getOptions,\n setOptions,\n manualConfig,\n mapToNewConfig,\n mergeConfigOptions,\n initExportSettings\n};\n","/**\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\n */\n\nimport http from 'http';\nimport https from 'https';\n\n/**\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\n *\n * @param {string} url - The URL to determine the protocol.\n *\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\n */\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\n\n/**\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to fetch data from.\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object\n * with added 'text' property or rejecting with an error.\n */\nasync function fetch(url, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n\n protocol\n .get(url, requestOptions, (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 .on('error', (error) => {\n reject(error);\n });\n });\n}\n\n/**\n * Sends a POST request to the specified URL with the provided JSON body using\n * either HTTP or HTTPS protocol.\n *\n * @param {string} url - The URL to send the POST request to.\n * @param {Object} body - The JSON body to include in the POST request\n * (optional, default is an empty object).\n * @param {Object} requestOptions - Options for the HTTP request (optional).\n *\n * @returns {Promise} Promise resolving to the HTTP response object with\n * added 'text' property or rejecting with an error.\n */\nasync function post(url, body = {}, requestOptions = {}) {\n return new Promise((resolve, reject) => {\n const protocol = getProtocol(url);\n const data = JSON.stringify(body);\n\n // Set default headers and merge with requestOptions\n const options = Object.assign(\n {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'Content-Length': data.length\n }\n },\n requestOptions\n );\n\n const req = protocol\n .request(url, options, (res) => {\n let responseData = '';\n\n // A chunk of data has been received.\n res.on('data', (chunk) => {\n responseData += chunk;\n });\n\n // The whole response has been received.\n res.on('end', () => {\n try {\n res.text = responseData;\n resolve(res);\n } catch (error) {\n reject(error);\n }\n });\n })\n .on('error', (error) => {\n reject(error);\n });\n\n // Write the request body and end the request.\n req.write(data);\n req.end();\n });\n}\n\nexport default fetch;\nexport { fetch, post };\n","class ExportError extends Error {\n constructor(message) {\n super();\n this.message = message;\n this.stackMessage = message;\n }\n\n setError(error) {\n this.error = error;\n if (error.name) {\n this.name = error.name;\n }\n if (error.statusCode) {\n this.statusCode = error.statusCode;\n }\n if (error.stack) {\n this.stackMessage = error.message;\n this.stack = error.stack;\n }\n return this;\n }\n}\n\nexport default ExportError;\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// The cache manager manages the Highcharts library and its dependencies.\n// The cache itself is stored in .cache, and is checked by the config system\n// before starting the service\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\nimport { join } from 'path';\n\nimport { HttpsProxyAgent } from 'https-proxy-agent';\n\nimport { getOptions } from './config.js';\nimport { envs } from './envs.js';\nimport { fetch } from './fetch.js';\nimport { log } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\nconst cache = {\n cdnURL: 'https://code.highcharts.com/',\n activeManifest: {},\n sources: '',\n hcVersion: ''\n};\n\n/**\n * Extracts and caches the Highcharts version from the sources string.\n *\n * @returns {string} The extracted Highcharts version.\n */\nexport const extractVersion = (cache) => {\n return cache.sources\n .substring(0, cache.sources.indexOf('*/'))\n .replace('/*', '')\n .replace('*/', '')\n .replace(/\\n/g, '')\n .trim();\n};\n\n/**\n * Extracts the Highcharts module name based on the scriptPath.\n */\nexport const extractModuleName = (scriptPath) => {\n return scriptPath.replace(\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\n ''\n );\n};\n\n/**\n * Saves the provided configuration and fetched modules to the cache manifest\n * file.\n *\n * @param {object} config - Highcharts-related configuration object.\n * @param {object} fetchedModules - An object that contains mapped names of\n * fetched Highcharts modules to use.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\n * the cache manifest.\n */\nexport const saveConfigToManifest = async (config, fetchedModules) => {\n const newManifest = {\n version: config.version,\n modules: fetchedModules || {}\n };\n\n // Update cache object with the current modules\n cache.activeManifest = newManifest;\n\n log(3, '[cache] Writing a new manifest.');\n try {\n writeFileSync(\n join(__dirname, config.cachePath, 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\n error\n );\n }\n};\n\n/**\n * Fetches a single script and updates the fetchedModules accordingly.\n *\n * @param {string} script - A path to script to get.\n * @param {Object} requestOptions - Additional options for the proxy agent\n * to use for a request.\n * @param {Object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\n * thrown. This should be used only for the core scripts.\n *\n * @returns {Promise} A Promise resolving to the text representation\n * of the fetched script.\n *\n * @throws {ExportError} Throws an ExportError if there is a problem with\n * fetching the script.\n */\nexport const fetchAndProcessScript = async (\n script,\n requestOptions,\n fetchedModules,\n shouldThrowError = false\n) => {\n // Get rid of the .js from the custom strings\n if (script.endsWith('.js')) {\n script = script.substring(0, script.length - 3);\n }\n\n log(4, `[cache] Fetching script - ${script}.js`);\n\n // Fetch the script\n const response = await fetch(`${script}.js`, requestOptions);\n\n // If OK, return its text representation\n if (response.statusCode === 200 && typeof response.text == 'string') {\n if (fetchedModules) {\n const moduleName = extractModuleName(script);\n fetchedModules[moduleName] = 1;\n }\n\n return response.text;\n }\n\n if (shouldThrowError) {\n throw new ExportError(\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\n ).setError(response);\n } else {\n log(\n 2,\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\n );\n }\n\n return '';\n};\n\n/**\n * Fetches Highcharts scripts and customScripts from the given CDNs.\n *\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\n * @param {string} customScripts - Array of custom script paths to fetch\n * (full URLs).\n * @param {object} proxyOptions - Options for the proxy agent to use for\n * a request.\n * @param {object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n *\n * @returns {Promise} The fetched scripts content joined.\n */\nexport const fetchScripts = async (\n coreScripts,\n moduleScripts,\n customScripts,\n proxyOptions,\n fetchedModules\n) => {\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = proxyOptions.host;\n const proxyPort = proxyOptions.port;\n\n // Try to create a Proxy Agent\n if (proxyHost && proxyPort) {\n try {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: proxyPort\n });\n } catch (error) {\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\n error\n );\n }\n }\n\n // If exists, add proxy agent to request options\n const requestOptions = proxyAgent\n ? {\n agent: proxyAgent,\n timeout: envs.SERVER_PROXY_TIMEOUT\n }\n : {};\n\n const allFetchPromises = [\n ...coreScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\n ),\n ...moduleScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\n ),\n ...customScripts.map((script) =>\n fetchAndProcessScript(`${script}`, requestOptions)\n )\n ];\n\n const fetchedScripts = await Promise.all(allFetchPromises);\n return fetchedScripts.join(';\\n');\n};\n\n/**\n * Updates the local cache with Highcharts scripts and their versions.\n *\n * @param {Object} options - Object containing all options.\n * @param {string} sourcePath - The path to the source file in the cache.\n *\n * @returns {Promise} A Promise resolving to an object representing\n * the fetched modules.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * the local Highcharts cache.\n */\nexport const updateCache = async (\n highchartsOptions,\n proxyOptions,\n sourcePath\n) => {\n const version = highchartsOptions.version;\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\n\n log(\n 3,\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\n );\n\n const fetchedModules = {};\n try {\n cache.sources = await fetchScripts(\n [\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\n ],\n [\n ...highchartsOptions.moduleScripts.map((m) =>\n m === 'map'\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\n : `${cdnURL}${hcVersion}modules/${m}`\n ),\n ...highchartsOptions.indicatorScripts.map(\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\n )\n ],\n highchartsOptions.customScripts,\n proxyOptions,\n fetchedModules\n );\n\n cache.hcVersion = extractVersion(cache);\n\n // Save the fetched modules into caches' source JSON\n writeFileSync(sourcePath, cache.sources);\n return fetchedModules;\n } catch (error) {\n throw new ExportError(\n '[cache] Unable to update the local Highcharts cache.'\n ).setError(error);\n }\n};\n\n/**\n * Updates the Highcharts version in the applied configuration and checks\n * the cache for the new version.\n *\n * @param {string} newVersion - The new Highcharts version to be applied.\n *\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\n * configuration with the new version, or false if no applied configuration\n * exists.\n */\nexport const updateVersion = async (newVersion) => {\n const options = getOptions();\n if (options?.highcharts) {\n options.highcharts.version = newVersion;\n }\n await checkAndUpdateCache(options);\n};\n\n/**\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\n * and loads the sources.\n *\n * @param {Object} options - Object containing all options.\n *\n * @returns {Promise} A Promise that resolves once the cache is checked\n * and updated.\n *\n * @throws {ExportError} Throws an ExportError if there is an issue updating\n * or reading the cache.\n */\nexport const checkAndUpdateCache = async (options) => {\n const { highcharts, server } = options;\n const cachePath = join(__dirname, highcharts.cachePath);\n\n let fetchedModules;\n // Prepare paths to manifest and sources from the .cache folder\n const manifestPath = join(cachePath, 'manifest.json');\n const sourcePath = join(cachePath, 'sources.js');\n\n // Create the cache destination if it doesn't exist already\n !existsSync(cachePath) && mkdirSync(cachePath);\n\n // Fetch all the scripts either if manifest.json does not exist\n // or if the forceFetch option is enabled\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n let requestUpdate = false;\n\n // Read the manifest JSON\n const manifest = JSON.parse(readFileSync(manifestPath));\n\n // Check if the modules is an array, if so, we rewrite it to a map to make\n // it easier to resolve modules.\n if (manifest.modules && Array.isArray(manifest.modules)) {\n const moduleMap = {};\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\n manifest.modules = moduleMap;\n }\n\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\n const numberOfModules =\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\n\n // Compare the loaded highcharts config with the contents in cache.\n // If there are changes, fetch requested modules and products,\n // and bake them into a giant blob. Save the blob.\n if (manifest.version !== highcharts.version) {\n log(\n 2,\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\n );\n requestUpdate = true;\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\n log(\n 2,\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\n );\n requestUpdate = true;\n } else {\n // Check each module, if anything is missing refetch everything\n requestUpdate = (moduleScripts || []).some((moduleName) => {\n if (!manifest.modules[moduleName]) {\n log(\n 2,\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\n );\n return true;\n }\n });\n }\n\n if (requestUpdate) {\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\n } else {\n log(3, '[cache] Dependency cache is up to date, proceeding.');\n\n // Load the sources\n cache.sources = readFileSync(sourcePath, 'utf8');\n\n // Get current modules map\n fetchedModules = manifest.modules;\n\n cache.hcVersion = extractVersion(cache);\n }\n }\n\n // Finally, save the new manifest, which is basically our current config\n // in a slightly different format\n await saveConfigToManifest(highcharts, fetchedModules);\n};\n\nexport const getCachePath = () =>\n join(__dirname, getOptions().highcharts.cachePath);\n\nexport const getCache = () => cache;\n\nexport const highcharts = () => cache.sources;\n\nexport const version = () => cache.hcVersion;\n\nexport default {\n checkAndUpdateCache,\n getCachePath,\n updateVersion,\n getCache,\n highcharts,\n version\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/* eslint-disable no-undef */\n\n/**\n * Setting the animObject. Called when initing the page.\n */\nexport function setupHighcharts() {\n Highcharts.animObject = function () {\n return { duration: 0 };\n };\n}\n\n/**\n * Creates the actual chart.\n *\n * @param {object} chartOptions - The options for the Highcharts chart.\n * @param {object} options - The export options.\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\n */\nexport async function triggerExport(chartOptions, options, displayErrors) {\n // Display errors flag taken from chart options nad debugger module\n window._displayErrors = displayErrors;\n\n // Get required functions\n const { getOptions, merge, setOptions, wrap } = Highcharts;\n\n // Create a separate object for a potential setOptions usages in order to\n // prevent from polluting other exports that can happen on the same page\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\n\n // Trigger custom code\n if (options.customLogic.customCode) {\n new Function(options.customLogic.customCode)();\n }\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 // 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 Highcharts[options.export.constr || 'chart'](\n 'container',\n finalOptions,\n finalCallback\n );\n\n // Get the current global options\n const defaultOptions = getOptions();\n\n // Clear it just in case (e.g. the setOptions was used in the customCode)\n for (const prop in defaultOptions) {\n if (typeof defaultOptions[prop] !== 'function') {\n delete defaultOptions[prop];\n }\n }\n\n // Set the default options back\n setOptions(Highcharts.setOptionsObj);\n\n // Empty the custom global options object\n Highcharts.setOptionsObj = {};\n}\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync } from 'fs';\nimport path from 'path';\n\nimport puppeteer from 'puppeteer';\n\nimport { getCachePath } from './cache.js';\nimport { getOptions } from './config.js';\nimport { setupHighcharts } from './highcharts.js';\nimport { log, logWithStack } from './logger.js';\nimport { __dirname } from './utils.js';\n\nimport ExportError from './errors/ExportError.js';\n\n// Get the template for the page\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\n\nlet browser;\n\n/**\n * Retrieves the existing Puppeteer browser instance.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if no valid browser has been\n * created.\n */\nexport function get() {\n if (!browser) {\n throw new ExportError('[browser] No valid browser has been created.');\n }\n return browser;\n}\n\n/**\n * Creates a Puppeteer browser instance with the specified arguments.\n *\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\n * instance are reached, or if no browser instance is found after retries.\n */\nexport async function create(puppeteerArgs) {\n // Get debug and other options\n const { debug, other } = getOptions();\n\n // Get the debug options\n const { enable: enabledDebug, ...debugOptions } = debug;\n\n const launchOptions = {\n headless: other.browserShellMode ? 'shell' : true,\n userDataDir: './tmp/',\n args: puppeteerArgs,\n handleSIGINT: false,\n handleSIGTERM: false,\n handleSIGHUP: false,\n waitForInitialPage: false,\n defaultViewport: null,\n ...(enabledDebug && debugOptions)\n };\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\n );\n browser = await puppeteer.launch(launchOptions);\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Failed to launch a browser instance.'\n );\n\n // Retry to launch browser until reaching max attempts\n if (tryCount < 25) {\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n throw error;\n }\n }\n };\n\n try {\n await open();\n\n // Shell mode inform\n if (launchOptions.headless === 'shell') {\n log(3, `[browser] Launched browser in shell mode.`);\n }\n\n // Debug mode inform\n if (enabledDebug) {\n log(3, `[browser] Launched browser in debug mode.`);\n }\n } catch (error) {\n throw new ExportError(\n '[browser] Maximum retries to open a browser instance reached.'\n ).setError(error);\n }\n\n if (!browser) {\n throw new ExportError('[browser] Cannot find a browser to open.');\n }\n }\n\n // Return a browser promise\n return browser;\n}\n\n/**\n * Closes the Puppeteer browser instance if it is connected.\n *\n * @returns {Promise} A Promise resolving to true after the browser\n * is closed.\n */\nexport async function close() {\n // Close the browser when connnected\n if (browser?.connected) {\n await browser.close();\n }\n log(4, '[browser] Closed the browser.');\n}\n\n/**\n * Creates a new Puppeteer Page within an existing browser instance.\n *\n * If the browser instance is not available, returns false.\n *\n * The function creates a new page, disables caching, sets content using\n * setPageContent(), and returns the created Puppeteer Page.\n *\n * @returns {(boolean|object)} Returns false if the browser instance is not\n * available, or a Puppeteer Page object representing the newly created page.\n */\nexport async function newPage() {\n if (!browser) {\n return false;\n }\n\n // Create a page\n const page = await browser.newPage();\n\n // Disable cache\n await page.setCacheEnabled(false);\n\n // Set the content\n await setPageContent(page);\n\n // Set page events\n setPageEvents(page);\n\n return page;\n}\n\n/**\n * Clears the content of a Puppeteer Page based on the specified mode.\n *\n * @param {Object} page - The Puppeteer Page object to be cleared.\n * @param {boolean} hardReset - A flag indicating the type of clearing\n * to be performed. If true, navigates to 'about:blank' and resets content\n * and scripts. If false, clears the body content by setting a predefined HTML\n * structure.\n *\n * @throws {Error} Logs thrown error if clearing the page content fails.\n */\nexport async function clearPage(page, hardReset = false) {\n try {\n if (!page.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 }\n } catch (error) {\n logWithStack(\n 2,\n error,\n '[browser] Could not clear the content of the page.'\n );\n }\n}\n\n/**\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\n * options.\n *\n * @param {Object} page - The Puppeteer Page object to which resources will be\n * added.\n * @param {Object} options - All options and configuration.\n *\n * @returns {Promise>} - Promise resolving to an array of injected\n * resources.\n */\nexport async function addPageResources(page, options) {\n // Injected resources array\n const injectedResources = [];\n\n // Use resources\n const resources = options.customLogic.resources;\n if (resources) {\n const injectedJs = [];\n\n // Load custom JS code\n if (resources.js) {\n injectedJs.push({\n content: resources.js\n });\n }\n\n // Load scripts from all custom files\n if (resources.files) {\n for (const file of resources.files) {\n const isLocal = !file.startsWith('http') ? true : false;\n\n // Add each custom script from resources' files\n injectedJs.push(\n isLocal\n ? {\n content: readFileSync(file, 'utf8')\n }\n : {\n url: file\n }\n );\n }\n }\n\n for (const jsResource of injectedJs) {\n try {\n injectedResources.push(await page.addScriptTag(jsResource));\n } catch (error) {\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\n }\n }\n injectedJs.length = 0;\n\n // Load CSS\n const injectedCss = [];\n if (resources.css) {\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\n if (cssImports) {\n // Handle css section\n for (let cssImportPath of cssImports) {\n if (cssImportPath) {\n cssImportPath = cssImportPath\n .replace('url(', '')\n .replace('@import', '')\n .replace(/\"/g, '')\n .replace(/'/g, '')\n .replace(/;/, '')\n .replace(/\\)/g, '')\n .trim();\n\n // Add each custom css from resources\n if (cssImportPath.startsWith('http')) {\n injectedCss.push({\n url: cssImportPath\n });\n } else if (options.customLogic.allowFileResources) {\n injectedCss.push({\n path: path.join(__dirname, cssImportPath)\n });\n }\n }\n }\n }\n\n // The rest of the CSS section will be content by now\n injectedCss.push({\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\n });\n\n for (const cssResource of injectedCss) {\n try {\n injectedResources.push(await page.addStyleTag(cssResource));\n } catch (error) {\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\n }\n }\n injectedCss.length = 0;\n }\n }\n return injectedResources;\n}\n\n/**\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\n * injected resources and resets CSS and script tags on the page. Additionally,\n * it destroys previously existing charts.\n *\n * @param {Object} page - The Puppeteer Page object from which resources will\n * be cleared.\n * @param {Array} injectedResources - Array of injected resources\n * to be cleared.\n */\nexport async function clearPageResources(page, injectedResources) {\n for (const resource of injectedResources) {\n await resource.dispose();\n }\n\n // Destroy old charts after export is done and reset all CSS and script tags\n await page.evaluate(() => {\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\n // exports\n if (typeof Highcharts !== 'undefined') {\n // eslint-disable-next-line no-undef\n const oldCharts = Highcharts.charts;\n\n // Check in any already existing charts\n if (Array.isArray(oldCharts) && oldCharts.length) {\n // Destroy old charts\n for (const oldChart of oldCharts) {\n oldChart && oldChart.destroy();\n // eslint-disable-next-line no-undef\n Highcharts.charts.shift();\n }\n }\n }\n\n // eslint-disable-next-line no-undef\n const [...scriptsToRemove] = document.getElementsByTagName('script');\n // eslint-disable-next-line no-undef\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\n // eslint-disable-next-line no-undef\n const [...linksToRemove] = document.getElementsByTagName('link');\n\n // Remove tags\n for (const element of [\n ...scriptsToRemove,\n ...stylesToRemove,\n ...linksToRemove\n ]) {\n element.remove();\n }\n });\n}\n\n/**\n * Sets the content for a Puppeteer Page using a predefined template\n * and additional scripts. Also, sets the pageerror in order to catch\n * and display errors from the window context.\n *\n * @param {Object} page - The Puppeteer Page object for which the content\n * is being set.\n */\nasync function setPageContent(page) {\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\n\n // Add all registered Higcharts scripts, quite demanding\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\n\n // Set the initial animObject\n await page.evaluate(setupHighcharts);\n}\n\n/**\n * Set events for a Puppeteer Page.\n *\n * @param {Object} page - The Puppeteer Page object to set events to.\n */\nfunction setPageEvents(page) {\n // Get debug options\n const { debug } = getOptions();\n\n // Set the console listener, if needed\n if (debug.enable && debug.listenToConsole) {\n page.on('console', (message) => {\n console.log(`[debug] ${message.text()}`);\n });\n }\n\n // Set the pageerror listener\n page.on('pageerror', async (error) => {\n // 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 return Promise.race([\n page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding\n }),\n new Promise((_resolve, reject) =>\n setTimeout(\n () => reject(new ExportError('Rasterization timeout')),\n rasterizationTimeout || 1500\n )\n )\n ]);\n};\n\n/**\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\n * inside an element with the id 'container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to the SVG string.\n */\nconst createSVG = (page) =>\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\n\n/**\n * Sets the specified chart and options as configuration into the triggerExport\n * function within the window context using page.evaluate.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object to be configured.\n * @param {Object} options - Configuration options for the chart.\n *\n * @returns {Promise} Promise resolving after the configuration is set.\n */\nconst setAsConfig = async (page, chart, options, displayErrors) =>\n page.evaluate(triggerExport, chart, options, displayErrors);\n\n/**\n * Exports to a chart from a page using Puppeteer.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object or SVG configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} Promise resolving to\n * the exported data or rejecting with an ExportError.\n */\nexport default async (page, chart, options) => {\n // Injected resources array (additional JS and CSS)\n let injectedResources = [];\n\n try {\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n getCache().activeManifest.modules.debugger;\n\n let isSVG;\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG input handling\n log(4, '[export] Treating as SVG.');\n\n // If input is also SVG, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n await page.setContent(svgTemplate(chart), {\n waitUntil: 'domcontentloaded'\n });\n } else {\n // JSON config handling\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options,\n displayErrors\n );\n } else {\n // Basic configuration export\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n await setAsConfig(page, chart, options, displayErrors);\n }\n }\n\n // Keeps track of all resources added on the page with addXXXTag. etc\n // It's VITAL that all added resources ends up here so we can clear things\n // out when doing a new export in the same page!\n injectedResources = await addPageResources(page, options);\n\n // Get the real chart size and set the zoom accordingly\n const size = isSVG\n ? await page.evaluate((scale) => {\n const svgElement = document.querySelector(\n '#chart-container svg:first-of-type'\n );\n\n // Get the values correctly scaled\n const chartHeight = svgElement.height.baseVal.value * scale;\n const chartWidth = svgElement.width.baseVal.value * scale;\n\n // In case of SVG the zoom must be set directly for body\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n\n return {\n chartHeight,\n chartWidth\n };\n }, parseFloat(exportOptions.scale))\n : await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n\n // No need for such scale manipulation in case of other types of exports\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n\n return {\n chartHeight,\n chartWidth\n };\n });\n\n // Set final height and width for viewport\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\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 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) {\n // We don't really need to wait around for this\n await workerHandle.page.close();\n }\n }\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 await clearPage(resource.page, false);\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\n });\n\n pool.on('destroySuccess', (eventId, resource) => {\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\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 // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack.\n if (result.message === 'Rasterization timeout') {\n workerHandle.page.close();\n workerHandle.page = await newPage();\n }\n\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 // Check the Puppeteer export time\n if (options.server.benchmarking) {\n log(\n 5,\n options.payload?.requestId\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\n : '[benchmark]',\n `Exported a chart sucessfully: ${exportCounter()}ms.`\n );\n }\n\n // Release the resource back to the pool\n pool.release(workerHandle);\n\n // Used for statistics in averageTime and processedWorkCount, which\n // in turn is used by the /health route.\n const workEnd = new Date().getTime();\n const exportTime = workEnd - workStart;\n stats.timeSpent += exportTime;\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\n\n log(4, `[pool] Work completed in ${exportTime} ms.`);\n\n // Otherwise return the result\n return {\n result,\n options\n };\n } catch (error) {\n ++stats.droppedExports;\n\n if (workerHandle) {\n pool.release(workerHandle);\n }\n\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\n error\n );\n }\n};\n\n/**\n * Retrieves the current pool instance.\n *\n * @returns {Object|null} The current pool instance if initialized, or null\n * if the pool has not been created.\n */\nexport const getPool = () => pool;\n\n/**\n * Retrieves pool information in JSON format, including minimum and maximum\n * workers, available workers, workers in use, and pending acquire requests.\n *\n * @returns {Object} Pool information in JSON format.\n */\nexport const getPoolInfoJSON = () => ({\n min: pool.min,\n max: pool.max,\n all: pool.numFree() + pool.numUsed(),\n available: pool.numFree(),\n used: pool.numUsed(),\n pending: pool.numPendingAcquires()\n});\n\n/**\n * Logs information about the current state of the pool, including the minimum\n * and maximum workers, available workers, workers in use, and pending acquire\n * requests.\n */\nexport function getPoolInfo() {\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\n\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\n log(5, `[pool] The number of all created resources: ${all}.`);\n log(5, `[pool] The number of available resources: ${available}.`);\n log(5, `[pool] The number of acquired resources: ${used}.`);\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\n}\n\nexport default {\n initPool,\n killPool,\n postWork,\n getPool,\n getPoolInfo,\n getPoolInfoJSON,\n getStats: () => stats\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { readFileSync, writeFileSync } from 'fs';\n\nimport { getOptions, initExportSettings } from './config.js';\nimport { log, logWithStack } from './logger.js';\nimport { killPool, postWork, stats } from './pool.js';\nimport {\n fixType,\n handleResources,\n isCorrectJSON,\n optionsStringify,\n roundNumber,\n toBoolean,\n wrapAround\n} from './utils.js';\nimport { sanitize } from './sanitize.js';\nimport ExportError from './errors/ExportError.js';\n\nlet allowCodeExecution = false;\n\n/**\n * Starts an export process. The `settings` contains final options gathered\n * from all possible sources (config, env, cli, json). The `endCallback` is\n * called when the export is completed, with an error object as the first\n * argument and the second containing the base64 respresentation of a chart.\n *\n * @param {Object} settings - The settings object containing export\n * configuration.\n * @param {function} endCallback - The callback function to be invoked upon\n * finalizing work or upon error occurance of the exporting process.\n *\n * @returns {void} This function does not return a value directly; instead,\n * it communicates results via the endCallback.\n */\nexport const startExport = async (settings, endCallback) => {\n // Starting exporting process message\n log(4, '[chart] Starting the exporting process.');\n\n // Initialize options\n const options = initExportSettings(settings, getOptions());\n\n // Get the export options\n const exportOptions = options.export;\n\n // If SVG is an input (argument can be sent only by the request)\n if (options.payload?.svg && options.payload.svg !== '') {\n try {\n log(4, '[chart] Attempting to export from a SVG input.');\n\n const result = exportAsString(\n sanitize(options.payload.svg), // #209\n options,\n endCallback\n );\n\n ++stats.exportFromSvgAttempts;\n return result;\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading SVG input.').setError(error)\n );\n }\n }\n\n // Export using options from the file\n if (exportOptions.infile && exportOptions.infile.length) {\n // Try to read the file to get the string representation\n try {\n log(4, '[chart] Attempting to export from an input file.');\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\n return exportAsString(options.export.instr.trim(), options, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading input file.').setError(error)\n );\n }\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n try {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading raw input.').setError(error)\n );\n }\n }\n\n // No input specified, pass an error message to the callback\n return endCallback(\n new ExportError(\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\n )\n );\n};\n\n/**\n * Starts a batch export process for multiple charts based on the information\n * in the batch option. The batch is a string in the following format:\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\n *\n * @param {Object} options - The options object containing configuration for\n * a batch export.\n *\n * @returns {Promise} A Promise that resolves once the batch export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * any of the batch export process.\n */\nexport const batchExport = async (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (error, info) => {\n // Throw an error\n if (error) {\n throw error;\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n info.options.export.type !== 'svg'\n ? Buffer.from(info.result, 'base64')\n : info.result\n );\n }\n )\n );\n }\n }\n\n try {\n // Await all exports are done\n await Promise.all(batchFunctions);\n\n // Kill pool and close browser after finishing batch export\n await killPool();\n } catch (error) {\n throw new ExportError(\n '[chart] Error encountered during batch export.'\n ).setError(error);\n }\n};\n\n/**\n * Starts a single export process based on the specified options.\n *\n * @param {Object} options - The options object containing configuration for\n * a single export.\n *\n * @returns {Promise} A Promise that resolves once the single export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * the single export process.\n */\nexport const singleExport = async (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n await startExport(options, async (error, info) => {\n // Exit process when error\n if (error) {\n throw error;\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\n );\n\n // Kill pool and close browser after finishing single export\n await killPool();\n });\n};\n\n/**\n * Determines the size and scale for chart export based on the provided options.\n *\n * @param {Object} options - The options object containing configuration for\n * chart export.\n *\n * @returns {Object} An object containing the calculated height, width,\n * and scale for the chart export.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n const size = {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n\n // Get rid of potential px and %\n for (let [param, value] of Object.entries(size)) {\n size[param] =\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\n }\n return size;\n};\n\n/**\n * Function for finalizing options before export.\n *\n * @param {Object} options - The options object containing configuration for\n * the export process.\n * @param {Object} chartJson - The JSON representation of the chart.\n * @param {Function} endCallback - The callback function to be called upon\n * completion or error.\n * @param {string} svg - The SVG representation of the chart.\n *\n * @returns {Promise} A Promise that resolves once the export process\n * is completed.\n */\nconst doExport = async (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customLogic: customLogicOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customLogicOptions.allowCodeExecution === 'boolean'\n ? customLogicOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customLogicOptions) {\n customLogicOptions = options.customLogic = {};\n } else if (allowCodeExecutionScoped) {\n if (typeof options.customLogic.resources === 'string') {\n // Process resources\n options.customLogic.resources = handleResources(\n options.customLogic.resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } else if (!options.customLogic.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customLogic.resources = handleResources(\n resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[chart] Unable to load the default resources.json file.`\n );\n }\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customLogicOptions) {\n if (\n customLogicOptions.callback ||\n customLogicOptions.resources ||\n customLogicOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return endCallback(\n new ExportError(\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\n )\n );\n }\n\n // Reset all additional custom code\n customLogicOptions.callback = false;\n customLogicOptions.resources = false;\n customLogicOptions.customCode = false;\n }\n\n // Clean properties to keep it lean and mean\n if (chartJson) {\n chartJson.chart = chartJson.chart || {};\n chartJson.exporting = chartJson.exporting || {};\n chartJson.exporting.enabled = false;\n }\n\n exportOptions.constr = exportOptions.constr || 'chart';\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\n if (exportOptions.type === 'svg') {\n exportOptions.width = false;\n }\n\n // Prepare global and theme options\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\n try {\n if (exportOptions && exportOptions[optionsName]) {\n if (\n typeof exportOptions[optionsName] === 'string' &&\n exportOptions[optionsName].endsWith('.json')\n ) {\n exportOptions[optionsName] = isCorrectJSON(\n readFileSync(exportOptions[optionsName], 'utf8'),\n true\n );\n } else {\n exportOptions[optionsName] = isCorrectJSON(\n exportOptions[optionsName],\n true\n );\n }\n }\n } catch (error) {\n exportOptions[optionsName] = {};\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\n }\n });\n\n // Prepare the customCode\n if (customLogicOptions.allowCodeExecution) {\n try {\n customLogicOptions.customCode = wrapAround(\n customLogicOptions.customCode,\n customLogicOptions.allowFileResources\n );\n } catch (error) {\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\n }\n }\n\n // Get the callback\n if (\n customLogicOptions &&\n customLogicOptions.callback &&\n customLogicOptions.callback?.indexOf('{') < 0\n ) {\n // The allowFileResources is always set to false for HTTP requests to avoid\n // injecting arbitrary files from the fs\n if (customLogicOptions.allowFileResources) {\n try {\n customLogicOptions.callback = readFileSync(\n customLogicOptions.callback,\n 'utf8'\n );\n } catch (error) {\n customLogicOptions.callback = false;\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\n }\n } else {\n customLogicOptions.callback = false;\n }\n }\n\n // Size search\n options.export = {\n ...options.export,\n ...findChartSize(options)\n };\n\n // Post the work to the pool\n try {\n const result = await postWork(\n exportOptions.strInj || chartJson || svg,\n options\n );\n return endCallback(false, result);\n } catch (error) {\n return endCallback(error);\n }\n};\n\n/**\n * Performs a direct inject of options before export. The function attempts\n * to stringify the provided options and removes unnecessary characters,\n * ensuring a clean and formatted input. The resulting string is saved as\n * a \"stright inject\" string in the export options. It then invokes the\n * doExport function with the updated options.\n *\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\n * a server (see the --allowCodeExecution option).\n *\n * @param {Object} options - The export options containing the input\n * to be injected.\n * @param {function} endCallback - The callback function to be invoked\n * at the end of the process.\n *\n * @returns {Promise} A Promise that resolves with the result of the export\n * operation or rejects with an error if any issues occur during the process.\n */\nconst doStraightInject = (options, endCallback) => {\n try {\n let strInj;\n let instr = options.export.instr || options.export.options;\n\n if (typeof instr !== 'string') {\n // Try to stringify options\n strInj = instr = optionsStringify(\n instr,\n options.customLogic?.allowCodeExecution\n );\n }\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\n\n // Get rid of the ;\n if (strInj[strInj.length - 1] === ';') {\n strInj = strInj.substring(0, strInj.length - 1);\n }\n\n // Save as stright inject string\n options.export.strInj = strInj;\n return doExport(options, false, endCallback);\n } catch (error) {\n return endCallback(\n new ExportError(\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\n ).setError(error)\n );\n }\n};\n\n/**\n * Exports a string based on the provided options and invokes an end callback.\n *\n * @param {string} stringToExport - The string content to be exported.\n * @param {Object} options - Export options, including customLogic with\n * allowCodeExecution flag.\n * @param {Function} endCallback - Callback function to be invoked at the end\n * of the export process.\n *\n * @returns {any} Result of the export process or an error if encountered.\n */\nconst exportAsString = (stringToExport, options, endCallback) => {\n const { allowCodeExecution } = options.customLogic;\n\n // Check if it is SVG\n if (\n stringToExport.indexOf('= 0 ||\n stringToExport.indexOf('= 0\n ) {\n log(4, '[chart] Parsing input as SVG.');\n return doExport(options, false, endCallback, stringToExport);\n }\n\n try {\n // Try to parse to JSON and call the doExport function\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\n\n // If a correct JSON, do the export\n return doExport(options, chartJSON, endCallback);\n } catch (error) {\n // Not a valid JSON\n if (toBoolean(allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n } else {\n // Do not allow straight injection without the allowCodeExecution flag\n return endCallback(\n new ExportError(\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\n ).setError(error)\n );\n }\n }\n};\n\n/**\n * Retrieves and returns the current status of code execution permission.\n *\n * @returns {any} The value of allowCodeExecution.\n */\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\n/**\n * Sets the code execution permission based on the provided boolean value.\n *\n * @param {any} value - The value to be converted and assigned\n * to allowCodeExecution.\n */\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/**\n * @overview Used to sanitize the strings coming from the exporting module\n * to prevent XSS attacks (with the DOMPurify library).\n **/\n\nimport { JSDOM } from 'jsdom';\nimport DOMPurify from 'dompurify';\n\n/**\n * Sanitizes a given HTML string by removing tags and any content within them.\n *\n * @param {string} input The HTML string to be sanitized.\n * @returns {string} The sanitized HTML string.\n */\nexport function sanitize(input) {\n const window = new JSDOM('').window;\n const purify = DOMPurify(window);\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\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 || 500;\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. Payload received: ${JSON.stringify(body)}.`\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', () => {\n connectionAborted = true;\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// Enable parsing of form data (files) with Multer package\nconst storage = multer.memoryStorage();\nconst upload = multer({\n storage,\n limits: {\n fieldSize: 50 * 1024 * 1024\n }\n});\n\n// Enable body parser\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\n\n// Use only non-file multipart form fields\napp.use(upload.none());\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) => {\n logWithStack(1, error, `[server] Client error: ${error.message}`);\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 // 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 });\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport { clearAllIntervals } from './intervals.js';\nimport { killPool } from './pool.js';\nimport { closeServers } from './server/server.js';\n\n/**\n * Clean up function to trigger before ending process for the graceful shutdown.\n *\n * @param {number} exitCode - An exit code for the process.exit() function.\n */\nexport const shutdownCleanUp = async (exitCode) => {\n // Await freeing all resources\n await Promise.allSettled([\n // Clear all ongoing intervals\n clearAllIntervals(),\n\n // Get available server instances (HTTP/HTTPS) and close them\n closeServers(),\n\n // Close pool along with its workers and the browser instance, if exists\n killPool()\n ]);\n\n // Exit process with a correct code\n process.exit(exitCode);\n};\n\nexport default {\n shutdownCleanUp\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport 'colors';\n\nimport { checkAndUpdateCache } from './cache.js';\nimport {\n batchExport,\n setAllowCodeExecution,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\nimport {\n initLogging,\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging\n} from './logger.js';\nimport { initPool, killPool } from './pool.js';\nimport { shutdownCleanUp } from './resource_release.js';\nimport server, { startServer } from './server/server.js';\nimport { printLogo, printUsage } from './utils.js';\n\n/**\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\n * 'uncaughtException' events.\n */\nconst attachProcessExitListeners = () => {\n log(3, '[process] Attaching exit listeners to the process.');\n\n // Handler for the 'exit'\n process.on('exit', (code) => {\n log(4, `Process exited with code ${code}.`);\n });\n\n // Handler for the 'SIGINT'\n process.on('SIGINT', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGTERM'\n process.on('SIGTERM', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGHUP'\n process.on('SIGHUP', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'uncaughtException'\n process.on('uncaughtException', async (error, name) => {\n logWithStack(1, error, `The ${name} error.`);\n await shutdownCleanUp(1);\n });\n};\n\n/**\n * Initializes the export process. Tasks such as configuring logging, checking\n * cache and sources, and initializing the pool of resources happen during\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\n *\n * @param {Object} options - All export options.\n *\n * @returns {Promise} Promise resolving to the updated export options.\n */\nconst initExport = async (options) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customLogic && options.customLogic.allowCodeExecution\n );\n\n // Init the logging\n initLogging(options.logging);\n\n // Attach process' exit listeners\n if (options.other.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n // Check if cache needs to be updated\n await checkAndUpdateCache(options);\n\n // Init the pool\n await initPool({\n pool: options.pool || {\n minWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer.args || []\n });\n\n // Return updated options\n return options;\n};\n\nexport default {\n // Server\n server,\n startServer,\n\n // Exporting\n initExport,\n singleExport,\n batchExport,\n startExport,\n\n // Pool\n initPool,\n killPool,\n\n // Other\n setOptions,\n shutdownCleanUp,\n\n // Logs\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n\n // Utils\n mapToNewConfig,\n manualConfig,\n printLogo,\n printUsage\n};\n"],"names":["scriptsNames","core","modules","indicators","custom","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","toConsole","toFile","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","LOGGING_LEVEL","LOGGING_FILE","LOGGING_DEST","LOGGING_TO_CONSOLE","LOGGING_TO_FILE","UI_ENABLE","UI_ROUTE","OTHER_NODE_ENV","OTHER_LISTEN_TO_PROCESS_EXITS","OTHER_NO_LOGO","OTHER_HARD_RESET_PAGE","OTHER_BROWSER_SHELL_MODE","DEBUG_ENABLE","DEBUG_HEADLESS","DEBUG_DEVTOOLS","DEBUG_LISTEN_TO_CONSOLE","DEBUG_DUMPIO","DEBUG_SLOW_MO","DEBUG_DEBUGGING_PORT","partial","parse","process","env","colors","pathCreated","levelsDesc","title","color","listeners","logToFile","texts","prefix","existsSync","mkdirSync","appendFile","concat","error","console","log","newLevel","Date","toString","fn","apply","logWithStack","customMessage","mainMessage","stackMessage","stack","slice","setLogLevel","enableFileLogging","logDest","logFile","endsWith","__dirname","fileURLToPath","URL","url","fixType","formats","outType","pop","find","t","handleResources","allowedProps","handledResources","correctResources","isCorrectJSON","readFileSync","files","propName","item","data","parsedData","JSON","stringify","deepCopy","copy","Array","isArray","key","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","option","entries","descName","green","i","blue","category","toUpperCase","red","toBoolean","wrapAround","replace","measureTime","start","hrtime","bigint","Number","generalOptions","getOptions","mergeConfigOptions","newOptions","mergedOptions","updateDefaultConfig","configObj","customObj","customValue","initOptions","items","recursiveProps","objectToUpdate","nestedNames","shift","assign","async","fetch","requestOptions","Promise","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","response","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","manifestPath","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","getCachePath","setupHighcharts","Highcharts","animObject","duration","triggerExport","chartOptions","displayErrors","_displayErrors","merge","setOptions","wrap","setOptionsObj","Function","chart","animation","strInj","isRenderComplete","Chart","proceed","userOptions","cb","exporting","enabled","plotOptions","series","label","tooltip","onHighchartsRender","addEvent","Series","finalOptions","finalCallback","defaultOptions","prop","template","browser","newPage","page","setCacheEnabled","setPageContent","$eval","element","errorMessage","innerHTML","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","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","isClosed","workCount","random","validate","workerHandle","close","initPool","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","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","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","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","removeAllListeners","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","setInterval","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","sendFile","uiRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","allSettled","exit","index","initExport","loggingOptions","initLogging","code","singleExport","batchExport","batchFunctions","pair","configIndex","findIndex","arg","fileName","loadConfigFile","showUsage","propertiesChain","argumentType","pairArgumentValue","mapToNewConfig","oldOptions","manualConfig","configFileName","configFile","choice","prompts","onSubmit","p","categories","questionsCounter","allQuestions","section","prompt","answer","module","writeFile","printLogo","packageVersion"],"mappings":"0lBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFC,WAAY,CAAC,kBACbC,OAAQ,CACN,wEACA,mGAMSC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOR,EAAaC,KACpBQ,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOR,EAAaE,QACpBO,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOR,EAAaG,WACpBM,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAOR,EAAaI,OACpBK,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,QAAS,cACTH,YAAa,6DAEfgB,OAAQ,CACNlB,MAAO,QACPC,KAAM,SACNI,QAAS,gBACTH,YACE,8EAEJiB,cAAe,CACbnB,MAAO,IACPC,KAAM,SACNI,QAAS,wBACTH,YACE,wEAEJkB,aAAc,CACZpB,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJmB,aAAc,CACZrB,MAAO,EACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJoB,OAAQ,CACNtB,OAAO,EACPC,KAAM,SACNC,YACE,kFAEJqB,MAAO,CACLvB,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJsB,MAAO,CACLxB,OAAO,EACPC,KAAM,SACNC,YACE,6GAEJuB,cAAe,CACbzB,OAAO,EACPC,KAAM,SACNC,YACE,2GAEJwB,aAAc,CACZ1B,OAAO,EACPC,KAAM,SACNC,YACE,iHAEJyB,MAAO,CACL3B,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJ0B,qBAAsB,CACpB5B,MAAO,KACPC,KAAM,SACNI,QAAS,+BACTH,YACE,kEAGN2B,YAAa,CACXC,mBAAoB,CAClB9B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,6FAEJ6B,mBAAoB,CAClB/B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,sHAEJ8B,WAAY,CACVhC,OAAO,EACPC,KAAM,SACNC,YACE,mJAEJ+B,SAAU,CACRjC,OAAO,EACPC,KAAM,SACNC,YACE,0GAEJgC,UAAW,CACTlC,OAAO,EACPC,KAAM,SACNC,YACE,yGAEJiC,WAAY,CACVnC,OAAO,EACPC,KAAM,SACNmC,WAAY,WACZlC,YAAa,yDAEfmC,aAAc,CACZrC,OAAO,EACPC,KAAM,SACNC,YACE,wFAGNoC,OAAQ,CACNC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTmC,QAAS,eACTtC,YACE,wEAEJuC,KAAM,CACJzC,MAAO,UACPC,KAAM,SACNI,QAAS,cACTH,YACE,0FAEJwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,cACTH,YAAa,iCAEfyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,sBACTmC,QAAS,qBACTtC,YACE,qIAEJ0C,MAAO,CACLH,KAAM,CACJzC,OAAO,EACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEfwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEf2C,QAAS,CACP7C,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTmC,QAAS,eACTtC,YAAa,2DAGjB4C,aAAc,CACZP,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,8BACTmC,QAAS,qBACTtC,YAAa,yCAEf6C,YAAa,CACX/C,MAAO,GACPC,KAAM,SACNI,QAAS,oCACT+B,WAAY,YACZlC,YAAa,yDAEf8C,OAAQ,CACNhD,MAAO,EACPC,KAAM,SACNI,QAAS,8BACTH,YAAa,uDAEf+C,MAAO,CACLjD,MAAO,EACPC,KAAM,SACNI,QAAS,6BACTH,YACE,qFAEJgD,WAAY,CACVlD,OAAO,EACPC,KAAM,UACNI,QAAS,mCACTH,YAAa,6DAEfiD,QAAS,CACPnD,OAAO,EACPC,KAAM,SACNI,QAAS,gCACTH,YACE,yFAEJkD,UAAW,CACTpD,OAAO,EACPC,KAAM,SACNI,QAAS,kCACTH,YACE,wFAGNmD,IAAK,CACHd,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,yCAEfoD,MAAO,CACLtD,OAAO,EACPC,KAAM,UACNI,QAAS,mBACTmC,QAAS,WACTJ,WAAY,UACZlC,YACE,oEAEJwC,KAAM,CACJ1C,MAAO,IACPC,KAAM,SACNI,QAAS,kBACTmC,QAAS,UACTtC,YAAa,4CAEfqD,SAAU,CACRvD,OAAO,EACPC,KAAM,SACNI,QAAS,uBACT+B,WAAY,UACZlC,YAAa,+CAInBsD,KAAM,CACJC,WAAY,CACVzD,MAAO,EACPC,KAAM,SACNI,QAAS,mBACTH,YAAa,4DAEfwD,WAAY,CACV1D,MAAO,EACPC,KAAM,SACNI,QAAS,mBACT+B,WAAY,UACZlC,YAAa,gDAEfyD,UAAW,CACT3D,MAAO,GACPC,KAAM,SACNI,QAAS,kBACTH,YACE,yFAEJ0D,eAAgB,CACd5D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oEAEJ2D,cAAe,CACb7D,MAAO,IACPC,KAAM,SACNI,QAAS,sBACTH,YACE,mEAEJ4D,eAAgB,CACd9D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,qEAEJ6D,YAAa,CACX/D,MAAO,IACPC,KAAM,SACNI,QAAS,oBACTH,YACE,6EAEJ8D,oBAAqB,CACnBhE,MAAO,IACPC,KAAM,SACNI,QAAS,6BACTH,YACE,mGAEJ+D,eAAgB,CACdjE,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oGAEJyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,mBACTtC,YACE,0EAGNgE,QAAS,CACPC,MAAO,CACLnE,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTmC,QAAS,WACTtC,YAAa,iCAEfkE,KAAM,CACJpE,MAAO,+BACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,6GAEJmE,KAAM,CACJrE,MAAO,OACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,oGAEJoE,UAAW,CACTtE,OAAO,EACPC,KAAM,UACNI,QAAS,qBACTmC,QAAS,eACTtC,YAAa,oDAEfqE,OAAQ,CACNvE,OAAO,EACPC,KAAM,UACNI,QAAS,kBACTmC,QAAS,YACTtC,YACE,2FAGNsE,GAAI,CACFjC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,YACTmC,QAAS,WACTtC,YACE,sEAEJuE,MAAO,CACLzE,MAAO,IACPC,KAAM,SACNI,QAAS,WACTmC,QAAS,UACTtC,YACE,4EAGNwE,MAAO,CACLC,QAAS,CACP3E,MAAO,aACPC,KAAM,SACNI,QAAS,iBACTH,YAAa,oCAEf0E,qBAAsB,CACpB5E,OAAO,EACPC,KAAM,UACNI,QAAS,gCACTH,YAAa,2DAEf2E,OAAQ,CACN7E,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTH,YACE,2EAEJ4E,cAAe,CACb9E,OAAO,EACPC,KAAM,UACNI,QAAS,wBACTH,YAAa,yDAEf6E,iBAAkB,CAChB/E,OAAO,EACPC,KAAM,UACNI,QAAS,2BACTH,YAAa,mDAGjB8E,MAAO,CACLzC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,eACTmC,QAAS,cACTtC,YAAa,8DAEf+E,SAAU,CACRjF,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJgF,SAAU,CACRlF,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJiF,gBAAiB,CACfnF,OAAO,EACPC,KAAM,UACNI,QAAS,0BACTH,YACE,oFAEJkF,OAAQ,CACNpF,OAAO,EACPC,KAAM,UACNI,QAAS,eACTH,YACE,qFAEJmF,OAAQ,CACNrF,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTH,YACE,4EAEJoF,cAAe,CACbtF,MAAO,KACPC,KAAM,SACNI,QAAS,uBACTH,YAAa,mCAWNqF,EAAgB,CAC3BzF,UAAW,CACT,CACEG,KAAM,OACNuF,KAAM,OACNC,QAAS,sBACTC,QAAS7F,EAAcC,UAAUC,KAAKC,MAAM2F,KAAK,KACjDC,UAAW,MAGfzF,WAAY,CACV,CACEF,KAAM,OACNuF,KAAM,UACNC,QAAS,qBACTC,QAAS7F,EAAcM,WAAWC,QAAQJ,OAE5C,CACEC,KAAM,OACNuF,KAAM,SACNC,QAAS,iBACTC,QAAS7F,EAAcM,WAAWG,OAAON,OAE3C,CACEC,KAAM,cACNuF,KAAM,cACNC,QAAS,yBACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWI,YAAYP,OAEhD,CACEC,KAAM,cACNuF,KAAM,gBACNC,QAAS,2BACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWK,cAAcR,OAElD,CACEC,KAAM,cACNuF,KAAM,mBACNC,QAAS,8BACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWM,iBAAiBT,OAErD,CACEC,KAAM,OACNuF,KAAM,gBACNC,QAAS,iBACTC,QAAS7F,EAAcM,WAAWO,cAAcV,MAAM2F,KAAK,KAC3DC,UAAW,KAEb,CACE3F,KAAM,SACNuF,KAAM,aACNC,QAAS,6BACTC,QAAS7F,EAAcM,WAAWQ,WAAWX,OAE/C,CACEC,KAAM,OACNuF,KAAM,YACNC,QAAS,kCACTC,QAAS7F,EAAcM,WAAWS,UAAUZ,QAGhDa,OAAQ,CACN,CACEZ,KAAM,SACNuF,KAAM,OACNC,QAAS,+BACTM,KAAM,YAAYlG,EAAcgB,OAAOZ,KAAKD,QAC5C0F,QAAS,EACTI,QAAS,CAAC,MAAO,OAAQ,MAAO,QAElC,CACE7F,KAAM,SACNuF,KAAM,SACNC,QAAS,yCACTM,KAAM,YAAYlG,EAAcgB,OAAOK,OAAOlB,QAC9C0F,QAAS,EACTI,QAAS,CAAC,QAAS,aAAc,WAAY,eAE/C,CACE7F,KAAM,SACNuF,KAAM,gBACNC,QAAS,oDACTC,QAAS7F,EAAcgB,OAAOM,cAAcnB,OAE9C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,mDACTC,QAAS7F,EAAcgB,OAAOO,aAAapB,OAE7C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,mDACTC,QAAS7F,EAAcgB,OAAOQ,aAAarB,MAC3CgG,IAAK,GACLC,IAAK,GAEP,CACEhG,KAAM,SACNuF,KAAM,uBACNC,QAAS,gDACTC,QAAS7F,EAAcgB,OAAOe,qBAAqB5B,QAGvD6B,YAAa,CACX,CACE5B,KAAM,SACNuF,KAAM,qBACNC,QAAS,kCACTC,QAAS7F,EAAcgC,YAAYC,mBAAmB9B,OAExD,CACEC,KAAM,SACNuF,KAAM,qBACNC,QAAS,wBACTC,QAAS7F,EAAcgC,YAAYE,mBAAmB/B,QAG1DsC,OAAQ,CACN,CACErC,KAAM,SACNuF,KAAM,SACNC,QAAS,+BACTC,QAAS7F,EAAcyC,OAAOC,OAAOvC,OAEvC,CACEC,KAAM,OACNuF,KAAM,OACNC,QAAS,kBACTC,QAAS7F,EAAcyC,OAAOG,KAAKzC,OAErC,CACEC,KAAM,SACNuF,KAAM,OACNC,QAAS,cACTC,QAAS7F,EAAcyC,OAAOI,KAAK1C,OAErC,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,6BACTC,QAAS7F,EAAcyC,OAAOK,aAAa3C,OAE7C,CACEC,KAAM,OACNuF,KAAM,aACNC,QAAS,sCACTC,QAAS7F,EAAcyC,OAAOM,MAAMH,KAAKzC,OAE3C,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,sCACTC,QAAS7F,EAAcyC,OAAOM,MAAMF,KAAK1C,OAE3C,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,0CACTC,QAAS7F,EAAcyC,OAAOM,MAAMC,QAAQ7C,OAE9C,CACEC,KAAM,SACNuF,KAAM,sBACNC,QAAS,uBACTC,QAAS7F,EAAcyC,OAAOQ,aAAaP,OAAOvC,OAEpD,CACEC,KAAM,SACNuF,KAAM,2BACNC,QAAS,0CACTC,QAAS7F,EAAcyC,OAAOQ,aAAaC,YAAY/C,OAEzD,CACEC,KAAM,SACNuF,KAAM,sBACNC,QAAS,2CACTC,QAAS7F,EAAcyC,OAAOQ,aAAaE,OAAOhD,OAEpD,CACEC,KAAM,SACNuF,KAAM,qBACNC,QACE,oEACFC,QAAS7F,EAAcyC,OAAOQ,aAAaG,MAAMjD,OAEnD,CACEC,KAAM,SACNuF,KAAM,0BACNC,QAAS,wCACTC,QAAS7F,EAAcyC,OAAOQ,aAAaI,WAAWlD,OAExD,CACEC,KAAM,OACNuF,KAAM,uBACNC,QACE,8EACFC,QAAS7F,EAAcyC,OAAOQ,aAAaK,QAAQnD,OAErD,CACEC,KAAM,OACNuF,KAAM,yBACNC,QACE,4EACFC,QAAS7F,EAAcyC,OAAOQ,aAAaM,UAAUpD,OAEvD,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,sBACTC,QAAS7F,EAAcyC,OAAOe,IAAId,OAAOvC,OAE3C,CACEC,KAAM,SACNuF,KAAM,YACNC,QAAS,gCACTC,QAAS7F,EAAcyC,OAAOe,IAAIC,MAAMtD,OAE1C,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,kBACTC,QAAS7F,EAAcyC,OAAOe,IAAIX,KAAK1C,OAEzC,CACEC,KAAM,OACNuF,KAAM,eACNC,QAAS,2CACTC,QAAS7F,EAAcyC,OAAOe,IAAIE,SAASvD,QAG/CwD,KAAM,CACJ,CACEvD,KAAM,SACNuF,KAAM,aACNC,QAAS,yCACTC,QAAS7F,EAAc2D,KAAKC,WAAWzD,OAEzC,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,yCACTC,QAAS7F,EAAc2D,KAAKE,WAAW1D,OAEzC,CACEC,KAAM,SACNuF,KAAM,YACNC,QACE,iFACFC,QAAS7F,EAAc2D,KAAKG,UAAU3D,OAExC,CACEC,KAAM,SACNuF,KAAM,iBACNC,QAAS,8DACTC,QAAS7F,EAAc2D,KAAKI,eAAe5D,OAE7C,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,6DACTC,QAAS7F,EAAc2D,KAAKK,cAAc7D,OAE5C,CACEC,KAAM,SACNuF,KAAM,iBACNC,QAAS,+DACTC,QAAS7F,EAAc2D,KAAKM,eAAe9D,OAE7C,CACEC,KAAM,SACNuF,KAAM,cACNC,QAAS,iEACTC,QAAS7F,EAAc2D,KAAKO,YAAY/D,OAE1C,CACEC,KAAM,SACNuF,KAAM,sBACNC,QACE,kEACFC,QAAS7F,EAAc2D,KAAKQ,oBAAoBhE,OAElD,CACEC,KAAM,SACNuF,KAAM,iBACNC,QACE,+FACFC,QAAS7F,EAAc2D,KAAKS,eAAejE,OAE7C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,0CACTC,QAAS7F,EAAc2D,KAAKb,aAAa3C,QAG7CkE,QAAS,CACP,CACEjE,KAAM,SACNuF,KAAM,QACNC,QACE,uFACFC,QAAS7F,EAAcqE,QAAQC,MAAMnE,MACrCkG,MAAO,EACPF,IAAK,EACLC,IAAK,GAEP,CACEhG,KAAM,OACNuF,KAAM,OACNC,QACE,0EACFC,QAAS7F,EAAcqE,QAAQE,KAAKpE,OAEtC,CACEC,KAAM,OACNuF,KAAM,OACNC,QAAS,0DACTC,QAAS7F,EAAcqE,QAAQG,KAAKrE,OAEtC,CACEC,KAAM,SACNuF,KAAM,YACNC,QAAS,gCACTC,QAAS7F,EAAcqE,QAAQI,UAAUtE,OAE3C,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,4BACTC,QAAS7F,EAAcqE,QAAQK,OAAOvE,QAG1CwE,GAAI,CACF,CACEvE,KAAM,SACNuF,KAAM,SACNC,QAAS,kCACTC,QAAS7F,EAAc2E,GAAGjC,OAAOvC,OAEnC,CACEC,KAAM,OACNuF,KAAM,QACNC,QAAS,2BACTC,QAAS7F,EAAc2E,GAAGC,MAAMzE,QAGpC0E,MAAO,CACL,CACEzE,KAAM,OACNuF,KAAM,UACNC,QAAS,kCACTC,QAAS7F,EAAc6E,MAAMC,QAAQ3E,OAEvC,CACEC,KAAM,SACNuF,KAAM,uBACNC,QAAS,uDACTC,QAAS7F,EAAc6E,MAAME,qBAAqB5E,OAEpD,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,6DACTC,QAAS7F,EAAc6E,MAAMG,OAAO7E,OAEtC,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,uDACTC,QAAS7F,EAAc6E,MAAMI,cAAc9E,OAE7C,CACEC,KAAM,SACNuF,KAAM,mBACNC,QAAS,gDACTC,QAAS7F,EAAc6E,MAAMK,iBAAiB/E,QAGlDgF,MAAO,CACL,CACE/E,KAAM,SACNuF,KAAM,SACNC,QAAS,8CACTC,QAAS7F,EAAcmF,MAAMzC,OAAOvC,OAEtC,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,mCACTC,QAAS7F,EAAcmF,MAAMC,SAASjF,OAExC,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,uCACTC,QAAS7F,EAAcmF,MAAME,SAASlF,OAExC,CACEC,KAAM,SACNuF,KAAM,kBACNC,QAAS,2DACTC,QAAS7F,EAAcmF,MAAMG,gBAAgBnF,OAE/C,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,4DACTC,QAAS7F,EAAcmF,MAAMI,OAAOpF,OAEtC,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,iDACTC,QAAS7F,EAAcmF,MAAMK,OAAOrF,OAEtC,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,gCACTC,QAAS7F,EAAcmF,MAAMM,cAActF,SAMpCmG,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,EAAM7G,MAEfqG,EAAiBQ,EAAO,GAAGN,KAAaI,MAGxCP,EAAWS,EAAMrE,SAAWmE,GAAK,GAAGJ,KAAaI,IAAIG,UAAU,QAGtCC,IAArBF,EAAMzE,aACRgE,EAAWS,EAAMzE,YAAc,GAAGmE,KAAaI,IAAIG,UAAU,IAGlE,IACD,EAGJT,EAAiBxG,GCnoCjBmH,EAAOC,SAIP,MAAMC,EAGIC,GACNC,EACGC,SACAC,WAAWtH,GACVA,EACGuH,MAAM,KACNC,KAAKxH,GAAUA,EAAMyH,SACrBC,QAAQ1H,GAAUmH,EAAYP,SAAS5G,OAE3CsH,WAAWtH,GAAWA,EAAM2H,OAAS3H,OAAQ+G,IAZ9CG,EAgBK,IACPE,EACGQ,KAAK,CAAC,OAAQ,QAAS,KACvBN,WAAWtH,GAAqB,KAAVA,EAAyB,SAAVA,OAAmB+G,IAnBzDG,EAuBGW,GACLT,EACGQ,KAAK,IAAIC,EAAQ,KACjBP,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IA1B9CG,EA8BI,IACNE,EACGC,SACAI,OACAK,QACE9H,IACE,CAAC,QAAS,YAAa,OAAQ,OAAO4G,SAAS5G,IACtC,KAAVA,IACDA,IAAW,CACVyF,QAAS,mDAAmDzF,SAG/DsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IA1C9CG,EA8CS,IACXE,EACGC,SACAI,OACAK,QACE9H,GACW,KAAVA,IAAkB+H,MAAMC,WAAWhI,KAAWgI,WAAWhI,GAAS,IACnEA,IAAW,CACVyF,QAAS,qDAAqDzF,SAGjEsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IAzD1DG,EA6DY,IACdE,EACGC,SACAI,OACAK,QACE9H,GACW,KAAVA,IAAkB+H,MAAMC,WAAWhI,KAAWgI,WAAWhI,IAAU,IACpEA,IAAW,CACVyF,QAAS,yDAAyDzF,SAGrEsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IA8HnDkB,EA3HSb,EAAEc,OAAO,CAE7BC,mBAAoBf,EACjBC,SACAI,OACAK,QACE9H,GAAU,6BAA6BoI,KAAKpI,IAAoB,KAAVA,IACtDA,IAAW,CACVyF,QAAS,4FAA4FzF,SAGxGsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IAChDsB,mBAAoBjB,EACjBC,SACAI,OACAK,QACE9H,GACCA,EAAMsI,WAAW,aACjBtI,EAAMsI,WAAW,YACP,KAAVtI,IACDA,IAAW,CACVyF,QAAS,6FAA6FzF,SAGzGsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IAChDwB,wBAAyBrB,EAAQ1H,EAAaC,MAC9C+I,0BAA2BtB,EAAQ1H,EAAaE,SAChD+I,6BAA8BvB,EAAQ1H,EAAaG,YACnD+I,uBAAwBxB,IACxByB,sBAAuBzB,IACvB0B,uBAAwB1B,IAGxB2B,YAAa3B,EAAO,CAAC,OAAQ,MAAO,MAAO,QAC3C4B,cAAe5B,EAAO,CAAC,QAAS,aAAc,WAAY,eAC1D6B,sBAAuB7B,IACvB8B,qBAAsB9B,IACtB+B,qBAAsB/B,IACtBgC,6BAA8BhC,IAG9BiC,kCAAmCjC,IACnCkC,kCAAmClC,IAGnCmC,cAAenC,IACfoC,YAAapC,IACbqC,YAAarC,IACbsC,oBAAqBtC,IAGrBuC,kBAAmBvC,IACnBwC,kBAAmBxC,IACnByC,qBAAsBzC,IAGtB0C,4BAA6B1C,IAC7B2C,kCAAmC3C,IACnC4C,4BAA6B5C,IAC7B6C,2BAA4B7C,IAC5B8C,iCAAkC9C,IAClC+C,8BAA+B/C,IAC/BgD,gCAAiChD,IAGjCiD,kBAAmBjD,IACnBkD,iBAAkBlD,IAClBmD,gBAAiBnD,IACjBoD,qBAAsBpD,IAGtBqD,iBAAkBrD,IAClBsD,iBAAkBtD,IAClBuD,gBAAiBvD,IACjBwD,qBAAsBxD,IACtByD,oBAAqBzD,IACrB0D,qBAAsB1D,IACtB2D,kBAAmB3D,IACnB4D,2BAA4B5D,IAC5B6D,qBAAsB7D,IACtB8D,kBAAmB9D,IAGnB+D,cAAe7D,EACZC,SACAI,OACAK,QACE9H,GACW,KAAVA,IACE+H,MAAMC,WAAWhI,KACjBgI,WAAWhI,IAAU,GACrBgI,WAAWhI,IAAU,IACxBA,IAAW,CACVyF,QAAS,mGAAmGzF,SAG/GsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IAC5DmE,aAAchE,IACdiE,aAAcjE,IACdkE,mBAAoBlE,IACpBmE,gBAAiBnE,IAGjBoE,UAAWpE,IACXqE,SAAUrE,IAGVsE,eAAgBtE,EAAO,CAAC,cAAe,aAAc,SACrDuE,8BAA+BvE,IAC/BwE,cAAexE,IACfyE,sBAAuBzE,IACvB0E,yBAA0B1E,IAG1B2E,aAAc3E,IACd4E,eAAgB5E,IAChB6E,eAAgB7E,IAChB8E,wBAAyB9E,IACzB+E,aAAc/E,IACdgF,cAAehF,IACfiF,qBAAsBjF,MAGGkF,UAAUC,MAAMC,QAAQC,KC3M7CC,EAAS,CAAC,MAAO,SAAU,OAAQ,OAAQ,SAGjD,IAAItI,EAAU,CAEZI,WAAW,EACXC,QAAQ,EACRkI,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,KACnB9I,EAAQuI,eAEVQ,EAAW/I,EAAQG,OAAS6I,EAAUhJ,EAAQG,MAI/CH,EAAQuI,aAAc,GAIxBU,EACE,GAAGjJ,EAAQG,OAAOH,EAAQE,OAC1B,CAAC4I,GAAQI,OAAOL,GAAOpH,KAAK,KAAO,MAClC0H,IACKA,IACFC,QAAQC,IAAI,yCAAyCF,KACrDnJ,EAAQK,QAAS,EAClB,GAEJ,EAWUgJ,EAAM,IAAIxN,KACrB,MAAOyN,KAAaT,GAAShN,GAGvB2M,WAAEA,EAAUvI,MAAEA,GAAUD,EAG9B,GACe,IAAbsJ,IACc,IAAbA,GAAkBA,EAAWrJ,GAASA,EAAQuI,EAAW/E,QAE1D,OAIF,MAGMqF,EAAS,IAHC,IAAIS,MAAOC,WAAWnG,MAAM,KAAK,GAAGE,WAGtBiF,EAAWc,EAAW,GAAGb,WAGvDzI,EAAQ2I,UAAUnG,SAASiH,IACzBA,EAAGX,EAAQD,EAAMpH,KAAK,KAAK,IAIzBzB,EAAQI,WACVgJ,QAAQC,IAAIK,WACV7G,EACA,CAACiG,EAAOU,WAAWxJ,EAAQwI,WAAWc,EAAW,GAAGZ,QAAQQ,OAAOL,IAKnE7I,EAAQK,QACVuI,EAAUC,EAAOC,EAClB,EAYUa,EAAe,CAACL,EAAUH,EAAOS,KAE5C,MAAMC,EAAcD,GAAiBT,EAAM5H,SAGrCtB,MAAEA,EAAKuI,WAAEA,GAAexI,EAG9B,GAAiB,IAAbsJ,GAAkBA,EAAWrJ,GAASA,EAAQuI,EAAW/E,OAC3D,OAIF,MAGMqF,EAAS,IAHC,IAAIS,MAAOC,WAAWnG,MAAM,KAAK,GAAGE,WAGtBiF,EAAWc,EAAW,GAAGb,WAGjDqB,EACJX,EAAM5H,UAAY4H,EAAMW,mBAAuCjH,IAAvBsG,EAAMW,aAC1CX,EAAMY,MACNZ,EAAMY,MAAM1G,MAAM,MAAM2G,MAAM,GAAGvI,KAAK,MAGtCoH,EAAQ,CAACgB,EAAa,KAAMC,GAG9B9J,EAAQI,WACVgJ,QAAQC,IAAIK,WACV7G,EACA,CAACiG,EAAOU,WAAWxJ,EAAQwI,WAAWc,EAAW,GAAGZ,QAAQQ,OAAO,CACjEW,EAAYvB,EAAOgB,EAAW,IAC9B,KACAQ,KAMN9J,EAAQ2I,UAAUnG,SAASiH,IACzBA,EAAGX,EAAQD,EAAMpH,KAAK,KAAK,IAIzBzB,EAAQK,QACVuI,EAAUC,EAAOC,EAClB,EASUmB,EAAeX,IACtBA,GAAY,GAAKA,GAAYtJ,EAAQwI,WAAW/E,SAClDzD,EAAQC,MAAQqJ,EACjB,EASUY,EAAoB,CAACC,EAASC,KASzC,GAPApK,EAAU,IACLA,EACHG,KAAMgK,GAAWnK,EAAQG,KACzBD,KAAMkK,GAAWpK,EAAQE,KACzBG,QAAQ,GAGkB,IAAxBL,EAAQG,KAAKsD,OACf,OAAO4F,EAAI,EAAG,2DAGXrJ,EAAQG,KAAKkK,SAAS,OACzBrK,EAAQG,MAAQ,IACjB,ECvMUmK,EAAYC,EAAc,IAAIC,IAAI,mBAAoBC,MAiEtDC,EAAU,CAAC3O,EAAMgB,KAE5B,MAQM4N,EAAU,CAAC,MAAO,OAAQ,MAAO,OAGvC,GAAI5N,EAAS,CACX,MAAM6N,EAAU7N,EAAQsG,MAAM,KAAKwH,MAEnB,QAAZD,EACF7O,EAAO,OACE4O,EAAQjI,SAASkI,IAAY7O,IAAS6O,IAC/C7O,EAAO6O,EAEV,CAGD,MAtBkB,CAChB,YAAa,MACb,aAAc,OACd,kBAAmB,MACnB,gBAAiB,OAkBF7O,IAAS4O,EAAQG,MAAMC,GAAMA,IAAMhP,KAAS,KAAK,EAcvDiP,EAAkB,CAAChN,GAAY,EAAOH,KACjD,MAAMoN,EAAe,CAAC,KAAM,MAAO,SAEnC,IAAIC,EAAmBlN,EACnBmN,GAAmB,EAGvB,GAAItN,GAAsBG,EAAUqM,SAAS,SAC3C,IACEa,EAAmBE,EAAcC,EAAarN,EAAW,QAC1D,CAAC,MAAOmL,GACP,OAAOQ,EAAa,EAAGR,EAAO,4BAC/B,MAGD+B,EAAmBE,EAAcpN,GAG7BkN,IAAqBrN,UAChBqN,EAAiBI,MAK5B,IAAK,MAAMC,KAAYL,EAChBD,EAAavI,SAAS6I,GAEfJ,IACVA,GAAmB,UAFZD,EAAiBK,GAO5B,OAAKJ,GAKDD,EAAiBI,QACnBJ,EAAiBI,MAAQJ,EAAiBI,MAAMhI,KAAKkI,GAASA,EAAKjI,WAC9D2H,EAAiBI,OAASJ,EAAiBI,MAAM7H,QAAU,WACvDyH,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,EAAYzJ,IACvB,GAAY,OAARA,GAA+B,iBAARA,EACzB,OAAOA,EAGT,MAAM0J,EAAOC,MAAMC,QAAQ5J,GAAO,GAAK,GAEvC,IAAK,MAAM6J,KAAO7J,EACZE,OAAO4J,UAAUC,eAAeC,KAAKhK,EAAK6J,KAC5CH,EAAKG,GAAOJ,EAASzJ,EAAI6J,KAI7B,OAAOH,CAAI,EAaAO,EAAmB,CAACvP,EAASwP,IAsBjCX,KAAKC,UAAU9O,GArBG,CAACwE,EAAMxF,KACT,iBAAVA,KACTA,EAAQA,EAAMyH,QAILa,WAAW,cAAgBtI,EAAMsI,WAAW,gBACnDtI,EAAMuO,SAAS,OAEfvO,EAAQwQ,EACJ,WAAWxQ,EAAQ,IAAIyQ,WAAW,YAAa,mBAC/C1J,GAIgB,mBAAV/G,EACV,WAAWA,EAAQ,IAAIyQ,WAAW,YAAa,cAC/CzQ,KAI2CyQ,WAC/C,qBACA,IAiCG,SAASC,IAKdpD,QAAQC,IACN,4BAA4BoD,KAC5B,WACA,yDANa,0DAMmDA,KAAKC,WAGvE,MAAMC,EAAmB7P,IACvB,IAAK,MAAOwE,EAAMsL,KAAWtK,OAAOuK,QAAQ/P,GAE1C,GAAKwF,OAAO4J,UAAUC,eAAeC,KAAKQ,EAAQ,SAE3C,CACL,IAAIE,EAAW,OAAOF,EAAOtO,SAAWgD,MACrC,IAAMsL,EAAO7Q,KAAO,KAAKgR,SAE5B,GAAID,EAASrJ,OAnBP,GAoBJ,IAAK,IAAIuJ,EAAIF,EAASrJ,OAAQuJ,EApB1B,GAoBmCA,IACrCF,GAAY,IAKhB1D,QAAQC,IACNyD,EACAF,EAAO5Q,YACP,aAAa4Q,EAAO9Q,MAAM0N,WAAWiD,QAAQQ,KAEhD,MAjBCN,EAAgBC,EAkBnB,EAIHtK,OAAOC,KAAK5G,GAAe6G,SAAS0K,IAE7B,CAAC,YAAa,cAAcxK,SAASwK,KACxC9D,QAAQC,IAAI,KAAK6D,EAASC,gBAAgBC,KAC1CT,EAAgBhR,EAAcuR,IAC/B,IAEH9D,QAAQC,IAAI,KACd,CAUO,MAYMgE,EAAa7B,IACxB,CAAC,QAAS,YAAa,OAAQ,MAAO,IAAK,IAAI9I,SAAS8I,MAElDA,EAWK8B,EAAa,CAACxP,EAAYD,KACrC,GAAIC,GAAoC,iBAAfA,EAGvB,OAFAA,EAAaA,EAAWyF,QAET8G,SAAS,SACfxM,GACHyP,EAAWjC,EAAavN,EAAY,SAGxCA,EAAWsG,WAAW,eACtBtG,EAAWsG,WAAW,gBACtBtG,EAAWsG,WAAW,SACtBtG,EAAWsG,WAAW,SAEf,IAAItG,OAENA,EAAWyP,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,CAACjR,EAASkR,EAAY/L,EAAgB,MACtE,MAAMgM,EAAgBpC,EAAS/O,GAE/B,IAAK,MAAOmP,EAAKnQ,KAAUwG,OAAOuK,QAAQmB,GACxCC,EAAchC,GDFA,iBADOT,ECIV1P,IDHgBiQ,MAAMC,QAAQR,IAAkB,OAATA,GCI/CvJ,EAAcS,SAASuJ,SACDpJ,IAAvBoL,EAAchC,QAEApJ,IAAV/G,EACEA,EACAmS,EAAchC,GAHhB8B,GAAmBE,EAAchC,GAAMnQ,EAAOmG,GDPhC,IAACuJ,ECavB,OAAOyC,CAAa,EAqFtB,SAASC,GAAoBC,EAAWC,EAAY,CAAA,EAAI/L,EAAY,IAClEC,OAAOC,KAAK4L,GAAW3L,SAASyJ,IAC9B,MAAMtJ,EAAQwL,EAAUlC,GAClBoC,EAAcD,GAAaA,EAAUnC,QAEhB,IAAhBtJ,EAAM7G,MACfoS,GAAoBvL,EAAO0L,EAAa,GAAGhM,KAAa4J,WAGpCpJ,IAAhBwL,IACF1L,EAAM7G,MAAQuS,GAIZ1L,EAAMxG,WAAW4H,QAAgClB,IAAxBkB,EAAKpB,EAAMxG,WACtCwG,EAAM7G,MAAQiI,EAAKpB,EAAMxG,UAE5B,GAEL,CAWA,SAASmS,GAAYC,GACnB,IAAIzR,EAAU,CAAA,EACd,IAAK,MAAOwE,EAAMkK,KAASlJ,OAAOuK,QAAQ0B,GACxCzR,EAAQwE,GAAQgB,OAAO4J,UAAUC,eAAeC,KAAKZ,EAAM,SACvDA,EAAK1P,MACLwS,GAAY9C,GAElB,OAAO1O,CACT,CA6EA,SAAS0R,GAAeC,EAAgBC,EAAa5S,GACnD,KAAO4S,EAAYjL,OAAS,GAAG,CAC7B,MAAM8H,EAAWmD,EAAYC,QAc7B,OAXKrM,OAAO4J,UAAUC,eAAeC,KAAKqC,EAAgBlD,KACxDkD,EAAelD,GAAY,IAI7BkD,EAAelD,GAAYiD,GACzBlM,OAAOsM,OAAO,CAAA,EAAIH,EAAelD,IACjCmD,EACA5S,GAGK2S,CACR,CAID,OADAA,EAAeC,EAAY,IAAM5S,EAC1B2S,CACT,CCtaAI,eAAeC,GAAMrE,EAAKsE,EAAiB,IACzC,OAAO,IAAIC,SAAQ,CAACC,EAASC,KAC3B,MAAMC,EAbU,CAAC1E,GAASA,EAAIrG,WAAW,SAAWgL,EAAQC,EAa3CC,CAAY7E,GAE7B0E,EACGI,IAAI9E,EAAKsE,GAAiBS,IACzB,IAAI/D,EAAO,GAGX+D,EAAIC,GAAG,QAASC,IACdjE,GAAQiE,CAAK,IAIfF,EAAIC,GAAG,OAAO,KACPhE,GACHyD,EAAO,qCAGTM,EAAIG,KAAOlE,EACXwD,EAAQO,EAAI,GACZ,IAEHC,GAAG,SAAUtG,IACZ+F,EAAO/F,EAAM,GACb,GAER,CCpDA,MAAMyG,WAAoBC,MACxB,WAAAC,CAAYvO,GACVwO,QACAC,KAAKzO,QAAUA,EACfyO,KAAKlG,aAAevI,CACrB,CAED,QAAA0O,CAAS9G,GAYP,OAXA6G,KAAK7G,MAAQA,EACTA,EAAM7H,OACR0O,KAAK1O,KAAO6H,EAAM7H,MAEhB6H,EAAM+G,aACRF,KAAKE,WAAa/G,EAAM+G,YAEtB/G,EAAMY,QACRiG,KAAKlG,aAAeX,EAAM5H,QAC1ByO,KAAKjG,MAAQZ,EAAMY,OAEdiG,IACR,ECWH,MAAMG,GAAQ,CACZ/T,OAAQ,+BACRgU,eAAgB,CAAE,EAClBC,QAAS,GACTC,UAAW,IAQAC,GAAkBJ,GACtBA,EAAME,QACVzN,UAAU,EAAGuN,EAAME,QAAQG,QAAQ,OACnCjD,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,MAAO,IACfhK,OAgEQkN,GAAwB5B,MACnC6B,EACA3B,EACA4B,EACAC,GAAmB,KAGfF,EAAOrG,SAAS,SAClBqG,EAASA,EAAO9N,UAAU,EAAG8N,EAAOjN,OAAS,IAG/C4F,EAAI,EAAG,6BAA6BqH,QAGpC,MAAMG,QAAiB/B,GAAM,GAAG4B,OAAa3B,GAG7C,GAA4B,MAAxB8B,EAASX,YAA8C,iBAAjBW,EAASlB,KAAkB,CACnE,GAAIgB,EAAgB,CAElBA,EADqCD,EA5EvBnD,QAChB,qEACA,KA2E+B,CAC9B,CAED,OAAOsD,EAASlB,IACjB,CAED,GAAIiB,EACF,MAAM,IAAIhB,GACR,uBAAuBc,2EAAgFG,EAASX,gBAChHD,SAASY,GAQb,OANExH,EACE,EACA,+BAA+BqH,8DAI5B,EAAE,EA+EEI,GAAcjC,MACzBkC,EACAC,EACAC,KAEA,MAAM/U,EAAU6U,EAAkB7U,QAC5BoU,EAAwB,WAAZpU,GAAyBA,EAAe,GAAGA,KAAR,GAC/CE,EAAS2U,EAAkB3U,QAAU+T,GAAM/T,OAEjDiN,EACE,EACA,iDAAiDiH,GAAa,aAGhE,MAAMK,EAAiB,CAAA,EACvB,IAwBE,OAvBAR,GAAME,aA9EkBxB,OAC1BxS,EACAC,EACAE,EACAwU,EACAL,KAGA,IAAIO,EACJ,MAAMC,EAAYH,EAAazS,KACzB6S,EAAYJ,EAAaxS,KAG/B,GAAI2S,GAAaC,EACf,IACEF,EAAa,IAAIG,EAAgB,CAC/B9S,KAAM4S,EACN3S,KAAM4S,GAET,CAAC,MAAOjI,GACP,MAAM,IAAIyG,GAAY,2CAA2CK,SAC/D9G,EAEH,CAIH,MAAM4F,EAAiBmC,EACnB,CACEI,MAAOJ,EACPvS,QAASoF,EAAK0B,sBAEhB,GAEE8L,EAAmB,IACpBlV,EAAYiH,KAAKoN,GAClBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,GAAgB,QAElErU,EAAcgH,KAAKoN,GACpBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,QAElDnU,EAAc8G,KAAKoN,GACpBD,GAAsB,GAAGC,IAAU3B,MAKvC,aAD6BC,QAAQwC,IAAID,IACnB9P,KAAK,MAAM,EA+BTgQ,CACpB,IACKV,EAAkB1U,YAAYiH,KAAKoO,GAAM,GAAGtV,IAASkU,IAAYoB,OAEtE,IACKX,EAAkBzU,cAAcgH,KAAKqO,GAChC,QAANA,EACI,GAAGvV,SAAckU,YAAoBqB,IACrC,GAAGvV,IAASkU,YAAoBqB,SAEnCZ,EAAkBxU,iBAAiB+G,KACnC0J,GAAM,GAAG5Q,UAAekU,eAAuBtD,OAGpD+D,EAAkBvU,cAClBwU,EACAL,GAGFR,GAAMG,UAAYC,GAAeJ,IAGjCyB,EAAcX,EAAYd,GAAME,SACzBM,CACR,CAAC,MAAOxH,GACP,MAAM,IAAIyG,GACR,wDACAK,SAAS9G,EACZ,GAiCU0I,GAAsBhD,MAAO/R,IACxC,MAAMb,WAAEA,EAAUmC,OAAEA,GAAWtB,EACzBJ,EAAY+E,EAAK6I,EAAWrO,EAAWS,WAE7C,IAAIiU,EAEJ,MAAMmB,EAAerQ,EAAK/E,EAAW,iBAC/BuU,EAAaxP,EAAK/E,EAAW,cAOnC,IAJCqM,EAAWrM,IAAcsM,EAAUtM,IAI/BqM,EAAW+I,IAAiB7V,EAAWQ,WAC1C4M,EAAI,EAAG,yDACPsH,QAAuBG,GAAY7U,EAAYmC,EAAOM,MAAOuS,OACxD,CACL,IAAIc,GAAgB,EAGpB,MAAMC,EAAWrG,KAAKxD,MAAMkD,EAAayG,IAIzC,GAAIE,EAASxW,SAAWuQ,MAAMC,QAAQgG,EAASxW,SAAU,CACvD,MAAMyW,EAAY,CAAA,EAClBD,EAASxW,QAAQgH,SAASmP,GAAOM,EAAUN,GAAK,IAChDK,EAASxW,QAAUyW,CACpB,CAED,MAAM5V,YAAEA,EAAWC,cAAEA,EAAaC,iBAAEA,GAAqBN,EACnDiW,EACJ7V,EAAYoH,OAASnH,EAAcmH,OAASlH,EAAiBkH,OAK3DuO,EAAS9V,UAAYD,EAAWC,SAClCmN,EACE,EACA,yEAEF0I,GAAgB,GACPzP,OAAOC,KAAKyP,EAASxW,SAAW,IAAIiI,SAAWyO,GACxD7I,EACE,EACA,+EAEF0I,GAAgB,GAGhBA,GAAiBzV,GAAiB,IAAI6V,MAAMC,IAC1C,IAAKJ,EAASxW,QAAQ4W,GAKpB,OAJA/I,EACE,EACA,eAAe+I,iDAEV,CACR,IAIDL,EACFpB,QAAuBG,GAAY7U,EAAYmC,EAAOM,MAAOuS,IAE7D5H,EAAI,EAAG,uDAGP8G,GAAME,QAAUhF,EAAa4F,EAAY,QAGzCN,EAAiBqB,EAASxW,QAE1B2U,GAAMG,UAAYC,GAAeJ,IAEpC,MArTiCtB,OAAO9L,EAAQ4N,KACjD,MAAM0B,EAAc,CAClBnW,QAAS6G,EAAO7G,QAChBV,QAASmV,GAAkB,CAAE,GAI/BR,GAAMC,eAAiBiC,EAEvBhJ,EAAI,EAAG,mCACP,IACEuI,EACEnQ,EAAK6I,EAAWvH,EAAOrG,UAAW,iBAClCiP,KAAKC,UAAUyG,GACf,OAEH,CAAC,MAAOlJ,GACP,MAAM,IAAIyG,GAAY,6CAA6CK,SACjE9G,EAEH,GAqSKmJ,CAAqBrW,EAAY0U,EAAe,EAG3C4B,GAAe,IAC1B9Q,EAAK6I,EAAWwD,KAAa7R,WAAWS,WAM7BR,GAAU,IAAMiU,GAAMG,UCzX5B,SAASkC,KACdC,WAAWC,WAAa,WACtB,MAAO,CAAEC,SAAU,EACvB,CACA,CASO9D,eAAe+D,GAAcC,EAAc/V,EAASgW,GAEzDhU,OAAOiU,eAAiBD,EAGxB,MAAMhF,WAAEA,EAAUkF,MAAEA,EAAKC,WAAEA,EAAUC,KAAEA,GAAST,WAIhDA,WAAWU,cAAgBH,GAAM,EAAO,CAAE,EAAElF,KAGxChR,EAAQa,YAAYG,YACtB,IAAIsV,SAAStW,EAAQa,YAAYG,WAAjC,GAIF,MAAMuV,EAAQ,CACZC,WAAW,GAITxW,EAAQH,OAAO4W,SACjBF,EAAMjW,OAASyV,EAAaQ,MAAMjW,OAClCiW,EAAMhW,MAAQwV,EAAaQ,MAAMhW,OAInCyB,OAAO0U,kBAAmB,EAC1BN,EAAKT,WAAWgB,MAAMvH,UAAW,QAAQ,SAAUwH,EAASC,EAAaC,KAEvED,EAAcX,EAAMW,EAAa,CAC/BE,UAAW,CACTC,SAAS,GAEXC,YAAa,CACXC,OAAQ,CACNC,MAAO,CACLH,SAAS,KAOfI,QAAS,CAAE,KAGAF,QAAU,IAAIxR,SAAQ,SAAUwR,GAC3CA,EAAOV,WAAY,CACzB,IAGSxU,OAAOqV,qBACVrV,OAAOqV,mBAAqB1B,WAAW2B,SAASpE,KAAM,UAAU,KAC9DlR,OAAO0U,kBAAmB,CAAI,KAIlCE,EAAQhK,MAAMsG,KAAM,CAAC2D,EAAaC,GACtC,IAEEV,EAAKT,WAAW4B,OAAOnI,UAAW,QAAQ,SAAUwH,EAASL,EAAOvW,GAClE4W,EAAQhK,MAAMsG,KAAM,CAACqD,EAAOvW,GAChC,IAGE,MAAM6W,EAAc7W,EAAQH,OAAO4W,OAC/B,IAAIH,SAAS,UAAUtW,EAAQH,OAAO4W,SAAtC,GACAV,EAIEyB,EAAetB,GACnB,EACArH,KAAKxD,MAAMrL,EAAQH,OAAOa,cAC1BmW,EAEA,CAAEN,UAGEkB,EAAgBzX,EAAQa,YAAYI,SACtC,IAAIqV,SAAS,UAAUtW,EAAQa,YAAYI,WAA3C,QACA8E,EAGEtF,EAAgBoO,KAAKxD,MAAMrL,EAAQH,OAAOY,eAC5CA,GACF0V,EAAW1V,GAGbkV,WAAW3V,EAAQH,OAAOK,QAAU,SAClC,YACAsX,EACAC,GAIF,MAAMC,EAAiB1G,IAGvB,IAAK,MAAM2G,KAAQD,EACmB,mBAAzBA,EAAeC,WACjBD,EAAeC,GAK1BxB,EAAWR,WAAWU,eAGtBV,WAAWU,cAAgB,EAC7B,CCpHA,MAAMuB,GAAWrJ,EAAaf,EAAY,2BAA4B,QAEtE,IAAIqK,GAiIG9F,eAAe+F,KACpB,IAAKD,GACH,OAAO,EAIT,MAAME,QAAaF,GAAQC,UAW3B,aARMC,EAAKC,iBAAgB,SAGrBC,GAAeF,GA+NvB,SAAuBA,GAErB,MAAM/T,MAAEA,GAAUgN,KAGdhN,EAAMzC,QAAUyC,EAAMG,iBACxB4T,EAAKpF,GAAG,WAAYlO,IAClB6H,QAAQC,IAAI,WAAW9H,EAAQoO,SAAS,IAK5CkF,EAAKpF,GAAG,aAAaZ,MAAO1F,UAGpB0L,EAAKG,MACT,cACA,CAACC,EAASC,KAEJpW,OAAOiU,iBACTkC,EAAQE,UAAYD,EACrB,GAEH,oCAAoC/L,EAAMK,aAC3C,GAEL,CAtPE4L,CAAcP,GAEPA,CACT,CAwJOhG,eAAewG,GAAmBR,EAAMS,GAC7C,IAAK,MAAMC,KAAYD,QACfC,EAASC,gBAIXX,EAAKY,UAAS,KAGlB,GAA0B,oBAAfhD,WAA4B,CAErC,MAAMiD,EAAYjD,WAAWkD,OAG7B,GAAI5J,MAAMC,QAAQ0J,IAAcA,EAAUjS,OAExC,IAAK,MAAMmS,KAAYF,EACrBE,GAAYA,EAASC,UAErBpD,WAAWkD,OAAOhH,OAGvB,CAGD,SAAUmH,GAAmBC,SAASC,qBAAqB,WAErD,IAAMC,GAAkBF,SAASC,qBAAqB,aAElDE,GAAiBH,SAASC,qBAAqB,QAGzD,IAAK,MAAMf,IAAW,IACjBa,KACAG,KACAC,GAEHjB,EAAQkB,QACT,GAEL,CAUAtH,eAAekG,GAAeF,SACtBA,EAAKuB,WAAW1B,GAAU,CAAE2B,UAAW,2BAGvCxB,EAAKyB,aAAa,CAAEC,KAAM,GAAGhE,0BAG7BsC,EAAKY,SAASjD,GACtB,CCnWA,MAwGMgE,GAAc3H,MAAOgG,EAAMxB,EAAOvW,EAASgW,IAC/C+B,EAAKY,SAAS7C,GAAeS,EAAOvW,EAASgW,GAY/C,IAAA2D,GAAe5H,MAAOgG,EAAMxB,EAAOvW,KAEjC,IAAIwY,EAAoB,GAExB,IACEjM,EAAI,EAAG,qCAEP,MAAMqN,EAAgB5Z,EAAQH,OAGxBmW,EACJ4D,GAAe5Z,SAASuW,OAAOP,eHwOP3C,GGvObC,eAAe5U,QAAQmb,SAEpC,IAAIC,EACJ,GACEvD,EAAM7C,UACL6C,EAAM7C,QAAQ,SAAW,GAAK6C,EAAM7C,QAAQ,UAAY,GACzD,CAKA,GAHAnH,EAAI,EAAG,6BAGoB,QAAvBqN,EAAc3a,KAChB,OAAOsX,EAGTuD,GAAQ,QACF/B,EAAKuB,WCjKF,CAAC/C,GAAU,knBAYlBA,wCDqJoBwD,CAAYxD,GAAQ,CACxCgD,UAAW,oBAEnB,MAEMhN,EAAI,EAAG,gCAGHqN,EAAcnD,aAEViD,GACJ3B,EACA,CACExB,MAAO,CACLjW,OAAQsZ,EAActZ,OACtBC,MAAOqZ,EAAcrZ,QAGzBP,EACAgW,IAIFO,EAAMA,MAAMjW,OAASsZ,EAActZ,OACnCiW,EAAMA,MAAMhW,MAAQqZ,EAAcrZ,YAE5BmZ,GAAY3B,EAAMxB,EAAOvW,EAASgW,IAO5CwC,QDiBGzG,eAAgCgG,EAAM/X,GAE3C,MAAMwY,EAAoB,GAGpBtX,EAAYlB,EAAQa,YAAYK,UACtC,GAAIA,EAAW,CACb,MAAM8Y,EAAa,GAUnB,GAPI9Y,EAAU+Y,IACZD,EAAWE,KAAK,CACdC,QAASjZ,EAAU+Y,KAKnB/Y,EAAUsN,MACZ,IAAK,MAAMpL,KAAQlC,EAAUsN,MAAO,CAClC,MAAM4L,GAAWhX,EAAKkE,WAAW,QAGjC0S,EAAWE,KACTE,EACI,CACED,QAAS5L,EAAanL,EAAM,SAE9B,CACEuK,IAAKvK,GAGd,CAGH,IAAK,MAAMiX,KAAcL,EACvB,IACExB,EAAkB0B,WAAWnC,EAAKyB,aAAaa,GAChD,CAAC,MAAOhO,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAEH2N,EAAWrT,OAAS,EAGpB,MAAM2T,EAAc,GACpB,GAAIpZ,EAAUqZ,IAAK,CACjB,IAAIC,EAAatZ,EAAUqZ,IAAIE,MAAM,uBACrC,GAAID,EAEF,IAAK,IAAIE,KAAiBF,EACpBE,IACFA,EAAgBA,EACbjK,QAAQ,OAAQ,IAChBA,QAAQ,UAAW,IACnBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,IAAK,IACbA,QAAQ,MAAO,IACfhK,OAGCiU,EAAcpT,WAAW,QAC3BgT,EAAYJ,KAAK,CACfvM,IAAK+M,IAEE1a,EAAQa,YAAYE,oBAC7BuZ,EAAYJ,KAAK,CACfT,KAAMA,EAAK9U,KAAK6I,EAAWkN,MAQrCJ,EAAYJ,KAAK,CACfC,QAASjZ,EAAUqZ,IAAI9J,QAAQ,sBAAuB,KAAO,MAG/D,IAAK,MAAMkK,KAAeL,EACxB,IACE9B,EAAkB0B,WAAWnC,EAAK6C,YAAYD,GAC/C,CAAC,MAAOtO,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CAEHiO,EAAY3T,OAAS,CACtB,CACF,CACD,OAAO6R,CACT,CC3G8BqC,CAAiB9C,EAAM/X,GAGjD,MAAM8a,EAAOhB,QACH/B,EAAKY,UAAUnY,IACnB,MAAMua,EAAa9B,SAAS+B,cAC1B,sCAIIC,EAAcF,EAAWza,OAAO4a,QAAQlc,MAAQwB,EAChD2a,EAAaJ,EAAWxa,MAAM2a,QAAQlc,MAAQwB,EAWpD,OANAyY,SAASmC,KAAKC,MAAMC,KAAO9a,EAI3ByY,SAASmC,KAAKC,MAAME,OAAS,MAEtB,CACLN,cACAE,aACD,GACAnU,WAAW4S,EAAcpZ,cACtBuX,EAAKY,UAAS,KAElB,MAAMsC,YAAEA,EAAWE,WAAEA,GAAenZ,OAAO2T,WAAWkD,OAAO,GAO7D,OAFAI,SAASmC,KAAKC,MAAMC,KAAO,EAEpB,CACLL,cACAE,aACD,IAIDK,EAAiBC,KAAKC,KAAKZ,EAAKG,aAAerB,EAActZ,QAC7Dqb,EAAgBF,KAAKC,KAAKZ,EAAKK,YAAcvB,EAAcrZ,QAG3Dqb,EAAEA,EAACC,EAAEA,QAjOO,CAAC9D,GACrBA,EAAKG,MAAM,oBAAqBC,IAC9B,MAAMyD,EAAEA,EAACC,EAAEA,EAACtb,MAAEA,EAAKD,OAAEA,GAAW6X,EAAQ2D,wBACxC,MAAO,CACLF,IACAC,IACAtb,QACAD,OAAQmb,KAAKM,MAAMzb,EAAS,EAAIA,EAAS,KAC1C,IAyNsB0b,CAAcjE,GASrC,IAAIpJ,EAEJ,SARMoJ,EAAKkE,YAAY,CACrB3b,OAAQkb,EACRjb,MAAOob,EACPO,kBAAmBpC,EAAQ,EAAI9S,WAAW4S,EAAcpZ,SAK/B,QAAvBoZ,EAAc3a,KAEhB0P,OAnJY,CAACoJ,GACjBA,EAAKG,MAAM,gCAAiCC,GAAYA,EAAQgE,YAkJ/CC,CAAUrE,QAClB,GAAI,CAAC,MAAO,QAAQnS,SAASgU,EAAc3a,MAEhD0P,OAxNc,EAACoJ,EAAM9Y,EAAMod,EAAUC,EAAM1b,IAC/CsR,QAAQqK,KAAK,CACXxE,EAAKyE,WAAW,CACdvd,OACAod,WACAC,OACAG,uBAAuB,EACvBC,UAAU,EACVC,kBAAkB,KACL,QAAT1d,EAAiB,CAAE2d,QAAS,IAAO,CAAE,EAIzCC,eAAwB,OAAR5d,IAElB,IAAIiT,SAAQ,CAAC4K,EAAU1K,IACrB2K,YACE,IAAM3K,EAAO,IAAIU,GAAY,2BAC7BlS,GAAwB,UAsMboc,CACXjF,EACA6B,EAAc3a,KACd,SACA,CACEsB,MAAOob,EACPrb,OAAQkb,EACRI,IACAC,KAEFjC,EAAchZ,0BAEX,IAA2B,QAAvBgZ,EAAc3a,KAUvB,MAAM,IAAI6T,GACR,sCAAsC8G,EAAc3a,SATtD0P,OApMYoD,OAChBgG,EACAzX,EACAC,EACA8b,EACAzb,WAEMmX,EAAKkF,iBAAiB,UACrB/K,QAAQqK,KAAK,CAClBxE,EAAKmF,IAAI,CAEP5c,OAAQA,EAAS,EACjBC,QACA8b,aAEF,IAAInK,SAAQ,CAAC4K,EAAU1K,IACrB2K,YACE,IAAM3K,EAAO,IAAIU,GAAY,2BAC7BlS,GAAwB,WAkLbuc,CACXpF,EACAyD,EACAG,EACA,SACA/B,EAAchZ,qBAMjB,CAID,aADM2X,GAAmBR,EAAMS,GACxB7J,CACR,CAAC,MAAOtC,GAEP,aADMkM,GAAmBR,EAAMS,GACxBnM,CACR,GEpRH,IAAI7J,IAAO,EAGJ,MAAM4a,GAAQ,CACnBC,iBAAkB,EAClBC,eAAgB,EAChBC,sBAAuB,EACvBC,UAAW,EACXC,eAAgB,EAChBC,aAAc,GAGhB,IAAIC,GAAa,CAAA,EAEjB,MAAMC,GAAU,CAUdC,OAAQ9L,UACN,IAAIgG,GAAO,EAEX,MAAM+F,EAAKC,IACLC,GAAY,IAAIvR,MAAOwR,UAE7B,IAGE,GAFAlG,QAAaD,MAERC,GAAQA,EAAKmG,WAChB,MAAM,IAAIpL,GAAY,kCAGxBvG,EACE,EACA,wCAAwCuR,aACtC,IAAIrR,MAAOwR,UAAYD,QAG5B,CAAC,MAAO3R,GACP,MAAM,IAAIyG,GACR,+CACAK,SAAS9G,EACZ,CAED,MAAO,CACLyR,KACA/F,OAEAoG,UAAW1C,KAAKvW,MAAMuW,KAAK2C,UAAYT,GAAWhb,UAAY,IAC/D,EAaH0b,SAAUtM,MAAOuM,KAEbX,GAAWhb,aACT2b,EAAaH,UAAYR,GAAWhb,aAEtC4J,EACE,EACA,kEAAkEoR,GAAWhb,gBAExE,GAWXoW,QAAShH,MAAOuM,IACd/R,EAAI,EAAG,gCAAgC+R,EAAaR,OAEhDQ,EAAavG,YAETuG,EAAavG,KAAKwG,OACzB,GAWQC,GAAWzM,MAAO9L,IAY7B,GAVA0X,GAAa1X,GAAUA,EAAOzD,KAAO,IAAKyD,EAAOzD,MAAS,SH7ErDuP,eAAsB0M,GAE3B,MAAMza,MAAEA,EAAKN,MAAEA,GAAUsN,MAGjBzP,OAAQmd,KAAiBC,GAAiB3a,EAE5C4a,EAAgB,CACpB3a,UAAUP,EAAMK,kBAAmB,QACnC8a,YAAa,SACb9f,KAAM0f,EACNK,cAAc,EACdC,eAAe,EACfC,cAAc,EACdC,oBAAoB,EACpBC,gBAAiB,QACbR,GAAgBC,GAItB,IAAK9G,GAAS,CACZ,IAAIsH,EAAW,EAEf,MAAMC,EAAOrN,UACX,IACExF,EACE,EACA,yDAAyD4S,OAE3DtH,SAAgB/Y,EAAUugB,OAAOT,EAClC,CAAC,MAAOvS,GAQP,GAPAQ,EACE,EACAR,EACA,oDAIE8S,EAAW,IAKb,MAAM9S,EAJNE,EAAI,EAAG,sCAAsC4S,uBACvC,IAAIjN,SAAS6B,GAAagJ,WAAWhJ,EAAU,aAC/CqL,GAIT,GAGH,UACQA,IAGyB,UAA3BR,EAAc3a,UAChBsI,EAAI,EAAG,6CAILmS,GACFnS,EAAI,EAAG,4CAEV,CAAC,MAAOF,GACP,MAAM,IAAIyG,GACR,iEACAK,SAAS9G,EACZ,CAED,IAAKwL,GACH,MAAM,IAAI/E,GAAY,2CAEzB,CAGD,OAAO+E,EACT,CGOQyH,CAAcrZ,EAAOwY,eAE3BlS,EACE,EACA,8CAA8CoR,GAAWlb,mBAAmBkb,GAAWjb,eAGrFF,GACF,OAAO+J,EACL,EACA,yEAIAgT,SAAS5B,GAAWlb,YAAc8c,SAAS5B,GAAWjb,cACxDib,GAAWlb,WAAakb,GAAWjb,YAGrC,IAEEF,GAAO,IAAIgd,EAAK,IAEX5B,GACH5Y,IAAKua,SAAS5B,GAAWlb,YACzBwC,IAAKsa,SAAS5B,GAAWjb,YACzB+c,qBAAsB9B,GAAW/a,eACjC8c,oBAAqB/B,GAAW9a,cAChC8c,qBAAsBhC,GAAW7a,eACjC8c,kBAAmBjC,GAAW5a,YAC9B8c,0BAA2BlC,GAAW3a,oBACtC8c,mBAAoBnC,GAAW1a,eAC/B8c,sBAAsB,IAIxBvd,GAAKmQ,GAAG,WAAWZ,MAAO0G,UHgBvB1G,eAAyBgG,EAAMiI,GAAY,GAChD,IACOjI,EAAKmG,aACJ8B,SAEIjI,EAAKkI,KAAK,cAAe,CAAE1G,UAAW,2BAGtCtB,GAAeF,UAGfA,EAAKY,UAAS,KAClBM,SAASmC,KAAK/C,UACZ,4DAA4D,IAIrE,CAAC,MAAOhM,GACPQ,EACE,EACAR,EACA,qDAEH,CACH,CGtCY6T,CAAUzH,EAASV,MAAM,GAC/BxL,EAAI,EAAG,qCAAqCkM,EAASqF,MAAM,IAG7Dtb,GAAKmQ,GAAG,kBAAkB,CAACwN,EAAS1H,KAClClM,EAAI,EAAG,qCAAqCkM,EAASqF,MAAM,IAG7D,MAAMsC,EAAmB,GAEzB,IAAK,IAAIlQ,EAAI,EAAGA,EAAIyN,GAAWlb,WAAYyN,IACzC,IACE,MAAMuI,QAAiBjW,GAAK6d,UAAUC,QACtCF,EAAiBlG,KAAKzB,EACvB,CAAC,MAAOpM,GACPQ,EAAa,EAAGR,EAAO,+CACxB,CAIH+T,EAAiB1a,SAAS+S,IACxBjW,GAAK+d,QAAQ9H,EAAS,IAGxBlM,EACE,EACA,4BAA2B6T,EAAiBzZ,OAAS,SAASyZ,EAAiBzZ,oCAAsC,KAExH,CAAC,MAAO0F,GACP,MAAM,IAAIyG,GACR,gDACAK,SAAS9G,EACZ,GAUI0F,eAAeyO,KAIpB,GAHAjU,EAAI,EAAG,6DAGH/J,GAAM,CAER,IAAK,MAAMie,KAAUje,GAAKke,KACxBle,GAAK+d,QAAQE,EAAOhI,UAIjBjW,GAAKme,kBACFne,GAAKuW,UACXxM,EAAI,EAAG,8CAEV,OH7FIwF,iBAED8F,IAAS+I,iBACL/I,GAAQ0G,QAEhBhS,EAAI,EAAG,gCACT,CG0FQsU,EACR,CAeO,MAAMC,GAAW/O,MAAOwE,EAAOvW,KACpC,IAAIse,EAEJ,IAQE,GAPA/R,EAAI,EAAG,gDAEL6Q,GAAME,eACJK,GAAWhc,cACbof,MAGGve,GACH,MAAM,IAAIsQ,GAAY,iDAIxB,MAAMkO,EAAiBtQ,KACvB,IACEnE,EAAI,EAAG,qCACP+R,QAAqB9b,GAAK6d,UAAUC,QAGhCtgB,EAAQsB,OAAOK,cACjB4K,EACE,EACAvM,EAAQihB,SAASC,UACb,+BAA+BlhB,EAAQihB,SAASC,cAChD,cACJ,6BAA6BF,SAGlC,CAAC,MAAO3U,GACP,MAAM,IAAIyG,IACP9S,EAAQihB,SAASC,UACd,uBAAuBlhB,EAAQihB,SAASC,eACxC,IACF,wDAAwDF,UAC1D7N,SAAS9G,EACZ,CAGD,GAFAE,EAAI,EAAG,qCAEF+R,EAAavG,KAChB,MAAM,IAAIjF,GACR,6DAKJ,IAAIqO,GAAY,IAAI1U,MAAOwR,UAE3B1R,EAAI,EAAG,8CAA8C+R,EAAaR,OAGlE,MAAMsD,EAAgB1Q,KAChB2Q,QAAe1H,GAAgB2E,EAAavG,KAAMxB,EAAOvW,GAG/D,GAAIqhB,aAAkBtO,MAOpB,KALuB,0BAAnBsO,EAAO5c,UACT6Z,EAAavG,KAAKwG,QAClBD,EAAavG,WAAaD,MAGtB,IAAIhF,IACP9S,EAAQihB,SAASC,UACd,uBAAuBlhB,EAAQihB,SAASC,eACxC,IAAM,oCAAoCE,UAC9CjO,SAASkO,GAITrhB,EAAQsB,OAAOK,cACjB4K,EACE,EACAvM,EAAQihB,SAASC,UACb,+BAA+BlhB,EAAQihB,SAASC,cAChD,cACJ,iCAAiCE,UAKrC5e,GAAK+d,QAAQjC,GAIb,MACMgD,GADU,IAAI7U,MAAOwR,UACEkD,EAO7B,OANA/D,GAAMI,WAAa8D,EACnBlE,GAAMM,aAAeN,GAAMI,YAAcJ,GAAMC,iBAE/C9Q,EAAI,EAAG,4BAA4B+U,SAG5B,CACLD,SACArhB,UAEH,CAAC,MAAOqM,GAOP,OANE+Q,GAAMK,eAEJa,GACF9b,GAAK+d,QAAQjC,GAGT,IAAIxL,GAAY,4BAA4BzG,EAAM5H,WAAW0O,SACjE9G,EAEH,GAiBUkV,GAAkB,KAAO,CACpCvc,IAAKxC,GAAKwC,IACVC,IAAKzC,GAAKyC,IACVyP,IAAKlS,GAAKgf,UAAYhf,GAAKif,UAC3BC,UAAWlf,GAAKgf,UAChBd,KAAMle,GAAKif,UACXE,QAASnf,GAAKof,uBAQT,SAASb,KACd,MAAM/b,IAAEA,EAAGC,IAAEA,EAAGyP,IAAEA,EAAGgN,UAAEA,EAAShB,KAAEA,EAAIiB,QAAEA,GAAYJ,KAEpDhV,EAAI,EAAG,2DAA2DvH,MAClEuH,EAAI,EAAG,2DAA2DtH,MAClEsH,EAAI,EAAG,+CAA+CmI,MACtDnI,EAAI,EAAG,6CAA6CmV,MACpDnV,EAAI,EAAG,4CAA4CmU,MACnDnU,EAAI,EAAG,0DAA0DoV,KACnE,CAEA,IAAeE,GAMbN,GANaM,GAOH,IAAMzE,GC3XlB,IAAItc,IAAqB,EAgBlB,MAAMghB,GAAc/P,MAAOgQ,EAAUC,KAE1CzV,EAAI,EAAG,2CAGP,MAAMvM,ETyL0B,EAAC4Z,EAAe7I,EAAiB,MACjE,IAAI/Q,EAAU,CAAA,EAsBd,OApBI4Z,EAAcqI,KAChBjiB,EAAU+O,EAASgC,GACnB/Q,EAAQH,OAAOZ,KAAO2a,EAAc3a,MAAQ2a,EAAc/Z,OAAOZ,KACjEe,EAAQH,OAAOW,MAAQoZ,EAAcpZ,OAASoZ,EAAc/Z,OAAOW,MACnER,EAAQH,OAAOI,QACb2Z,EAAc3Z,SAAW2Z,EAAc/Z,OAAOI,QAChDD,EAAQihB,QAAU,CAChBgB,IAAKrI,EAAcqI,MAGrBjiB,EAAUiR,GACRF,EACA6I,EAEAzU,GAIJnF,EAAQH,OAAOI,QACbD,EAAQH,QAAQI,SAAW,SAASD,EAAQH,QAAQZ,MAAQ,QACvDe,CAAO,EShNEkiB,CAAmBH,EAAU/Q,MAGvC4I,EAAgB5Z,EAAQH,OAG9B,GAAIG,EAAQihB,SAASgB,KAA+B,KAAxBjiB,EAAQihB,QAAQgB,IAC1C,IACE1V,EAAI,EAAG,kDAEP,MAAM8U,EAASc,GChCd,SAAkBC,GACvB,MAAMpgB,EAAS,IAAIqgB,EAAM,IAAIrgB,OAE7B,OADesgB,EAAUtgB,GACXugB,SAASH,EAAO,CAAEI,SAAU,CAAC,kBAC7C,CD6BQD,CAASviB,EAAQihB,QAAQgB,KACzBjiB,EACAgiB,GAIF,QADE5E,GAAMG,sBACD8D,CACR,CAAC,MAAOhV,GACP,OAAO2V,EACL,IAAIlP,GAAY,oCAAoCK,SAAS9G,GAEhE,CAIH,GAAIuN,EAAc9Z,QAAU8Z,EAAc9Z,OAAO6G,OAE/C,IAGE,OAFA4F,EAAI,EAAG,oDACPvM,EAAQH,OAAOE,MAAQwO,EAAaqL,EAAc9Z,OAAQ,QACnDqiB,GAAeniB,EAAQH,OAAOE,MAAM0G,OAAQzG,EAASgiB,EAC7D,CAAC,MAAO3V,GACP,OAAO2V,EACL,IAAIlP,GAAY,qCAAqCK,SAAS9G,GAEjE,CAIH,GACGuN,EAAc7Z,OAAiC,KAAxB6Z,EAAc7Z,OACrC6Z,EAAc5Z,SAAqC,KAA1B4Z,EAAc5Z,QAExC,IAIE,OAHAuM,EAAI,EAAG,kDAGHgE,EAAUvQ,EAAQa,aAAaC,oBAC1B2hB,GAAiBziB,EAASgiB,GAIG,iBAAxBpI,EAAc7Z,MACxBoiB,GAAevI,EAAc7Z,MAAM0G,OAAQzG,EAASgiB,GACpDU,GACE1iB,EACA4Z,EAAc7Z,OAAS6Z,EAAc5Z,QACrCgiB,EAEP,CAAC,MAAO3V,GACP,OAAO2V,EACL,IAAIlP,GAAY,oCAAoCK,SAAS9G,GAEhE,CAIH,OAAO2V,EACL,IAAIlP,GACF,iJAEH,EA+GU6P,GAAiB3iB,IAC5B,MAAMuW,MAAEA,EAAKQ,UAAEA,GACb/W,EAAQH,QAAQG,SAAWsO,EAActO,EAAQH,QAAQE,OAGrDU,EAAgB6N,EAActO,EAAQH,QAAQY,eAGpD,IAAID,EACFR,EAAQH,QAAQW,OAChBuW,GAAWvW,OACXC,GAAesW,WAAWvW,OAC1BR,EAAQH,QAAQQ,cAChB,EAGFG,EAAQib,KAAKxW,IAAI,GAAKwW,KAAKzW,IAAIxE,EAAO,IAGtCA,EV2IyB,EAACxB,EAAO4jB,EAAY,KAC7C,MAAMC,EAAapH,KAAKqH,IAAI,GAAIF,GAAa,GAC7C,OAAOnH,KAAKvW,OAAOlG,EAAQ6jB,GAAcA,CAAU,EU7I3CE,CAAYviB,EAAO,GAG3B,MAAMsa,EAAO,CACXxa,OACEN,EAAQH,QAAQS,QAChByW,GAAWiM,cACXzM,GAAOjW,QACPG,GAAesW,WAAWiM,cAC1BviB,GAAe8V,OAAOjW,QACtBN,EAAQH,QAAQM,eAChB,IACFI,MACEP,EAAQH,QAAQU,OAChBwW,GAAWkM,aACX1M,GAAOhW,OACPE,GAAesW,WAAWkM,aAC1BxiB,GAAe8V,OAAOhW,OACtBP,EAAQH,QAAQO,cAChB,IACFI,SAIF,IAAK,IAAK0iB,EAAOlkB,KAAUwG,OAAOuK,QAAQ+K,GACxCA,EAAKoI,GACc,iBAAVlkB,GAAsBA,EAAMyR,QAAQ,SAAU,IAAMzR,EAE/D,OAAO8b,CAAI,EAgBP4H,GAAW3Q,MAAO/R,EAASmjB,EAAWnB,EAAaC,KACvD,IAAMpiB,OAAQ+Z,EAAe/Y,YAAauiB,GAAuBpjB,EAEjE,MAAMqjB,EAC6C,kBAA1CD,EAAmBtiB,mBACtBsiB,EAAmBtiB,mBACnBA,GAEN,GAAKsiB,GAEE,GAAIC,EACT,GAA6C,iBAAlCrjB,EAAQa,YAAYK,UAE7BlB,EAAQa,YAAYK,UAAYgN,EAC9BlO,EAAQa,YAAYK,UACpBqP,EAAUvQ,EAAQa,YAAYE,0BAE3B,IAAKf,EAAQa,YAAYK,UAC9B,IACE,MAAMA,EAAYqN,EAAa,iBAAkB,QACjDvO,EAAQa,YAAYK,UAAYgN,EAC9BhN,EACAqP,EAAUvQ,EAAQa,YAAYE,oBAEjC,CAAC,MAAOsL,GACPQ,EACE,EACAR,EACA,0DAEH,OArBH+W,EAAqBpjB,EAAQa,YAAc,GA6B7C,IAAKwiB,GAA4BD,EAAoB,CACnD,GACEA,EAAmBniB,UACnBmiB,EAAmBliB,WACnBkiB,EAAmBpiB,WAInB,OAAOghB,EACL,IAAIlP,GACF,qGAMNsQ,EAAmBniB,UAAW,EAC9BmiB,EAAmBliB,WAAY,EAC/BkiB,EAAmBpiB,YAAa,CACjC,CAyCD,GAtCImiB,IACFA,EAAU5M,MAAQ4M,EAAU5M,OAAS,CAAA,EACrC4M,EAAUpM,UAAYoM,EAAUpM,WAAa,CAAA,EAC7CoM,EAAUpM,UAAUC,SAAU,GAGhC4C,EAAc1Z,OAAS0Z,EAAc1Z,QAAU,QAC/C0Z,EAAc3a,KAAO2O,EAAQgM,EAAc3a,KAAM2a,EAAc3Z,SACpC,QAAvB2Z,EAAc3a,OAChB2a,EAAcrZ,OAAQ,GAIxB,CAAC,gBAAiB,gBAAgBmF,SAAS4d,IACzC,IACM1J,GAAiBA,EAAc0J,KAEO,iBAA/B1J,EAAc0J,IACrB1J,EAAc0J,GAAa/V,SAAS,SAEpCqM,EAAc0J,GAAehV,EAC3BC,EAAaqL,EAAc0J,GAAc,SACzC,GAGF1J,EAAc0J,GAAehV,EAC3BsL,EAAc0J,IACd,GAIP,CAAC,MAAOjX,GACPuN,EAAc0J,GAAe,GAC7BzW,EAAa,EAAGR,EAAO,gBAAgBiX,uBACxC,KAICF,EAAmBtiB,mBACrB,IACEsiB,EAAmBpiB,WAAawP,EAC9B4S,EAAmBpiB,WACnBoiB,EAAmBriB,mBAEtB,CAAC,MAAOsL,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAIH,GACE+W,GACAA,EAAmBniB,UACnBmiB,EAAmBniB,UAAUyS,QAAQ,KAAO,EAI5C,GAAI0P,EAAmBriB,mBACrB,IACEqiB,EAAmBniB,SAAWsN,EAC5B6U,EAAmBniB,SACnB,OAEH,CAAC,MAAOoL,GACP+W,EAAmBniB,UAAW,EAC9B4L,EAAa,EAAGR,EAAO,2CACxB,MAED+W,EAAmBniB,UAAW,EAKlCjB,EAAQH,OAAS,IACZG,EAAQH,UACR8iB,GAAc3iB,IAInB,IAKE,OAAOgiB,GAAY,QAJElB,GACnBlH,EAAcnD,QAAU0M,GAAalB,EACrCjiB,GAGH,CAAC,MAAOqM,GACP,OAAO2V,EAAY3V,EACpB,GAqBGoW,GAAmB,CAACziB,EAASgiB,KACjC,IACE,IAAIvL,EACA1W,EAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,QAkBnD,MAhBqB,iBAAVD,IAET0W,EAAS1W,EAAQwP,EACfxP,EACAC,EAAQa,aAAaC,qBAGzB2V,EAAS1W,EAAM0P,WAAW,YAAa,IAAIhJ,OAGT,MAA9BgQ,EAAOA,EAAO9P,OAAS,KACzB8P,EAASA,EAAO3Q,UAAU,EAAG2Q,EAAO9P,OAAS,IAI/C3G,EAAQH,OAAO4W,OAASA,EACjBiM,GAAS1iB,GAAS,EAAOgiB,EACjC,CAAC,MAAO3V,GACP,OAAO2V,EACL,IAAIlP,GACF,wCAAwC9S,EAAQH,QAAQqhB,WAAa,kJACrE/N,SAAS9G,GAEd,GAcG8V,GAAiB,CAACoB,EAAgBvjB,EAASgiB,KAC/C,MAAMlhB,mBAAEA,GAAuBd,EAAQa,YAGvC,GACE0iB,EAAe7P,QAAQ,SAAW,GAClC6P,EAAe7P,QAAQ,UAAY,EAGnC,OADAnH,EAAI,EAAG,iCACAmW,GAAS1iB,GAAS,EAAOgiB,EAAauB,GAG/C,IAEE,MAAMC,EAAY3U,KAAKxD,MAAMkY,EAAe9T,WAAW,YAAa,MAGpE,OAAOiT,GAAS1iB,EAASwjB,EAAWxB,EACrC,CAAC,MAAO3V,GAEP,OAAIkE,EAAUzP,GACL2hB,GAAiBziB,EAASgiB,GAG1BA,EACL,IAAIlP,GACF,kMACAK,SAAS9G,GAGhB,GEzgBGoX,GAAc,GAcPC,GAAoB,KAC/BnX,EAAI,EAAG,+CACP,IAAK,MAAMuR,KAAM2F,GACfE,cAAc7F,EACf,ECxBG8F,GAAqB,CAACvX,EAAOwX,EAAKnR,EAAKoR,KAE3CjX,EAAa,EAAGR,GAGY,gBAAxBpF,EAAKuD,uBACA6B,EAAMY,MAIf6W,EAAKzX,EAAM,EAWP0X,GAAwB,CAAC1X,EAAOwX,EAAKnR,EAAKoR,KAE9C,MAAQ1Q,WAAY4Q,EAAMC,OAAEA,EAAMxf,QAAEA,EAAOwI,MAAEA,GAAUZ,EACjD+G,EAAa4Q,GAAUC,GAAU,IAGvCvR,EAAIuR,OAAO7Q,GAAY8Q,KAAK,CAAE9Q,aAAY3O,UAASwI,SAAQ,EAG7D,ICjBAkX,GAAe,CAACC,EAAKC,KACnB,MAAMC,EACJ,yEAGIC,EAAc,CAClBtf,IAAKof,EAAYtiB,aAAe,GAChCC,OAAQqiB,EAAYriB,QAAU,EAC9BC,MAAOoiB,EAAYpiB,OAAS,EAC5BC,WAAYmiB,EAAYniB,aAAc,EACtCC,QAASkiB,EAAYliB,UAAW,EAChCC,UAAWiiB,EAAYjiB,YAAa,GAIlCmiB,EAAYriB,YACdkiB,EAAI7iB,OAAO,eAIb,MAAMijB,EAAUL,EAAU,CACxBM,SAA+B,GAArBF,EAAYviB,OAAc,IAEpCiD,IAAKsf,EAAYtf,IAEjByf,QAASH,EAAYtiB,MACrB0iB,QAAS,CAACC,EAAS7Q,KACjBA,EAAS8Q,OAAO,CACdX,KAAM,KACJnQ,EAASkQ,OAAO,KAAKa,KAAK,CAAErgB,QAAS6f,GAAM,EAE7CS,QAAS,KACPhR,EAASkQ,OAAO,KAAKa,KAAKR,EAAI,GAEhC,EAEJU,KAAOJ,IAGqB,IAAxBL,EAAYpiB,UACc,IAA1BoiB,EAAYniB,WACZwiB,EAAQK,MAAM9V,MAAQoV,EAAYpiB,SAClCyiB,EAAQK,MAAMC,eAAiBX,EAAYniB,YAE3CmK,EAAI,EAAG,2CACA,KAOb6X,EAAIe,IAAIX,GAERjY,EACE,EACA,8CAA8CgY,EAAYtf,oBAAoBsf,EAAYviB,8CAA8CuiB,EAAYriB,cACrJ,EC/EH,MAAMkjB,WAAkBtS,GACtB,WAAAE,CAAYvO,EAASwf,GACnBhR,MAAMxO,GACNyO,KAAK+Q,OAAS/Q,KAAKE,WAAa6Q,CACjC,CAED,SAAAoB,CAAUpB,GAER,OADA/Q,KAAK+Q,OAASA,EACP/Q,IACR,ECcH,IAAAoS,GAAgBlB,KACbA,GAEGA,EAAImB,KACF,+BACAxT,MAAO6S,EAAS7Q,EAAU+P,KACxB,IACE,MAAM0B,EAAave,EAAKW,uBAGxB,IAAK4d,IAAeA,EAAW7e,OAC7B,MAAM,IAAIye,GACR,uGACA,KAKJ,MAAMK,EAAQb,EAAQnS,IAAI,WAC1B,IAAKgT,GAASA,IAAUD,EACtB,MAAM,IAAIJ,GACR,iEACA,KAKJ,MAAMM,EAAad,EAAQe,OAAOD,WAClC,IAAIA,EAmBF,MAAM,IAAIN,GAAU,2BAA4B,KAlBhD,SZwOerT,OAAO2T,IAClC,MAAM1lB,EAAUgR,KACZhR,GAASb,aACXa,EAAQb,WAAWC,QAAUsmB,SAEzB3Q,GAAoB/U,EAAQ,EY3Od4lB,CAAcF,EACrB,CAAC,MAAOrZ,GACP,MAAM,IAAI+Y,GACR,mBAAmB/Y,EAAM5H,UACzB4H,EAAM+G,YACND,SAAS9G,EACZ,CAGD0H,EAASkQ,OAAO,KAAKa,KAAK,CACxB1R,WAAY,IACZhU,QAASA,KACTqF,QAAS,+CAA+CihB,MAM7D,CAAC,MAAOrZ,GACPyX,EAAKzX,EACN,KC7CX,MAAMwZ,GAAe,CACnBC,IAAK,YACLC,KAAM,aACNC,IAAK,YACL9I,IAAK,kBACL+E,IAAK,iBAIP,IAAIgE,GAAkB,EAGtB,MAAMC,GAAgB,GAGhBC,GAAe,GAgBfC,GAAc,CAACC,EAAWzB,EAAS7Q,EAAUpF,KACjD,IAAI0S,GAAS,EACb,MAAMvD,GAAEA,EAAEwI,SAAEA,EAAQrnB,KAAEA,EAAImc,KAAEA,GAASzM,EAcrC,OAZA0X,EAAUhR,MAAMpU,IACd,GAAIA,EAAU,CACZ,IAAIslB,EAAetlB,EAAS2jB,EAAS7Q,EAAU+J,EAAIwI,EAAUrnB,EAAMmc,GAMnE,YAJqBrV,IAAjBwgB,IAA+C,IAAjBA,IAChClF,EAASkF,IAGJ,CACR,KAGIlF,CAAM,EAaTmF,GAAgBzU,MAAO6S,EAAS7Q,EAAU+P,KAC9C,IAEE,MAAM2C,EAAc/V,KAGd4V,EAAWvI,IAAOtN,QAAQ,KAAM,IAGhCiH,EAAiB1G,KAEjBoK,EAAOwJ,EAAQxJ,KACf0C,IAAOmI,GAEb,IAAIhnB,EAAO2O,EAAQwN,EAAKnc,MAGxB,IAAKmc,GjBmHS,iBADY1M,EiBlHC0M,KjBoH5BnM,MAAMC,QAAQR,IACN,OAATA,GAC6B,IAA7BlJ,OAAOC,KAAKiJ,GAAM/H,OiBrHd,MAAM,IAAIye,GACR,sJACA,KAKJ,IAAIrlB,EAAQuO,EAAc8M,EAAKtb,QAAUsb,EAAKpb,SAAWob,EAAKzM,MAG9D,IAAK5O,IAAUqb,EAAK6G,IAQlB,MAPA1V,EACE,EACA,uBAAuB+Z,UACrB1B,EAAQ8B,QAAQ,oBAAsB9B,EAAQ+B,WAAWC,kDACtB/X,KAAKC,UAAUsM,OAGhD,IAAIgK,GACR,oQACA,KAIJ,IAAImB,GAAe,EAWnB,GARAA,EAAeH,GAAYF,GAAetB,EAAS7Q,EAAU,CAC3D+J,KACAwI,WACArnB,OACAmc,UAImB,IAAjBmL,EACF,OAAOxS,EAAS+Q,KAAKyB,GAGvB,IAAIM,GAAoB,EAGxBjC,EAAQkC,OAAOnU,GAAG,SAAS,KACzBkU,GAAoB,CAAI,IAG1Bta,EAAI,EAAG,iDAAiD+Z,MAExDlL,EAAKlb,OAAiC,iBAAhBkb,EAAKlb,QAAuBkb,EAAKlb,QAAW,QAGlE,MAAM+R,EAAiB,CACrBpS,OAAQ,CACNE,QACAd,OACAiB,OAAQkb,EAAKlb,OAAO,GAAG6mB,cAAgB3L,EAAKlb,OAAO8mB,OAAO,GAC1D1mB,OAAQ8a,EAAK9a,OACbC,MAAO6a,EAAK7a,MACZC,MAAO4a,EAAK5a,OAASkX,EAAe7X,OAAOW,MAC3CC,cAAe6N,EAAc8M,EAAK3a,eAAe,GACjDC,aAAc4N,EAAc8M,EAAK1a,cAAc,IAEjDG,YAAa,CACXC,mBPsXmCA,GOrXnCC,oBAAoB,EACpBG,UAAWoN,EAAc8M,EAAKla,WAAW,GACzCD,SAAUma,EAAKna,SACfD,WAAYoa,EAAKpa,aAIjBjB,IAEFkS,EAAepS,OAAOE,MAAQwP,EAC5BxP,EACAkS,EAAepR,YAAYC,qBAK/B,MAAMd,EAAUiR,GAAmByG,EAAgBzF,GAcnD,GAXAjS,EAAQH,OAAOG,QAAUD,EAGzBC,EAAQihB,QAAU,CAChBgB,IAAK7G,EAAK6G,MAAO,EACjBgF,IAAK7L,EAAK6L,MAAO,EACjBC,WAAY9L,EAAK8L,aAAc,EAC/BhG,UAAWoF,GAITlL,EAAK6G,KjBiCyB,CAACvT,GACf,CACpB,mDACA,uEACA,wEACA,uFACA,qEAGmB2G,MAAM8R,GAAYA,EAAQ/f,KAAKsH,KiB1ClC0Y,CAAuBpnB,EAAQihB,QAAQgB,KACrD,MAAM,IAAImD,GACR,6KACA,WAKEtD,GAAY9hB,GAAS,CAACqM,EAAOgb,KAajC,GAXAzC,EAAQkC,OAAOQ,mBAAmB,SAG9B5P,EAAepW,OAAOK,cACxB4K,EACE,EACA,+BAA+B+Z,0CAAiDG,UAKhFI,EACF,OAAOta,EACL,EACA,mFAKJ,GAAIF,EACF,MAAMA,EAIR,IAAKgb,IAASA,EAAKhG,OACjB,MAAM,IAAI+D,GACR,oGAAoGkB,oBAA2Be,EAAKhG,UACpI,KAUJ,OALApiB,EAAOooB,EAAKrnB,QAAQH,OAAOZ,KAG3BmnB,GAAYD,GAAcvB,EAAS7Q,EAAU,CAAE+J,KAAI1C,KAAMiM,EAAKhG,SAE1DgG,EAAKhG,OAEHjG,EAAK6L,IAEM,QAAThoB,GAA0B,OAARA,EACb8U,EAAS+Q,KACdyC,OAAOC,KAAKH,EAAKhG,OAAQ,QAAQ3U,SAAS,WAIvCqH,EAAS+Q,KAAKuC,EAAKhG,SAI5BtN,EAAS0T,OAAO,eAAgB5B,GAAa5mB,IAAS,aAGjDmc,EAAK8L,YACRnT,EAAS2T,WACP,GAAG9C,EAAQe,OAAOgC,UAAY/C,EAAQxJ,KAAKuM,UAAY,WACrD1oB,GAAQ,SAME,QAATA,EACH8U,EAAS+Q,KAAKuC,EAAKhG,QACnBtN,EAAS+Q,KAAKyC,OAAOC,KAAKH,EAAKhG,OAAQ,iBA5B7C,CA6BC,GAEJ,CAAC,MAAOhV,GACPyX,EAAKzX,EACN,CjB7D0B,IAACqC,CiB6D3B,ECpQH,MAAMkZ,GAAU/Y,KAAKxD,MAAMkD,EAAasZ,EAAOra,EAAW,kBAEpDsa,GAAkB,IAAIrb,KAEtBsb,GAAe,GAuCN,SAASC,GAAgB5D,GACtC,IAAKA,EACH,OAAO,EN5CgB,IAACtG,IMyB1BmK,aAAY,KACV,MAAM7K,EAAQ5a,KACR0lB,EACqB,IAAzB9K,EAAME,eACF,EACCF,EAAMC,iBAAmBD,EAAME,eAAkB,IAExDyK,GAAa7N,KAAKgO,GACdH,GAAaphB,OA5BF,IA6BbohB,GAAalW,OACd,GA/BkB,KNHrB4R,GAAYvJ,KAAK4D,GMkDjBsG,EAAI3R,IAAI,WAAW,CAAC0V,EAAGzV,KACrB,MAAM0K,EAAQ5a,KACR4lB,EAASL,GAAaphB,OACtB0hB,EAxCIN,GAAaO,QAAO,CAACC,EAAGC,IAAMD,EAAIC,GAAG,GACpCT,GAAaphB,OAyCxB4F,EAAI,EAAG,4DAEPmG,EAAIoS,KAAK,CACPb,OAAQ,KACRwE,SAAUX,GACVY,OACEjN,KAAKkN,QACF,IAAIlc,MAAOwR,UAAY6J,GAAgB7J,WAAa,IAAO,IAC1D,WACN7e,QAASwoB,GAAQxoB,QACjBwpB,kBAAmBxpB,KACnBypB,sBAAuBzL,EAAMM,aAC7BL,iBAAkBD,EAAMC,iBACxByL,cAAe1L,EAAMK,eACrBH,eAAgBF,EAAME,eACtByL,YAAc3L,EAAMC,iBAAmBD,EAAME,eAAkB,IAE/D9a,KAAMA,KAGN4lB,SACAC,gBACA5jB,QACEsC,MAAMshB,KAAmBN,GAAaphB,OAClC,oEACA,QAAQyhB,mCAAwCC,EAAcW,QAAQ,OAG5EC,kBAAmB7L,EAAMG,sBACzB2L,mBAAoB9L,EAAMC,iBAAmBD,EAAMG,uBACnD,GAEN,CC5EA,MAAM4L,GAAgB,IAAIC,IAGpBhF,GAAMiF,IAGZjF,GAAIkF,QAAQ,gBAGZlF,GAAIe,IAAIoE,KAGR,MAAMC,GAAUC,EAAOC,gBACjBC,GAASF,EAAO,CACpBD,WACAI,OAAQ,CACNC,UAAW,YAKfzF,GAAIe,IAAIkE,EAAQnF,KAAK,CAAE4F,MAAO,YAC9B1F,GAAIe,IAAIkE,EAAQU,WAAW,CAAEC,UAAU,EAAMF,MAAO,YAGpD1F,GAAIe,IAAIwE,GAAOM,QAOf,MAAMC,GAA6B5oB,IACjCA,EAAOqR,GAAG,eAAgBtG,IACxBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM5H,UAAU,IAGnEnD,EAAOqR,GAAG,SAAUtG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM5H,UAAU,IAGnEnD,EAAOqR,GAAG,cAAemU,IACvBA,EAAOnU,GAAG,SAAUtG,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM5H,UAAU,GACjE,GACF,EAaS0lB,GAAcpY,MAAOqY,IAChC,IAEE,IAAKA,EAAa7oB,OAChB,OAAO,EAIT,IAAK6oB,EAAa/nB,IAAIC,MAAO,CAE3B,MAAM+nB,EAAa9X,EAAK+X,aAAalG,IAGrC8F,GAA0BG,GAG1BA,EAAWE,OAAOH,EAAa1oB,KAAM0oB,EAAa3oB,MAGlD0nB,GAAcqB,IAAIJ,EAAa1oB,KAAM2oB,GAErC9d,EACE,EACA,mCAAmC6d,EAAa3oB,QAAQ2oB,EAAa1oB,QAExE,CAGD,GAAI0oB,EAAa/nB,IAAId,OAAQ,CAE3B,IAAI4N,EAAKsb,EAET,IAEEtb,QAAYub,EAAWC,SACrBC,EAAMjmB,KAAKylB,EAAa/nB,IAAIE,SAAU,cACtC,QAIFkoB,QAAaC,EAAWC,SACtBC,EAAMjmB,KAAKylB,EAAa/nB,IAAIE,SAAU,cACtC,OAEH,CAAC,MAAO8J,GACPE,EACE,EACA,qDAAqD6d,EAAa/nB,IAAIE,sDAEzE,CAED,GAAI4M,GAAOsb,EAAM,CAEf,MAAMI,EAAcvY,EAAMgY,aAAa,CAAEnb,MAAKsb,QAAQrG,IAGtD8F,GAA0BW,GAG1BA,EAAYN,OAAOH,EAAa/nB,IAAIX,KAAM0oB,EAAa3oB,MAGvD0nB,GAAcqB,IAAIJ,EAAa/nB,IAAIX,KAAMmpB,GAEzCte,EACE,EACA,oCAAoC6d,EAAa3oB,QAAQ2oB,EAAa/nB,IAAIX,QAE7E,CACF,CAIC0oB,EAAatoB,cACbsoB,EAAatoB,aAAaP,SACzB,CAAC,EAAGupB,KAAKllB,SAASwkB,EAAatoB,aAAaC,cAE7CoiB,GAAUC,GAAKgG,EAAatoB,cAI9BsiB,GAAIe,IAAIkE,EAAQ0B,OAAOH,EAAMjmB,KAAK6I,EAAW,YAG7Cwd,GAAY5G,IF4GD,CAACA,IAIdA,EAAImB,KAAK,IAAKiB,IAMdpC,EAAImB,KAAK,aAAciB,GAAc,EErHnCyE,CAAa7G,IC9JF,CAACA,MACbA,GAEGA,EAAI3R,IAAI,KAAK,CAACmS,EAAS7Q,KACrBA,EAASmX,SAASvmB,EAAK6I,EAAW,SAAU,cAAc,GAC1D,ED0JJ2d,CAAQ/G,IACRkB,GAAalB,IN5IF,CAACA,IAEdA,EAAIe,IAAIvB,IAGRQ,EAAIe,IAAIpB,GAAsB,EM0I5BqH,CAAahH,GACd,CAAC,MAAO/X,GACP,MAAM,IAAIyG,GACR,sDACAK,SAAS9G,EACZ,GAMUgf,GAAe,KAC1B9e,EAAI,EAAG,iCACP,IAAK,MAAO7K,EAAMJ,KAAW6nB,GAC3B7nB,EAAOid,OAAM,KACX4K,GAAcmC,OAAO5pB,GACrB6K,EAAI,EAAG,mCAAmC7K,KAAQ,GAErD,EA6DH,IAAeJ,GAAA,CACb6oB,eACAkB,gBACAE,WAxDwB,IAAMpC,GAyD9BqC,mBAlDiCnH,GAAgBF,GAAUC,GAAKC,GAmDhEoH,WA5CwB,IAAMpC,EA6C9BqC,OAtCoB,IAAMtH,GAuC1Be,IA/BiB,CAAC1L,KAASkS,KAC3BvH,GAAIe,IAAI1L,KAASkS,EAAY,EA+B7BlZ,IAtBiB,CAACgH,KAASkS,KAC3BvH,GAAI3R,IAAIgH,KAASkS,EAAY,EAsB7BpG,KAbkB,CAAC9L,KAASkS,KAC5BvH,GAAImB,KAAK9L,KAASkS,EAAY,GE7OzB,MAAMC,GAAkB7Z,MAAO8Z,UAE9B3Z,QAAQ4Z,WAAW,CAEvBpI,KAGA2H,KAGA7K,OAIFlV,QAAQygB,KAAKF,EAAS,EC4ExB,IAAeG,GAAA,CAEb1qB,UACA6oB,eAGA8B,WApCiBla,MAAO/R,IZudW,IAAChB,EY5bpC,OZ4boCA,EYpdlCgB,EAAQa,aAAeb,EAAQa,YAAYC,mBZqd7CA,GAAqByP,EAAUvR,GXrUN,CAACktB,IAE1B,IAAK,MAAO/c,EAAKnQ,KAAUwG,OAAOuK,QAAQmc,GACxChpB,EAAQiM,GAAOnQ,EAIjBmO,EAAY+e,GAAkB3M,SAAS2M,EAAe/oB,QAGlD+oB,GAAkBA,EAAe7oB,MAAQ6oB,EAAe3oB,QAC1D6J,EACE8e,EAAe7oB,KACf6oB,EAAe9oB,MAAQ,+BAE1B,EuB3JD+oB,CAAYnsB,EAAQkD,SAGhBlD,EAAQ0D,MAAME,uBAnDlB2I,EAAI,EAAG,sDAGPjB,QAAQqH,GAAG,QAASyZ,IAClB7f,EAAI,EAAG,4BAA4B6f,KAAQ,IAI7C9gB,QAAQqH,GAAG,UAAUZ,MAAOvN,EAAM4nB,KAChC7f,EAAI,EAAG,OAAO/H,sBAAyB4nB,YACjCR,GAAgB,EAAE,IAI1BtgB,QAAQqH,GAAG,WAAWZ,MAAOvN,EAAM4nB,KACjC7f,EAAI,EAAG,OAAO/H,sBAAyB4nB,YACjCR,GAAgB,EAAE,IAI1BtgB,QAAQqH,GAAG,UAAUZ,MAAOvN,EAAM4nB,KAChC7f,EAAI,EAAG,OAAO/H,sBAAyB4nB,YACjCR,GAAgB,EAAE,IAI1BtgB,QAAQqH,GAAG,qBAAqBZ,MAAO1F,EAAO7H,KAC5CqI,EAAa,EAAGR,EAAO,OAAO7H,kBACxBonB,GAAgB,EAAE,WA4BpB7W,GAAoB/U,SAGpBwe,GAAS,CACbhc,KAAMxC,EAAQwC,MAAQ,CACpBC,WAAY,EACZC,WAAY,GAEd+b,cAAeze,EAAQlB,UAAUC,MAAQ,KAIpCiB,CAAO,EAUdqsB,aZkF0Bta,MAAO/R,IAEjCA,EAAQH,OAAOE,MAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,cAGxD8hB,GAAY9hB,GAAS+R,MAAO1F,EAAOgb,KAEvC,GAAIhb,EACF,MAAMA,EAGR,MAAMpM,QAAEA,EAAOhB,KAAEA,GAASooB,EAAKrnB,QAAQH,OAGvCiV,EACE7U,GAAW,SAAShB,IACX,QAATA,EAAiBsoB,OAAOC,KAAKH,EAAKhG,OAAQ,UAAYgG,EAAKhG,cAIvDb,IAAU,GAChB,EYtGF8L,YZoByBva,MAAO/R,IAChC,MAAMusB,EAAiB,GAGvB,IAAK,IAAIC,KAAQxsB,EAAQH,OAAOc,MAAM4F,MAAM,KAC1CimB,EAAOA,EAAKjmB,MAAM,KACE,IAAhBimB,EAAK7lB,QACP4lB,EAAerS,KACb4H,GACE,IACK9hB,EACHH,OAAQ,IACHG,EAAQH,OACXC,OAAQ0sB,EAAK,GACbvsB,QAASusB,EAAK,MAGlB,CAACngB,EAAOgb,KAEN,GAAIhb,EACF,MAAMA,EAIRyI,EACEuS,EAAKrnB,QAAQH,OAAOI,QACS,QAA7BonB,EAAKrnB,QAAQH,OAAOZ,KAChBsoB,OAAOC,KAAKH,EAAKhG,OAAQ,UACzBgG,EAAKhG,OACV,KAOX,UAEQnP,QAAQwC,IAAI6X,SAGZ/L,IACP,CAAC,MAAOnU,GACP,MAAM,IAAIyG,GACR,kDACAK,SAAS9G,EACZ,GYjEDyV,eAGAtD,YACAgC,YAGArK,WrBjFwB,CAACU,EAAa9X,KAElCA,GAAM4H,SAERoK,GA6NJ,SAAwBhS,GAEtB,MAAM0tB,EAAc1tB,EAAK2tB,WACtBC,GAAkC,eAA1BA,EAAIlc,QAAQ,KAAM,MAI7B,GAAIgc,GAAe,GAAK1tB,EAAK0tB,EAAc,GAAI,CAC7C,MAAMG,EAAW7tB,EAAK0tB,EAAc,GACpC,IAEE,GAAIG,GAAYA,EAASrf,SAAS,SAEhC,OAAOsB,KAAKxD,MAAMkD,EAAaqe,GAElC,CAAC,MAAOvgB,GACPQ,EACE,EACAR,EACA,sDAAsDugB,UAEzD,CACF,CAGD,MAAO,EACT,CAvPqBC,CAAe9tB,IAIlCqS,GAAoBvS,EAAekS,IAGnCA,GAAiBS,GAAY3S,GAGzBgY,IAEF9F,GAAiBE,GACfF,GACA8F,EACA1R,IAKApG,GAAM4H,SAERoK,GA+RJ,SAA2B/Q,EAASjB,EAAMF,GACxC,IAAIiuB,GAAY,EAChB,IAAK,IAAI5c,EAAI,EAAGA,EAAInR,EAAK4H,OAAQuJ,IAAK,CACpC,MAAMJ,EAAS/Q,EAAKmR,GAAGO,QAAQ,KAAM,IAG/Bsc,EAAkB3nB,EAAW0K,GAC/B1K,EAAW0K,GAAQvJ,MAAM,KACzB,GAGJ,IAAIymB,EACJD,EAAgBzE,QAAO,CAAChjB,EAAKqS,EAAMqU,KAC7Be,EAAgBpmB,OAAS,IAAMqlB,IACjCgB,EAAe1nB,EAAIqS,GAAM1Y,MAEpBqG,EAAIqS,KACV9Y,GAEHkuB,EAAgBzE,QAAO,CAAChjB,EAAKqS,EAAMqU,KAC7Be,EAAgBpmB,OAAS,IAAMqlB,QAER,IAAd1mB,EAAIqS,KACT5Y,IAAOmR,GACY,YAAjB8c,EACF1nB,EAAIqS,GAAQpH,EAAUxR,EAAKmR,IACD,WAAjB8c,EACT1nB,EAAIqS,IAAS5Y,EAAKmR,GACT8c,EAAatZ,QAAQ,MAAQ,EACtCpO,EAAIqS,GAAQ5Y,EAAKmR,GAAG3J,MAAM,KAE1BjB,EAAIqS,GAAQ5Y,EAAKmR,IAGnB3D,EACE,EACA,mCAAmCuD,yCAErCgd,GAAY,IAIXxnB,EAAIqS,KACV3X,EACJ,CAGG8sB,GACFpd,IAGF,OAAO1P,CACT,CAnVqBitB,CAAkBlc,GAAgBhS,EAAMF,IAIpDkS,IqBoDP6a,mBAGArf,MACAM,eACAM,cACAC,oBAGA8f,erB6C6BC,IAC7B,MAAMjc,EAAa,CAAA,EAEnB,IAAK,MAAO/B,EAAKnQ,KAAUwG,OAAOuK,QAAQod,GAAa,CACrD,MAAMJ,EAAkB3nB,EAAW+J,GAAO/J,EAAW+J,GAAK5I,MAAM,KAAO,GAGvEwmB,EAAgBzE,QACd,CAAChjB,EAAKqS,EAAMqU,IACT1mB,EAAIqS,GACHoV,EAAgBpmB,OAAS,IAAMqlB,EAAQhtB,EAAQsG,EAAIqS,IAAS,IAChEzG,EAEH,CACD,OAAOA,CAAU,EqB1DjBkc,arBlD0Brb,MAAOsb,IAEjC,IAAIC,EAAa,CAAA,EAGbrhB,EAAWohB,KACbC,EAAaze,KAAKxD,MAAMkD,EAAa8e,EAAgB,UAIvD,MAwDMvoB,EAAUU,OAAOC,KAAKlB,GAAeiC,KAAK+mB,IAAY,CAC1D5hB,MAAO,GAAG4hB,YACVvuB,MAAOuuB,MAIT,OAAOC,EACL,CACEvuB,KAAM,cACNuF,KAAM,WACNC,QAAS,2CACTM,KAAM,yDACNF,aAAc,GACdC,WAEF,CAAE2oB,SAvEa1b,MAAO2b,EAAGC,KACzB,IAAIC,EAAmB,EACnBC,EAAe,GAGnB,IAAK,MAAMC,KAAWH,EAEpBppB,EAAcupB,GAAWvpB,EAAcupB,GAAStnB,KAAKsJ,IAAY,IAC5DA,EACHge,cAIFD,EAAe,IAAIA,KAAiBtpB,EAAcupB,IAuCpD,aApCMN,EAAQK,EAAc,CAC1BJ,SAAU1b,MAAOgc,EAAQC,KAgBvB,GAdoB,kBAAhBD,EAAOvpB,MACTwpB,EAASA,EAAOrnB,OACZqnB,EAAOxnB,KAAKynB,GAAWF,EAAOjpB,QAAQmpB,KACtCF,EAAOjpB,QAEXwoB,EAAWS,EAAOD,SAASC,EAAOvpB,MAAQwpB,GAE1CV,EAAWS,EAAOD,SAAWpc,GAC3BlM,OAAOsM,OAAO,GAAIwb,EAAWS,EAAOD,UAAY,IAChDC,EAAOvpB,KAAK+B,MAAM,KAClBwnB,EAAOjpB,QAAUipB,EAAOjpB,QAAQkpB,GAAUA,KAIxCJ,IAAqBC,EAAalnB,OAAQ,CAC9C,UACQ+jB,EAAWwD,UACfb,EACAxe,KAAKC,UAAUwe,EAAY,KAAM,GACjC,OAEH,CAAC,MAAOjhB,GACPQ,EACE,EACAR,EACA,iDAAiDghB,UAEpD,CACD,OAAO,CACR,MAIE,CAAI,GAoBZ,EqB/BDc,UtB8KwBtqB,IAExB,MAAMuqB,EAAiBvf,KAAKxD,MAC1BkD,EAAa5J,EAAK6I,EAAW,kBAC7BpO,QAGEyE,EACFyI,QAAQC,IAAI,sCAAsC6hB,QAKpD9hB,QAAQC,IACNgC,EAAaf,EAAY,oBAAoBd,WAAWiD,KAAKC,OAC7D,IAAIwe,MAAmBze,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/intervals.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n// Possible names for Highcharts scripts\nexport const scriptsNames = {\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\n modules: [\n 'stock',\n 'map',\n 'gantt',\n 'exporting',\n 'parallel-coordinates',\n 'accessibility',\n // 'annotations-advanced',\n 'boost-canvas',\n 'boost',\n 'data',\n 'data-tools',\n 'draggable-points',\n 'static-scale',\n 'broken-axis',\n 'heatmap',\n 'tilemap',\n 'tiledwebmap',\n 'timeline',\n 'treemap',\n 'treegraph',\n 'item-series',\n 'drilldown',\n 'histogram-bellcurve',\n 'bullet',\n 'funnel',\n 'funnel3d',\n 'geoheatmap',\n 'pyramid3d',\n 'networkgraph',\n 'overlapping-datalabels',\n 'pareto',\n 'pattern-fill',\n 'pictorial',\n 'price-indicator',\n 'sankey',\n 'arc-diagram',\n 'dependency-wheel',\n 'series-label',\n 'series-on-point',\n 'solid-gauge',\n 'sonification',\n // 'stock-tools',\n 'streamgraph',\n 'sunburst',\n 'variable-pie',\n 'variwide',\n 'vector',\n 'venn',\n 'windbarb',\n 'wordcloud',\n 'xrange',\n 'no-data-to-display',\n 'drag-panes',\n 'debugger',\n 'dumbbell',\n 'lollipop',\n 'cylinder',\n 'organization',\n 'dotplot',\n 'marker-clusters',\n 'hollowcandlestick',\n 'heikinashi',\n 'flowmap',\n 'export-data',\n 'navigator',\n 'textpath'\n ],\n indicators: ['indicators-all'],\n custom: [\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.30.1/moment.min.js',\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.45/moment-timezone-with-data.min.js'\n ]\n};\n\n// This is the configuration object with all options and their default values,\n// also from the .env file if one exists\nexport const defaultConfig = {\n puppeteer: {\n args: {\n value: [\n '--allow-running-insecure-content',\n '--ash-no-nudges',\n '--autoplay-policy=user-gesture-required',\n '--block-new-web-contents',\n '--disable-accelerated-2d-canvas',\n '--disable-background-networking',\n '--disable-background-timer-throttling',\n '--disable-backgrounding-occluded-windows',\n '--disable-breakpad',\n '--disable-checker-imaging',\n '--disable-client-side-phishing-detection',\n '--disable-component-extensions-with-background-pages',\n '--disable-component-update',\n '--disable-default-apps',\n '--disable-dev-shm-usage',\n '--disable-domain-reliability',\n '--disable-extensions',\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\n '--disable-hang-monitor',\n '--disable-ipc-flooding-protection',\n '--disable-logging',\n '--disable-notifications',\n '--disable-offer-store-unmasked-wallet-cards',\n '--disable-popup-blocking',\n '--disable-print-preview',\n '--disable-prompt-on-repost',\n '--disable-renderer-backgrounding',\n '--disable-search-engine-choice-screen',\n '--disable-session-crashed-bubble',\n '--disable-setuid-sandbox',\n '--disable-site-isolation-trials',\n '--disable-speech-api',\n '--disable-sync',\n '--enable-unsafe-webgpu',\n '--hide-crash-restore-bubble',\n '--hide-scrollbars',\n '--metrics-recording-only',\n '--mute-audio',\n '--no-default-browser-check',\n '--no-first-run',\n '--no-pings',\n '--no-sandbox',\n '--no-startup-window',\n '--no-zygote',\n '--password-store=basic',\n '--process-per-tab',\n '--use-mock-keychain'\n ],\n type: 'string[]',\n description: 'Arguments array to send to Puppeteer.'\n }\n },\n highcharts: {\n version: {\n value: 'latest',\n type: 'string',\n envLink: 'HIGHCHARTS_VERSION',\n description: 'The Highcharts version to be used.'\n },\n cdnURL: {\n value: 'https://code.highcharts.com/',\n type: 'string',\n envLink: 'HIGHCHARTS_CDN_URL',\n description: 'The CDN URL for Highcharts scripts to be used.'\n },\n coreScripts: {\n value: scriptsNames.core,\n type: 'string[]',\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\n description: 'The core Highcharts scripts to fetch.'\n },\n moduleScripts: {\n value: scriptsNames.modules,\n type: 'string[]',\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\n description: 'The modules of Highcharts to fetch.'\n },\n indicatorScripts: {\n value: scriptsNames.indicators,\n type: 'string[]',\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\n description: 'The indicators of Highcharts to fetch.'\n },\n customScripts: {\n value: scriptsNames.custom,\n type: 'string[]',\n description: 'Additional custom scripts or dependencies to fetch.'\n },\n forceFetch: {\n value: false,\n type: 'boolean',\n envLink: 'HIGHCHARTS_FORCE_FETCH',\n description:\n 'The flag to determine whether to refetch all scripts after each server rerun.'\n },\n cachePath: {\n value: '.cache',\n type: 'string',\n envLink: 'HIGHCHARTS_CACHE_PATH',\n description:\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\n }\n },\n export: {\n infile: {\n value: false,\n type: 'string',\n description:\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\n },\n instr: {\n value: false,\n type: 'string',\n description:\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\n },\n options: {\n value: false,\n type: 'string',\n description: 'An alias for the --instr option.'\n },\n outfile: {\n value: false,\n type: 'string',\n description:\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\n },\n type: {\n value: 'png',\n type: 'string',\n envLink: 'EXPORT_TYPE',\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\n },\n constr: {\n value: 'chart',\n type: 'string',\n envLink: 'EXPORT_CONSTR',\n description:\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\n },\n defaultHeight: {\n value: 400,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_HEIGHT',\n description:\n 'the default height of the exported chart. Used when no value is set.'\n },\n defaultWidth: {\n value: 600,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_WIDTH',\n description:\n 'The default width of the exported chart. Used when no value is set.'\n },\n defaultScale: {\n value: 1,\n type: 'number',\n envLink: 'EXPORT_DEFAULT_SCALE',\n description:\n 'The default scale of the exported chart. Used when no value is set.'\n },\n height: {\n value: false,\n type: 'number',\n description:\n 'The height of the exported chart, overriding the option in the chart settings.'\n },\n width: {\n value: false,\n type: 'number',\n description:\n 'The width of the exported chart, overriding the option in the chart settings.'\n },\n scale: {\n value: false,\n type: 'number',\n description:\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\n },\n globalOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\n },\n themeOptions: {\n value: false,\n type: 'string',\n description:\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\n },\n batch: {\n value: false,\n type: 'string',\n description:\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\n },\n rasterizationTimeout: {\n value: 1500,\n type: 'number',\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\n description:\n 'The duration in milliseconds to wait for rendering a webpage.'\n }\n },\n customLogic: {\n allowCodeExecution: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\n description:\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\n },\n allowFileResources: {\n value: false,\n type: 'boolean',\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\n description:\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\n },\n customCode: {\n value: false,\n type: 'string',\n description:\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\n },\n callback: {\n value: false,\n type: 'string',\n description:\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\n },\n resources: {\n value: false,\n type: 'string',\n description:\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\n },\n loadConfig: {\n value: false,\n type: 'string',\n legacyName: 'fromFile',\n description: 'A file containing a pre-defined configuration to use.'\n },\n createConfig: {\n value: false,\n type: 'string',\n description:\n 'Enables setting options through a prompt and saving them in a provided config file.'\n }\n },\n server: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_ENABLE',\n cliName: 'enableServer',\n description:\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\n },\n host: {\n value: '0.0.0.0',\n type: 'string',\n envLink: 'SERVER_HOST',\n description:\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\n },\n port: {\n value: 7801,\n type: 'number',\n envLink: 'SERVER_PORT',\n description: 'The server port when enabled.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_BENCHMARKING',\n cliName: 'serverBenchmarking',\n description:\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\n },\n proxy: {\n host: {\n value: false,\n type: 'string',\n envLink: 'SERVER_PROXY_HOST',\n cliName: 'proxyHost',\n description: 'The host of the proxy server to use, if it exists.'\n },\n port: {\n value: 8080,\n type: 'number',\n envLink: 'SERVER_PROXY_PORT',\n cliName: 'proxyPort',\n description: 'The port of the proxy server to use, if it exists.'\n },\n timeout: {\n value: 5000,\n type: 'number',\n envLink: 'SERVER_PROXY_TIMEOUT',\n cliName: 'proxyTimeout',\n description: 'The timeout for the proxy server to use, if it exists.'\n }\n },\n rateLimiting: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\n cliName: 'enableRateLimiting',\n description: 'Enables rate limiting for the server.'\n },\n maxRequests: {\n value: 10,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\n legacyName: 'rateLimit',\n description: 'The maximum number of requests allowed in one minute.'\n },\n window: {\n value: 1,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\n description: 'The time window, in minutes, for the rate limiting.'\n },\n delay: {\n value: 0,\n type: 'number',\n envLink: 'SERVER_RATE_LIMITING_DELAY',\n description:\n 'The delay duration for each successive request before reaching the maximum limit.'\n },\n trustProxy: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\n description: 'Set this to true if the server is behind a load balancer.'\n },\n skipKey: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\n },\n skipToken: {\n value: false,\n type: 'string',\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\n description:\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\n }\n },\n ssl: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_ENABLE',\n cliName: 'enableSsl',\n description: 'Enables or disables the SSL protocol.'\n },\n force: {\n value: false,\n type: 'boolean',\n envLink: 'SERVER_SSL_FORCE',\n cliName: 'sslForce',\n legacyName: 'sslOnly',\n description:\n 'When set to true, the server is forced to serve only over HTTPS.'\n },\n port: {\n value: 443,\n type: 'number',\n envLink: 'SERVER_SSL_PORT',\n cliName: 'sslPort',\n description: 'The port on which to run the SSL server.'\n },\n certPath: {\n value: false,\n type: 'string',\n envLink: 'SERVER_SSL_CERT_PATH',\n legacyName: 'sslPath',\n description: 'The path to the SSL certificate/key file.'\n }\n }\n },\n pool: {\n minWorkers: {\n value: 4,\n type: 'number',\n envLink: 'POOL_MIN_WORKERS',\n description: 'The number of minimum and initial pool workers to spawn.'\n },\n maxWorkers: {\n value: 8,\n type: 'number',\n envLink: 'POOL_MAX_WORKERS',\n legacyName: 'workers',\n description: 'The number of maximum pool workers to spawn.'\n },\n workLimit: {\n value: 40,\n type: 'number',\n envLink: 'POOL_WORK_LIMIT',\n description:\n 'The number of work pieces that can be performed before restarting the worker process.'\n },\n acquireTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_ACQUIRE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for acquiring a resource.'\n },\n createTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_CREATE_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for creating a resource.'\n },\n destroyTimeout: {\n value: 5000,\n type: 'number',\n envLink: 'POOL_DESTROY_TIMEOUT',\n description:\n 'The duration, in milliseconds, to wait for destroying a resource.'\n },\n idleTimeout: {\n value: 30000,\n type: 'number',\n envLink: 'POOL_IDLE_TIMEOUT',\n description:\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\n },\n createRetryInterval: {\n value: 200,\n type: 'number',\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\n description:\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\n },\n reaperInterval: {\n value: 1000,\n type: 'number',\n envLink: 'POOL_REAPER_INTERVAL',\n description:\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\n },\n benchmarking: {\n value: false,\n type: 'boolean',\n envLink: 'POOL_BENCHMARKING',\n cliName: 'poolBenchmarking',\n description:\n 'Indicate whether to show statistics for the pool of resources or not.'\n }\n },\n logging: {\n level: {\n value: 4,\n type: 'number',\n envLink: 'LOGGING_LEVEL',\n cliName: 'logLevel',\n description: 'The logging level to be used.'\n },\n file: {\n value: 'highcharts-export-server.log',\n type: 'string',\n envLink: 'LOGGING_FILE',\n cliName: 'logFile',\n description:\n 'The name of a log file. The `logToFile` and `logDest` options also need to be set to enable file logging.'\n },\n dest: {\n value: 'log/',\n type: 'string',\n envLink: 'LOGGING_DEST',\n cliName: 'logDest',\n description:\n 'The path to store log files. The `logToFile` option also needs to be set to enable file logging.'\n },\n toConsole: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_CONSOLE',\n cliName: 'logToConsole',\n description: 'Enables or disables showing logs in the console.'\n },\n toFile: {\n value: true,\n type: 'boolean',\n envLink: 'LOGGING_TO_FILE',\n cliName: 'logToFile',\n description:\n 'Enables or disables creation of the log directory and saving the log into a .log file.'\n }\n },\n ui: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'UI_ENABLE',\n cliName: 'enableUi',\n description:\n 'Enables or disables the user interface (UI) for the export server.'\n },\n route: {\n value: '/',\n type: 'string',\n envLink: 'UI_ROUTE',\n cliName: 'uiRoute',\n description:\n 'The endpoint route to which the user interface (UI) should be attached.'\n }\n },\n other: {\n nodeEnv: {\n value: 'production',\n type: 'string',\n envLink: 'OTHER_NODE_ENV',\n description: 'The type of Node.js environment.'\n },\n listenToProcessExits: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\n description: 'Decides whether or not to attach process.exit handlers.'\n },\n noLogo: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_NO_LOGO',\n description:\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\n },\n hardResetPage: {\n value: false,\n type: 'boolean',\n envLink: 'OTHER_HARD_RESET_PAGE',\n description: 'Decides if the page content should be reset entirely.'\n },\n browserShellMode: {\n value: true,\n type: 'boolean',\n envLink: 'OTHER_BROWSER_SHELL_MODE',\n description: 'Decides if the browser runs in the shell mode.'\n }\n },\n debug: {\n enable: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_ENABLE',\n cliName: 'enableDebug',\n description: 'Enables or disables debug mode for the underlying browser.'\n },\n headless: {\n value: true,\n type: 'boolean',\n envLink: 'DEBUG_HEADLESS',\n description:\n 'Controls the mode in which the browser is launched when in the debug mode.'\n },\n devtools: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DEVTOOLS',\n description:\n 'Decides whether to enable DevTools when the browser is in a headful state.'\n },\n listenToConsole: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\n description:\n 'Decides whether to enable a listener for console messages sent from the browser.'\n },\n dumpio: {\n value: false,\n type: 'boolean',\n envLink: 'DEBUG_DUMPIO',\n description:\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\n },\n slowMo: {\n value: 0,\n type: 'number',\n envLink: 'DEBUG_SLOW_MO',\n description:\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\n },\n debuggingPort: {\n value: 9222,\n type: 'number',\n envLink: 'DEBUG_DEBUGGING_PORT',\n description: 'Specifies the debugging port.'\n }\n }\n};\n\n// The config descriptions object for the prompts functionality. It contains\n// information like:\n// * Type of a prompt\n// * Name of an option\n// * Short description of a chosen option\n// * Initial value\nexport const promptsConfig = {\n puppeteer: [\n {\n type: 'list',\n name: 'args',\n message: 'Puppeteer arguments',\n initial: defaultConfig.puppeteer.args.value.join(','),\n separator: ','\n }\n ],\n highcharts: [\n {\n type: 'text',\n name: 'version',\n message: 'Highcharts version',\n initial: defaultConfig.highcharts.version.value\n },\n {\n type: 'text',\n name: 'cdnURL',\n message: 'The URL of CDN',\n initial: defaultConfig.highcharts.cdnURL.value\n },\n {\n type: 'multiselect',\n name: 'coreScripts',\n message: 'Available core scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.coreScripts.value\n },\n {\n type: 'multiselect',\n name: 'moduleScripts',\n message: 'Available module scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.moduleScripts.value\n },\n {\n type: 'multiselect',\n name: 'indicatorScripts',\n message: 'Available indicator scripts',\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\n choices: defaultConfig.highcharts.indicatorScripts.value\n },\n {\n type: 'list',\n name: 'customScripts',\n message: 'Custom scripts',\n initial: defaultConfig.highcharts.customScripts.value.join(','),\n separator: ','\n },\n {\n type: 'toggle',\n name: 'forceFetch',\n message: 'Force re-fetch the scripts',\n initial: defaultConfig.highcharts.forceFetch.value\n },\n {\n type: 'text',\n name: 'cachePath',\n message: 'The path to the cache directory',\n initial: defaultConfig.highcharts.cachePath.value\n }\n ],\n export: [\n {\n type: 'select',\n name: 'type',\n message: 'The default export file type',\n hint: `Default: ${defaultConfig.export.type.value}`,\n initial: 0,\n choices: ['png', 'jpeg', 'pdf', 'svg']\n },\n {\n type: 'select',\n name: 'constr',\n message: 'The default constructor for Highcharts',\n hint: `Default: ${defaultConfig.export.constr.value}`,\n initial: 0,\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\n },\n {\n type: 'number',\n name: 'defaultHeight',\n message: 'The default fallback height of the exported chart',\n initial: defaultConfig.export.defaultHeight.value\n },\n {\n type: 'number',\n name: 'defaultWidth',\n message: 'The default fallback width of the exported chart',\n initial: defaultConfig.export.defaultWidth.value\n },\n {\n type: 'number',\n name: 'defaultScale',\n message: 'The default fallback scale of the exported chart',\n initial: defaultConfig.export.defaultScale.value,\n min: 0.1,\n max: 5\n },\n {\n type: 'number',\n name: 'rasterizationTimeout',\n message: 'The rendering webpage timeout in milliseconds',\n initial: defaultConfig.export.rasterizationTimeout.value\n }\n ],\n customLogic: [\n {\n type: 'toggle',\n name: 'allowCodeExecution',\n message: 'Enable execution of custom code',\n initial: defaultConfig.customLogic.allowCodeExecution.value\n },\n {\n type: 'toggle',\n name: 'allowFileResources',\n message: 'Enable file resources',\n initial: defaultConfig.customLogic.allowFileResources.value\n }\n ],\n server: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Starts the server on 0.0.0.0',\n initial: defaultConfig.server.enable.value\n },\n {\n type: 'text',\n name: 'host',\n message: 'Server hostname',\n initial: defaultConfig.server.host.value\n },\n {\n type: 'number',\n name: 'port',\n message: 'Server port',\n initial: defaultConfig.server.port.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable server benchmarking',\n initial: defaultConfig.server.benchmarking.value\n },\n {\n type: 'text',\n name: 'proxy.host',\n message: 'The host of the proxy server to use',\n initial: defaultConfig.server.proxy.host.value\n },\n {\n type: 'number',\n name: 'proxy.port',\n message: 'The port of the proxy server to use',\n initial: defaultConfig.server.proxy.port.value\n },\n {\n type: 'number',\n name: 'proxy.timeout',\n message: 'The timeout for the proxy server to use',\n initial: defaultConfig.server.proxy.timeout.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.enable',\n message: 'Enable rate limiting',\n initial: defaultConfig.server.rateLimiting.enable.value\n },\n {\n type: 'number',\n name: 'rateLimiting.maxRequests',\n message: 'The maximum requests allowed per minute',\n initial: defaultConfig.server.rateLimiting.maxRequests.value\n },\n {\n type: 'number',\n name: 'rateLimiting.window',\n message: 'The rate-limiting time window in minutes',\n initial: defaultConfig.server.rateLimiting.window.value\n },\n {\n type: 'number',\n name: 'rateLimiting.delay',\n message:\n 'The delay for each successive request before reaching the maximum',\n initial: defaultConfig.server.rateLimiting.delay.value\n },\n {\n type: 'toggle',\n name: 'rateLimiting.trustProxy',\n message: 'Set to true if behind a load balancer',\n initial: defaultConfig.server.rateLimiting.trustProxy.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipKey',\n message:\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\n initial: defaultConfig.server.rateLimiting.skipKey.value\n },\n {\n type: 'text',\n name: 'rateLimiting.skipToken',\n message:\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\n initial: defaultConfig.server.rateLimiting.skipToken.value\n },\n {\n type: 'toggle',\n name: 'ssl.enable',\n message: 'Enable SSL protocol',\n initial: defaultConfig.server.ssl.enable.value\n },\n {\n type: 'toggle',\n name: 'ssl.force',\n message: 'Force serving only over HTTPS',\n initial: defaultConfig.server.ssl.force.value\n },\n {\n type: 'number',\n name: 'ssl.port',\n message: 'SSL server port',\n initial: defaultConfig.server.ssl.port.value\n },\n {\n type: 'text',\n name: 'ssl.certPath',\n message: 'The path to find the SSL certificate/key',\n initial: defaultConfig.server.ssl.certPath.value\n }\n ],\n pool: [\n {\n type: 'number',\n name: 'minWorkers',\n message: 'The initial number of workers to spawn',\n initial: defaultConfig.pool.minWorkers.value\n },\n {\n type: 'number',\n name: 'maxWorkers',\n message: 'The maximum number of workers to spawn',\n initial: defaultConfig.pool.maxWorkers.value\n },\n {\n type: 'number',\n name: 'workLimit',\n message:\n 'The pieces of work that can be performed before restarting a Puppeteer process',\n initial: defaultConfig.pool.workLimit.value\n },\n {\n type: 'number',\n name: 'acquireTimeout',\n message: 'The number of milliseconds to wait for acquiring a resource',\n initial: defaultConfig.pool.acquireTimeout.value\n },\n {\n type: 'number',\n name: 'createTimeout',\n message: 'The number of milliseconds to wait for creating a resource',\n initial: defaultConfig.pool.createTimeout.value\n },\n {\n type: 'number',\n name: 'destroyTimeout',\n message: 'The number of milliseconds to wait for destroying a resource',\n initial: defaultConfig.pool.destroyTimeout.value\n },\n {\n type: 'number',\n name: 'idleTimeout',\n message: 'The number of milliseconds after an idle resource is destroyed',\n initial: defaultConfig.pool.idleTimeout.value\n },\n {\n type: 'number',\n name: 'createRetryInterval',\n message:\n 'The retry interval in milliseconds after a create process fails',\n initial: defaultConfig.pool.createRetryInterval.value\n },\n {\n type: 'number',\n name: 'reaperInterval',\n message:\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\n initial: defaultConfig.pool.reaperInterval.value\n },\n {\n type: 'toggle',\n name: 'benchmarking',\n message: 'Enable benchmarking for a resource pool',\n initial: defaultConfig.pool.benchmarking.value\n }\n ],\n logging: [\n {\n type: 'number',\n name: 'level',\n message:\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\n initial: defaultConfig.logging.level.value,\n round: 0,\n min: 0,\n max: 5\n },\n {\n type: 'text',\n name: 'file',\n message:\n 'A log file name. Set with --toFile and --logDest to enable file logging',\n initial: defaultConfig.logging.file.value\n },\n {\n type: 'text',\n name: 'dest',\n message: 'The path to a log file when the file logging is enabled',\n initial: defaultConfig.logging.dest.value\n },\n {\n type: 'toggle',\n name: 'toConsole',\n message: 'Enable logging to the console',\n initial: defaultConfig.logging.toConsole.value\n },\n {\n type: 'toggle',\n name: 'toFile',\n message: 'Enables logging to a file',\n initial: defaultConfig.logging.toFile.value\n }\n ],\n ui: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enable UI for the export server',\n initial: defaultConfig.ui.enable.value\n },\n {\n type: 'text',\n name: 'route',\n message: 'A route to attach the UI',\n initial: defaultConfig.ui.route.value\n }\n ],\n other: [\n {\n type: 'text',\n name: 'nodeEnv',\n message: 'The type of Node.js environment',\n initial: defaultConfig.other.nodeEnv.value\n },\n {\n type: 'toggle',\n name: 'listenToProcessExits',\n message: 'Set to false to skip attaching process.exit handlers',\n initial: defaultConfig.other.listenToProcessExits.value\n },\n {\n type: 'toggle',\n name: 'noLogo',\n message: 'Skip printing the logo on startup. Replaced by simple text',\n initial: defaultConfig.other.noLogo.value\n },\n {\n type: 'toggle',\n name: 'hardResetPage',\n message: 'Decides if the page content should be reset entirely',\n initial: defaultConfig.other.hardResetPage.value\n },\n {\n type: 'toggle',\n name: 'browserShellMode',\n message: 'Decides if the browser runs in the shell mode',\n initial: defaultConfig.other.browserShellMode.value\n }\n ],\n debug: [\n {\n type: 'toggle',\n name: 'enable',\n message: 'Enables debug mode for the browser instance',\n initial: defaultConfig.debug.enable.value\n },\n {\n type: 'toggle',\n name: 'headless',\n message: 'The mode setting for the browser',\n initial: defaultConfig.debug.headless.value\n },\n {\n type: 'toggle',\n name: 'devtools',\n message: 'The DevTools for the headful browser',\n initial: defaultConfig.debug.devtools.value\n },\n {\n type: 'toggle',\n name: 'listenToConsole',\n message: 'The event listener for console messages from the browser',\n initial: defaultConfig.debug.listenToConsole.value\n },\n {\n type: 'toggle',\n name: 'dumpio',\n message: 'Redirects the browser stdout and stderr to NodeJS process',\n initial: defaultConfig.debug.dumpio.value\n },\n {\n type: 'number',\n name: 'slowMo',\n message: 'Puppeteer operations slow down in milliseconds',\n initial: defaultConfig.debug.slowMo.value\n },\n {\n type: 'number',\n name: 'debuggingPort',\n message: 'The port number for debugging',\n initial: defaultConfig.debug.debuggingPort.value\n }\n ]\n};\n\n// Absolute props that, in case of merging recursively, need to be force merged\nexport const absoluteProps = [\n 'options',\n 'globalOptions',\n 'themeOptions',\n 'resources',\n 'payload'\n];\n\n// Argument nesting level of all export server options\nexport const nestedArgs = {};\n\n/**\n * Recursively creates a chain of nested arguments from an object.\n *\n * @param {Object} obj - The object containing nested arguments.\n * @param {string} propChain - The current chain of nested properties\n * (used internally during recursion).\n */\nconst createNestedArgs = (obj, propChain = '') => {\n Object.keys(obj).forEach((k) => {\n if (!['puppeteer', 'highcharts'].includes(k)) {\n const entry = obj[k];\n if (typeof entry.value === 'undefined') {\n // Go deeper in the nested arguments\n createNestedArgs(entry, `${propChain}.${k}`);\n } else {\n // Create the chain of nested arguments\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\n\n // Support for the legacy, PhantomJS properties names\n if (entry.legacyName !== undefined) {\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\n }\n }\n }\n });\n};\n\ncreateNestedArgs(defaultConfig);\n","/**\n * @fileoverview\n * This file is responsible for parsing the environment variables with the 'zod'\n * library. The parsed environment variables are then exported to be used\n * in the application as \"envs\". We should not use process.env directly\n * in the application as these would not be parsed properly.\n *\n * The environment variables are parsed and validated only once when\n * the application starts. We should write a custom validator or a transformer\n * for each of the options.\n */\n\nimport dotenv from 'dotenv';\nimport { z } from 'zod';\n\nimport { scriptsNames } from './schemas/config.js';\n\n// Load .env into environment variables\ndotenv.config();\n\n// Object with custom validators and transformers, to avoid repetition\n// in the Config object\nconst v = {\n // Splits string value into elements in an array, trims every element, checks\n // if an array is correct, if it is empty, and if it is, returns undefined\n array: (filterArray) =>\n z\n .string()\n .transform((value) =>\n value\n .split(',')\n .map((value) => value.trim())\n .filter((value) => filterArray.includes(value))\n )\n .transform((value) => (value.length ? value : undefined)),\n\n // Allows only true, false and correctly parse the value to boolean\n // or no value in which case the returned value will be undefined\n boolean: () =>\n z\n .enum(['true', 'false', ''])\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\n\n // Allows passed values or no value in which case the returned value will\n // be undefined\n enum: (values) =>\n z\n .enum([...values, ''])\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Trims the string value and checks if it is empty or contains stringified\n // values such as false, undefined, null, NaN, if it does, returns undefined\n string: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\n value === '',\n (value) => ({\n message: `The string contains forbidden values, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n\n // Allows positive numbers or no value in which case the returned value will\n // be undefined\n positiveNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\n (value) => ({\n message: `The value must be numeric and positive, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\n\n // Allows non-negative numbers or no value in which case the returned value\n // will be undefined\n nonNegativeNum: () =>\n z\n .string()\n .trim()\n .refine(\n (value) =>\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\n (value) => ({\n message: `The value must be numeric and non-negative, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\n};\n\nexport const Config = z.object({\n // highcharts\n HIGHCHARTS_VERSION: z\n .string()\n .trim()\n .refine(\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\n (value) => ({\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CDN_URL: z\n .string()\n .trim()\n .refine(\n (value) =>\n value.startsWith('https://') ||\n value.startsWith('http://') ||\n value === '',\n (value) => ({\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\n })\n )\n .transform((value) => (value !== '' ? value : undefined)),\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\n HIGHCHARTS_CACHE_PATH: v.string(),\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\n\n // export\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\n\n // custom\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\n\n // server\n SERVER_ENABLE: v.boolean(),\n SERVER_HOST: v.string(),\n SERVER_PORT: v.positiveNum(),\n SERVER_BENCHMARKING: v.boolean(),\n\n // server proxy\n SERVER_PROXY_HOST: v.string(),\n SERVER_PROXY_PORT: v.positiveNum(),\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\n\n // server rate limiting\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\n\n // server ssl\n SERVER_SSL_ENABLE: v.boolean(),\n SERVER_SSL_FORCE: v.boolean(),\n SERVER_SSL_PORT: v.positiveNum(),\n SERVER_SSL_CERT_PATH: v.string(),\n\n // pool\n POOL_MIN_WORKERS: v.nonNegativeNum(),\n POOL_MAX_WORKERS: v.nonNegativeNum(),\n POOL_WORK_LIMIT: v.positiveNum(),\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\n POOL_BENCHMARKING: v.boolean(),\n POOL_RESOURCES_INTERVAL: v.nonNegativeNum(),\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_CONNECTION_OVER_PIPE: 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 of 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(url, requestOptions, (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 .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 /**\n * @param {string} message\n * @param {number} [status] describes the status code (400, 500, etc.)\n */\n constructor(message, status) {\n super();\n\n this.message = message;\n this.stackMessage = message;\n\n if (status) {\n this.status = status;\n }\n }\n\n setError(error) {\n this.error = error;\n\n if (error.name) {\n this.name = error.name;\n }\n\n if (!this.status && error.statusCode) {\n this.status = error.statusCode;\n }\n\n if (error.stack) {\n this.stackMessage = error.message;\n this.stack = error.stack;\n }\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 { isAbsolute, 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(getCachePath(), 'manifest.json'),\n JSON.stringify(newManifest),\n 'utf8'\n );\n } catch (error) {\n throw new ExportError(\n '[cache] Error writing the cache manifest.',\n 400\n ).setError(error);\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 500\n ).setError(response);\n } else {\n log(\n 2,\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\n );\n }\n\n return '';\n};\n\n/**\n * Fetches Highcharts scripts and customScripts from the given CDNs.\n *\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\n * @param {string} customScripts - Array of custom script paths to fetch\n * (full URLs).\n * @param {object} proxyOptions - Options for the proxy agent to use for\n * a request.\n * @param {object} fetchedModules - An object which tracks which Highcharts\n * modules have been fetched.\n *\n * @returns {Promise} The fetched scripts content joined.\n */\nexport const fetchScripts = async (\n coreScripts,\n moduleScripts,\n customScripts,\n proxyOptions,\n fetchedModules\n) => {\n // Configure proxy if exists\n let proxyAgent;\n const proxyHost = proxyOptions.host;\n const proxyPort = proxyOptions.port;\n\n // Try to create a Proxy Agent\n if (proxyHost && proxyPort) {\n try {\n proxyAgent = new HttpsProxyAgent({\n host: proxyHost,\n port: proxyPort\n });\n } catch (error) {\n throw new ExportError(\n '[cache] Could not create a Proxy Agent.',\n 500\n ).setError(error);\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 500\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\n const cachePath = getCachePath();\n\n let fetchedModules;\n\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, { recursive: true });\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\n/**\n * Returns the path to the cache folder.\n * @returns {string} The path to the cache folder.\n */\nexport const getCachePath = () => {\n const cachePathOption = getOptions().highcharts.cachePath;\n\n // issue #562: support for absolute paths\n return isAbsolute(cachePathOption)\n ? cachePathOption\n : join(__dirname, cachePathOption);\n};\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 Highcharts[options.export.constr || 'chart'](\n 'container',\n finalOptions,\n finalCallback\n );\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 { envs } from './envs.js';\nimport { setupHighcharts } from './highcharts.js';\nimport { log, logWithStack } from './logger.js';\nimport { __dirname, expBackoff } 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\n// To save the browser\nlet browser;\n\n// To save the WebSocket endpoint in case of a sudden disconnect\nlet wsEndpoint;\n\n/**\n * Reconnects to the browser instance when it is disconnected. If the current\n * browser connection is lost, it attempts to reconnect using the previous\n * WebSocket endpoint. If the reconnection fails, it will try to close the\n * browser and relaunch a new instance.\n */\nasync function reconnect() {\n try {\n // Start the reconnecting\n log(3, `[browser] Restarting the browser connection.`);\n\n // Try to reconnect the browser\n if (browser && !browser.connected) {\n browser = await puppeteer.connect({\n browserWSEndpoint: wsEndpoint\n });\n }\n\n // Save a new WebSocket endpoint\n wsEndpoint = browser.wsEndpoint();\n\n // Add the reconnect event again\n browser.on('disconnected', reconnect);\n\n // Log the success message\n log(3, `[browser] Browser reconnected successfully.`);\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Could not restore the browser connection, attempting to relaunch.'\n );\n\n // Try to close the browser before relaunching\n try {\n await close();\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Could not close the browser before relaunching (probably is already closed).'\n );\n }\n\n // Try to relaunch the browser\n await create(getOptions().puppeteer.args || []);\n\n // Log the success message\n log(3, `[browser] Browser relaunched successfully.`);\n }\n}\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.', 500);\n }\n return browser;\n}\n\n/**\n * Creates a Puppeteer browser instance with the specified arguments.\n *\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\n *\n * @returns {Promise} A Promise resolving to the Puppeteer browser\n * instance.\n *\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\n * instance are reached, or if no browser instance is found after retries.\n */\nexport async function create(puppeteerArgs) {\n // Get debug and other options\n const { debug, other } = getOptions();\n\n // Get the debug options\n const { enable: enabledDebug, ...debugOptions } = debug;\n\n const launchOptions = {\n headless: other.browserShellMode ? 'shell' : true,\n userDataDir: './tmp/',\n args: puppeteerArgs,\n // Must be disabled for debugging to work\n pipe: envs.OTHER_CONNECTION_OVER_PIPE,\n handleSIGINT: false,\n handleSIGTERM: false,\n handleSIGHUP: false,\n waitForInitialPage: false,\n defaultViewport: null,\n ...(enabledDebug && debugOptions)\n };\n\n // Create a browser\n if (!browser) {\n let tryCount = 0;\n\n const open = async () => {\n try {\n log(\n 3,\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\n );\n\n // Launch the browser\n browser = await puppeteer.launch(launchOptions);\n\n // Close the initial pages if any found\n const pages = await browser.pages();\n if (pages) {\n for (const page of pages) {\n await page.close();\n }\n }\n\n // Only for the WebSocket connection\n if (!launchOptions.pipe) {\n // Save WebSocket endpoint\n wsEndpoint = browser.wsEndpoint();\n\n // Attach the disconnected event\n browser.on('disconnected', reconnect);\n }\n } catch (error) {\n logWithStack(\n 1,\n error,\n '[browser] Failed to launch a browser instance.'\n );\n\n // Retry to launch browser until reaching max attempts\n if (tryCount < 25) {\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\n await new Promise((response) => setTimeout(response, 4000));\n await open();\n } else {\n throw error;\n }\n }\n };\n\n try {\n await open();\n\n // Shell mode inform\n if (launchOptions.headless === 'shell') {\n log(3, `[browser] Launched browser in shell mode.`);\n }\n\n // Debug mode inform\n if (enabledDebug) {\n log(3, `[browser] Launched browser in debug mode.`);\n }\n } catch (error) {\n throw new ExportError(\n '[browser] Maximum retries to open a browser instance reached.',\n 500\n ).setError(error);\n }\n\n if (!browser) {\n throw new ExportError('[browser] Cannot find a browser to open.', 500);\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 connected\n if (browser && browser.connected) {\n await browser.close();\n }\n browser = null;\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 * @param {Object} poolResource - The pool resource that contians page and id.\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(poolResource) {\n const startDate = new Date().getTime();\n\n // Throw an error in case of no connected browser\n if (!browser || !browser.connected) {\n throw new ExportError(`[browser] Browser is not yet connected.`, 500);\n }\n\n // Create a page\n poolResource.page = await browser.newPage();\n\n // Disable cache\n await poolResource.page.setCacheEnabled(false);\n\n // Set the content\n await setPageContent(poolResource.page);\n\n // Set page events\n setPageEvents(poolResource);\n\n // Check if the page is correctly created\n if (!poolResource.page || poolResource.page.isClosed()) {\n throw new ExportError('The page is invalid or closed.', 500);\n }\n\n log(\n 3,\n `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${\n new Date().getTime() - startDate\n }ms.`\n );\n\n // Return the resource with a ready to use page\n return poolResource;\n}\n\n/**\n * Clears the content of a Puppeteer Page based on the specified mode.\n *\n * @param {Object} poolResource - The pool resource that contians page and id.\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(poolResource, hardReset = false) {\n try {\n if (!poolResource.page.isClosed()) {\n if (hardReset) {\n // Navigate to about:blank\n await poolResource.page.goto('about:blank', {\n waitUntil: 'domcontentloaded'\n });\n\n // Set the content and and scripts again\n await setPageContent(poolResource.page);\n } else {\n // Clear body content\n await poolResource.page.evaluate(() => {\n document.body.innerHTML =\n '
';\n });\n }\n }\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.`\n );\n // Set the `workLimit` to exceeded in order to recreate the resource\n poolResource.workCount = getOptions().pool.workLimit + 1;\n }\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(1, 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} poolResource - The pool resource that contians page and id.\n */\nfunction setPageEvents(poolResource) {\n // Get debug options\n const { debug, pool } = getOptions();\n\n // Set the pageerror listener\n poolResource.page.on('pageerror', async (error) => {\n // TODO: Consider adding a switch here that turns on log(0) logging\n // on page errors.\n await poolResource.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 // Set the console listener, if needed\n if (debug.enable && debug.listenToConsole) {\n poolResource.page.on('console', (message) => {\n console.log(`[debug] ${message.text()}`);\n });\n }\n\n // Add the framedetached event if the connection is over WebSocket\n if (envs.OTHER_CONNECTION_OVER_PIPE === false) {\n poolResource.page.on('framedetached', async (frame) => {\n // Get the main frame\n const mainFrame = poolResource.page.mainFrame();\n\n // Check if a page's frame is detached and requires to be recreated\n if (\n frame === mainFrame &&\n mainFrame.detached &&\n poolResource.workCount <= pool.workLimit\n ) {\n log(\n 3,\n `[browser] Pool resource [${poolResource.id}] - Page's frame detached.`\n );\n try {\n // Try to connect to a new page using exponential backoff strategy\n expBackoff(\n async (poolResourceId, poolResource) => {\n try {\n // Try to close the page with a detached frame\n if (!poolResource.page.isClosed()) {\n await poolResource.page.close();\n }\n } catch (error) {\n log(\n 3,\n `[browser] Pool resource [${poolResourceId}] - Could not close the page with a detached frame.`\n );\n }\n\n // Trigger a page creation\n await newPage(poolResource);\n },\n 0,\n poolResource.id,\n poolResource\n );\n } catch (error) {\n logWithStack(\n 3,\n error,\n `[browser] Pool resource [${poolResource.id}] - Could not create a new page.`\n );\n\n // Set the `workLimit` to exceeded in order to recreate the resource\n poolResource.workCount = pool.workLimit + 1;\n }\n }\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', 408)),\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 return Promise.race([\n page.pdf({\n // This will remove an extra empty page in PDF exports\n height: height + 1,\n width,\n encoding\n }),\n new Promise((_resolve, reject) =>\n setTimeout(\n () => reject(new ExportError('Rasterization timeout', 408)),\n rasterizationTimeout || 1500\n )\n )\n ]);\n};\n\n/**\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\n * inside an element with the id 'container'.\n *\n * @param {Object} page - Puppeteer page object.\n *\n * @returns {Promise} Promise resolving to the SVG string.\n */\nconst createSVG = (page) =>\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\n\n/**\n * Sets the specified chart and options as configuration into the triggerExport\n * function within the window context using page.evaluate.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object to be configured.\n * @param {Object} options - Configuration options for the chart.\n *\n * @returns {Promise} Promise resolving after the configuration is set.\n */\nconst setAsConfig = async (page, chart, options, displayErrors) =>\n page.evaluate(triggerExport, chart, options, displayErrors);\n\n/**\n * Exports to a chart from a page using Puppeteer.\n *\n * @param {Object} page - Puppeteer page object.\n * @param {any} chart - The chart object or SVG configuration to be exported.\n * @param {Object} options - Export options and configuration.\n *\n * @returns {Promise} Promise resolving to\n * the exported data or rejecting with an ExportError.\n */\nexport default async (page, chart, options) => {\n // Injected resources array (additional JS and CSS)\n let injectedResources = [];\n\n try {\n log(4, '[export] Determining export path.');\n\n const exportOptions = options.export;\n\n // Decide whether display error or debbuger wrapper around it\n const displayErrors =\n exportOptions?.options?.chart?.displayErrors &&\n getCache().activeManifest.modules.debugger;\n\n let isSVG;\n if (\n chart.indexOf &&\n (chart.indexOf('= 0 || chart.indexOf('= 0)\n ) {\n // SVG input handling\n log(4, '[export] Treating as SVG.');\n\n // If input is also SVG, just return it\n if (exportOptions.type === 'svg') {\n return chart;\n }\n\n isSVG = true;\n await page.setContent(svgTemplate(chart), {\n waitUntil: 'domcontentloaded'\n });\n } else {\n // JSON config handling\n log(4, '[export] Treating as config.');\n\n // Need to perform straight inject\n if (exportOptions.strInj) {\n // Injection based configuration export\n await setAsConfig(\n page,\n {\n chart: {\n height: exportOptions.height,\n width: exportOptions.width\n }\n },\n options,\n displayErrors\n );\n } else {\n // Basic configuration export\n chart.chart.height = exportOptions.height;\n chart.chart.width = exportOptions.width;\n\n await setAsConfig(page, chart, options, displayErrors);\n }\n }\n\n // Keeps track of all resources added on the page with addXXXTag. etc\n // It's VITAL that all added resources ends up here so we can clear things\n // out when doing a new export in the same page!\n injectedResources = await addPageResources(page, options);\n\n // Get the real chart size and set the zoom accordingly\n const size = isSVG\n ? await page.evaluate((scale) => {\n const svgElement = document.querySelector(\n '#chart-container svg:first-of-type'\n );\n\n // Get the values correctly scaled\n const chartHeight = svgElement.height.baseVal.value * scale;\n const chartWidth = svgElement.width.baseVal.value * scale;\n\n // In case of SVG the zoom must be set directly for body\n // Set the zoom as scale\n // eslint-disable-next-line no-undef\n document.body.style.zoom = scale;\n\n // Set the margin to 0px\n // eslint-disable-next-line no-undef\n document.body.style.margin = '0px';\n\n return {\n chartHeight,\n chartWidth\n };\n }, parseFloat(exportOptions.scale))\n : await page.evaluate(() => {\n // eslint-disable-next-line no-undef\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\n\n // No need for such scale manipulation in case of other types of exports\n // Reset the zoom for other exports than to SVGs\n // eslint-disable-next-line no-undef\n document.body.style.zoom = 1;\n\n return {\n chartHeight,\n chartWidth\n };\n });\n\n // Set final height and width for viewport\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\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 400\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 { 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","/*******************************************************************************\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 { envs } from './envs.js';\nimport puppeteerExport from './export.js';\nimport { addInterval } from './intervals.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 try {\n const poolResource = {\n id: uuid(),\n // Try to distribute the initial work count\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\n };\n\n return await newPage(poolResource);\n } catch (error) {\n throw new ExportError(\n 'Error encountered when creating a new page.',\n 500\n ).setError(error);\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} poolResource - 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 (poolResource) => {\n let validated = true;\n\n // Check if the `workLimit` is exceeded\n if (\n poolConfig.workLimit &&\n ++poolResource.workCount > poolConfig.workLimit\n ) {\n log(\n 3,\n `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolConfig.workLimit} works limit).`\n );\n validated = false;\n }\n\n // Check if the `page` is not valid\n if (!poolResource.page) {\n // Check if the `page` is closed\n if (poolResource.page.isClosed()) {\n log(\n 3,\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).`\n );\n }\n\n // Check if the `mainFrame` is detached\n if (poolResource.page.mainFrame().detached) {\n log(\n 3,\n `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).`\n );\n }\n validated = false;\n }\n\n return validated;\n },\n\n /**\n * Destroys a worker entry in the export pool, closing its associated page.\n *\n * @param {Object} poolResource - The handle to the worker, containing\n * the worker's ID and a reference to the browser page.\n */\n destroy: async (poolResource) => {\n log(3, `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`);\n\n if (poolResource.page) {\n try {\n // Remove all attached event listeners from the resource\n poolResource.page.removeAllListeners('pageerror');\n poolResource.page.removeAllListeners('console');\n poolResource.page.removeAllListeners('framedetached');\n\n // We need to wait around for this\n await poolResource.page.close();\n } catch (error) {\n log(\n 3,\n `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.`\n );\n }\n }\n }\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 log(4, `[pool] Pool resource [${resource.id}] - Releasing a worker.`);\n await clearPage(resource, false);\n });\n\n pool.on('destroySuccess', (_eventId, resource) => {\n log(\n 4,\n `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.`\n );\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 // Init the interval for checking if the minimum number of resources exist\n if (envs.POOL_RESOURCES_INTERVAL) {\n // Register interval for the later clearing\n addInterval(_checkingResourcesInterval(envs.POOL_RESOURCES_INTERVAL));\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 500\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 // Remove all attached event listeners from the pool\n pool.removeAllListeners('release');\n pool.removeAllListeners('destroySuccess');\n pool.removeAllListeners('destroyFail');\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 pool = null;\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(\n 'Work received, but pool has not been started.',\n 500\n );\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 // Set the `workLimit` to exceeded in order to recreate the resource\n workerHandle.workCount = poolConfig.workLimit + 1;\n throw new ExportError(\n 'Resolved worker page is invalid: the pool setup is wonky.',\n 500\n );\n }\n\n // Save the start time\n let workStart = new Date().getTime();\n\n log(\n 4,\n `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.`\n );\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 if (result.message === 'Rasterization timeout') {\n // Set the `workLimit` to exceeded in order to recreate the resource\n workerHandle.workCount = poolConfig.workLimit + 1;\n }\n\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 // 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 used: pool.numUsed(),\n available: pool.numFree(),\n allCreated: pool.numUsed() + pool.numFree(),\n pendingAcquires: pool.numPendingAcquires(),\n pendingCreates: pool.numPendingCreates(),\n pendingValidations: pool.numPendingValidations(),\n pendingDestroys: pool.pendingDestroys.length,\n absoluteAll:\n pool.numUsed() +\n pool.numFree() +\n pool.numPendingAcquires() +\n pool.numPendingCreates() +\n pool.numPendingValidations() +\n pool.pendingDestroys.length\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 {\n min,\n max,\n used,\n available,\n allCreated,\n pendingAcquires,\n pendingCreates,\n pendingValidations,\n pendingDestroys,\n absoluteAll\n } = 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 used resources: ${used}.`);\n log(5, `[pool] The number of free resources: ${available}.`);\n log(\n 5,\n `[pool] The number of all created (used and free) resources: ${allCreated}.`\n );\n log(\n 5,\n `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.`\n );\n log(\n 5,\n `[pool] The number of resources waiting to be created: ${pendingCreates}.`\n );\n log(\n 5,\n `[pool] The number of resources waiting to be validated: ${pendingValidations}.`\n );\n log(\n 5,\n `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.`\n );\n log(5, `[pool] The number of all resources: ${absoluteAll}.`);\n}\n\n/**\n * Periodically checks and ensures the minimum number of resources in the pool.\n * If the total number of used, free and about to be created resources falls\n * below the minimum set with the `pool.min`, it creates additional resources to\n * meet the minimum requirement.\n *\n * @param {number} resourceCheckInterval - The interval, in milliseconds, at\n * which the pool resources are checked.\n *\n * @returns {NodeJS.Timeout} - Returns a timer ID that can be used to clear the\n * interval later.\n */\nfunction _checkingResourcesInterval(resourceCheckInterval) {\n // Set the interval for checking the number of pool resources\n return setInterval(async () => {\n try {\n // Get the current number of resources\n let currentNumber =\n pool.numUsed() + pool.numFree() + pool.numPendingCreates();\n\n // Create missing resources\n while (currentNumber++ < pool.min) {\n try {\n // Explicitly creating a resource\n await pool._doCreate();\n } catch (error) {\n logWithStack(2, error, '[pool] Could not create a missing resource.');\n }\n }\n } catch (error) {\n logWithStack(\n 1,\n error,\n `[pool] Something went wrong when trying to create missing resources.`\n );\n }\n }, resourceCheckInterval);\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.', 400).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.', 400).setError(\n error\n )\n );\n }\n }\n\n // Export with options from the raw representation\n if (\n (exportOptions.instr && exportOptions.instr !== '') ||\n (exportOptions.options && exportOptions.options !== '')\n ) {\n try {\n log(4, '[chart] Attempting to export from a raw input.');\n\n // Perform a direct inject when forced\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\n return doStraightInject(options, endCallback);\n }\n\n // Either try to parse to JSON first or do the direct export\n return typeof exportOptions.instr === 'string'\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\n : doExport(\n options,\n exportOptions.instr || exportOptions.options,\n endCallback\n );\n } catch (error) {\n return endCallback(\n new ExportError('[chart] Error loading raw input.', 400).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 400\n )\n );\n};\n\n/**\n * Starts a batch export process for multiple charts based on the information\n * in the batch option. The batch is a string in the following format:\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\n *\n * @param {Object} options - The options object containing configuration for\n * a batch export.\n *\n * @returns {Promise} A Promise that resolves once the batch export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * any of the batch export process.\n */\nexport const batchExport = async (options) => {\n const batchFunctions = [];\n\n // Split and pair the --batch arguments\n for (let pair of options.export.batch.split(';')) {\n pair = pair.split('=');\n if (pair.length === 2) {\n batchFunctions.push(\n startExport(\n {\n ...options,\n export: {\n ...options.export,\n infile: pair[0],\n outfile: pair[1]\n }\n },\n (error, info) => {\n // Throw an error\n if (error) {\n throw error;\n }\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n info.options.export.outfile,\n info.options.export.type !== 'svg'\n ? Buffer.from(info.result, 'base64')\n : info.result\n );\n }\n )\n );\n }\n }\n\n try {\n // Await all exports are done\n await Promise.all(batchFunctions);\n\n // Kill pool and close browser after finishing batch export\n await killPool();\n } catch (error) {\n throw new ExportError(\n '[chart] Error encountered during batch export.'\n ).setError(error);\n }\n};\n\n/**\n * Starts a single export process based on the specified options.\n *\n * @param {Object} options - The options object containing configuration for\n * a single export.\n *\n * @returns {Promise} A Promise that resolves once the single export\n * process is completed.\n *\n * @throws {ExportError} Throws an ExportError if an error occurs during\n * the single export process.\n */\nexport const singleExport = async (options) => {\n // Use instr or its alias, options\n options.export.instr = options.export.instr || options.export.options;\n\n // Perform an export\n await startExport(options, async (error, info) => {\n // Exit process when error\n if (error) {\n throw error;\n }\n\n const { outfile, type } = info.options.export;\n\n // Save the base64 from a buffer to a correct image file\n writeFileSync(\n outfile || `chart.${type}`,\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\n );\n\n // Kill pool and close browser after finishing single export\n await killPool();\n });\n};\n\n/**\n * Determines the size and scale for chart export based on the provided options.\n *\n * @param {Object} options - The options object containing configuration for\n * chart export.\n *\n * @returns {Object} An object containing the calculated height, width,\n * and scale for the chart export.\n */\nexport const findChartSize = (options) => {\n const { chart, exporting } =\n options.export?.options || isCorrectJSON(options.export?.instr);\n\n // See if globalOptions holds chart or exporting size\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\n\n // Secure scale value\n let scale =\n options.export?.scale ||\n exporting?.scale ||\n globalOptions?.exporting?.scale ||\n options.export?.defaultScale ||\n 1;\n\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\n scale = Math.max(0.1, Math.min(scale, 5.0));\n\n // we want to round the numbers like 0.23234 -> 0.23\n scale = roundNumber(scale, 2);\n\n // Find chart size and scale\n const size = {\n height:\n options.export?.height ||\n exporting?.sourceHeight ||\n chart?.height ||\n globalOptions?.exporting?.sourceHeight ||\n globalOptions?.chart?.height ||\n options.export?.defaultHeight ||\n 400,\n width:\n options.export?.width ||\n exporting?.sourceWidth ||\n chart?.width ||\n globalOptions?.exporting?.sourceWidth ||\n globalOptions?.chart?.width ||\n options.export?.defaultWidth ||\n 600,\n scale\n };\n\n // Get rid of potential px and %\n for (let [param, value] of Object.entries(size)) {\n size[param] =\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\n }\n return size;\n};\n\n/**\n * Function for finalizing options before export.\n *\n * @param {Object} options - The options object containing configuration for\n * the export process.\n * @param {Object} chartJson - The JSON representation of the chart.\n * @param {Function} endCallback - The callback function to be called upon\n * completion or error.\n * @param {string} svg - The SVG representation of the chart.\n *\n * @returns {Promise} A Promise that resolves once the export process\n * is completed.\n */\nconst doExport = async (options, chartJson, endCallback, svg) => {\n let { export: exportOptions, customLogic: customLogicOptions } = options;\n\n const allowCodeExecutionScoped =\n typeof customLogicOptions.allowCodeExecution === 'boolean'\n ? customLogicOptions.allowCodeExecution\n : allowCodeExecution;\n\n if (!customLogicOptions) {\n customLogicOptions = options.customLogic = {};\n } else if (allowCodeExecutionScoped) {\n if (typeof options.customLogic.resources === 'string') {\n // Process resources\n options.customLogic.resources = handleResources(\n options.customLogic.resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } else if (!options.customLogic.resources) {\n try {\n const resources = readFileSync('resources.json', 'utf8');\n options.customLogic.resources = handleResources(\n resources,\n toBoolean(options.customLogic.allowFileResources)\n );\n } catch (error) {\n logWithStack(\n 2,\n error,\n `[chart] Unable to load the default resources.json file.`\n );\n }\n }\n }\n\n // If the allowCodeExecution flag isn't set, we should refuse the usage\n // of callback, resources, and custom code. Additionally, the worker will\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\n // option, then we should take a look at the overall pool option.\n if (!allowCodeExecutionScoped && customLogicOptions) {\n if (\n customLogicOptions.callback ||\n customLogicOptions.resources ||\n customLogicOptions.customCode\n ) {\n // Send back a friendly message saying that the exporter does not support\n // these settings.\n return endCallback(\n new ExportError(\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`,\n 400\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 400\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 (!chartJSON || typeof chartJSON !== 'object') {\n return endCallback(\n new ExportError(\n '[chart] Invalid configuration provided - the options must be an object, not a string',\n 400\n )\n );\n }\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 400\n ).setError(error)\n );\n }\n }\n};\n\n/**\n * Retrieves and returns the current status of code execution permission.\n *\n * @returns {any} The value of allowCodeExecution.\n */\nexport const getAllowCodeExecution = () => allowCodeExecution;\n\n/**\n * Sets the code execution permission based on the provided boolean value.\n *\n * @param {any} value - The value to be converted and assigned\n * to allowCodeExecution.\n */\nexport const setAllowCodeExecution = (value) => {\n allowCodeExecution = toBoolean(value);\n};\n\nexport default {\n batchExport,\n singleExport,\n getAllowCodeExecution,\n setAllowCodeExecution,\n startExport,\n findChartSize\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\n/**\n * @overview Used to sanitize the strings coming from the exporting module\n * to prevent XSS attacks (with the DOMPurify library).\n **/\n\nimport { JSDOM } from 'jsdom';\nimport DOMPurify from 'dompurify';\n\n/**\n * Sanitizes a given HTML string by removing tags and any content within them.\n *\n * @param {string} input The HTML string to be sanitized.\n * @returns {string} The sanitized HTML string.\n */\nexport function sanitize(input) {\n const window = new JSDOM('').window;\n const purify = DOMPurify(window);\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\n}\n\nexport default sanitize;\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 || 500;\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. Payload received: ${JSON.stringify(body)}.`\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', () => {\n connectionAborted = true;\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(\n cors({\n methods: ['POST', 'GET', 'OPTIONS']\n })\n);\n\n// Enable parsing of form data (files) with Multer package\nconst storage = multer.memoryStorage();\nconst upload = multer({\n storage,\n limits: {\n fieldSize: 50 * 1024 * 1024\n }\n});\n\n// Enable body parser\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\n\n// Use only non-file multipart form fields\napp.use(upload.none());\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) => {\n logWithStack(1, error, `[server] Client error: ${error.message}`);\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 // 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 500\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 });\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';\nimport { get as getBrowser } from './browser.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 // Remove all attached event listeners from the browser\n getBrowser().removeAllListeners('disconnected');\n\n // Await freeing all resources\n await Promise.allSettled([\n // Clear all ongoing intervals\n clearAllIntervals(),\n\n // Get available server instances (HTTP/HTTPS) and close them\n closeServers(),\n\n // Close pool along with its workers and the browser instance, if exists\n killPool()\n ]);\n\n // Exit process with a correct code\n process.exit(exitCode);\n};\n\nexport default {\n shutdownCleanUp\n};\n","/*******************************************************************************\n\nHighcharts Export Server\n\nCopyright (c) 2016-2024, Highsoft\n\nLicenced under the MIT licence.\n\nAdditionally a valid Highcharts license is required for use.\n\nSee LICENSE file in root for details.\n\n*******************************************************************************/\n\nimport 'colors';\n\nimport { checkAndUpdateCache } from './cache.js';\nimport {\n batchExport,\n setAllowCodeExecution,\n singleExport,\n startExport\n} from './chart.js';\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\nimport {\n initLogging,\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging\n} from './logger.js';\nimport { initPool, killPool } from './pool.js';\nimport { shutdownCleanUp } from './resource_release.js';\nimport server, { startServer } from './server/server.js';\nimport { printLogo, printUsage } from './utils.js';\n\n/**\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\n * 'uncaughtException' events.\n */\nconst attachProcessExitListeners = () => {\n log(3, '[process] Attaching exit listeners to the process.');\n\n // Handler for the 'exit'\n process.on('exit', (code) => {\n log(4, `Process exited with code ${code}.`);\n });\n\n // Handler for the 'SIGINT'\n process.on('SIGINT', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGTERM'\n process.on('SIGTERM', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'SIGHUP'\n process.on('SIGHUP', async (name, code) => {\n log(4, `The ${name} event with code: ${code}.`);\n await shutdownCleanUp(0);\n });\n\n // Handler for the 'uncaughtException'\n process.on('uncaughtException', async (error, name) => {\n logWithStack(1, error, `The ${name} error.`);\n await shutdownCleanUp(1);\n });\n};\n\n/**\n * Initializes the export process. Tasks such as configuring logging, checking\n * cache and sources, and initializing the pool of resources happen during\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\n *\n * @param {Object} options - All export options.\n *\n * @returns {Promise} Promise resolving to the updated export options.\n */\nconst initExport = async (options) => {\n // Set the allowCodeExecution per export module scope\n setAllowCodeExecution(\n options.customLogic && options.customLogic.allowCodeExecution\n );\n\n // Init the logging\n initLogging(options.logging);\n\n // Attach process' exit listeners\n if (options.other.listenToProcessExits) {\n attachProcessExitListeners();\n }\n\n // Check if cache needs to be updated\n await checkAndUpdateCache(options);\n\n // Init the pool\n await initPool({\n pool: options.pool || {\n minWorkers: 1,\n maxWorkers: 1\n },\n puppeteerArgs: options.puppeteer.args || []\n });\n\n // Return updated options\n return options;\n};\n\nexport default {\n // Server\n server,\n startServer,\n\n // Exporting\n initExport,\n singleExport,\n batchExport,\n startExport,\n\n // Pool\n initPool,\n killPool,\n\n // Other\n setOptions,\n shutdownCleanUp,\n\n // Logs\n log,\n logWithStack,\n setLogLevel,\n enableFileLogging,\n\n // Utils\n mapToNewConfig,\n manualConfig,\n printLogo,\n printUsage\n};\n"],"names":["scriptsNames","core","modules","indicators","custom","defaultConfig","puppeteer","args","value","type","description","highcharts","version","envLink","cdnURL","coreScripts","moduleScripts","indicatorScripts","customScripts","forceFetch","cachePath","export","infile","instr","options","outfile","constr","defaultHeight","defaultWidth","defaultScale","height","width","scale","globalOptions","themeOptions","batch","rasterizationTimeout","customLogic","allowCodeExecution","allowFileResources","customCode","callback","resources","loadConfig","legacyName","createConfig","server","enable","cliName","host","port","benchmarking","proxy","timeout","rateLimiting","maxRequests","window","delay","trustProxy","skipKey","skipToken","ssl","force","certPath","pool","minWorkers","maxWorkers","workLimit","acquireTimeout","createTimeout","destroyTimeout","idleTimeout","createRetryInterval","reaperInterval","logging","level","file","dest","toConsole","toFile","ui","route","other","nodeEnv","listenToProcessExits","noLogo","hardResetPage","browserShellMode","debug","headless","devtools","listenToConsole","dumpio","slowMo","debuggingPort","promptsConfig","name","message","initial","join","separator","instructions","choices","hint","min","max","round","absoluteProps","nestedArgs","createNestedArgs","obj","propChain","Object","keys","forEach","k","includes","entry","substring","undefined","dotenv","config","v","filterArray","z","string","transform","split","map","trim","filter","length","enum","values","refine","isNaN","parseFloat","envs","object","HIGHCHARTS_VERSION","test","HIGHCHARTS_CDN_URL","startsWith","HIGHCHARTS_CORE_SCRIPTS","HIGHCHARTS_MODULE_SCRIPTS","HIGHCHARTS_INDICATOR_SCRIPTS","HIGHCHARTS_FORCE_FETCH","HIGHCHARTS_CACHE_PATH","HIGHCHARTS_ADMIN_TOKEN","EXPORT_TYPE","EXPORT_CONSTR","EXPORT_DEFAULT_HEIGHT","EXPORT_DEFAULT_WIDTH","EXPORT_DEFAULT_SCALE","EXPORT_RASTERIZATION_TIMEOUT","CUSTOM_LOGIC_ALLOW_CODE_EXECUTION","CUSTOM_LOGIC_ALLOW_FILE_RESOURCES","SERVER_ENABLE","SERVER_HOST","SERVER_PORT","SERVER_BENCHMARKING","SERVER_PROXY_HOST","SERVER_PROXY_PORT","SERVER_PROXY_TIMEOUT","SERVER_RATE_LIMITING_ENABLE","SERVER_RATE_LIMITING_MAX_REQUESTS","SERVER_RATE_LIMITING_WINDOW","SERVER_RATE_LIMITING_DELAY","SERVER_RATE_LIMITING_TRUST_PROXY","SERVER_RATE_LIMITING_SKIP_KEY","SERVER_RATE_LIMITING_SKIP_TOKEN","SERVER_SSL_ENABLE","SERVER_SSL_FORCE","SERVER_SSL_PORT","SERVER_SSL_CERT_PATH","POOL_MIN_WORKERS","POOL_MAX_WORKERS","POOL_WORK_LIMIT","POOL_ACQUIRE_TIMEOUT","POOL_CREATE_TIMEOUT","POOL_DESTROY_TIMEOUT","POOL_IDLE_TIMEOUT","POOL_CREATE_RETRY_INTERVAL","POOL_REAPER_INTERVAL","POOL_BENCHMARKING","POOL_RESOURCES_INTERVAL","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_CONNECTION_OVER_PIPE","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","expBackoff","async","attempt","delayInMs","Promise","response","setTimeout","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","fetch","requestOptions","resolve","reject","protocol","https","http","getProtocol","get","res","on","chunk","text","ExportError","Error","constructor","status","super","this","setError","statusCode","cache","activeManifest","sources","hcVersion","extractVersion","indexOf","fetchAndProcessScript","script","fetchedModules","shouldThrowError","updateCache","highchartsOptions","proxyOptions","sourcePath","proxyAgent","proxyHost","proxyPort","HttpsProxyAgent","agent","allFetchPromises","all","fetchScripts","c","m","writeFileSync","checkAndUpdateCache","getCachePath","manifestPath","recursive","requestUpdate","manifest","moduleMap","numberOfModules","some","moduleName","newManifest","saveConfigToManifest","cachePathOption","isAbsolute","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","wsEndpoint","reconnect","connected","connect","browserWSEndpoint","close","create","puppeteerArgs","enabledDebug","debugOptions","launchOptions","userDataDir","pipe","handleSIGINT","handleSIGTERM","handleSIGHUP","waitForInitialPage","defaultViewport","tryCount","open","launch","pages","page","newPage","poolResource","startDate","getTime","setCacheEnabled","setPageContent","$eval","element","errorMessage","innerHTML","frame","mainFrame","detached","workCount","id","poolResourceId","isClosed","setPageEvents","clearPageResources","injectedResources","resource","dispose","evaluate","oldCharts","charts","oldChart","destroy","scriptsToRemove","document","getElementsByTagName","stylesToRemove","linksToRemove","remove","setContent","waitUntil","addScriptTag","path","setAsConfig","puppeteerExport","exportOptions","debugger","isSVG","svgTemplate","injectedJs","js","push","content","isLocal","jsResource","injectedCss","css","cssImports","match","cssImportPath","cssResource","addStyleTag","addPageResources","size","svgElement","querySelector","chartHeight","baseVal","chartWidth","body","style","zoom","margin","viewportHeight","Math","ceil","viewportWidth","x","y","getBoundingClientRect","trunc","getClipRegion","setViewport","deviceScaleFactor","outerHTML","createSVG","encoding","clip","race","screenshot","captureBeyondViewport","fullPage","optimizeForSpeed","quality","omitBackground","_resolve","createImage","emulateMediaType","pdf","createPDF","intervalIds","addInterval","clearAllIntervals","clearInterval","stats","performedExports","exportAttempts","exportFromSvgAttempts","timeSpent","droppedExports","spentAverage","poolConfig","factory","uuid","random","validate","validated","removeAllListeners","initPool","createBrowser","parseInt","Pool","acquireTimeoutMillis","createTimeoutMillis","destroyTimeoutMillis","idleTimeoutMillis","createRetryIntervalMillis","reapIntervalMillis","propagateCreateError","hardReset","goto","clearPage","_eventId","initialResources","acquire","promise","release","resourceCheckInterval","setInterval","currentNumber","numUsed","numFree","numPendingCreates","_doCreate","killPool","worker","used","destroyed","closeBrowser","postWork","workerHandle","getPoolInfo","acquireCounter","payload","requestId","workStart","exportCounter","result","exportTime","getPoolInfoJSON","available","allCreated","pendingAcquires","numPendingAcquires","pendingCreates","pendingValidations","numPendingValidations","pendingDestroys","absoluteAll","pool$1","startExport","settings","endCallback","svg","initExportSettings","exportAsString","input","JSDOM","DOMPurify","sanitize","ADD_TAGS","doStraightInject","doExport","findChartSize","precision","multiplier","pow","roundNumber","sourceHeight","sourceWidth","param","chartJson","customLogicOptions","allowCodeExecutionScoped","optionsName","stringToExport","chartJSON","logErrorMiddleware","req","next","returnErrorMiddleware","stCode","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","headers","connection","remoteAddress","connectionAborted","socket","toLowerCase","substr","b64","noDownload","pattern","isPrivateRangeUrlFound","info","Buffer","from","header","attachment","filename","pkgFile","pather","serverStartTime","successRates","addHealthRoutes","successRatio","_","period","movingAverage","reduce","a","b","bootTime","uptime","floor","highchartsVersion","averageProcessingTime","failedExports","sucessRatio","toFixed","svgExportAttempts","jsonExportAttempts","activeServers","Map","express","disable","cors","methods","storage","multer","memoryStorage","upload","limits","fieldSize","limit","urlencoded","extended","none","attachServerErrorHandlers","startServer","serverConfig","httpServer","createServer","listen","set","cert","fsPromises","readFile","posix","httpsServer","NaN","static","healthRoute","exportRoutes","sendFile","uiRoute","errorHandler","closeServers","delete","getServers","enableRateLimiting","getExpress","getApp","middlewares","shutdownCleanUp","exitCode","getBrowser","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":"0mBAeO,MAAMA,EAAe,CAC1BC,KAAM,CAAC,aAAc,kBAAmB,iBACxCC,QAAS,CACP,QACA,MACA,QACA,YACA,uBACA,gBAEA,eACA,QACA,OACA,aACA,mBACA,eACA,cACA,UACA,UACA,cACA,WACA,UACA,YACA,cACA,YACA,sBACA,SACA,SACA,WACA,aACA,YACA,eACA,yBACA,SACA,eACA,YACA,kBACA,SACA,cACA,mBACA,eACA,kBACA,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,UACA,cACA,YACA,YAEFC,WAAY,CAAC,kBACbC,OAAQ,CACN,wEACA,mGAMSC,EAAgB,CAC3BC,UAAW,CACTC,KAAM,CACJC,MAAO,CACL,mCACA,kBACA,0CACA,2BACA,kCACA,kCACA,wCACA,2CACA,qBACA,4BACA,2CACA,uDACA,6BACA,yBACA,0BACA,+BACA,uBACA,uFACA,yBACA,oCACA,oBACA,0BACA,8CACA,2BACA,0BACA,6BACA,mCACA,wCACA,mCACA,2BACA,kCACA,uBACA,iBACA,yBACA,8BACA,oBACA,2BACA,eACA,6BACA,iBACA,aACA,eACA,sBACA,cACA,yBACA,oBACA,uBAEFC,KAAM,WACNC,YAAa,0CAGjBC,WAAY,CACVC,QAAS,CACPJ,MAAO,SACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,sCAEfI,OAAQ,CACNN,MAAO,+BACPC,KAAM,SACNI,QAAS,qBACTH,YAAa,kDAEfK,YAAa,CACXP,MAAOR,EAAaC,KACpBQ,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOR,EAAaE,QACpBO,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOR,EAAaG,WACpBM,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAOR,EAAaI,OACpBK,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,SACPC,KAAM,SACNI,QAAS,wBACTH,YACE,oGAGNW,OAAQ,CACNC,OAAQ,CACNd,OAAO,EACPC,KAAM,SACNC,YACE,wHAEJa,MAAO,CACLf,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJc,QAAS,CACPhB,OAAO,EACPC,KAAM,SACNC,YAAa,oCAEfe,QAAS,CACPjB,OAAO,EACPC,KAAM,SACNC,YACE,qGAEJD,KAAM,CACJD,MAAO,MACPC,KAAM,SACNI,QAAS,cACTH,YAAa,6DAEfgB,OAAQ,CACNlB,MAAO,QACPC,KAAM,SACNI,QAAS,gBACTH,YACE,8EAEJiB,cAAe,CACbnB,MAAO,IACPC,KAAM,SACNI,QAAS,wBACTH,YACE,wEAEJkB,aAAc,CACZpB,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJmB,aAAc,CACZrB,MAAO,EACPC,KAAM,SACNI,QAAS,uBACTH,YACE,uEAEJoB,OAAQ,CACNtB,OAAO,EACPC,KAAM,SACNC,YACE,kFAEJqB,MAAO,CACLvB,OAAO,EACPC,KAAM,SACNC,YACE,iFAEJsB,MAAO,CACLxB,OAAO,EACPC,KAAM,SACNC,YACE,6GAEJuB,cAAe,CACbzB,OAAO,EACPC,KAAM,SACNC,YACE,2GAEJwB,aAAc,CACZ1B,OAAO,EACPC,KAAM,SACNC,YACE,iHAEJyB,MAAO,CACL3B,OAAO,EACPC,KAAM,SACNC,YACE,2FAEJ0B,qBAAsB,CACpB5B,MAAO,KACPC,KAAM,SACNI,QAAS,+BACTH,YACE,kEAGN2B,YAAa,CACXC,mBAAoB,CAClB9B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,6FAEJ6B,mBAAoB,CAClB/B,OAAO,EACPC,KAAM,UACNI,QAAS,oCACTH,YACE,sHAEJ8B,WAAY,CACVhC,OAAO,EACPC,KAAM,SACNC,YACE,mJAEJ+B,SAAU,CACRjC,OAAO,EACPC,KAAM,SACNC,YACE,0GAEJgC,UAAW,CACTlC,OAAO,EACPC,KAAM,SACNC,YACE,yGAEJiC,WAAY,CACVnC,OAAO,EACPC,KAAM,SACNmC,WAAY,WACZlC,YAAa,yDAEfmC,aAAc,CACZrC,OAAO,EACPC,KAAM,SACNC,YACE,wFAGNoC,OAAQ,CACNC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTmC,QAAS,eACTtC,YACE,wEAEJuC,KAAM,CACJzC,MAAO,UACPC,KAAM,SACNI,QAAS,cACTH,YACE,0FAEJwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,cACTH,YAAa,iCAEfyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,sBACTmC,QAAS,qBACTtC,YACE,qIAEJ0C,MAAO,CACLH,KAAM,CACJzC,OAAO,EACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEfwC,KAAM,CACJ1C,MAAO,KACPC,KAAM,SACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,sDAEf2C,QAAS,CACP7C,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTmC,QAAS,eACTtC,YAAa,2DAGjB4C,aAAc,CACZP,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,8BACTmC,QAAS,qBACTtC,YAAa,yCAEf6C,YAAa,CACX/C,MAAO,GACPC,KAAM,SACNI,QAAS,oCACT+B,WAAY,YACZlC,YAAa,yDAEf8C,OAAQ,CACNhD,MAAO,EACPC,KAAM,SACNI,QAAS,8BACTH,YAAa,uDAEf+C,MAAO,CACLjD,MAAO,EACPC,KAAM,SACNI,QAAS,6BACTH,YACE,qFAEJgD,WAAY,CACVlD,OAAO,EACPC,KAAM,UACNI,QAAS,mCACTH,YAAa,6DAEfiD,QAAS,CACPnD,OAAO,EACPC,KAAM,SACNI,QAAS,gCACTH,YACE,yFAEJkD,UAAW,CACTpD,OAAO,EACPC,KAAM,SACNI,QAAS,kCACTH,YACE,wFAGNmD,IAAK,CACHd,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,YACTtC,YAAa,yCAEfoD,MAAO,CACLtD,OAAO,EACPC,KAAM,UACNI,QAAS,mBACTmC,QAAS,WACTJ,WAAY,UACZlC,YACE,oEAEJwC,KAAM,CACJ1C,MAAO,IACPC,KAAM,SACNI,QAAS,kBACTmC,QAAS,UACTtC,YAAa,4CAEfqD,SAAU,CACRvD,OAAO,EACPC,KAAM,SACNI,QAAS,uBACT+B,WAAY,UACZlC,YAAa,+CAInBsD,KAAM,CACJC,WAAY,CACVzD,MAAO,EACPC,KAAM,SACNI,QAAS,mBACTH,YAAa,4DAEfwD,WAAY,CACV1D,MAAO,EACPC,KAAM,SACNI,QAAS,mBACT+B,WAAY,UACZlC,YAAa,gDAEfyD,UAAW,CACT3D,MAAO,GACPC,KAAM,SACNI,QAAS,kBACTH,YACE,yFAEJ0D,eAAgB,CACd5D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oEAEJ2D,cAAe,CACb7D,MAAO,IACPC,KAAM,SACNI,QAAS,sBACTH,YACE,mEAEJ4D,eAAgB,CACd9D,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,qEAEJ6D,YAAa,CACX/D,MAAO,IACPC,KAAM,SACNI,QAAS,oBACTH,YACE,6EAEJ8D,oBAAqB,CACnBhE,MAAO,IACPC,KAAM,SACNI,QAAS,6BACTH,YACE,mGAEJ+D,eAAgB,CACdjE,MAAO,IACPC,KAAM,SACNI,QAAS,uBACTH,YACE,oGAEJyC,aAAc,CACZ3C,OAAO,EACPC,KAAM,UACNI,QAAS,oBACTmC,QAAS,mBACTtC,YACE,0EAGNgE,QAAS,CACPC,MAAO,CACLnE,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTmC,QAAS,WACTtC,YAAa,iCAEfkE,KAAM,CACJpE,MAAO,+BACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,6GAEJmE,KAAM,CACJrE,MAAO,OACPC,KAAM,SACNI,QAAS,eACTmC,QAAS,UACTtC,YACE,oGAEJoE,UAAW,CACTtE,OAAO,EACPC,KAAM,UACNI,QAAS,qBACTmC,QAAS,eACTtC,YAAa,oDAEfqE,OAAQ,CACNvE,OAAO,EACPC,KAAM,UACNI,QAAS,kBACTmC,QAAS,YACTtC,YACE,2FAGNsE,GAAI,CACFjC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,YACTmC,QAAS,WACTtC,YACE,sEAEJuE,MAAO,CACLzE,MAAO,IACPC,KAAM,SACNI,QAAS,WACTmC,QAAS,UACTtC,YACE,4EAGNwE,MAAO,CACLC,QAAS,CACP3E,MAAO,aACPC,KAAM,SACNI,QAAS,iBACTH,YAAa,oCAEf0E,qBAAsB,CACpB5E,OAAO,EACPC,KAAM,UACNI,QAAS,gCACTH,YAAa,2DAEf2E,OAAQ,CACN7E,OAAO,EACPC,KAAM,UACNI,QAAS,gBACTH,YACE,2EAEJ4E,cAAe,CACb9E,OAAO,EACPC,KAAM,UACNI,QAAS,wBACTH,YAAa,yDAEf6E,iBAAkB,CAChB/E,OAAO,EACPC,KAAM,UACNI,QAAS,2BACTH,YAAa,mDAGjB8E,MAAO,CACLzC,OAAQ,CACNvC,OAAO,EACPC,KAAM,UACNI,QAAS,eACTmC,QAAS,cACTtC,YAAa,8DAEf+E,SAAU,CACRjF,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJgF,SAAU,CACRlF,OAAO,EACPC,KAAM,UACNI,QAAS,iBACTH,YACE,8EAEJiF,gBAAiB,CACfnF,OAAO,EACPC,KAAM,UACNI,QAAS,0BACTH,YACE,oFAEJkF,OAAQ,CACNpF,OAAO,EACPC,KAAM,UACNI,QAAS,eACTH,YACE,qFAEJmF,OAAQ,CACNrF,MAAO,EACPC,KAAM,SACNI,QAAS,gBACTH,YACE,4EAEJoF,cAAe,CACbtF,MAAO,KACPC,KAAM,SACNI,QAAS,uBACTH,YAAa,mCAWNqF,EAAgB,CAC3BzF,UAAW,CACT,CACEG,KAAM,OACNuF,KAAM,OACNC,QAAS,sBACTC,QAAS7F,EAAcC,UAAUC,KAAKC,MAAM2F,KAAK,KACjDC,UAAW,MAGfzF,WAAY,CACV,CACEF,KAAM,OACNuF,KAAM,UACNC,QAAS,qBACTC,QAAS7F,EAAcM,WAAWC,QAAQJ,OAE5C,CACEC,KAAM,OACNuF,KAAM,SACNC,QAAS,iBACTC,QAAS7F,EAAcM,WAAWG,OAAON,OAE3C,CACEC,KAAM,cACNuF,KAAM,cACNC,QAAS,yBACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWI,YAAYP,OAEhD,CACEC,KAAM,cACNuF,KAAM,gBACNC,QAAS,2BACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWK,cAAcR,OAElD,CACEC,KAAM,cACNuF,KAAM,mBACNC,QAAS,8BACTI,aAAc,yDACdC,QAASjG,EAAcM,WAAWM,iBAAiBT,OAErD,CACEC,KAAM,OACNuF,KAAM,gBACNC,QAAS,iBACTC,QAAS7F,EAAcM,WAAWO,cAAcV,MAAM2F,KAAK,KAC3DC,UAAW,KAEb,CACE3F,KAAM,SACNuF,KAAM,aACNC,QAAS,6BACTC,QAAS7F,EAAcM,WAAWQ,WAAWX,OAE/C,CACEC,KAAM,OACNuF,KAAM,YACNC,QAAS,kCACTC,QAAS7F,EAAcM,WAAWS,UAAUZ,QAGhDa,OAAQ,CACN,CACEZ,KAAM,SACNuF,KAAM,OACNC,QAAS,+BACTM,KAAM,YAAYlG,EAAcgB,OAAOZ,KAAKD,QAC5C0F,QAAS,EACTI,QAAS,CAAC,MAAO,OAAQ,MAAO,QAElC,CACE7F,KAAM,SACNuF,KAAM,SACNC,QAAS,yCACTM,KAAM,YAAYlG,EAAcgB,OAAOK,OAAOlB,QAC9C0F,QAAS,EACTI,QAAS,CAAC,QAAS,aAAc,WAAY,eAE/C,CACE7F,KAAM,SACNuF,KAAM,gBACNC,QAAS,oDACTC,QAAS7F,EAAcgB,OAAOM,cAAcnB,OAE9C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,mDACTC,QAAS7F,EAAcgB,OAAOO,aAAapB,OAE7C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,mDACTC,QAAS7F,EAAcgB,OAAOQ,aAAarB,MAC3CgG,IAAK,GACLC,IAAK,GAEP,CACEhG,KAAM,SACNuF,KAAM,uBACNC,QAAS,gDACTC,QAAS7F,EAAcgB,OAAOe,qBAAqB5B,QAGvD6B,YAAa,CACX,CACE5B,KAAM,SACNuF,KAAM,qBACNC,QAAS,kCACTC,QAAS7F,EAAcgC,YAAYC,mBAAmB9B,OAExD,CACEC,KAAM,SACNuF,KAAM,qBACNC,QAAS,wBACTC,QAAS7F,EAAcgC,YAAYE,mBAAmB/B,QAG1DsC,OAAQ,CACN,CACErC,KAAM,SACNuF,KAAM,SACNC,QAAS,+BACTC,QAAS7F,EAAcyC,OAAOC,OAAOvC,OAEvC,CACEC,KAAM,OACNuF,KAAM,OACNC,QAAS,kBACTC,QAAS7F,EAAcyC,OAAOG,KAAKzC,OAErC,CACEC,KAAM,SACNuF,KAAM,OACNC,QAAS,cACTC,QAAS7F,EAAcyC,OAAOI,KAAK1C,OAErC,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,6BACTC,QAAS7F,EAAcyC,OAAOK,aAAa3C,OAE7C,CACEC,KAAM,OACNuF,KAAM,aACNC,QAAS,sCACTC,QAAS7F,EAAcyC,OAAOM,MAAMH,KAAKzC,OAE3C,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,sCACTC,QAAS7F,EAAcyC,OAAOM,MAAMF,KAAK1C,OAE3C,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,0CACTC,QAAS7F,EAAcyC,OAAOM,MAAMC,QAAQ7C,OAE9C,CACEC,KAAM,SACNuF,KAAM,sBACNC,QAAS,uBACTC,QAAS7F,EAAcyC,OAAOQ,aAAaP,OAAOvC,OAEpD,CACEC,KAAM,SACNuF,KAAM,2BACNC,QAAS,0CACTC,QAAS7F,EAAcyC,OAAOQ,aAAaC,YAAY/C,OAEzD,CACEC,KAAM,SACNuF,KAAM,sBACNC,QAAS,2CACTC,QAAS7F,EAAcyC,OAAOQ,aAAaE,OAAOhD,OAEpD,CACEC,KAAM,SACNuF,KAAM,qBACNC,QACE,oEACFC,QAAS7F,EAAcyC,OAAOQ,aAAaG,MAAMjD,OAEnD,CACEC,KAAM,SACNuF,KAAM,0BACNC,QAAS,wCACTC,QAAS7F,EAAcyC,OAAOQ,aAAaI,WAAWlD,OAExD,CACEC,KAAM,OACNuF,KAAM,uBACNC,QACE,8EACFC,QAAS7F,EAAcyC,OAAOQ,aAAaK,QAAQnD,OAErD,CACEC,KAAM,OACNuF,KAAM,yBACNC,QACE,4EACFC,QAAS7F,EAAcyC,OAAOQ,aAAaM,UAAUpD,OAEvD,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,sBACTC,QAAS7F,EAAcyC,OAAOe,IAAId,OAAOvC,OAE3C,CACEC,KAAM,SACNuF,KAAM,YACNC,QAAS,gCACTC,QAAS7F,EAAcyC,OAAOe,IAAIC,MAAMtD,OAE1C,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,kBACTC,QAAS7F,EAAcyC,OAAOe,IAAIX,KAAK1C,OAEzC,CACEC,KAAM,OACNuF,KAAM,eACNC,QAAS,2CACTC,QAAS7F,EAAcyC,OAAOe,IAAIE,SAASvD,QAG/CwD,KAAM,CACJ,CACEvD,KAAM,SACNuF,KAAM,aACNC,QAAS,yCACTC,QAAS7F,EAAc2D,KAAKC,WAAWzD,OAEzC,CACEC,KAAM,SACNuF,KAAM,aACNC,QAAS,yCACTC,QAAS7F,EAAc2D,KAAKE,WAAW1D,OAEzC,CACEC,KAAM,SACNuF,KAAM,YACNC,QACE,iFACFC,QAAS7F,EAAc2D,KAAKG,UAAU3D,OAExC,CACEC,KAAM,SACNuF,KAAM,iBACNC,QAAS,8DACTC,QAAS7F,EAAc2D,KAAKI,eAAe5D,OAE7C,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,6DACTC,QAAS7F,EAAc2D,KAAKK,cAAc7D,OAE5C,CACEC,KAAM,SACNuF,KAAM,iBACNC,QAAS,+DACTC,QAAS7F,EAAc2D,KAAKM,eAAe9D,OAE7C,CACEC,KAAM,SACNuF,KAAM,cACNC,QAAS,iEACTC,QAAS7F,EAAc2D,KAAKO,YAAY/D,OAE1C,CACEC,KAAM,SACNuF,KAAM,sBACNC,QACE,kEACFC,QAAS7F,EAAc2D,KAAKQ,oBAAoBhE,OAElD,CACEC,KAAM,SACNuF,KAAM,iBACNC,QACE,+FACFC,QAAS7F,EAAc2D,KAAKS,eAAejE,OAE7C,CACEC,KAAM,SACNuF,KAAM,eACNC,QAAS,0CACTC,QAAS7F,EAAc2D,KAAKb,aAAa3C,QAG7CkE,QAAS,CACP,CACEjE,KAAM,SACNuF,KAAM,QACNC,QACE,uFACFC,QAAS7F,EAAcqE,QAAQC,MAAMnE,MACrCkG,MAAO,EACPF,IAAK,EACLC,IAAK,GAEP,CACEhG,KAAM,OACNuF,KAAM,OACNC,QACE,0EACFC,QAAS7F,EAAcqE,QAAQE,KAAKpE,OAEtC,CACEC,KAAM,OACNuF,KAAM,OACNC,QAAS,0DACTC,QAAS7F,EAAcqE,QAAQG,KAAKrE,OAEtC,CACEC,KAAM,SACNuF,KAAM,YACNC,QAAS,gCACTC,QAAS7F,EAAcqE,QAAQI,UAAUtE,OAE3C,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,4BACTC,QAAS7F,EAAcqE,QAAQK,OAAOvE,QAG1CwE,GAAI,CACF,CACEvE,KAAM,SACNuF,KAAM,SACNC,QAAS,kCACTC,QAAS7F,EAAc2E,GAAGjC,OAAOvC,OAEnC,CACEC,KAAM,OACNuF,KAAM,QACNC,QAAS,2BACTC,QAAS7F,EAAc2E,GAAGC,MAAMzE,QAGpC0E,MAAO,CACL,CACEzE,KAAM,OACNuF,KAAM,UACNC,QAAS,kCACTC,QAAS7F,EAAc6E,MAAMC,QAAQ3E,OAEvC,CACEC,KAAM,SACNuF,KAAM,uBACNC,QAAS,uDACTC,QAAS7F,EAAc6E,MAAME,qBAAqB5E,OAEpD,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,6DACTC,QAAS7F,EAAc6E,MAAMG,OAAO7E,OAEtC,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,uDACTC,QAAS7F,EAAc6E,MAAMI,cAAc9E,OAE7C,CACEC,KAAM,SACNuF,KAAM,mBACNC,QAAS,gDACTC,QAAS7F,EAAc6E,MAAMK,iBAAiB/E,QAGlDgF,MAAO,CACL,CACE/E,KAAM,SACNuF,KAAM,SACNC,QAAS,8CACTC,QAAS7F,EAAcmF,MAAMzC,OAAOvC,OAEtC,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,mCACTC,QAAS7F,EAAcmF,MAAMC,SAASjF,OAExC,CACEC,KAAM,SACNuF,KAAM,WACNC,QAAS,uCACTC,QAAS7F,EAAcmF,MAAME,SAASlF,OAExC,CACEC,KAAM,SACNuF,KAAM,kBACNC,QAAS,2DACTC,QAAS7F,EAAcmF,MAAMG,gBAAgBnF,OAE/C,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,4DACTC,QAAS7F,EAAcmF,MAAMI,OAAOpF,OAEtC,CACEC,KAAM,SACNuF,KAAM,SACNC,QAAS,iDACTC,QAAS7F,EAAcmF,MAAMK,OAAOrF,OAEtC,CACEC,KAAM,SACNuF,KAAM,gBACNC,QAAS,gCACTC,QAAS7F,EAAcmF,MAAMM,cAActF,SAMpCmG,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,EAAM7G,MAEfqG,EAAiBQ,EAAO,GAAGN,KAAaI,MAGxCP,EAAWS,EAAMrE,SAAWmE,GAAK,GAAGJ,KAAaI,IAAIG,UAAU,QAGtCC,IAArBF,EAAMzE,aACRgE,EAAWS,EAAMzE,YAAc,GAAGmE,KAAaI,IAAIG,UAAU,IAGlE,IACD,EAGJT,EAAiBxG,GCnoCjBmH,EAAOC,SAIP,MAAMC,EAGIC,GACNC,EACGC,SACAC,WAAWtH,GACVA,EACGuH,MAAM,KACNC,KAAKxH,GAAUA,EAAMyH,SACrBC,QAAQ1H,GAAUmH,EAAYP,SAAS5G,OAE3CsH,WAAWtH,GAAWA,EAAM2H,OAAS3H,OAAQ+G,IAZ9CG,EAgBK,IACPE,EACGQ,KAAK,CAAC,OAAQ,QAAS,KACvBN,WAAWtH,GAAqB,KAAVA,EAAyB,SAAVA,OAAmB+G,IAnBzDG,EAuBGW,GACLT,EACGQ,KAAK,IAAIC,EAAQ,KACjBP,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IA1B9CG,EA8BI,IACNE,EACGC,SACAI,OACAK,QACE9H,IACE,CAAC,QAAS,YAAa,OAAQ,OAAO4G,SAAS5G,IACtC,KAAVA,IACDA,IAAW,CACVyF,QAAS,mDAAmDzF,SAG/DsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IA1C9CG,EA8CS,IACXE,EACGC,SACAI,OACAK,QACE9H,GACW,KAAVA,IAAkB+H,MAAMC,WAAWhI,KAAWgI,WAAWhI,GAAS,IACnEA,IAAW,CACVyF,QAAS,qDAAqDzF,SAGjEsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IAzD1DG,EA6DY,IACdE,EACGC,SACAI,OACAK,QACE9H,GACW,KAAVA,IAAkB+H,MAAMC,WAAWhI,KAAWgI,WAAWhI,IAAU,IACpEA,IAAW,CACVyF,QAAS,yDAAyDzF,SAGrEsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IAgInDkB,EA7HSb,EAAEc,OAAO,CAE7BC,mBAAoBf,EACjBC,SACAI,OACAK,QACE9H,GAAU,6BAA6BoI,KAAKpI,IAAoB,KAAVA,IACtDA,IAAW,CACVyF,QAAS,4FAA4FzF,SAGxGsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IAChDsB,mBAAoBjB,EACjBC,SACAI,OACAK,QACE9H,GACCA,EAAMsI,WAAW,aACjBtI,EAAMsI,WAAW,YACP,KAAVtI,IACDA,IAAW,CACVyF,QAAS,6FAA6FzF,SAGzGsH,WAAWtH,GAAqB,KAAVA,EAAeA,OAAQ+G,IAChDwB,wBAAyBrB,EAAQ1H,EAAaC,MAC9C+I,0BAA2BtB,EAAQ1H,EAAaE,SAChD+I,6BAA8BvB,EAAQ1H,EAAaG,YACnD+I,uBAAwBxB,IACxByB,sBAAuBzB,IACvB0B,uBAAwB1B,IAGxB2B,YAAa3B,EAAO,CAAC,OAAQ,MAAO,MAAO,QAC3C4B,cAAe5B,EAAO,CAAC,QAAS,aAAc,WAAY,eAC1D6B,sBAAuB7B,IACvB8B,qBAAsB9B,IACtB+B,qBAAsB/B,IACtBgC,6BAA8BhC,IAG9BiC,kCAAmCjC,IACnCkC,kCAAmClC,IAGnCmC,cAAenC,IACfoC,YAAapC,IACbqC,YAAarC,IACbsC,oBAAqBtC,IAGrBuC,kBAAmBvC,IACnBwC,kBAAmBxC,IACnByC,qBAAsBzC,IAGtB0C,4BAA6B1C,IAC7B2C,kCAAmC3C,IACnC4C,4BAA6B5C,IAC7B6C,2BAA4B7C,IAC5B8C,iCAAkC9C,IAClC+C,8BAA+B/C,IAC/BgD,gCAAiChD,IAGjCiD,kBAAmBjD,IACnBkD,iBAAkBlD,IAClBmD,gBAAiBnD,IACjBoD,qBAAsBpD,IAGtBqD,iBAAkBrD,IAClBsD,iBAAkBtD,IAClBuD,gBAAiBvD,IACjBwD,qBAAsBxD,IACtByD,oBAAqBzD,IACrB0D,qBAAsB1D,IACtB2D,kBAAmB3D,IACnB4D,2BAA4B5D,IAC5B6D,qBAAsB7D,IACtB8D,kBAAmB9D,IACnB+D,wBAAyB/D,IAGzBgE,cAAe9D,EACZC,SACAI,OACAK,QACE9H,GACW,KAAVA,IACE+H,MAAMC,WAAWhI,KACjBgI,WAAWhI,IAAU,GACrBgI,WAAWhI,IAAU,IACxBA,IAAW,CACVyF,QAAS,mGAAmGzF,SAG/GsH,WAAWtH,GAAqB,KAAVA,EAAegI,WAAWhI,QAAS+G,IAC5DoE,aAAcjE,IACdkE,aAAclE,IACdmE,mBAAoBnE,IACpBoE,gBAAiBpE,IAGjBqE,UAAWrE,IACXsE,SAAUtE,IAGVuE,eAAgBvE,EAAO,CAAC,cAAe,aAAc,SACrDwE,8BAA+BxE,IAC/ByE,cAAezE,IACf0E,sBAAuB1E,IACvB2E,yBAA0B3E,IAC1B4E,2BAA4B5E,IAG5B6E,aAAc7E,IACd8E,eAAgB9E,IAChB+E,eAAgB/E,IAChBgF,wBAAyBhF,IACzBiF,aAAcjF,IACdkF,cAAelF,IACfmF,qBAAsBnF,MAGGoF,UAAUC,MAAMC,QAAQC,KC7M7CC,EAAS,CAAC,MAAO,SAAU,OAAQ,OAAQ,SAGjD,IAAIxI,EAAU,CAEZI,WAAW,EACXC,QAAQ,EACRoI,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,KACnBhJ,EAAQyI,eAEVQ,EAAWjJ,EAAQG,OAAS+I,EAAUlJ,EAAQG,MAI/CH,EAAQyI,aAAc,GAIxBU,EACE,GAAGnJ,EAAQG,OAAOH,EAAQE,OAC1B,CAAC8I,GAAQI,OAAOL,GAAOtH,KAAK,KAAO,MAClC4H,IACKA,IACFC,QAAQC,IAAI,yCAAyCF,KACrDrJ,EAAQK,QAAS,EAClB,GAEJ,EAWUkJ,EAAM,IAAI1N,KACrB,MAAO2N,KAAaT,GAASlN,GAGvB6M,WAAEA,EAAUzI,MAAEA,GAAUD,EAG9B,GACe,IAAbwJ,IACc,IAAbA,GAAkBA,EAAWvJ,GAASA,EAAQyI,EAAWjF,QAE1D,OAIF,MAGMuF,EAAS,IAHC,IAAIS,MAAOC,WAAWrG,MAAM,KAAK,GAAGE,WAGtBmF,EAAWc,EAAW,GAAGb,WAGvD3I,EAAQ6I,UAAUrG,SAASmH,IACzBA,EAAGX,EAAQD,EAAMtH,KAAK,KAAK,IAIzBzB,EAAQI,WACVkJ,QAAQC,IAAIK,WACV/G,EACA,CAACmG,EAAOU,WAAW1J,EAAQ0I,WAAWc,EAAW,GAAGZ,QAAQQ,OAAOL,IAKnE/I,EAAQK,QACVyI,EAAUC,EAAOC,EAClB,EAYUa,EAAe,CAACL,EAAUH,EAAOS,KAE5C,MAAMC,EAAcD,GAAiBT,EAAM9H,SAGrCtB,MAAEA,EAAKyI,WAAEA,GAAe1I,EAG9B,GAAiB,IAAbwJ,GAAkBA,EAAWvJ,GAASA,EAAQyI,EAAWjF,OAC3D,OAIF,MAGMuF,EAAS,IAHC,IAAIS,MAAOC,WAAWrG,MAAM,KAAK,GAAGE,WAGtBmF,EAAWc,EAAW,GAAGb,WAGjDqB,EACJX,EAAM9H,UAAY8H,EAAMW,mBAAuCnH,IAAvBwG,EAAMW,aAC1CX,EAAMY,MACNZ,EAAMY,MAAM5G,MAAM,MAAM6G,MAAM,GAAGzI,KAAK,MAGtCsH,EAAQ,CAACgB,EAAa,KAAMC,GAG9BhK,EAAQI,WACVkJ,QAAQC,IAAIK,WACV/G,EACA,CAACmG,EAAOU,WAAW1J,EAAQ0I,WAAWc,EAAW,GAAGZ,QAAQQ,OAAO,CACjEW,EAAYvB,EAAOgB,EAAW,IAC9B,KACAQ,KAMNhK,EAAQ6I,UAAUrG,SAASmH,IACzBA,EAAGX,EAAQD,EAAMtH,KAAK,KAAK,IAIzBzB,EAAQK,QACVyI,EAAUC,EAAOC,EAClB,EASUmB,EAAeX,IACtBA,GAAY,GAAKA,GAAYxJ,EAAQ0I,WAAWjF,SAClDzD,EAAQC,MAAQuJ,EACjB,EASUY,EAAoB,CAACC,EAASC,KASzC,GAPAtK,EAAU,IACLA,EACHG,KAAMkK,GAAWrK,EAAQG,KACzBD,KAAMoK,GAAWtK,EAAQE,KACzBG,QAAQ,GAGkB,IAAxBL,EAAQG,KAAKsD,OACf,OAAO8F,EAAI,EAAG,2DAGXvJ,EAAQG,KAAKoK,SAAS,OACzBvK,EAAQG,MAAQ,IACjB,ECvMUqK,EAAYC,EAAc,IAAIC,IAAI,mBAAoBC,MAgCtDC,EAAaC,MAAOlB,EAAImB,EAAU,KAAMjP,KACnD,IAEE,aAAa8N,KAAM9N,EACpB,CAAC,MAAOwN,GAEP,MAAM0B,EAAY,GAAKD,EAAU,IAGjC,KAAMA,GA3CmB,EA4CvB,MAAMzB,EAWR,aAPM,IAAI2B,SAASC,GAAaC,WAAWD,EAAUF,KACrDxB,EACE,EACA,iBAAiBwB,+CAAuDlP,EAAK,OAIxE+O,EAAWjB,EAAImB,KAAYjP,EACnC,GAWUsP,EAAU,CAACpP,EAAMgB,KAE5B,MAQMqO,EAAU,CAAC,MAAO,OAAQ,MAAO,OAGvC,GAAIrO,EAAS,CACX,MAAMsO,EAAUtO,EAAQsG,MAAM,KAAKiI,MAEnB,QAAZD,EACFtP,EAAO,OACEqP,EAAQ1I,SAAS2I,IAAYtP,IAASsP,IAC/CtP,EAAOsP,EAEV,CAGD,MAtBkB,CAChB,YAAa,MACb,aAAc,OACd,kBAAmB,MACnB,gBAAiB,OAkBFtP,IAASqP,EAAQG,MAAMC,GAAMA,IAAMzP,KAAS,KAAK,EAcvD0P,EAAkB,CAACzN,GAAY,EAAOH,KACjD,MAAM6N,EAAe,CAAC,KAAM,MAAO,SAEnC,IAAIC,EAAmB3N,EACnB4N,GAAmB,EAGvB,GAAI/N,GAAsBG,EAAUuM,SAAS,SAC3C,IACEoB,EAAmBE,EAAcC,EAAa9N,EAAW,QAC1D,CAAC,MAAOqL,GACP,OAAOQ,EAAa,EAAGR,EAAO,4BAC/B,MAGDsC,EAAmBE,EAAc7N,GAG7B2N,IAAqB9N,UAChB8N,EAAiBI,MAK5B,IAAK,MAAMC,KAAYL,EAChBD,EAAahJ,SAASsJ,GAEfJ,IACVA,GAAmB,UAFZD,EAAiBK,GAO5B,OAAKJ,GAKDD,EAAiBI,QACnBJ,EAAiBI,MAAQJ,EAAiBI,MAAMzI,KAAK2I,GAASA,EAAK1I,WAC9DoI,EAAiBI,OAASJ,EAAiBI,MAAMtI,QAAU,WACvDkI,EAAiBI,OAKrBJ,GAZEpC,EAAI,EAAG,4BAYO,EAclB,SAASsC,EAAcK,EAAMxC,GAClC,IAEE,MAAMyC,EAAaC,KAAK/D,MACN,iBAAT6D,EAAoBE,KAAKC,UAAUH,GAAQA,GAIpD,MAA0B,iBAAfC,GAA2BzC,EAC7B0C,KAAKC,UAAUF,GAIjBA,CACX,CAAI,MACA,OAAO,CACR,CACH,CASO,MA2CMG,EAAYlK,IACvB,GAAY,OAARA,GAA+B,iBAARA,EACzB,OAAOA,EAGT,MAAMmK,EAAOC,MAAMC,QAAQrK,GAAO,GAAK,GAEvC,IAAK,MAAMsK,KAAOtK,EACZE,OAAOqK,UAAUC,eAAeC,KAAKzK,EAAKsK,KAC5CH,EAAKG,GAAOJ,EAASlK,EAAIsK,KAI7B,OAAOH,CAAI,EAaAO,EAAmB,CAAChQ,EAASiQ,IAsBjCX,KAAKC,UAAUvP,GArBG,CAACwE,EAAMxF,KACT,iBAAVA,KACTA,EAAQA,EAAMyH,QAILa,WAAW,cAAgBtI,EAAMsI,WAAW,gBACnDtI,EAAMyO,SAAS,OAEfzO,EAAQiR,EACJ,WAAWjR,EAAQ,IAAIkR,WAAW,YAAa,mBAC/CnK,GAIgB,mBAAV/G,EACV,WAAWA,EAAQ,IAAIkR,WAAW,YAAa,cAC/ClR,KAI2CkR,WAC/C,qBACA,IAiCG,SAASC,IAKd3D,QAAQC,IACN,4BAA4B2D,KAC5B,WACA,yDANa,0DAMmDA,KAAKC,WAGvE,MAAMC,EAAmBtQ,IACvB,IAAK,MAAOwE,EAAM+L,KAAW/K,OAAOgL,QAAQxQ,GAE1C,GAAKwF,OAAOqK,UAAUC,eAAeC,KAAKQ,EAAQ,SAE3C,CACL,IAAIE,EAAW,OAAOF,EAAO/O,SAAWgD,MACrC,IAAM+L,EAAOtR,KAAO,KAAKyR,SAE5B,GAAID,EAAS9J,OAnBP,GAoBJ,IAAK,IAAIgK,EAAIF,EAAS9J,OAAQgK,EApB1B,GAoBmCA,IACrCF,GAAY,IAKhBjE,QAAQC,IACNgE,EACAF,EAAOrR,YACP,aAAaqR,EAAOvR,MAAM4N,WAAWwD,QAAQQ,KAEhD,MAjBCN,EAAgBC,EAkBnB,EAIH/K,OAAOC,KAAK5G,GAAe6G,SAASmL,IAE7B,CAAC,YAAa,cAAcjL,SAASiL,KACxCrE,QAAQC,IAAI,KAAKoE,EAASC,gBAAgBC,KAC1CT,EAAgBzR,EAAcgS,IAC/B,IAEHrE,QAAQC,IAAI,KACd,CAUO,MAYMuE,GAAa7B,IACxB,CAAC,QAAS,YAAa,OAAQ,MAAO,IAAK,IAAIvJ,SAASuJ,MAElDA,EAWK8B,GAAa,CAACjQ,EAAYD,KACrC,GAAIC,GAAoC,iBAAfA,EAGvB,OAFAA,EAAaA,EAAWyF,QAETgH,SAAS,SACf1M,GACHkQ,GAAWjC,EAAahO,EAAY,SAGxCA,EAAWsG,WAAW,eACtBtG,EAAWsG,WAAW,gBACtBtG,EAAWsG,WAAW,SACtBtG,EAAWsG,WAAW,SAEf,IAAItG,OAENA,EAAWkQ,QAAQ,KAAM,GACjC,EASUC,GAAc,KACzB,MAAMC,EAAQ5F,QAAQ6F,OAAOC,SAC7B,MAAO,IAAMC,OAAO/F,QAAQ6F,OAAOC,SAAWF,GAAS,GAAO,ECnahE,IAAII,GAAiB,CAAA,EAOd,MAAMC,GAAa,IAAMD,GAgLnBE,GAAqB,CAAC1R,EAAS2R,EAAYxM,EAAgB,MACtE,MAAMyM,EAAgBpC,EAASxP,GAE/B,IAAK,MAAO4P,EAAK5Q,KAAUwG,OAAOgL,QAAQmB,GACxCC,EAAchC,GDFA,iBADOT,ECIVnQ,IDHgB0Q,MAAMC,QAAQR,IAAkB,OAATA,GCI/ChK,EAAcS,SAASgK,SACD7J,IAAvB6L,EAAchC,QAEA7J,IAAV/G,EACEA,EACA4S,EAAchC,GAHhB8B,GAAmBE,EAAchC,GAAM5Q,EAAOmG,GDPhC,IAACgK,ECavB,OAAOyC,CAAa,EAqFtB,SAASC,GAAoBC,EAAWC,EAAY,CAAA,EAAIxM,EAAY,IAClEC,OAAOC,KAAKqM,GAAWpM,SAASkK,IAC9B,MAAM/J,EAAQiM,EAAUlC,GAClBoC,EAAcD,GAAaA,EAAUnC,QAEhB,IAAhB/J,EAAM7G,MACf6S,GAAoBhM,EAAOmM,EAAa,GAAGzM,KAAaqK,WAGpC7J,IAAhBiM,IACFnM,EAAM7G,MAAQgT,GAIZnM,EAAMxG,WAAW4H,QAAgClB,IAAxBkB,EAAKpB,EAAMxG,WACtCwG,EAAM7G,MAAQiI,EAAKpB,EAAMxG,UAE5B,GAEL,CAWA,SAAS4S,GAAYC,GACnB,IAAIlS,EAAU,CAAA,EACd,IAAK,MAAOwE,EAAM2K,KAAS3J,OAAOgL,QAAQ0B,GACxClS,EAAQwE,GAAQgB,OAAOqK,UAAUC,eAAeC,KAAKZ,EAAM,SACvDA,EAAKnQ,MACLiT,GAAY9C,GAElB,OAAOnP,CACT,CA6EA,SAASmS,GAAeC,EAAgBC,EAAarT,GACnD,KAAOqT,EAAY1L,OAAS,GAAG,CAC7B,MAAMuI,EAAWmD,EAAYC,QAc7B,OAXK9M,OAAOqK,UAAUC,eAAeC,KAAKqC,EAAgBlD,KACxDkD,EAAelD,GAAY,IAI7BkD,EAAelD,GAAYiD,GACzB3M,OAAO+M,OAAO,CAAA,EAAIH,EAAelD,IACjCmD,EACArT,GAGKoT,CACR,CAID,OADAA,EAAeC,EAAY,IAAMrT,EAC1BoT,CACT,CCtaArE,eAAeyE,GAAM3E,EAAK4E,EAAiB,IACzC,OAAO,IAAIvE,SAAQ,CAACwE,EAASC,KAC3B,MAAMC,EAbU,CAAC/E,GAASA,EAAIvG,WAAW,SAAWuL,EAAQC,EAa3CC,CAAYlF,GAE7B+E,EACGI,IAAInF,EAAK4E,GAAiBQ,IACzB,IAAI7D,EAAO,GAGX6D,EAAIC,GAAG,QAASC,IACd/D,GAAQ+D,CAAK,IAIfF,EAAIC,GAAG,OAAO,KACP9D,GACHuD,EAAO,qCAGTM,EAAIG,KAAOhE,EACXsD,EAAQO,EAAI,GACZ,IAEHC,GAAG,SAAU3G,IACZoG,EAAOpG,EAAM,GACb,GAER,CCpDA,MAAM8G,WAAoBC,MAKxB,WAAAC,CAAY9O,EAAS+O,GACnBC,QAEAC,KAAKjP,QAAUA,EACfiP,KAAKxG,aAAezI,EAEhB+O,IACFE,KAAKF,OAASA,EAEjB,CAED,QAAAG,CAASpH,GAgBP,OAfAmH,KAAKnH,MAAQA,EAETA,EAAM/H,OACRkP,KAAKlP,KAAO+H,EAAM/H,OAGfkP,KAAKF,QAAUjH,EAAMqH,aACxBF,KAAKF,OAASjH,EAAMqH,YAGlBrH,EAAMY,QACRuG,KAAKxG,aAAeX,EAAM9H,QAC1BiP,KAAKvG,MAAQZ,EAAMY,OAGduG,IACR,ECFH,MAAMG,GAAQ,CACZvU,OAAQ,+BACRwU,eAAgB,CAAE,EAClBC,QAAS,GACTC,UAAW,IAQAC,GAAkBJ,GACtBA,EAAME,QACVjO,UAAU,EAAG+N,EAAME,QAAQG,QAAQ,OACnChD,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,MAAO,IACfzK,OAiEQ0N,GAAwBpG,MACnCqG,EACA3B,EACA4B,EACAC,GAAmB,KAGfF,EAAO3G,SAAS,SAClB2G,EAASA,EAAOtO,UAAU,EAAGsO,EAAOzN,OAAS,IAG/C8F,EAAI,EAAG,6BAA6B2H,QAGpC,MAAMjG,QAAiBqE,GAAM,GAAG4B,OAAa3B,GAG7C,GAA4B,MAAxBtE,EAASyF,YAA8C,iBAAjBzF,EAASiF,KAAkB,CACnE,GAAIiB,EAAgB,CAElBA,EADqCD,EA7EvBlD,QAChB,qEACA,KA4E+B,CAC9B,CAED,OAAO/C,EAASiF,IACjB,CAED,GAAIkB,EACF,MAAM,IAAIjB,GACR,uBAAuBe,2EAAgFjG,EAASyF,eAChH,KACAD,SAASxF,GAQb,OANE1B,EACE,EACA,+BAA+B2H,8DAI5B,EAAE,EAgFEG,GAAcxG,MACzByG,EACAC,EACAC,KAEA,MAAMtV,EAAUoV,EAAkBpV,QAC5B4U,EAAwB,WAAZ5U,GAAyBA,EAAe,GAAGA,KAAR,GAC/CE,EAASkV,EAAkBlV,QAAUuU,GAAMvU,OAEjDmN,EACE,EACA,iDAAiDuH,GAAa,aAGhE,MAAMK,EAAiB,CAAA,EACvB,IAwBE,OAvBAR,GAAME,aA/EkBhG,OAC1BxO,EACAC,EACAE,EACA+U,EACAJ,KAGA,IAAIM,EACJ,MAAMC,EAAYH,EAAahT,KACzBoT,EAAYJ,EAAa/S,KAG/B,GAAIkT,GAAaC,EACf,IACEF,EAAa,IAAIG,EAAgB,CAC/BrT,KAAMmT,EACNlT,KAAMmT,GAET,CAAC,MAAOtI,GACP,MAAM,IAAI8G,GACR,0CACA,KACAM,SAASpH,EACZ,CAIH,MAAMkG,EAAiBkC,EACnB,CACEI,MAAOJ,EACP9S,QAASoF,EAAK0B,sBAEhB,GAEEqM,EAAmB,IACpBzV,EAAYiH,KAAK4N,GAClBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,GAAgB,QAElE7U,EAAcgH,KAAK4N,GACpBD,GAAsB,GAAGC,IAAU3B,EAAgB4B,QAElD3U,EAAc8G,KAAK4N,GACpBD,GAAsB,GAAGC,IAAU3B,MAKvC,aAD6BvE,QAAQ+G,IAAID,IACnBrQ,KAAK,MAAM,EA+BTuQ,CACpB,IACKV,EAAkBjV,YAAYiH,KAAK2O,GAAM,GAAG7V,IAAS0U,IAAYmB,OAEtE,IACKX,EAAkBhV,cAAcgH,KAAK4O,GAChC,QAANA,EACI,GAAG9V,SAAc0U,YAAoBoB,IACrC,GAAG9V,IAAS0U,YAAoBoB,SAEnCZ,EAAkB/U,iBAAiB+G,KACnCmK,GAAM,GAAGrR,UAAe0U,eAAuBrD,OAGpD6D,EAAkB9U,cAClB+U,EACAJ,GAGFR,GAAMG,UAAYC,GAAeJ,IAGjCwB,EAAcX,EAAYb,GAAME,SACzBM,CACR,CAAC,MAAO9H,GACP,MAAM,IAAI8G,GACR,uDACA,KACAM,SAASpH,EACZ,GAiCU+I,GAAsBvH,MAAO/N,IACxC,MAAMb,WAAEA,EAAUmC,OAAEA,GAAWtB,EAEzBJ,EAAY2V,KAElB,IAAIlB,EAGJ,MAAMmB,EAAe7Q,EAAK/E,EAAW,iBAC/B8U,EAAa/P,EAAK/E,EAAW,cAOnC,IAJCuM,EAAWvM,IAAcwM,EAAUxM,EAAW,CAAE6V,WAAW,KAIvDtJ,EAAWqJ,IAAiBrW,EAAWQ,WAC1C8M,EAAI,EAAG,yDACP4H,QAAuBE,GAAYpV,EAAYmC,EAAOM,MAAO8S,OACxD,CACL,IAAIgB,GAAgB,EAGpB,MAAMC,EAAWrG,KAAK/D,MAAMyD,EAAawG,IAIzC,GAAIG,EAASjX,SAAWgR,MAAMC,QAAQgG,EAASjX,SAAU,CACvD,MAAMkX,EAAY,CAAA,EAClBD,EAASjX,QAAQgH,SAAS0P,GAAOQ,EAAUR,GAAK,IAChDO,EAASjX,QAAUkX,CACpB,CAED,MAAMrW,YAAEA,EAAWC,cAAEA,EAAaC,iBAAEA,GAAqBN,EACnD0W,EACJtW,EAAYoH,OAASnH,EAAcmH,OAASlH,EAAiBkH,OAK3DgP,EAASvW,UAAYD,EAAWC,SAClCqN,EACE,EACA,yEAEFiJ,GAAgB,GACPlQ,OAAOC,KAAKkQ,EAASjX,SAAW,IAAIiI,SAAWkP,GACxDpJ,EACE,EACA,+EAEFiJ,GAAgB,GAGhBA,GAAiBlW,GAAiB,IAAIsW,MAAMC,IAC1C,IAAKJ,EAASjX,QAAQqX,GAKpB,OAJAtJ,EACE,EACA,eAAesJ,iDAEV,CACR,IAIDL,EACFrB,QAAuBE,GAAYpV,EAAYmC,EAAOM,MAAO8S,IAE7DjI,EAAI,EAAG,uDAGPoH,GAAME,QAAU/E,EAAa0F,EAAY,QAGzCL,EAAiBsB,EAASjX,QAE1BmV,GAAMG,UAAYC,GAAeJ,IAEpC,MA3TiC9F,OAAO9H,EAAQoO,KACjD,MAAM2B,EAAc,CAClB5W,QAAS6G,EAAO7G,QAChBV,QAAS2V,GAAkB,CAAE,GAI/BR,GAAMC,eAAiBkC,EAEvBvJ,EAAI,EAAG,mCACP,IACE4I,EACE1Q,EAAK4Q,KAAgB,iBACrBjG,KAAKC,UAAUyG,GACf,OAEH,CAAC,MAAOzJ,GACP,MAAM,IAAI8G,GACR,4CACA,KACAM,SAASpH,EACZ,GA0SK0J,CAAqB9W,EAAYkV,EAAe,EAO3CkB,GAAe,KAC1B,MAAMW,EAAkBzE,KAAatS,WAAWS,UAGhD,OAAOuW,EAAWD,GACdA,EACAvR,EAAK+I,EAAWwI,EAAgB,EAOzB9W,GAAU,IAAMyU,GAAMG,UCzY5B,SAASoC,KACdC,WAAWC,WAAa,WACtB,MAAO,CAAEC,SAAU,EACvB,CACA,CASOxI,eAAeyI,GAAcC,EAAczW,EAAS0W,GAEzD1U,OAAO2U,eAAiBD,EAGxB,MAAMjF,WAAEA,EAAUmF,MAAEA,EAAKC,WAAEA,EAAUC,KAAEA,GAAST,WAIhDA,WAAWU,cAAgBH,GAAM,EAAO,CAAE,EAAEnF,KAG5C,MAAMuF,EAAQ,CACZC,WAAW,GAITjX,EAAQH,OAAOqX,SACjBF,EAAM1W,OAASmW,EAAaO,MAAM1W,OAClC0W,EAAMzW,MAAQkW,EAAaO,MAAMzW,OAInCyB,OAAOmV,kBAAmB,EAC1BL,EAAKT,WAAWe,MAAMvH,UAAW,QAAQ,SAAUwH,EAASC,EAAaC,KAEvED,EAAcV,EAAMU,EAAa,CAC/BE,UAAW,CACTC,SAAS,GAEXC,YAAa,CACXC,OAAQ,CACNC,MAAO,CACLH,SAAS,KAOfI,QAAS,CAAE,KAGAF,QAAU,IAAIjS,SAAQ,SAAUiS,GAC3CA,EAAOV,WAAY,CACzB,IAGSjV,OAAO8V,qBACV9V,OAAO8V,mBAAqBzB,WAAW0B,SAASrE,KAAM,UAAU,KAC9D1R,OAAOmV,kBAAmB,CAAI,KAIlCE,EAAQvK,MAAM4G,KAAM,CAAC4D,EAAaC,GACtC,IAEET,EAAKT,WAAW2B,OAAOnI,UAAW,QAAQ,SAAUwH,EAASL,EAAOhX,GAClEqX,EAAQvK,MAAM4G,KAAM,CAACsD,EAAOhX,GAChC,IAGE,MAAMsX,EAActX,EAAQH,OAAOqX,OAC/B,IAAIe,SAAS,UAAUjY,EAAQH,OAAOqX,SAAtC,GACAT,EAGAzW,EAAQa,YAAYG,YACtB,IAAIiX,SAAS,UAAWjY,EAAQa,YAAYG,WAA5C,CAAwDsW,GAK1D,MAAMY,EAAetB,GACnB,EACAtH,KAAK/D,MAAMvL,EAAQH,OAAOa,cAC1B4W,EAEA,CAAEN,UAGEmB,EAAgBnY,EAAQa,YAAYI,SACtC,IAAIgX,SAAS,UAAUjY,EAAQa,YAAYI,WAA3C,QACA8E,EAGEtF,EAAgB6O,KAAK/D,MAAMvL,EAAQH,OAAOY,eAC5CA,GACFoW,EAAWpW,GAGb4V,WAAWrW,EAAQH,OAAOK,QAAU,SAClC,YACAgY,EACAC,GAIF,MAAMC,EAAiB3G,IAGvB,IAAK,MAAM4G,KAAQD,EACmB,mBAAzBA,EAAeC,WACjBD,EAAeC,GAK1BxB,EAAWR,WAAWU,eAGtBV,WAAWU,cAAgB,EAC7B,CCnHA,MAAMuB,GAAWtJ,EAAatB,EAAY,2BAA4B,QAGtE,IAAI6K,GAGAC,GAQJzK,eAAe0K,KACb,IAEEhM,EAAI,EAAG,gDAGH8L,KAAYA,GAAQG,YACtBH,SAAgBzZ,EAAU6Z,QAAQ,CAChCC,kBAAmBJ,MAKvBA,GAAaD,GAAQC,aAGrBD,GAAQrF,GAAG,eAAgBuF,IAG3BhM,EAAI,EAAG,8CACR,CAAC,MAAOF,GACPQ,EACE,EACAR,EACA,+EAIF,UACQsM,IACP,CAAC,MAAOtM,GACPQ,EACE,EACAR,EACA,yFAEH,OAGKuM,GAAOrH,KAAa3S,UAAUC,MAAQ,IAG5C0N,EAAI,EAAG,6CACR,CACH,CA6BOsB,eAAe+K,GAAOC,GAE3B,MAAM/U,MAAEA,EAAKN,MAAEA,GAAU+N,MAGjBlQ,OAAQyX,KAAiBC,GAAiBjV,EAE5CkV,EAAgB,CACpBjV,UAAUP,EAAMK,kBAAmB,QACnCoV,YAAa,SACbpa,KAAMga,EAENK,KAAMnS,EAAK6D,2BACXuO,cAAc,EACdC,eAAe,EACfC,cAAc,EACdC,oBAAoB,EACpBC,gBAAiB,QACbT,GAAgBC,GAItB,IAAKV,GAAS,CACZ,IAAImB,EAAW,EAEf,MAAMC,EAAO5L,UACX,IACEtB,EACE,EACA,yDAAyDiN,OAI3DnB,SAAgBzZ,EAAU8a,OAAOV,GAGjC,MAAMW,QAActB,GAAQsB,QAC5B,GAAIA,EACF,IAAK,MAAMC,KAAQD,QACXC,EAAKjB,QAKVK,EAAcE,OAEjBZ,GAAaD,GAAQC,aAGrBD,GAAQrF,GAAG,eAAgBuF,IAE9B,CAAC,MAAOlM,GAQP,GAPAQ,EACE,EACAR,EACA,oDAIEmN,EAAW,IAKb,MAAMnN,EAJNE,EAAI,EAAG,sCAAsCiN,uBACvC,IAAIxL,SAASC,GAAaC,WAAWD,EAAU,aAC/CwL,GAIT,GAGH,UACQA,IAGyB,UAA3BT,EAAcjV,UAChBwI,EAAI,EAAG,6CAILuM,GACFvM,EAAI,EAAG,4CAEV,CAAC,MAAOF,GACP,MAAM,IAAI8G,GACR,gEACA,KACAM,SAASpH,EACZ,CAED,IAAKgM,GACH,MAAM,IAAIlF,GAAY,2CAA4C,IAErE,CAGD,OAAOkF,EACT,CAQOxK,eAAe8K,KAEhBN,IAAWA,GAAQG,iBACfH,GAAQM,QAEhBN,GAAU,KACV9L,EAAI,EAAG,gCACT,CAeOsB,eAAegM,GAAQC,GAC5B,MAAMC,GAAY,IAAItN,MAAOuN,UAG7B,IAAK3B,KAAYA,GAAQG,UACvB,MAAM,IAAIrF,GAAY,0CAA2C,KAgBnE,GAZA2G,EAAaF,WAAavB,GAAQwB,gBAG5BC,EAAaF,KAAKK,iBAAgB,SAGlCC,GAAeJ,EAAaF,MAoPpC,SAAuBE,GAErB,MAAMhW,MAAEA,EAAKxB,KAAEA,GAASiP,KAGxBuI,EAAaF,KAAK5G,GAAG,aAAanF,MAAOxB,UAGjCyN,EAAaF,KAAKO,MACtB,cACA,CAACC,EAASC,KAEJvY,OAAO2U,iBACT2D,EAAQE,UAAYD,EACrB,GAEH,oCAAoChO,EAAMK,aAC3C,IAIC5I,EAAMzC,QAAUyC,EAAMG,iBACxB6V,EAAaF,KAAK5G,GAAG,WAAYzO,IAC/B+H,QAAQC,IAAI,WAAWhI,EAAQ2O,SAAS,KAKJ,IAApCnM,EAAK6D,4BACPkP,EAAaF,KAAK5G,GAAG,iBAAiBnF,MAAO0M,IAE3C,MAAMC,EAAYV,EAAaF,KAAKY,YAGpC,GACED,IAAUC,GACVA,EAAUC,UACVX,EAAaY,WAAapY,EAAKG,UAC/B,CACA8J,EACE,EACA,4BAA4BuN,EAAaa,gCAE3C,IAEE/M,GACEC,MAAO+M,EAAgBd,KACrB,IAEOA,EAAaF,KAAKiB,kBACff,EAAaF,KAAKjB,OAE3B,CAAC,MAAOtM,GACPE,EACE,EACA,4BAA4BqO,uDAE/B,OAGKf,GAAQC,EAAa,GAE7B,EACAA,EAAaa,GACbb,EAEH,CAAC,MAAOzN,GACPQ,EACE,EACAR,EACA,4BAA4ByN,EAAaa,sCAI3Cb,EAAaY,UAAYpY,EAAKG,UAAY,CAC3C,CACF,IAGP,CAhUEqY,CAAchB,IAGTA,EAAaF,MAAQE,EAAaF,KAAKiB,WAC1C,MAAM,IAAI1H,GAAY,iCAAkC,KAW1D,OARA5G,EACE,EACA,yBAAyBuN,EAAaa,8CACpC,IAAIlO,MAAOuN,UAAYD,QAKpBD,CACT,CA4JOjM,eAAekN,GAAmBnB,EAAMoB,GAC7C,IACE,IAAK,MAAMC,KAAYD,QACfC,EAASC,gBAIXtB,EAAKuB,UAAS,KAGlB,GAA0B,oBAAfhF,WAA4B,CAErC,MAAMiF,EAAYjF,WAAWkF,OAG7B,GAAI7L,MAAMC,QAAQ2L,IAAcA,EAAU3U,OAExC,IAAK,MAAM6U,KAAYF,EACrBE,GAAYA,EAASC,UAErBpF,WAAWkF,OAAOjJ,OAGvB,CAGD,SAAUoJ,GAAmBC,SAASC,qBAAqB,WAErD,IAAMC,GAAkBF,SAASC,qBAAqB,aAElDE,GAAiBH,SAASC,qBAAqB,QAGzD,IAAK,MAAMtB,IAAW,IACjBoB,KACAG,KACAC,GAEHxB,EAAQyB,QACT,GAEJ,CAAC,MAAOxP,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CACH,CAUAwB,eAAeqM,GAAeN,SACtBA,EAAKkC,WAAW1D,GAAU,CAAE2D,UAAW,2BAGvCnC,EAAKoC,aAAa,CAAEC,KAAM,GAAG5G,0BAG7BuE,EAAKuB,SAASjF,GACtB,CC7cA,MAwGMgG,GAAcrO,MAAO+L,EAAM9C,EAAOhX,EAAS0W,IAC/CoD,EAAKuB,SAAS7E,GAAeQ,EAAOhX,EAAS0W,GAY/C,IAAA2F,GAAetO,MAAO+L,EAAM9C,EAAOhX,KAEjC,IAAIkb,EAAoB,GAExB,IACEzO,EAAI,EAAG,qCAEP,MAAM6P,EAAgBtc,EAAQH,OAGxB6W,EACJ4F,GAAetc,SAASgX,OAAON,eHwPP7C,GGvPbC,eAAepV,QAAQ6d,SAEpC,IAAIC,EACJ,GACExF,EAAM9C,UACL8C,EAAM9C,QAAQ,SAAW,GAAK8C,EAAM9C,QAAQ,UAAY,GACzD,CAKA,GAHAzH,EAAI,EAAG,6BAGoB,QAAvB6P,EAAcrd,KAChB,OAAO+X,EAGTwF,GAAQ,QACF1C,EAAKkC,WCjKF,CAAChF,GAAU,knBAYlBA,wCDqJoByF,CAAYzF,GAAQ,CACxCiF,UAAW,oBAEnB,MAEMxP,EAAI,EAAG,gCAGH6P,EAAcpF,aAEVkF,GACJtC,EACA,CACE9C,MAAO,CACL1W,OAAQgc,EAAchc,OACtBC,MAAO+b,EAAc/b,QAGzBP,EACA0W,IAIFM,EAAMA,MAAM1W,OAASgc,EAAchc,OACnC0W,EAAMA,MAAMzW,MAAQ+b,EAAc/b,YAE5B6b,GAAYtC,EAAM9C,EAAOhX,EAAS0W,IAO5CwE,QDuHGnN,eAAgC+L,EAAM9Z,GAE3C,MAAMkb,EAAoB,GAGpBha,EAAYlB,EAAQa,YAAYK,UACtC,GAAIA,EAAW,CACb,MAAMwb,EAAa,GAUnB,GAPIxb,EAAUyb,IACZD,EAAWE,KAAK,CACdC,QAAS3b,EAAUyb,KAKnBzb,EAAU+N,MACZ,IAAK,MAAM7L,KAAQlC,EAAU+N,MAAO,CAClC,MAAM6N,GAAW1Z,EAAKkE,WAAW,QAGjCoV,EAAWE,KACTE,EACI,CACED,QAAS7N,EAAa5L,EAAM,SAE9B,CACEyK,IAAKzK,GAGd,CAGH,IAAK,MAAM2Z,KAAcL,EACvB,IACExB,EAAkB0B,WAAW9C,EAAKoC,aAAaa,GAChD,CAAC,MAAOxQ,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAEHmQ,EAAW/V,OAAS,EAGpB,MAAMqW,EAAc,GACpB,GAAI9b,EAAU+b,IAAK,CACjB,IAAIC,EAAahc,EAAU+b,IAAIE,MAAM,uBACrC,GAAID,EAEF,IAAK,IAAIE,KAAiBF,EACpBE,IACFA,EAAgBA,EACblM,QAAQ,OAAQ,IAChBA,QAAQ,UAAW,IACnBA,QAAQ,KAAM,IACdA,QAAQ,KAAM,IACdA,QAAQ,IAAK,IACbA,QAAQ,MAAO,IACfzK,OAGC2W,EAAc9V,WAAW,QAC3B0V,EAAYJ,KAAK,CACf/O,IAAKuP,IAEEpd,EAAQa,YAAYE,oBAC7Bic,EAAYJ,KAAK,CACfT,KAAMA,EAAKxX,KAAK+I,EAAW0P,MAQrCJ,EAAYJ,KAAK,CACfC,QAAS3b,EAAU+b,IAAI/L,QAAQ,sBAAuB,KAAO,MAG/D,IAAK,MAAMmM,KAAeL,EACxB,IACE9B,EAAkB0B,WAAW9C,EAAKwD,YAAYD,GAC/C,CAAC,MAAO9Q,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CAEHyQ,EAAYrW,OAAS,CACtB,CACF,CACD,OAAOuU,CACT,CCjN8BqC,CAAiBzD,EAAM9Z,GAGjD,MAAMwd,EAAOhB,QACH1C,EAAKuB,UAAU7a,IACnB,MAAMid,EAAa9B,SAAS+B,cAC1B,sCAIIC,EAAcF,EAAWnd,OAAOsd,QAAQ5e,MAAQwB,EAChDqd,EAAaJ,EAAWld,MAAMqd,QAAQ5e,MAAQwB,EAWpD,OANAmb,SAASmC,KAAKC,MAAMC,KAAOxd,EAI3Bmb,SAASmC,KAAKC,MAAME,OAAS,MAEtB,CACLN,cACAE,aACD,GACA7W,WAAWsV,EAAc9b,cACtBsZ,EAAKuB,UAAS,KAElB,MAAMsC,YAAEA,EAAWE,WAAEA,GAAe7b,OAAOqU,WAAWkF,OAAO,GAO7D,OAFAI,SAASmC,KAAKC,MAAMC,KAAO,EAEpB,CACLL,cACAE,aACD,IAIDK,EAAiBC,KAAKC,KAAKZ,EAAKG,aAAerB,EAAchc,QAC7D+d,EAAgBF,KAAKC,KAAKZ,EAAKK,YAAcvB,EAAc/b,QAG3D+d,EAAEA,EAACC,EAAEA,QAjOO,CAACzE,GACrBA,EAAKO,MAAM,oBAAqBC,IAC9B,MAAMgE,EAAEA,EAACC,EAAEA,EAAChe,MAAEA,EAAKD,OAAEA,GAAWga,EAAQkE,wBACxC,MAAO,CACLF,IACAC,IACAhe,QACAD,OAAQ6d,KAAKM,MAAMne,EAAS,EAAIA,EAAS,KAC1C,IAyNsBoe,CAAc5E,GASrC,IAAI1K,EAEJ,SARM0K,EAAK6E,YAAY,CACrBre,OAAQ4d,EACR3d,MAAO8d,EACPO,kBAAmBpC,EAAQ,EAAIxV,WAAWsV,EAAc9b,SAK/B,QAAvB8b,EAAcrd,KAEhBmQ,OAnJY,CAAC0K,GACjBA,EAAKO,MAAM,gCAAiCC,GAAYA,EAAQuE,YAkJ/CC,CAAUhF,QAClB,GAAI,CAAC,MAAO,QAAQlU,SAAS0W,EAAcrd,MAEhDmQ,OAxNc,EAAC0K,EAAM7a,EAAM8f,EAAUC,EAAMpe,IAC/CsN,QAAQ+Q,KAAK,CACXnF,EAAKoF,WAAW,CACdjgB,OACA8f,WACAC,OACAG,uBAAuB,EACvBC,UAAU,EACVC,kBAAkB,KACL,QAATpgB,EAAiB,CAAEqgB,QAAS,IAAO,CAAA,EAIvCC,eAAwB,OAARtgB,IAElB,IAAIiP,SAAQ,CAACsR,EAAU7M,IACrBvE,YACE,IAAMuE,EAAO,IAAIU,GAAY,wBAAyB,OACtDzS,GAAwB,UAsMb6e,CACX3F,EACAwC,EAAcrd,KACd,SACA,CACEsB,MAAO8d,EACP/d,OAAQ4d,EACRI,IACAC,KAEFjC,EAAc1b,0BAEX,IAA2B,QAAvB0b,EAAcrd,KAUvB,MAAM,IAAIoU,GACR,sCAAsCiJ,EAAcrd,QACpD,KAVFmQ,OApMYrB,OAChB+L,EACAxZ,EACAC,EACAwe,EACAne,WAEMkZ,EAAK4F,iBAAiB,UACrBxR,QAAQ+Q,KAAK,CAClBnF,EAAK6F,IAAI,CAEPrf,OAAQA,EAAS,EACjBC,QACAwe,aAEF,IAAI7Q,SAAQ,CAACsR,EAAU7M,IACrBvE,YACE,IAAMuE,EAAO,IAAIU,GAAY,wBAAyB,OACtDzS,GAAwB,WAkLbgf,CACX9F,EACAoE,EACAG,EACA,SACA/B,EAAc1b,qBAOjB,CAID,aADMqa,GAAmBnB,EAAMoB,GACxB9L,CACR,CAAC,MAAO7C,GAEP,aADM0O,GAAmBnB,EAAMoB,GACxB3O,CACR,GElSH,MAAMsT,GAAc,GAOPC,GAAejF,IAC1BgF,GAAYjD,KAAK/B,EAAG,EAMTkF,GAAoB,KAC/BtT,EAAI,EAAG,+CACP,IAAK,MAAMoO,KAAMgF,GACfG,cAAcnF,EACf,ECHH,IAAIrY,IAAO,EAGJ,MAAMyd,GAAQ,CACnBC,iBAAkB,EAClBC,eAAgB,EAChBC,sBAAuB,EACvBC,UAAW,EACXC,eAAgB,EAChBC,aAAc,GAGhB,IAAIC,GAAa,CAAA,EAEjB,MAAMC,GAAU,CAUd3H,OAAQ/K,UACN,IACE,MAAMiM,EAAe,CACnBa,GAAI6F,IAEJ9F,UAAWuD,KAAKjZ,MAAMiZ,KAAKwC,UAAYH,GAAW7d,UAAY,KAGhE,aAAaoX,GAAQC,EACtB,CAAC,MAAOzN,GACP,MAAM,IAAI8G,GACR,8CACA,KACAM,SAASpH,EACZ,GAaHqU,SAAU7S,MAAOiM,IACf,IAAI6G,GAAY,EAkChB,OA9BEL,GAAW7d,aACTqX,EAAaY,UAAY4F,GAAW7d,YAEtC8J,EACE,EACA,yBAAyBuN,EAAaa,yCAAyC2F,GAAW7d,2BAE5Fke,GAAY,GAIT7G,EAAaF,OAEZE,EAAaF,KAAKiB,YACpBtO,EACE,EACA,yBAAyBuN,EAAaa,wDAKtCb,EAAaF,KAAKY,YAAYC,UAChClO,EACE,EACA,yBAAyBuN,EAAaa,uDAG1CgG,GAAY,GAGPA,CAAS,EASlBpF,QAAS1N,MAAOiM,IAGd,GAFAvN,EAAI,EAAG,yBAAyBuN,EAAaa,8BAEzCb,EAAaF,KACf,IAEEE,EAAaF,KAAKgH,mBAAmB,aACrC9G,EAAaF,KAAKgH,mBAAmB,WACrC9G,EAAaF,KAAKgH,mBAAmB,uBAG/B9G,EAAaF,KAAKjB,OACzB,CAAC,MAAOtM,GACPE,EACE,EACA,yBAAyBuN,EAAaa,kDAEzC,CACF,GAWQkG,GAAWhT,MAAO9H,IAY7B,GAVAua,GAAava,GAAUA,EAAOzD,KAAO,IAAKyD,EAAOzD,MAAS,SAGpDwe,GAAc/a,EAAO8S,eAE3BtM,EACE,EACA,8CAA8C+T,GAAW/d,mBAAmB+d,GAAW9d,eAGrFF,GACF,OAAOiK,EACL,EACA,yEAIAwU,SAAST,GAAW/d,YAAcwe,SAAST,GAAW9d,cACxD8d,GAAW/d,WAAa+d,GAAW9d,YAGrC,IAEEF,GAAO,IAAI0e,EAAK,IAEXT,GACHzb,IAAKic,SAAST,GAAW/d,YACzBwC,IAAKgc,SAAST,GAAW9d,YACzBye,qBAAsBX,GAAW5d,eACjCwe,oBAAqBZ,GAAW3d,cAChCwe,qBAAsBb,GAAW1d,eACjCwe,kBAAmBd,GAAWzd,YAC9Bwe,0BAA2Bf,GAAWxd,oBACtCwe,mBAAoBhB,GAAWvd,eAC/Bwe,sBAAsB,IAIxBjf,GAAK0Q,GAAG,WAAWnF,MAAOoN,IACxB1O,EAAI,EAAG,yBAAyB0O,EAASN,mCJ2FxC9M,eAAyBiM,EAAc0H,GAAY,GACxD,IACO1H,EAAaF,KAAKiB,aACjB2G,SAEI1H,EAAaF,KAAK6H,KAAK,cAAe,CAC1C1F,UAAW,2BAIP7B,GAAeJ,EAAaF,aAG5BE,EAAaF,KAAKuB,UAAS,KAC/BM,SAASmC,KAAKtD,UACZ,4DAA4D,IAIrE,CAAC,MAAOjO,GACPQ,EACE,EACAR,EACA,yBAAyByN,EAAaa,mDAGxCb,EAAaY,UAAYnJ,KAAajP,KAAKG,UAAY,CACxD,CACH,CItHYif,CAAUzG,GAAU,EAAM,IAGlC3Y,GAAK0Q,GAAG,kBAAkB,CAAC2O,EAAU1G,KACnC1O,EACE,EACA,yBAAyB0O,EAASN,0CAEpCM,EAASrB,KAAO,IAAI,IAGtB,MAAMgI,EAAmB,GAEzB,IAAK,IAAInR,EAAI,EAAGA,EAAI6P,GAAW/d,WAAYkO,IACzC,IACE,MAAMwK,QAAiB3Y,GAAKuf,UAAUC,QACtCF,EAAiBlF,KAAKzB,EACvB,CAAC,MAAO5O,GACPQ,EAAa,EAAGR,EAAO,+CACxB,CAIHuV,EAAiBpc,SAASyV,IACxB3Y,GAAKyf,QAAQ9G,EAAS,IAIpBlU,EAAKgD,yBAEP6V,IAiR8BoC,EAjRSjb,EAAKgD,wBAmRzCkY,aAAYpU,UACjB,IAEE,IAAIqU,EACF5f,GAAK6f,UAAY7f,GAAK8f,UAAY9f,GAAK+f,oBAGzC,KAAOH,IAAkB5f,GAAKwC,KAC5B,UAEQxC,GAAKggB,WACZ,CAAC,MAAOjW,GACPQ,EAAa,EAAGR,EAAO,8CACxB,CAEJ,CAAC,MAAOA,GACPQ,EACE,EACAR,EACA,uEAEH,IACA2V,KAtSDzV,EACE,EACA,4BAA2BqV,EAAiBnb,OAAS,SAASmb,EAAiBnb,oCAAsC,KAExH,CAAC,MAAO4F,GACP,MAAM,IAAI8G,GACR,+CACA,KACAM,SAASpH,EACZ,CAqQH,IAAoC2V,CArQjC,EAUInU,eAAe0U,KAIpB,GAHAhW,EAAI,EAAG,6DAGHjK,GAAM,CAER,IAAK,MAAMkgB,KAAUlgB,GAAKmgB,KACxBngB,GAAKyf,QAAQS,EAAOvH,UAItB3Y,GAAKse,mBAAmB,WACxBte,GAAKse,mBAAmB,kBACxBte,GAAKse,mBAAmB,eAGnBte,GAAKogB,kBACFpgB,GAAKiZ,UACXhP,EAAI,EAAG,+CAETjK,GAAO,IACR,OAGKqgB,IACR,CAeO,MAAMC,GAAW/U,MAAOiJ,EAAOhX,KACpC,IAAI+iB,EAEJ,IAQE,GAPAtW,EAAI,EAAG,gDAELwT,GAAME,eACJK,GAAW7e,cACbqhB,MAGGxgB,GACH,MAAM,IAAI6Q,GACR,gDACA,KAKJ,MAAM4P,EAAiB9R,KACvB,IACE1E,EAAI,EAAG,qCACPsW,QAAqBvgB,GAAKuf,UAAUC,QAGhChiB,EAAQsB,OAAOK,cACjB8K,EACE,EACAzM,EAAQkjB,SAASC,UACb,+BAA+BnjB,EAAQkjB,SAASC,cAChD,cACJ,6BAA6BF,SAGlC,CAAC,MAAO1W,GACP,MAAM,IAAI8G,IACPrT,EAAQkjB,SAASC,UACd,uBAAuBnjB,EAAQkjB,SAASC,eACxC,IACF,wDAAwDF,UAC1DtP,SAASpH,EACZ,CAGD,GAFAE,EAAI,EAAG,qCAEFsW,EAAajJ,KAGhB,MADAiJ,EAAanI,UAAY4F,GAAW7d,UAAY,EAC1C,IAAI0Q,GACR,4DACA,KAKJ,IAAI+P,GAAY,IAAIzW,MAAOuN,UAE3BzN,EACE,EACA,yBAAyBsW,EAAalI,2CAIxC,MAAMwI,EAAgBlS,KAChBmS,QAAejH,GAAgB0G,EAAajJ,KAAM9C,EAAOhX,GAG/D,GAAIsjB,aAAkBhQ,MAMpB,KALuB,0BAAnBgQ,EAAO7e,UAETse,EAAanI,UAAY4F,GAAW7d,UAAY,GAG5C,IAAI0Q,IACPrT,EAAQkjB,SAASC,UACd,uBAAuBnjB,EAAQkjB,SAASC,eACxC,IAAM,oCAAoCE,UAC9C1P,SAAS2P,GAITtjB,EAAQsB,OAAOK,cACjB8K,EACE,EACAzM,EAAQkjB,SAASC,UACb,+BAA+BnjB,EAAQkjB,SAASC,cAChD,cACJ,iCAAiCE,UAKrC7gB,GAAKyf,QAAQc,GAIb,MACMQ,GADU,IAAI5W,MAAOuN,UACEkJ,EAO7B,OANAnD,GAAMI,WAAakD,EACnBtD,GAAMM,aAAeN,GAAMI,YAAcJ,GAAMC,iBAE/CzT,EAAI,EAAG,4BAA4B8W,SAG5B,CACLD,SACAtjB,UAEH,CAAC,MAAOuM,GAOP,OANE0T,GAAMK,eAEJyC,GACFvgB,GAAKyf,QAAQc,GAGT,IAAI1P,GAAY,4BAA4B9G,EAAM9H,WAAWkP,SACjEpH,EAEH,GAiBUiX,GAAkB,KAAO,CACpCxe,IAAKxC,GAAKwC,IACVC,IAAKzC,GAAKyC,IACV0d,KAAMngB,GAAK6f,UACXoB,UAAWjhB,GAAK8f,UAChBoB,WAAYlhB,GAAK6f,UAAY7f,GAAK8f,UAClCqB,gBAAiBnhB,GAAKohB,qBACtBC,eAAgBrhB,GAAK+f,oBACrBuB,mBAAoBthB,GAAKuhB,wBACzBC,gBAAiBxhB,GAAKwhB,gBAAgBrd,OACtCsd,YACEzhB,GAAK6f,UACL7f,GAAK8f,UACL9f,GAAKohB,qBACLphB,GAAK+f,oBACL/f,GAAKuhB,wBACLvhB,GAAKwhB,gBAAgBrd,SAQlB,SAASqc,KACd,MAAMhe,IACJA,EAAGC,IACHA,EAAG0d,KACHA,EAAIc,UACJA,EAASC,WACTA,EAAUC,gBACVA,EAAeE,eACfA,EAAcC,mBACdA,EAAkBE,gBAClBA,EAAeC,YACfA,GACET,KAEJ/W,EAAI,EAAG,2DAA2DzH,MAClEyH,EAAI,EAAG,2DAA2DxH,MAClEwH,EAAI,EAAG,wCAAwCkW,MAC/ClW,EAAI,EAAG,wCAAwCgX,MAC/ChX,EACE,EACA,+DAA+DiX,MAEjEjX,EACE,EACA,0DAA0DkX,MAE5DlX,EACE,EACA,yDAAyDoX,MAE3DpX,EACE,EACA,2DAA2DqX,MAE7DrX,EACE,EACA,2DAA2DuX,MAE7DvX,EAAI,EAAG,uCAAuCwX,KAChD,CAyCA,IAAeC,GAMbV,GANaU,GAOH,IAAMjE,GCxflB,IAAInf,IAAqB,EAgBlB,MAAMqjB,GAAcpW,MAAOqW,EAAUC,KAE1C5X,EAAI,EAAG,2CAGP,MAAMzM,EVyL0B,EAACsc,EAAe9K,EAAiB,MACjE,IAAIxR,EAAU,CAAA,EAsBd,OApBIsc,EAAcgI,KAChBtkB,EAAUwP,EAASgC,GACnBxR,EAAQH,OAAOZ,KAAOqd,EAAcrd,MAAQqd,EAAczc,OAAOZ,KACjEe,EAAQH,OAAOW,MAAQ8b,EAAc9b,OAAS8b,EAAczc,OAAOW,MACnER,EAAQH,OAAOI,QACbqc,EAAcrc,SAAWqc,EAAczc,OAAOI,QAChDD,EAAQkjB,QAAU,CAChBoB,IAAKhI,EAAcgI,MAGrBtkB,EAAU0R,GACRF,EACA8K,EAEAnX,GAIJnF,EAAQH,OAAOI,QACbD,EAAQH,QAAQI,SAAW,SAASD,EAAQH,QAAQZ,MAAQ,QACvDe,CAAO,EUhNEukB,CAAmBH,EAAU3S,MAGvC6K,EAAgBtc,EAAQH,OAG9B,GAAIG,EAAQkjB,SAASoB,KAA+B,KAAxBtkB,EAAQkjB,QAAQoB,IAC1C,IACE7X,EAAI,EAAG,kDAEP,MAAM6W,EAASkB,GChCd,SAAkBC,GACvB,MAAMziB,EAAS,IAAI0iB,EAAM,IAAI1iB,OAE7B,OADe2iB,EAAU3iB,GACX4iB,SAASH,EAAO,CAAEI,SAAU,CAAC,kBAC7C,CD6BQD,CAAS5kB,EAAQkjB,QAAQoB,KACzBtkB,EACAqkB,GAIF,QADEpE,GAAMG,sBACDkD,CACR,CAAC,MAAO/W,GACP,OAAO8X,EACL,IAAIhR,GAAY,mCAAoC,KAAKM,SAASpH,GAErE,CAIH,GAAI+P,EAAcxc,QAAUwc,EAAcxc,OAAO6G,OAE/C,IAGE,OAFA8F,EAAI,EAAG,oDACPzM,EAAQH,OAAOE,MAAQiP,EAAasN,EAAcxc,OAAQ,QACnD0kB,GAAexkB,EAAQH,OAAOE,MAAM0G,OAAQzG,EAASqkB,EAC7D,CAAC,MAAO9X,GACP,OAAO8X,EACL,IAAIhR,GAAY,oCAAqC,KAAKM,SACxDpH,GAGL,CAIH,GACG+P,EAAcvc,OAAiC,KAAxBuc,EAAcvc,OACrCuc,EAActc,SAAqC,KAA1Bsc,EAActc,QAExC,IAIE,OAHAyM,EAAI,EAAG,kDAGHuE,GAAUhR,EAAQa,aAAaC,oBAC1BgkB,GAAiB9kB,EAASqkB,GAIG,iBAAxB/H,EAAcvc,MACxBykB,GAAelI,EAAcvc,MAAM0G,OAAQzG,EAASqkB,GACpDU,GACE/kB,EACAsc,EAAcvc,OAASuc,EAActc,QACrCqkB,EAEP,CAAC,MAAO9X,GACP,OAAO8X,EACL,IAAIhR,GAAY,mCAAoC,KAAKM,SAASpH,GAErE,CAIH,OAAO8X,EACL,IAAIhR,GACF,gJACA,KAEH,EA+GU2R,GAAiBhlB,IAC5B,MAAMgX,MAAEA,EAAKQ,UAAEA,GACbxX,EAAQH,QAAQG,SAAW+O,EAAc/O,EAAQH,QAAQE,OAGrDU,EAAgBsO,EAAc/O,EAAQH,QAAQY,eAGpD,IAAID,EACFR,EAAQH,QAAQW,OAChBgX,GAAWhX,OACXC,GAAe+W,WAAWhX,OAC1BR,EAAQH,QAAQQ,cAChB,EAGFG,EAAQ2d,KAAKlZ,IAAI,GAAKkZ,KAAKnZ,IAAIxE,EAAO,IAGtCA,EXwIyB,EAACxB,EAAOimB,EAAY,KAC7C,MAAMC,EAAa/G,KAAKgH,IAAI,GAAIF,GAAa,GAC7C,OAAO9G,KAAKjZ,OAAOlG,EAAQkmB,GAAcA,CAAU,EW1I3CE,CAAY5kB,EAAO,GAG3B,MAAMgd,EAAO,CACXld,OACEN,EAAQH,QAAQS,QAChBkX,GAAW6N,cACXrO,GAAO1W,QACPG,GAAe+W,WAAW6N,cAC1B5kB,GAAeuW,OAAO1W,QACtBN,EAAQH,QAAQM,eAChB,IACFI,MACEP,EAAQH,QAAQU,OAChBiX,GAAW8N,aACXtO,GAAOzW,OACPE,GAAe+W,WAAW8N,aAC1B7kB,GAAeuW,OAAOzW,OACtBP,EAAQH,QAAQO,cAChB,IACFI,SAIF,IAAK,IAAK+kB,EAAOvmB,KAAUwG,OAAOgL,QAAQgN,GACxCA,EAAK+H,GACc,iBAAVvmB,GAAsBA,EAAMkS,QAAQ,SAAU,IAAMlS,EAE/D,OAAOwe,CAAI,EAgBPuH,GAAWhX,MAAO/N,EAASwlB,EAAWnB,EAAaC,KACvD,IAAMzkB,OAAQyc,EAAezb,YAAa4kB,GAAuBzlB,EAEjE,MAAM0lB,EAC6C,kBAA1CD,EAAmB3kB,mBACtB2kB,EAAmB3kB,mBACnBA,GAEN,GAAK2kB,GAEE,GAAIC,EACT,GAA6C,iBAAlC1lB,EAAQa,YAAYK,UAE7BlB,EAAQa,YAAYK,UAAYyN,EAC9B3O,EAAQa,YAAYK,UACpB8P,GAAUhR,EAAQa,YAAYE,0BAE3B,IAAKf,EAAQa,YAAYK,UAC9B,IACE,MAAMA,EAAY8N,EAAa,iBAAkB,QACjDhP,EAAQa,YAAYK,UAAYyN,EAC9BzN,EACA8P,GAAUhR,EAAQa,YAAYE,oBAEjC,CAAC,MAAOwL,GACPQ,EACE,EACAR,EACA,0DAEH,OArBHkZ,EAAqBzlB,EAAQa,YAAc,GA6B7C,IAAK6kB,GAA4BD,EAAoB,CACnD,GACEA,EAAmBxkB,UACnBwkB,EAAmBvkB,WACnBukB,EAAmBzkB,WAInB,OAAOqjB,EACL,IAAIhR,GACF,mGACA,MAMNoS,EAAmBxkB,UAAW,EAC9BwkB,EAAmBvkB,WAAY,EAC/BukB,EAAmBzkB,YAAa,CACjC,CAyCD,GAtCIwkB,IACFA,EAAUxO,MAAQwO,EAAUxO,OAAS,CAAA,EACrCwO,EAAUhO,UAAYgO,EAAUhO,WAAa,CAAA,EAC7CgO,EAAUhO,UAAUC,SAAU,GAGhC6E,EAAcpc,OAASoc,EAAcpc,QAAU,QAC/Coc,EAAcrd,KAAOoP,EAAQiO,EAAcrd,KAAMqd,EAAcrc,SACpC,QAAvBqc,EAAcrd,OAChBqd,EAAc/b,OAAQ,GAIxB,CAAC,gBAAiB,gBAAgBmF,SAASigB,IACzC,IACMrJ,GAAiBA,EAAcqJ,KAEO,iBAA/BrJ,EAAcqJ,IACrBrJ,EAAcqJ,GAAalY,SAAS,SAEpC6O,EAAcqJ,GAAe5W,EAC3BC,EAAasN,EAAcqJ,GAAc,SACzC,GAGFrJ,EAAcqJ,GAAe5W,EAC3BuN,EAAcqJ,IACd,GAIP,CAAC,MAAOpZ,GACP+P,EAAcqJ,GAAe,GAC7B5Y,EAAa,EAAGR,EAAO,gBAAgBoZ,uBACxC,KAICF,EAAmB3kB,mBACrB,IACE2kB,EAAmBzkB,WAAaiQ,GAC9BwU,EAAmBzkB,WACnBykB,EAAmB1kB,mBAEtB,CAAC,MAAOwL,GACPQ,EAAa,EAAGR,EAAO,6CACxB,CAIH,GACEkZ,GACAA,EAAmBxkB,UACnBwkB,EAAmBxkB,UAAUiT,QAAQ,KAAO,EAI5C,GAAIuR,EAAmB1kB,mBACrB,IACE0kB,EAAmBxkB,SAAW+N,EAC5ByW,EAAmBxkB,SACnB,OAEH,CAAC,MAAOsL,GACPkZ,EAAmBxkB,UAAW,EAC9B8L,EAAa,EAAGR,EAAO,2CACxB,MAEDkZ,EAAmBxkB,UAAW,EAKlCjB,EAAQH,OAAS,IACZG,EAAQH,UACRmlB,GAAchlB,IAInB,IAKE,OAAOqkB,GAAY,QAJEvB,GACnBxG,EAAcpF,QAAUsO,GAAalB,EACrCtkB,GAGH,CAAC,MAAOuM,GACP,OAAO8X,EAAY9X,EACpB,GAqBGuY,GAAmB,CAAC9kB,EAASqkB,KACjC,IACE,IAAInN,EACAnX,EAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,QAkBnD,MAhBqB,iBAAVD,IAETmX,EAASnX,EAAQiQ,EACfjQ,EACAC,EAAQa,aAAaC,qBAGzBoW,EAASnX,EAAMmQ,WAAW,YAAa,IAAIzJ,OAGT,MAA9ByQ,EAAOA,EAAOvQ,OAAS,KACzBuQ,EAASA,EAAOpR,UAAU,EAAGoR,EAAOvQ,OAAS,IAI/C3G,EAAQH,OAAOqX,OAASA,EACjB6N,GAAS/kB,GAAS,EAAOqkB,EACjC,CAAC,MAAO9X,GACP,OAAO8X,EACL,IAAIhR,GACF,wCAAwCrT,EAAQH,QAAQsjB,WAAa,iJACrE,KACAxP,SAASpH,GAEd,GAcGiY,GAAiB,CAACoB,EAAgB5lB,EAASqkB,KAC/C,MAAMvjB,mBAAEA,GAAuBd,EAAQa,YAGvC,GACE+kB,EAAe1R,QAAQ,SAAW,GAClC0R,EAAe1R,QAAQ,UAAY,EAGnC,OADAzH,EAAI,EAAG,iCACAsY,GAAS/kB,GAAS,EAAOqkB,EAAauB,GAG/C,IAEE,MAAMC,EAAYvW,KAAK/D,MAAMqa,EAAe1V,WAAW,YAAa,MAEpE,OAAK2V,GAAkC,iBAAdA,EAUlBd,GAAS/kB,EAAS6lB,EAAWxB,GAT3BA,EACL,IAAIhR,GACF,uFACA,KAOP,CAAC,MAAO9G,GAEP,OAAIyE,GAAUlQ,GACLgkB,GAAiB9kB,EAASqkB,GAG1BA,EACL,IAAIhR,GACF,iMACA,KACAM,SAASpH,GAGhB,GE9hBGuZ,GAAqB,CAACvZ,EAAOwZ,EAAK9S,EAAK+S,KAE3CjZ,EAAa,EAAGR,GAGY,gBAAxBtF,EAAKwD,uBACA8B,EAAMY,MAIf6Y,EAAKzZ,EAAM,EAWP0Z,GAAwB,CAAC1Z,EAAOwZ,EAAK9S,EAAK+S,KAE9C,MAAQpS,WAAYsS,EAAM1S,OAAEA,EAAM/O,QAAEA,EAAO0I,MAAEA,GAAUZ,EACjDqH,EAAasS,GAAU1S,GAAU,IAGvCP,EAAIO,OAAOI,GAAYuS,KAAK,CAAEvS,aAAYnP,UAAS0I,SAAQ,EAG7D,ICjBAiZ,GAAe,CAACC,EAAKC,KACnB,MAAMC,EACJ,yEAGIC,EAAc,CAClBvhB,IAAKqhB,EAAYvkB,aAAe,GAChCC,OAAQskB,EAAYtkB,QAAU,EAC9BC,MAAOqkB,EAAYrkB,OAAS,EAC5BC,WAAYokB,EAAYpkB,aAAc,EACtCC,QAASmkB,EAAYnkB,UAAW,EAChCC,UAAWkkB,EAAYlkB,YAAa,GAIlCokB,EAAYtkB,YACdmkB,EAAI9kB,OAAO,eAIb,MAAMklB,EAAUL,EAAU,CACxBM,SAA+B,GAArBF,EAAYxkB,OAAc,IAEpCiD,IAAKuhB,EAAYvhB,IAEjB0hB,QAASH,EAAYvkB,MACrB2kB,QAAS,CAACC,EAAS1Y,KACjBA,EAAS2Y,OAAO,CACdX,KAAM,KACJhY,EAASqF,OAAO,KAAKuT,KAAK,CAAEtiB,QAAS8hB,GAAM,EAE7CS,QAAS,KACP7Y,EAASqF,OAAO,KAAKuT,KAAKR,EAAI,GAEhC,EAEJU,KAAOJ,IAGqB,IAAxBL,EAAYrkB,UACc,IAA1BqkB,EAAYpkB,WACZykB,EAAQK,MAAMtX,MAAQ4W,EAAYrkB,SAClC0kB,EAAQK,MAAMC,eAAiBX,EAAYpkB,YAE3CqK,EAAI,EAAG,2CACA,KAOb4Z,EAAIe,IAAIX,GAERha,EACE,EACA,8CAA8C+Z,EAAYvhB,oBAAoBuhB,EAAYxkB,8CAA8CwkB,EAAYtkB,cACrJ,EC/EH,MAAMmlB,WAAkBhU,GACtB,WAAAE,CAAY9O,EAAS+O,GACnBC,MAAMhP,GACNiP,KAAKF,OAASE,KAAKE,WAAaJ,CACjC,CAED,SAAA8T,CAAU9T,GAER,OADAE,KAAKF,OAASA,EACPE,IACR,ECcH,IAAA6T,GAAgBlB,KACbA,GAEGA,EAAImB,KACF,+BACAzZ,MAAO8Y,EAAS1Y,EAAU6X,KACxB,IACE,MAAMyB,EAAaxgB,EAAKW,uBAGxB,IAAK6f,IAAeA,EAAW9gB,OAC7B,MAAM,IAAI0gB,GACR,uGACA,KAKJ,MAAMK,EAAQb,EAAQ7T,IAAI,WAC1B,IAAK0U,GAASA,IAAUD,EACtB,MAAM,IAAIJ,GACR,iEACA,KAKJ,MAAMM,EAAad,EAAQe,OAAOD,WAClC,IAAIA,EAmBF,MAAM,IAAIN,GAAU,2BAA4B,KAlBhD,SZ4OetZ,OAAO4Z,IAClC,MAAM3nB,EAAUyR,KACZzR,GAASb,aACXa,EAAQb,WAAWC,QAAUuoB,SAEzBrS,GAAoBtV,EAAQ,EY/Od6nB,CAAcF,EACrB,CAAC,MAAOpb,GACP,MAAM,IAAI8a,GACR,mBAAmB9a,EAAM9H,UACzB8H,EAAMqH,YACND,SAASpH,EACZ,CAGD4B,EAASqF,OAAO,KAAKuT,KAAK,CACxBnT,WAAY,IACZxU,QAASA,KACTqF,QAAS,+CAA+CkjB,MAM7D,CAAC,MAAOpb,GACPyZ,EAAKzZ,EACN,KC7CX,MAAMub,GAAe,CACnBC,IAAK,YACLC,KAAM,aACNC,IAAK,YACLtI,IAAK,kBACL2E,IAAK,iBAIP,IAAI4D,GAAkB,EAGtB,MAAMC,GAAgB,GAGhBC,GAAe,GAgBfC,GAAc,CAACC,EAAWzB,EAAS1Y,EAAUiB,KACjD,IAAIkU,GAAS,EACb,MAAMzI,GAAEA,EAAE0N,SAAEA,EAAQtpB,KAAEA,EAAI6e,KAAEA,GAAS1O,EAcrC,OAZAkZ,EAAUxS,MAAM7U,IACd,GAAIA,EAAU,CACZ,IAAIunB,EAAevnB,EAAS4lB,EAAS1Y,EAAU0M,EAAI0N,EAAUtpB,EAAM6e,GAMnE,YAJqB/X,IAAjByiB,IAA+C,IAAjBA,IAChClF,EAASkF,IAGJ,CACR,KAGIlF,CAAM,EAaTmF,GAAgB1a,MAAO8Y,EAAS1Y,EAAU6X,KAC9C,IAEE,MAAM0C,EAAcvX,KAGdoX,EAAW7H,IAAOxP,QAAQ,KAAM,IAGhCkH,EAAiB3G,KAEjBqM,EAAO+I,EAAQ/I,KACfjD,IAAOqN,GAEb,IAAIjpB,EAAOoP,EAAQyP,EAAK7e,MAGxB,IAAK6e,GjBmHS,iBADY3O,EiBlHC2O,KjBoH5BpO,MAAMC,QAAQR,IACN,OAATA,GAC6B,IAA7B3J,OAAOC,KAAK0J,GAAMxI,OiBrHd,MAAM,IAAI0gB,GACR,sJACA,KAKJ,IAAItnB,EAAQgP,EAAc+O,EAAKhe,QAAUge,EAAK9d,SAAW8d,EAAK1O,MAG9D,IAAKrP,IAAU+d,EAAKwG,IAQlB,MAPA7X,EACE,EACA,uBAAuB8b,UACrB1B,EAAQ8B,QAAQ,oBAAsB9B,EAAQ+B,WAAWC,kDACtBvZ,KAAKC,UAAUuO,OAGhD,IAAIuJ,GACR,oQACA,KAIJ,IAAImB,GAAe,EAWnB,GARAA,EAAeH,GAAYF,GAAetB,EAAS1Y,EAAU,CAC3D0M,KACA0N,WACAtpB,OACA6e,UAImB,IAAjB0K,EACF,OAAOra,EAAS4Y,KAAKyB,GAGvB,IAAIM,GAAoB,EAGxBjC,EAAQkC,OAAO7V,GAAG,SAAS,KACzB4V,GAAoB,CAAI,IAG1Brc,EAAI,EAAG,iDAAiD8b,MAExDzK,EAAK5d,OAAiC,iBAAhB4d,EAAK5d,QAAuB4d,EAAK5d,QAAW,QAGlE,MAAMuS,EAAiB,CACrB5S,OAAQ,CACNE,QACAd,OACAiB,OAAQ4d,EAAK5d,OAAO,GAAG8oB,cAAgBlL,EAAK5d,OAAO+oB,OAAO,GAC1D3oB,OAAQwd,EAAKxd,OACbC,MAAOud,EAAKvd,MACZC,MAAOsd,EAAKtd,OAAS4X,EAAevY,OAAOW,MAC3CC,cAAesO,EAAc+O,EAAKrd,eAAe,GACjDC,aAAcqO,EAAc+O,EAAKpd,cAAc,IAEjDG,YAAa,CACXC,mBNqYmCA,GMpYnCC,oBAAoB,EACpBG,UAAW6N,EAAc+O,EAAK5c,WAAW,GACzCD,SAAU6c,EAAK7c,SACfD,WAAY8c,EAAK9c,aAIjBjB,IAEF0S,EAAe5S,OAAOE,MAAQiQ,EAC5BjQ,EACA0S,EAAe5R,YAAYC,qBAK/B,MAAMd,EAAU0R,GAAmB0G,EAAgB3F,GAcnD,GAXAzS,EAAQH,OAAOG,QAAUD,EAGzBC,EAAQkjB,QAAU,CAChBoB,IAAKxG,EAAKwG,MAAO,EACjB4E,IAAKpL,EAAKoL,MAAO,EACjBC,WAAYrL,EAAKqL,aAAc,EAC/BhG,UAAWoF,GAITzK,EAAKwG,KjBiCyB,CAACnV,GACf,CACpB,mDACA,uEACA,wEACA,uFACA,qEAGmB2G,MAAMsT,GAAYA,EAAQhiB,KAAK+H,KiB1ClCka,CAAuBrpB,EAAQkjB,QAAQoB,KACrD,MAAM,IAAI+C,GACR,6KACA,WAKElD,GAAYnkB,GAAS,CAACuM,EAAO+c,KAajC,GAXAzC,EAAQkC,OAAOjI,mBAAmB,SAG9B1I,EAAe9W,OAAOK,cACxB8K,EACE,EACA,+BAA+B8b,0CAAiDG,UAKhFI,EACF,OAAOrc,EACL,EACA,mFAKJ,GAAIF,EACF,MAAMA,EAIR,IAAK+c,IAASA,EAAKhG,OACjB,MAAM,IAAI+D,GACR,oGAAoGkB,oBAA2Be,EAAKhG,UACpI,KAUJ,OALArkB,EAAOqqB,EAAKtpB,QAAQH,OAAOZ,KAG3BopB,GAAYD,GAAcvB,EAAS1Y,EAAU,CAAE0M,KAAIiD,KAAMwL,EAAKhG,SAE1DgG,EAAKhG,OAEHxF,EAAKoL,IAEM,QAATjqB,GAA0B,OAARA,EACbkP,EAAS4Y,KACdwC,OAAOC,KAAKF,EAAKhG,OAAQ,QAAQ1W,SAAS,WAIvCuB,EAAS4Y,KAAKuC,EAAKhG,SAI5BnV,EAASsb,OAAO,eAAgB3B,GAAa7oB,IAAS,aAGjD6e,EAAKqL,YACRhb,EAASub,WACP,GAAG7C,EAAQe,OAAO+B,UAAY9C,EAAQ/I,KAAK6L,UAAY,WACrD1qB,GAAQ,SAME,QAATA,EACHkP,EAAS4Y,KAAKuC,EAAKhG,QACnBnV,EAAS4Y,KAAKwC,OAAOC,KAAKF,EAAKhG,OAAQ,iBA5B7C,CA6BC,GAEJ,CAAC,MAAO/W,GACPyZ,EAAKzZ,EACN,CjB7D0B,IAAC4C,CiB6D3B,ECpQH,MAAMya,GAAUta,KAAK/D,MAAMyD,EAAa6a,EAAOnc,EAAW,kBAEpDoc,GAAkB,IAAInd,KAEtBod,GAAe,GAuCN,SAASC,GAAgB3D,GACtC,IAAKA,EACH,OAAO,EAKTvG,GAxBAqC,aAAY,KACV,MAAMlC,EAAQzd,KACRynB,EACqB,IAAzBhK,EAAME,eACF,EACCF,EAAMC,iBAAmBD,EAAME,eAAkB,IAExD4J,GAAanN,KAAKqN,GACdF,GAAapjB,OA5BF,IA6BbojB,GAAazX,OACd,GA/BkB,MA+CrB+T,EAAIrT,IAAI,WAAW,CAACkX,EAAGjX,KACrB,MAAMgN,EAAQzd,KACR2nB,EAASJ,GAAapjB,OACtByjB,EAxCIL,GAAaM,QAAO,CAACC,EAAGC,IAAMD,EAAIC,GAAG,GACpCR,GAAapjB,OAyCxB8F,EAAI,EAAG,4DAEPwG,EAAI8T,KAAK,CACPvT,OAAQ,KACRgX,SAAUV,GACVW,OACEtM,KAAKuM,QACF,IAAI/d,MAAOuN,UAAY4P,GAAgB5P,WAAa,IAAO,IAC1D,WACN9a,QAASwqB,GAAQxqB,QACjBurB,kBAAmBvrB,KACnBwrB,sBAAuB3K,EAAMM,aAC7BL,iBAAkBD,EAAMC,iBACxB2K,cAAe5K,EAAMK,eACrBH,eAAgBF,EAAME,eACtB2K,YAAc7K,EAAMC,iBAAmBD,EAAME,eAAkB,IAE/D3d,KAAMA,KAGN2nB,SACAC,gBACA3lB,QACEsC,MAAMqjB,KAAmBL,GAAapjB,OAClC,oEACA,QAAQwjB,mCAAwCC,EAAcW,QAAQ,OAG5EC,kBAAmB/K,EAAMG,sBACzB6K,mBAAoBhL,EAAMC,iBAAmBD,EAAMG,uBACnD,GAEN,CC5EA,MAAM8K,GAAgB,IAAIC,IAGpB9E,GAAM+E,IAGZ/E,GAAIgF,QAAQ,gBAGZhF,GAAIe,IACFkE,EAAK,CACHC,QAAS,CAAC,OAAQ,MAAO,cAK7B,MAAMC,GAAUC,EAAOC,gBACjBC,GAASF,EAAO,CACpBD,WACAI,OAAQ,CACNC,UAAW,YAKfxF,GAAIe,IAAIgE,EAAQjF,KAAK,CAAE2F,MAAO,YAC9BzF,GAAIe,IAAIgE,EAAQW,WAAW,CAAEC,UAAU,EAAMF,MAAO,YAGpDzF,GAAIe,IAAIuE,GAAOM,QAOf,MAAMC,GAA6B5qB,IACjCA,EAAO4R,GAAG,eAAgB3G,IACxBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM9H,UAAU,IAGnEnD,EAAO4R,GAAG,SAAU3G,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM9H,UAAU,IAGnEnD,EAAO4R,GAAG,cAAe6V,IACvBA,EAAO7V,GAAG,SAAU3G,IAClBQ,EAAa,EAAGR,EAAO,0BAA0BA,EAAM9H,UAAU,GACjE,GACF,EAaS0nB,GAAcpe,MAAOqe,IAChC,IAEE,IAAKA,EAAa7qB,OAChB,OAAO,EAIT,IAAK6qB,EAAa/pB,IAAIC,MAAO,CAE3B,MAAM+pB,EAAavZ,EAAKwZ,aAAajG,IAGrC6F,GAA0BG,GAG1BA,EAAWE,OAAOH,EAAa1qB,KAAM0qB,EAAa3qB,MAGlDypB,GAAcsB,IAAIJ,EAAa1qB,KAAM2qB,GAErC5f,EACE,EACA,mCAAmC2f,EAAa3qB,QAAQ2qB,EAAa1qB,QAExE,CAGD,GAAI0qB,EAAa/pB,IAAId,OAAQ,CAE3B,IAAIqO,EAAK6c,EAET,IAEE7c,QAAY8c,EAAWC,SACrBC,EAAMjoB,KAAKynB,EAAa/pB,IAAIE,SAAU,cACtC,QAIFkqB,QAAaC,EAAWC,SACtBC,EAAMjoB,KAAKynB,EAAa/pB,IAAIE,SAAU,cACtC,OAEH,CAAC,MAAOgK,GACPE,EACE,EACA,qDAAqD2f,EAAa/pB,IAAIE,sDAEzE,CAED,GAAIqN,GAAO6c,EAAM,CAEf,MAAMI,EAAcha,EAAMyZ,aAAa,CAAE1c,MAAK6c,QAAQpG,IAGtD6F,GAA0BW,GAG1BA,EAAYN,OAAOH,EAAa/pB,IAAIX,KAAM0qB,EAAa3qB,MAGvDypB,GAAcsB,IAAIJ,EAAa/pB,IAAIX,KAAMmrB,GAEzCpgB,EACE,EACA,oCAAoC2f,EAAa3qB,QAAQ2qB,EAAa/pB,IAAIX,QAE7E,CACF,CAIC0qB,EAAatqB,cACbsqB,EAAatqB,aAAaP,SACzB,CAAC,EAAGurB,KAAKlnB,SAASwmB,EAAatqB,aAAaC,cAE7CqkB,GAAUC,GAAK+F,EAAatqB,cAI9BukB,GAAIe,IAAIgE,EAAQ2B,OAAOH,EAAMjoB,KAAK+I,EAAW,YAG7Csf,GAAY3G,IFwGD,CAACA,IAIdA,EAAImB,KAAK,IAAKiB,IAMdpC,EAAImB,KAAK,aAAciB,GAAc,EEjHnCwE,CAAa5G,IClKF,CAACA,MACbA,GAEGA,EAAIrT,IAAI,KAAK,CAAC6T,EAAS1Y,KACrBA,EAAS+e,SAASvoB,EAAK+I,EAAW,SAAU,cAAc,GAC1D,ED8JJyf,CAAQ9G,IACRkB,GAAalB,INhJF,CAACA,IAEdA,EAAIe,IAAItB,IAGRO,EAAIe,IAAInB,GAAsB,EM8I5BmH,CAAa/G,GACd,CAAC,MAAO9Z,GACP,MAAM,IAAI8G,GACR,qDACA,KACAM,SAASpH,EACZ,GAMU8gB,GAAe,KAC1B5gB,EAAI,EAAG,iCACP,IAAK,MAAO/K,EAAMJ,KAAW4pB,GAC3B5pB,EAAOuX,OAAM,KACXqS,GAAcoC,OAAO5rB,GACrB+K,EAAI,EAAG,mCAAmC/K,KAAQ,GAErD,EA6DH,IAAeJ,GAAA,CACb6qB,eACAkB,gBACAE,WAxDwB,IAAMrC,GAyD9BsC,mBAlDiClH,GAAgBF,GAAUC,GAAKC,GAmDhEmH,WA5CwB,IAAMrC,EA6C9BsC,OAtCoB,IAAMrH,GAuC1Be,IA/BiB,CAACjL,KAASwR,KAC3BtH,GAAIe,IAAIjL,KAASwR,EAAY,EA+B7B3a,IAtBiB,CAACmJ,KAASwR,KAC3BtH,GAAIrT,IAAImJ,KAASwR,EAAY,EAsB7BnG,KAbkB,CAACrL,KAASwR,KAC5BtH,GAAImB,KAAKrL,KAASwR,EAAY,GEjPzB,MAAMC,GAAkB7f,MAAO8f,Kf0E/B,WACL,IAAKtV,GACH,MAAM,IAAIlF,GAAY,+CAAgD,KAExE,OAAOkF,EACT,Ee7EEuV,GAAahN,mBAAmB,sBAG1B5S,QAAQ6f,WAAW,CAEvBhO,KAGAsN,KAGA5K,OAIFjX,QAAQwiB,KAAKH,EAAS,ECwExB,IAAeI,GAAA,CAEb3sB,UACA6qB,eAGA+B,WApCiBngB,MAAO/N,IXseW,IAAChB,EW3cpC,OX2coCA,EWnelCgB,EAAQa,aAAeb,EAAQa,YAAYC,mBXoe7CA,GAAqBkQ,GAAUhS,GZpVN,CAACmvB,IAE1B,IAAK,MAAOve,EAAK5Q,KAAUwG,OAAOgL,QAAQ2d,GACxCjrB,EAAQ0M,GAAO5Q,EAIjBqO,EAAY8gB,GAAkBlN,SAASkN,EAAehrB,QAGlDgrB,GAAkBA,EAAe9qB,MAAQ8qB,EAAe5qB,QAC1D+J,EACE6gB,EAAe9qB,KACf8qB,EAAe/qB,MAAQ,+BAE1B,EuB3JDgrB,CAAYpuB,EAAQkD,SAGhBlD,EAAQ0D,MAAME,uBAnDlB6I,EAAI,EAAG,sDAGPjB,QAAQ0H,GAAG,QAASmb,IAClB5hB,EAAI,EAAG,4BAA4B4hB,KAAQ,IAI7C7iB,QAAQ0H,GAAG,UAAUnF,MAAOvJ,EAAM6pB,KAChC5hB,EAAI,EAAG,OAAOjI,sBAAyB6pB,YACjCT,GAAgB,EAAE,IAI1BpiB,QAAQ0H,GAAG,WAAWnF,MAAOvJ,EAAM6pB,KACjC5hB,EAAI,EAAG,OAAOjI,sBAAyB6pB,YACjCT,GAAgB,EAAE,IAI1BpiB,QAAQ0H,GAAG,UAAUnF,MAAOvJ,EAAM6pB,KAChC5hB,EAAI,EAAG,OAAOjI,sBAAyB6pB,YACjCT,GAAgB,EAAE,IAI1BpiB,QAAQ0H,GAAG,qBAAqBnF,MAAOxB,EAAO/H,KAC5CuI,EAAa,EAAGR,EAAO,OAAO/H,kBACxBopB,GAAgB,EAAE,WA4BpBtY,GAAoBtV,SAGpB+gB,GAAS,CACbve,KAAMxC,EAAQwC,MAAQ,CACpBC,WAAY,EACZC,WAAY,GAEdqW,cAAe/Y,EAAQlB,UAAUC,MAAQ,KAIpCiB,CAAO,EAUdsuB,aXqF0BvgB,MAAO/N,IAEjCA,EAAQH,OAAOE,MAAQC,EAAQH,OAAOE,OAASC,EAAQH,OAAOG,cAGxDmkB,GAAYnkB,GAAS+N,MAAOxB,EAAO+c,KAEvC,GAAI/c,EACF,MAAMA,EAGR,MAAMtM,QAAEA,EAAOhB,KAAEA,GAASqqB,EAAKtpB,QAAQH,OAGvCwV,EACEpV,GAAW,SAAShB,IACX,QAATA,EAAiBsqB,OAAOC,KAAKF,EAAKhG,OAAQ,UAAYgG,EAAKhG,cAIvDb,IAAU,GAChB,EWzGF8L,YXuByBxgB,MAAO/N,IAChC,MAAMwuB,EAAiB,GAGvB,IAAK,IAAIC,KAAQzuB,EAAQH,OAAOc,MAAM4F,MAAM,KAC1CkoB,EAAOA,EAAKloB,MAAM,KACE,IAAhBkoB,EAAK9nB,QACP6nB,EAAe5R,KACbuH,GACE,IACKnkB,EACHH,OAAQ,IACHG,EAAQH,OACXC,OAAQ2uB,EAAK,GACbxuB,QAASwuB,EAAK,MAGlB,CAACliB,EAAO+c,KAEN,GAAI/c,EACF,MAAMA,EAIR8I,EACEiU,EAAKtpB,QAAQH,OAAOI,QACS,QAA7BqpB,EAAKtpB,QAAQH,OAAOZ,KAChBsqB,OAAOC,KAAKF,EAAKhG,OAAQ,UACzBgG,EAAKhG,OACV,KAOX,UAEQpV,QAAQ+G,IAAIuZ,SAGZ/L,IACP,CAAC,MAAOlW,GACP,MAAM,IAAI8G,GACR,kDACAM,SAASpH,EACZ,GWpED4X,eAGApD,YACA0B,YAGA5L,WrBjFwB,CAACS,EAAavY,KAElCA,GAAM4H,SAER6K,GA6NJ,SAAwBzS,GAEtB,MAAM2vB,EAAc3vB,EAAK4vB,WACtBC,GAAkC,eAA1BA,EAAI1d,QAAQ,KAAM,MAI7B,GAAIwd,GAAe,GAAK3vB,EAAK2vB,EAAc,GAAI,CAC7C,MAAMG,EAAW9vB,EAAK2vB,EAAc,GACpC,IAEE,GAAIG,GAAYA,EAASphB,SAAS,SAEhC,OAAO6B,KAAK/D,MAAMyD,EAAa6f,GAElC,CAAC,MAAOtiB,GACPQ,EACE,EACAR,EACA,sDAAsDsiB,UAEzD,CACF,CAGD,MAAO,EACT,CAvPqBC,CAAe/vB,IAIlC8S,GAAoBhT,EAAe2S,IAGnCA,GAAiBS,GAAYpT,GAGzByY,IAEF9F,GAAiBE,GACfF,GACA8F,EACAnS,IAKApG,GAAM4H,SAER6K,GA+RJ,SAA2BxR,EAASjB,EAAMF,GACxC,IAAIkwB,GAAY,EAChB,IAAK,IAAIpe,EAAI,EAAGA,EAAI5R,EAAK4H,OAAQgK,IAAK,CACpC,MAAMJ,EAASxR,EAAK4R,GAAGO,QAAQ,KAAM,IAG/B8d,EAAkB5pB,EAAWmL,GAC/BnL,EAAWmL,GAAQhK,MAAM,KACzB,GAGJ,IAAI0oB,EACJD,EAAgB3E,QAAO,CAAC/kB,EAAK+S,EAAM4V,KAC7Be,EAAgBroB,OAAS,IAAMsnB,IACjCgB,EAAe3pB,EAAI+S,GAAMpZ,MAEpBqG,EAAI+S,KACVxZ,GAEHmwB,EAAgB3E,QAAO,CAAC/kB,EAAK+S,EAAM4V,KAC7Be,EAAgBroB,OAAS,IAAMsnB,QAER,IAAd3oB,EAAI+S,KACTtZ,IAAO4R,GACY,YAAjBse,EACF3pB,EAAI+S,GAAQrH,GAAUjS,EAAK4R,IACD,WAAjBse,EACT3pB,EAAI+S,IAAStZ,EAAK4R,GACTse,EAAa/a,QAAQ,MAAQ,EACtC5O,EAAI+S,GAAQtZ,EAAK4R,GAAGpK,MAAM,KAE1BjB,EAAI+S,GAAQtZ,EAAK4R,IAGnBlE,EACE,EACA,mCAAmC8D,yCAErCwe,GAAY,IAIXzpB,EAAI+S,KACVrY,EACJ,CAGG+uB,GACF5e,IAGF,OAAOnQ,CACT,CAnVqBkvB,CAAkB1d,GAAgBzS,EAAMF,IAIpD2S,IqBoDPoc,mBAGAnhB,MACAM,eACAM,cACAC,oBAGA6hB,erB6C6BC,IAC7B,MAAMzd,EAAa,CAAA,EAEnB,IAAK,MAAO/B,EAAK5Q,KAAUwG,OAAOgL,QAAQ4e,GAAa,CACrD,MAAMJ,EAAkB5pB,EAAWwK,GAAOxK,EAAWwK,GAAKrJ,MAAM,KAAO,GAGvEyoB,EAAgB3E,QACd,CAAC/kB,EAAK+S,EAAM4V,IACT3oB,EAAI+S,GACH2W,EAAgBroB,OAAS,IAAMsnB,EAAQjvB,EAAQsG,EAAI+S,IAAS,IAChE1G,EAEH,CACD,OAAOA,CAAU,EqB1DjB0d,arBlD0BthB,MAAOuhB,IAEjC,IAAIC,EAAa,CAAA,EAGbpjB,EAAWmjB,KACbC,EAAajgB,KAAK/D,MAAMyD,EAAasgB,EAAgB,UAIvD,MAwDMxqB,EAAUU,OAAOC,KAAKlB,GAAeiC,KAAKgpB,IAAY,CAC1D3jB,MAAO,GAAG2jB,YACVxwB,MAAOwwB,MAIT,OAAOC,EACL,CACExwB,KAAM,cACNuF,KAAM,WACNC,QAAS,2CACTM,KAAM,yDACNF,aAAc,GACdC,WAEF,CAAE4qB,SAvEa3hB,MAAO4hB,EAAGC,KACzB,IAAIC,EAAmB,EACnBC,EAAe,GAGnB,IAAK,MAAMC,KAAWH,EAEpBrrB,EAAcwrB,GAAWxrB,EAAcwrB,GAASvpB,KAAK+J,IAAY,IAC5DA,EACHwf,cAIFD,EAAe,IAAIA,KAAiBvrB,EAAcwrB,IAuCpD,aApCMN,EAAQK,EAAc,CAC1BJ,SAAU3hB,MAAOiiB,EAAQC,KAgBvB,GAdoB,kBAAhBD,EAAOxrB,MACTyrB,EAASA,EAAOtpB,OACZspB,EAAOzpB,KAAK0pB,GAAWF,EAAOlrB,QAAQorB,KACtCF,EAAOlrB,QAEXyqB,EAAWS,EAAOD,SAASC,EAAOxrB,MAAQyrB,GAE1CV,EAAWS,EAAOD,SAAW5d,GAC3B3M,OAAO+M,OAAO,GAAIgd,EAAWS,EAAOD,UAAY,IAChDC,EAAOxrB,KAAK+B,MAAM,KAClBypB,EAAOlrB,QAAUkrB,EAAOlrB,QAAQmrB,GAAUA,KAIxCJ,IAAqBC,EAAanpB,OAAQ,CAC9C,UACQ+lB,EAAWyD,UACfb,EACAhgB,KAAKC,UAAUggB,EAAY,KAAM,GACjC,OAEH,CAAC,MAAOhjB,GACPQ,EACE,EACAR,EACA,iDAAiD+iB,UAEpD,CACD,OAAO,CACR,MAIE,CAAI,GAoBZ,EqB/BDc,UtB8KwBvsB,IAExB,MAAMwsB,EAAiB/gB,KAAK/D,MAC1ByD,EAAarK,EAAK+I,EAAW,kBAC7BtO,QAGEyE,EACF2I,QAAQC,IAAI,sCAAsC4jB,QAKpD7jB,QAAQC,IACNuC,EAAatB,EAAY,oBAAoBd,WAAWwD,KAAKC,OAC7D,IAAIggB,MAAmBjgB,KACxB,EsB7LDD"} \ No newline at end of file diff --git a/jest.config.js b/jest.config.js index f57f9616..4ee06fd5 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,7 +1,10 @@ -export default { +/** @type {import('jest').Config} */ +const config = { testEnvironment: 'jest-environment-node', testMatch: ['**/tests/unit/**/*.test.js'], transform: { // '^.+\\.test.js?$': 'babel-jest' } }; + +export default config; diff --git a/lib/browser.js b/lib/browser.js index bd42990d..a4820f9e 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -19,17 +19,74 @@ import puppeteer from 'puppeteer'; import { getCachePath } from './cache.js'; import { getOptions } from './config.js'; +import { envs } from './envs.js'; import { setupHighcharts } from './highcharts.js'; import { log, logWithStack } from './logger.js'; -import { __dirname } from './utils.js'; +import { __dirname, expBackoff } from './utils.js'; import ExportError from './errors/ExportError.js'; // Get the template for the page const template = readFileSync(__dirname + '/templates/template.html', 'utf8'); +// To save the browser let browser; +// To save the WebSocket endpoint in case of a sudden disconnect +let wsEndpoint; + +/** + * Reconnects to the browser instance when it is disconnected. If the current + * browser connection is lost, it attempts to reconnect using the previous + * WebSocket endpoint. If the reconnection fails, it will try to close the + * browser and relaunch a new instance. + */ +async function reconnect() { + try { + // Start the reconnecting + log(3, `[browser] Restarting the browser connection.`); + + // Try to reconnect the browser + if (browser && !browser.connected) { + browser = await puppeteer.connect({ + browserWSEndpoint: wsEndpoint + }); + } + + // Save a new WebSocket endpoint + wsEndpoint = browser.wsEndpoint(); + + // Add the reconnect event again + browser.on('disconnected', reconnect); + + // Log the success message + log(3, `[browser] Browser reconnected successfully.`); + } catch (error) { + logWithStack( + 1, + error, + '[browser] Could not restore the browser connection, attempting to relaunch.' + ); + + // Try to close the browser before relaunching + try { + await close(); + } catch (error) { + logWithStack( + 1, + error, + '[browser] Could not close the browser before relaunching (probably is already closed).' + ); + } + + // Try to relaunch the browser + await create(getOptions().puppeteer.args || []); + + // Log the success message + log(3, `[browser] Browser relaunched successfully.`); + } +} + /** * Retrieves the existing Puppeteer browser instance. * @@ -41,7 +98,7 @@ let browser; */ export function get() { if (!browser) { - throw new ExportError('[browser] No valid browser has been created.'); + throw new ExportError('[browser] No valid browser has been created.', 500); } return browser; } @@ -68,6 +125,8 @@ export async function create(puppeteerArgs) { headless: other.browserShellMode ? 'shell' : true, userDataDir: './tmp/', args: puppeteerArgs, + // Must be disabled for debugging to work + pipe: envs.OTHER_CONNECTION_OVER_PIPE, handleSIGINT: false, handleSIGTERM: false, handleSIGHUP: false, @@ -86,7 +145,26 @@ export async function create(puppeteerArgs) { 3, `[browser] Attempting to get a browser instance (try ${++tryCount}).` ); + + // Launch the browser browser = await puppeteer.launch(launchOptions); + + // Close the initial pages if any found + const pages = await browser.pages(); + if (pages) { + for (const page of pages) { + await page.close(); + } + } + + // Only for the WebSocket connection + if (!launchOptions.pipe) { + // Save WebSocket endpoint + wsEndpoint = browser.wsEndpoint(); + + // Attach the disconnected event + browser.on('disconnected', reconnect); + } } catch (error) { logWithStack( 1, @@ -119,12 +197,13 @@ export async function create(puppeteerArgs) { } } catch (error) { throw new ExportError( - '[browser] Maximum retries to open a browser instance reached.' + '[browser] Maximum retries to open a browser instance reached.', + 500 ).setError(error); } if (!browser) { - throw new ExportError('[browser] Cannot find a browser to open.'); + throw new ExportError('[browser] Cannot find a browser to open.', 500); } } @@ -139,10 +218,11 @@ export async function create(puppeteerArgs) { * is closed. */ export async function close() { - // Close the browser when connnected - if (browser?.connected) { + // Close the browser when connected + if (browser && browser.connected) { await browser.close(); } + browser = null; log(4, '[browser] Closed the browser.'); } @@ -154,33 +234,51 @@ export async function close() { * The function creates a new page, disables caching, sets content using * setPageContent(), and returns the created Puppeteer Page. * + * @param {Object} poolResource - The pool resource that contians page and id. + * * @returns {(boolean|object)} Returns false if the browser instance is not * available, or a Puppeteer Page object representing the newly created page. */ -export async function newPage() { - if (!browser) { - return false; +export async function newPage(poolResource) { + const startDate = new Date().getTime(); + + // Throw an error in case of no connected browser + if (!browser || !browser.connected) { + throw new ExportError(`[browser] Browser is not yet connected.`, 500); } // Create a page - const page = await browser.newPage(); + poolResource.page = await browser.newPage(); // Disable cache - await page.setCacheEnabled(false); + await poolResource.page.setCacheEnabled(false); // Set the content - await setPageContent(page); + await setPageContent(poolResource.page); // Set page events - setPageEvents(page); + setPageEvents(poolResource); + + // Check if the page is correctly created + if (!poolResource.page || poolResource.page.isClosed()) { + throw new ExportError('The page is invalid or closed.', 500); + } - return page; + log( + 3, + `[pool] Pool resource [${poolResource.id}] - Successfully created a worker, took ${ + new Date().getTime() - startDate + }ms.` + ); + + // Return the resource with a ready to use page + return poolResource; } /** * Clears the content of a Puppeteer Page based on the specified mode. * - * @param {Object} page - The Puppeteer Page object to be cleared. + * @param {Object} poolResource - The pool resource that contians page and id. * @param {boolean} hardReset - A flag indicating the type of clearing * to be performed. If true, navigates to 'about:blank' and resets content * and scripts. If false, clears the body content by setting a predefined HTML @@ -188,18 +286,20 @@ export async function newPage() { * * @throws {Error} Logs thrown error if clearing the page content fails. */ -export async function clearPage(page, hardReset = false) { +export async function clearPage(poolResource, hardReset = false) { try { - if (!page.isClosed()) { + if (!poolResource.page.isClosed()) { if (hardReset) { // Navigate to about:blank - await page.goto('about:blank', { waitUntil: 'domcontentloaded' }); + await poolResource.page.goto('about:blank', { + waitUntil: 'domcontentloaded' + }); // Set the content and and scripts again - await setPageContent(page); + await setPageContent(poolResource.page); } else { // Clear body content - await page.evaluate(() => { + await poolResource.page.evaluate(() => { document.body.innerHTML = '
'; }); @@ -209,8 +309,10 @@ export async function clearPage(page, hardReset = false) { logWithStack( 2, error, - '[browser] Could not clear the content of the page.' + `[pool] Pool resource [${poolResource.id}] - Content of the page could not be cleared.` ); + // Set the `workLimit` to exceeded in order to recreate the resource + poolResource.workCount = getOptions().pool.workLimit + 1; } } @@ -328,45 +430,49 @@ export async function addPageResources(page, options) { * to be cleared. */ export async function clearPageResources(page, injectedResources) { - for (const resource of injectedResources) { - await resource.dispose(); - } + try { + for (const resource of injectedResources) { + await resource.dispose(); + } - // Destroy old charts after export is done and reset all CSS and script tags - await page.evaluate(() => { - // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG - // exports - if (typeof Highcharts !== 'undefined') { - // eslint-disable-next-line no-undef - const oldCharts = Highcharts.charts; - - // Check in any already existing charts - if (Array.isArray(oldCharts) && oldCharts.length) { - // Destroy old charts - for (const oldChart of oldCharts) { - oldChart && oldChart.destroy(); - // eslint-disable-next-line no-undef - Highcharts.charts.shift(); + // Destroy old charts after export is done and reset all CSS and script tags + await page.evaluate(() => { + // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG + // exports + if (typeof Highcharts !== 'undefined') { + // eslint-disable-next-line no-undef + const oldCharts = Highcharts.charts; + + // Check in any already existing charts + if (Array.isArray(oldCharts) && oldCharts.length) { + // Destroy old charts + for (const oldChart of oldCharts) { + oldChart && oldChart.destroy(); + // eslint-disable-next-line no-undef + Highcharts.charts.shift(); + } } } - } - // eslint-disable-next-line no-undef - const [...scriptsToRemove] = document.getElementsByTagName('script'); - // eslint-disable-next-line no-undef - const [, ...stylesToRemove] = document.getElementsByTagName('style'); - // eslint-disable-next-line no-undef - const [...linksToRemove] = document.getElementsByTagName('link'); - - // Remove tags - for (const element of [ - ...scriptsToRemove, - ...stylesToRemove, - ...linksToRemove - ]) { - element.remove(); - } - }); + // eslint-disable-next-line no-undef + const [...scriptsToRemove] = document.getElementsByTagName('script'); + // eslint-disable-next-line no-undef + const [, ...stylesToRemove] = document.getElementsByTagName('style'); + // eslint-disable-next-line no-undef + const [...linksToRemove] = document.getElementsByTagName('link'); + + // Remove tags + for (const element of [ + ...scriptsToRemove, + ...stylesToRemove, + ...linksToRemove + ]) { + element.remove(); + } + }); + } catch (error) { + logWithStack(1, error, `[browser] Could not clear page's resources.`); + } } /** @@ -390,24 +496,17 @@ async function setPageContent(page) { /** * Set events for a Puppeteer Page. * - * @param {Object} page - The Puppeteer Page object to set events to. + * @param {Object} poolResource - The pool resource that contians page and id. */ -function setPageEvents(page) { +function setPageEvents(poolResource) { // Get debug options - const { debug } = getOptions(); - - // Set the console listener, if needed - if (debug.enable && debug.listenToConsole) { - page.on('console', (message) => { - console.log(`[debug] ${message.text()}`); - }); - } + const { debug, pool } = getOptions(); // Set the pageerror listener - page.on('pageerror', async (error) => { + poolResource.page.on('pageerror', async (error) => { // TODO: Consider adding a switch here that turns on log(0) logging // on page errors. - await page.$eval( + await poolResource.page.$eval( '#container', (element, errorMessage) => { // eslint-disable-next-line no-undef @@ -418,6 +517,66 @@ function setPageEvents(page) { `

Chart input data error:

${error.toString()}` ); }); + + // Set the console listener, if needed + if (debug.enable && debug.listenToConsole) { + poolResource.page.on('console', (message) => { + console.log(`[debug] ${message.text()}`); + }); + } + + // Add the framedetached event if the connection is over WebSocket + if (envs.OTHER_CONNECTION_OVER_PIPE === false) { + poolResource.page.on('framedetached', async (frame) => { + // Get the main frame + const mainFrame = poolResource.page.mainFrame(); + + // Check if a page's frame is detached and requires to be recreated + if ( + frame === mainFrame && + mainFrame.detached && + poolResource.workCount <= pool.workLimit + ) { + log( + 3, + `[browser] Pool resource [${poolResource.id}] - Page's frame detached.` + ); + try { + // Try to connect to a new page using exponential backoff strategy + expBackoff( + async (poolResourceId, poolResource) => { + try { + // Try to close the page with a detached frame + if (!poolResource.page.isClosed()) { + await poolResource.page.close(); + } + } catch (error) { + log( + 3, + `[browser] Pool resource [${poolResourceId}] - Could not close the page with a detached frame.` + ); + } + + // Trigger a page creation + await newPage(poolResource); + }, + 0, + poolResource.id, + poolResource + ); + } catch (error) { + logWithStack( + 3, + error, + `[browser] Pool resource [${poolResource.id}] - Could not create a new page.` + ); + + // Set the `workLimit` to exceeded in order to recreate the resource + poolResource.workCount = pool.workLimit + 1; + } + } + }); + } } export default { diff --git a/lib/cache.js b/lib/cache.js index cd712a15..1a640498 100644 --- a/lib/cache.js +++ b/lib/cache.js @@ -17,7 +17,7 @@ See LICENSE file in root for details. // before starting the service import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs'; -import { join } from 'path'; +import { isAbsolute, join } from 'path'; import { HttpsProxyAgent } from 'https-proxy-agent'; @@ -83,14 +83,15 @@ export const saveConfigToManifest = async (config, fetchedModules) => { log(3, '[cache] Writing a new manifest.'); try { writeFileSync( - join(__dirname, config.cachePath, 'manifest.json'), + join(getCachePath(), 'manifest.json'), JSON.stringify(newManifest), 'utf8' ); } catch (error) { - throw new ExportError('[cache] Error writing the cache manifest.').setError( - error - ); + throw new ExportError( + '[cache] Error writing the cache manifest.', + 400 + ).setError(error); } }; @@ -139,7 +140,8 @@ export const fetchAndProcessScript = async ( if (shouldThrowError) { throw new ExportError( - `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).` + `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`, + 500 ).setError(response); } else { log( @@ -185,9 +187,10 @@ export const fetchScripts = async ( port: proxyPort }); } catch (error) { - throw new ExportError('[cache] Could not create a Proxy Agent.').setError( - error - ); + throw new ExportError( + '[cache] Could not create a Proxy Agent.', + 500 + ).setError(error); } } @@ -269,7 +272,8 @@ export const updateCache = async ( return fetchedModules; } catch (error) { throw new ExportError( - '[cache] Unable to update the local Highcharts cache.' + '[cache] Unable to update the local Highcharts cache.', + 500 ).setError(error); } }; @@ -306,15 +310,17 @@ export const updateVersion = async (newVersion) => { */ export const checkAndUpdateCache = async (options) => { const { highcharts, server } = options; - const cachePath = join(__dirname, highcharts.cachePath); + + const cachePath = getCachePath(); let fetchedModules; + // Prepare paths to manifest and sources from the .cache folder const manifestPath = join(cachePath, 'manifest.json'); const sourcePath = join(cachePath, 'sources.js'); // Create the cache destination if it doesn't exist already - !existsSync(cachePath) && mkdirSync(cachePath); + !existsSync(cachePath) && mkdirSync(cachePath, { recursive: true }); // Fetch all the scripts either if manifest.json does not exist // or if the forceFetch option is enabled @@ -387,8 +393,18 @@ export const checkAndUpdateCache = async (options) => { await saveConfigToManifest(highcharts, fetchedModules); }; -export const getCachePath = () => - join(__dirname, getOptions().highcharts.cachePath); +/** + * Returns the path to the cache folder. + * @returns {string} The path to the cache folder. + */ +export const getCachePath = () => { + const cachePathOption = getOptions().highcharts.cachePath; + + // issue #562: support for absolute paths + return isAbsolute(cachePathOption) + ? cachePathOption + : join(__dirname, cachePathOption); +}; export const getCache = () => cache; diff --git a/lib/chart.js b/lib/chart.js index 47b28f8d..74de2371 100644 --- a/lib/chart.js +++ b/lib/chart.js @@ -70,7 +70,7 @@ export const startExport = async (settings, endCallback) => { return result; } catch (error) { return endCallback( - new ExportError('[chart] Error loading SVG input.').setError(error) + new ExportError('[chart] Error loading SVG input.', 400).setError(error) ); } } @@ -84,7 +84,9 @@ export const startExport = async (settings, endCallback) => { return exportAsString(options.export.instr.trim(), options, endCallback); } catch (error) { return endCallback( - new ExportError('[chart] Error loading input file.').setError(error) + new ExportError('[chart] Error loading input file.', 400).setError( + error + ) ); } } @@ -112,7 +114,7 @@ export const startExport = async (settings, endCallback) => { ); } catch (error) { return endCallback( - new ExportError('[chart] Error loading raw input.').setError(error) + new ExportError('[chart] Error loading raw input.', 400).setError(error) ); } } @@ -120,7 +122,8 @@ export const startExport = async (settings, endCallback) => { // No input specified, pass an error message to the callback return endCallback( new ExportError( - `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.` + `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`, + 400 ) ); }; @@ -344,7 +347,8 @@ const doExport = async (options, chartJson, endCallback, svg) => { // these settings. return endCallback( new ExportError( - `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.` + `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`, + 400 ) ); } @@ -489,7 +493,8 @@ const doStraightInject = (options, endCallback) => { } catch (error) { return endCallback( new ExportError( - `[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.` + `[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.`, + 400 ).setError(error) ); } @@ -522,6 +527,15 @@ const exportAsString = (stringToExport, options, endCallback) => { // Try to parse to JSON and call the doExport function const chartJSON = JSON.parse(stringToExport.replaceAll(/\t|\n|\r/g, ' ')); + if (!chartJSON || typeof chartJSON !== 'object') { + return endCallback( + new ExportError( + '[chart] Invalid configuration provided - the options must be an object, not a string', + 400 + ) + ); + } + // If a correct JSON, do the export return doExport(options, chartJSON, endCallback); } catch (error) { @@ -532,7 +546,8 @@ const exportAsString = (stringToExport, options, endCallback) => { // Do not allow straight injection without the allowCodeExecution flag return endCallback( new ExportError( - '[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.' + '[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.', + 400 ).setError(error) ); } diff --git a/lib/envs.js b/lib/envs.js index 885d7f07..96488f8b 100644 --- a/lib/envs.js +++ b/lib/envs.js @@ -176,6 +176,7 @@ export const Config = z.object({ POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(), POOL_REAPER_INTERVAL: v.nonNegativeNum(), POOL_BENCHMARKING: v.boolean(), + POOL_RESOURCES_INTERVAL: v.nonNegativeNum(), // logger LOGGING_LEVEL: z @@ -207,6 +208,7 @@ export const Config = z.object({ OTHER_NO_LOGO: v.boolean(), OTHER_HARD_RESET_PAGE: v.boolean(), OTHER_BROWSER_SHELL_MODE: v.boolean(), + OTHER_CONNECTION_OVER_PIPE: v.boolean(), // debugger DEBUG_ENABLE: v.boolean(), diff --git a/lib/errors/ExportError.js b/lib/errors/ExportError.js index be659551..6e5b8160 100644 --- a/lib/errors/ExportError.js +++ b/lib/errors/ExportError.js @@ -1,22 +1,35 @@ class ExportError extends Error { - constructor(message) { + /** + * @param {string} message + * @param {number} [status] describes the status code (400, 500, etc.) + */ + constructor(message, status) { super(); + this.message = message; this.stackMessage = message; + + if (status) { + this.status = status; + } } setError(error) { this.error = error; + if (error.name) { this.name = error.name; } - if (error.statusCode) { - this.statusCode = error.statusCode; + + if (!this.status && error.statusCode) { + this.status = error.statusCode; } + if (error.stack) { this.stackMessage = error.message; this.stack = error.stack; } + return this; } } diff --git a/lib/export.js b/lib/export.js index 5ccd8629..a93b43c4 100644 --- a/lib/export.js +++ b/lib/export.js @@ -72,7 +72,7 @@ const createImage = (page, type, encoding, clip, rasterizationTimeout) => }), new Promise((_resolve, reject) => setTimeout( - () => reject(new ExportError('Rasterization timeout')), + () => reject(new ExportError('Rasterization timeout', 408)), rasterizationTimeout || 1500 ) ) @@ -106,7 +106,7 @@ const createPDF = async ( }), new Promise((_resolve, reject) => setTimeout( - () => reject(new ExportError('Rasterization timeout')), + () => reject(new ExportError('Rasterization timeout', 408)), rasterizationTimeout || 1500 ) ) @@ -294,7 +294,8 @@ export default async (page, chart, options) => { ); } else { throw new ExportError( - `[export] Unsupported output format ${exportOptions.type}.` + `[export] Unsupported output format ${exportOptions.type}.`, + 400 ); } diff --git a/lib/highcharts.js b/lib/highcharts.js index e82a2213..5e4b1df6 100644 --- a/lib/highcharts.js +++ b/lib/highcharts.js @@ -95,7 +95,7 @@ export async function triggerExport(chartOptions, options, displayErrors) { const userOptions = options.export.strInj ? new Function(`return ${options.export.strInj}`)() : chartOptions; - + // Trigger custom code if (options.customLogic.customCode) { new Function('options', options.customLogic.customCode)(userOptions); diff --git a/lib/pool.js b/lib/pool.js index 6a875a5e..ce27fd99 100644 --- a/lib/pool.js +++ b/lib/pool.js @@ -21,7 +21,9 @@ import { newPage, clearPage } from './browser.js'; +import { envs } from './envs.js'; import puppeteerExport from './export.js'; +import { addInterval } from './intervals.js'; import { log, logWithStack } from './logger.js'; import { measureTime } from './utils.js'; @@ -53,74 +55,94 @@ const factory = { * page. */ create: async () => { - let page = false; - - const id = uuid(); - const startDate = new Date().getTime(); - try { - page = await newPage(); - - if (!page || page.isClosed()) { - throw new ExportError('The page is invalid or closed.'); - } + const poolResource = { + id: uuid(), + // Try to distribute the initial work count + workCount: Math.round(Math.random() * (poolConfig.workLimit / 2)) + }; - log( - 3, - `[pool] Successfully created a worker ${id} - took ${ - new Date().getTime() - startDate - } ms.` - ); + return await newPage(poolResource); } catch (error) { throw new ExportError( - 'Error encountered when creating a new page.' + 'Error encountered when creating a new page.', + 500 ).setError(error); } - - return { - id, - page, - // Try to distribute the initial work count - workCount: Math.round(Math.random() * (poolConfig.workLimit / 2)) - }; }, /** * Validates a worker page in the export pool, checking if it has exceeded * the work limit. * - * @param {Object} workerHandle - The handle to the worker, containing the + * @param {Object} poolResource - The handle to the worker, containing the * worker's ID, a reference to the browser page, and work count. * * @returns {boolean} - Returns true if the worker is valid and within * the work limit; otherwise, returns false. */ - validate: async (workerHandle) => { + validate: async (poolResource) => { + let validated = true; + + // Check if the `workLimit` is exceeded if ( poolConfig.workLimit && - ++workerHandle.workCount > poolConfig.workLimit + ++poolResource.workCount > poolConfig.workLimit ) { log( 3, - `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).` + `[pool] Pool resource [${poolResource.id}] - Validation failed (exceeded the ${poolConfig.workLimit} works limit).` ); - return false; + validated = false; + } + + // Check if the `page` is not valid + if (!poolResource.page) { + // Check if the `page` is closed + if (poolResource.page.isClosed()) { + log( + 3, + `[pool] Pool resource [${poolResource.id}] - Validation failed (page is closed or invalid).` + ); + } + + // Check if the `mainFrame` is detached + if (poolResource.page.mainFrame().detached) { + log( + 3, + `[pool] Pool resource [${poolResource.id}] - Validation failed (page's frame is detached).` + ); + } + validated = false; } - return true; + + return validated; }, /** * Destroys a worker entry in the export pool, closing its associated page. * - * @param {Object} workerHandle - The handle to the worker, containing + * @param {Object} poolResource - The handle to the worker, containing * the worker's ID and a reference to the browser page. */ - destroy: async (workerHandle) => { - log(3, `[pool] Destroying pool entry ${workerHandle.id}.`); + destroy: async (poolResource) => { + log(3, `[pool] Pool resource [${poolResource.id}] - Destroying a worker.`); + + if (poolResource.page) { + try { + // Remove all attached event listeners from the resource + poolResource.page.removeAllListeners('pageerror'); + poolResource.page.removeAllListeners('console'); + poolResource.page.removeAllListeners('framedetached'); - if (workerHandle.page) { - // We don't really need to wait around for this - await workerHandle.page.close(); + // We need to wait around for this + await poolResource.page.close(); + } catch (error) { + log( + 3, + `[pool] Pool resource [${poolResource.id}] - Page could not be closed upon destroying.` + ); + } } } }; @@ -173,13 +195,16 @@ export const initPool = async (config) => { // Set events pool.on('release', async (resource) => { - // Clear page - await clearPage(resource.page, false); - log(4, `[pool] Releasing a worker with ID ${resource.id}.`); + log(4, `[pool] Pool resource [${resource.id}] - Releasing a worker.`); + await clearPage(resource, false); }); - pool.on('destroySuccess', (eventId, resource) => { - log(4, `[pool] Destroyed a worker with ID ${resource.id}.`); + pool.on('destroySuccess', (_eventId, resource) => { + log( + 4, + `[pool] Pool resource [${resource.id}] - Destroyed a worker successfully.` + ); + resource.page = null; }); const initialResources = []; @@ -198,13 +223,20 @@ export const initPool = async (config) => { pool.release(resource); }); + // Init the interval for checking if the minimum number of resources exist + if (envs.POOL_RESOURCES_INTERVAL) { + // Register interval for the later clearing + addInterval(_checkingResourcesInterval(envs.POOL_RESOURCES_INTERVAL)); + } + log( 3, `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}` ); } catch (error) { throw new ExportError( - '[pool] Could not create the pool of workers.' + '[pool] Could not create the pool of workers.', + 500 ).setError(error); } }; @@ -226,11 +258,17 @@ export async function killPool() { pool.release(worker.resource); } + // Remove all attached event listeners from the pool + pool.removeAllListeners('release'); + pool.removeAllListeners('destroySuccess'); + pool.removeAllListeners('destroyFail'); + // Destroy the pool if it is still available if (!pool.destroyed) { await pool.destroy(); log(4, '[browser] Destroyed the pool of resources.'); } + pool = null; } // Close the browser instance @@ -262,7 +300,10 @@ export const postWork = async (chart, options) => { } if (!pool) { - throw new ExportError('Work received, but pool has not been started.'); + throw new ExportError( + 'Work received, but pool has not been started.', + 500 + ); } // Acquire the worker along with the id of resource and work count @@ -292,15 +333,21 @@ export const postWork = async (chart, options) => { log(4, '[pool] Acquired a worker handle.'); if (!workerHandle.page) { + // Set the `workLimit` to exceeded in order to recreate the resource + workerHandle.workCount = poolConfig.workLimit + 1; throw new ExportError( - 'Resolved worker page is invalid: the pool setup is wonky.' + 'Resolved worker page is invalid: the pool setup is wonky.', + 500 ); } // Save the start time let workStart = new Date().getTime(); - log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`); + log( + 4, + `[pool] Pool resource [${workerHandle.id}] - Starting work on this pool entry.` + ); // Perform an export on a puppeteer level const exportCounter = measureTime(); @@ -308,10 +355,9 @@ export const postWork = async (chart, options) => { // Check if it's an error if (result instanceof Error) { - // TODO: If the export failed because puppeteer timed out, we need to force kill the worker so we get a new page. That needs to be handled better than this hack. if (result.message === 'Rasterization timeout') { - workerHandle.page.close(); - workerHandle.page = await newPage(); + // Set the `workLimit` to exceeded in order to recreate the resource + workerHandle.workCount = poolConfig.workLimit + 1; } throw new ExportError( @@ -379,10 +425,20 @@ export const getPool = () => pool; export const getPoolInfoJSON = () => ({ min: pool.min, max: pool.max, - all: pool.numFree() + pool.numUsed(), - available: pool.numFree(), used: pool.numUsed(), - pending: pool.numPendingAcquires() + available: pool.numFree(), + allCreated: pool.numUsed() + pool.numFree(), + pendingAcquires: pool.numPendingAcquires(), + pendingCreates: pool.numPendingCreates(), + pendingValidations: pool.numPendingValidations(), + pendingDestroys: pool.pendingDestroys.length, + absoluteAll: + pool.numUsed() + + pool.numFree() + + pool.numPendingAcquires() + + pool.numPendingCreates() + + pool.numPendingValidations() + + pool.pendingDestroys.length }); /** @@ -391,14 +447,83 @@ export const getPoolInfoJSON = () => ({ * requests. */ export function getPoolInfo() { - const { min, max, all, available, used, pending } = getPoolInfoJSON(); + const { + min, + max, + used, + available, + allCreated, + pendingAcquires, + pendingCreates, + pendingValidations, + pendingDestroys, + absoluteAll + } = getPoolInfoJSON(); log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`); log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`); - log(5, `[pool] The number of all created resources: ${all}.`); - log(5, `[pool] The number of available resources: ${available}.`); - log(5, `[pool] The number of acquired resources: ${used}.`); - log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`); + log(5, `[pool] The number of used resources: ${used}.`); + log(5, `[pool] The number of free resources: ${available}.`); + log( + 5, + `[pool] The number of all created (used and free) resources: ${allCreated}.` + ); + log( + 5, + `[pool] The number of resources waiting to be acquired: ${pendingAcquires}.` + ); + log( + 5, + `[pool] The number of resources waiting to be created: ${pendingCreates}.` + ); + log( + 5, + `[pool] The number of resources waiting to be validated: ${pendingValidations}.` + ); + log( + 5, + `[pool] The number of resources waiting to be destroyed: ${pendingDestroys}.` + ); + log(5, `[pool] The number of all resources: ${absoluteAll}.`); +} + +/** + * Periodically checks and ensures the minimum number of resources in the pool. + * If the total number of used, free and about to be created resources falls + * below the minimum set with the `pool.min`, it creates additional resources to + * meet the minimum requirement. + * + * @param {number} resourceCheckInterval - The interval, in milliseconds, at + * which the pool resources are checked. + * + * @returns {NodeJS.Timeout} - Returns a timer ID that can be used to clear the + * interval later. + */ +function _checkingResourcesInterval(resourceCheckInterval) { + // Set the interval for checking the number of pool resources + return setInterval(async () => { + try { + // Get the current number of resources + let currentNumber = + pool.numUsed() + pool.numFree() + pool.numPendingCreates(); + + // Create missing resources + while (currentNumber++ < pool.min) { + try { + // Explicitly creating a resource + await pool._doCreate(); + } catch (error) { + logWithStack(2, error, '[pool] Could not create a missing resource.'); + } + } + } catch (error) { + logWithStack( + 1, + error, + `[pool] Something went wrong when trying to create missing resources.` + ); + } + }, resourceCheckInterval); } export default { diff --git a/lib/resource_release.js b/lib/resource_release.js index 1d8e85ce..10d47428 100644 --- a/lib/resource_release.js +++ b/lib/resource_release.js @@ -15,6 +15,7 @@ See LICENSE file in root for details. import { clearAllIntervals } from './intervals.js'; import { killPool } from './pool.js'; import { closeServers } from './server/server.js'; +import { get as getBrowser } from './browser.js'; /** * Clean up function to trigger before ending process for the graceful shutdown. @@ -22,6 +23,9 @@ import { closeServers } from './server/server.js'; * @param {number} exitCode - An exit code for the process.exit() function. */ export const shutdownCleanUp = async (exitCode) => { + // Remove all attached event listeners from the browser + getBrowser().removeAllListeners('disconnected'); + // Await freeing all resources await Promise.allSettled([ // Clear all ongoing intervals diff --git a/lib/server/server.js b/lib/server/server.js index 45c03b86..286dda24 100644 --- a/lib/server/server.js +++ b/lib/server/server.js @@ -43,7 +43,11 @@ const app = express(); app.disable('x-powered-by'); // Enable CORS support -app.use(cors()); +app.use( + cors({ + methods: ['POST', 'GET', 'OPTIONS'] + }) +); // Enable parsing of form data (files) with Multer package const storage = multer.memoryStorage(); @@ -185,7 +189,8 @@ export const startServer = async (serverConfig) => { errorHandler(app); } catch (error) { throw new ExportError( - '[server] Could not configure and start the server.' + '[server] Could not configure and start the server.', + 500 ).setError(error); } }; diff --git a/lib/utils.js b/lib/utils.js index 6823c003..f0535326 100644 --- a/lib/utils.js +++ b/lib/utils.js @@ -70,7 +70,7 @@ export const expBackoff = async (fn, attempt = 0, ...args) => { await new Promise((response) => setTimeout(response, delayInMs)); log( 3, - `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.` + `[pool] Waited ${delayInMs}ms until next call for the resource of ID: ${args[0]}.` ); // Try again diff --git a/package-lock.json b/package-lock.json index 172be3fe..993b5130 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "highcharts-export-server", - "version": "4.0.2", + "version": "4.0.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "highcharts-export-server", - "version": "4.0.2", + "version": "4.0.3", "hasInstallScript": true, "license": "MIT", "dependencies": { @@ -20,7 +20,7 @@ "jsdom": "^24.1.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.12.1", + "puppeteer": "^23.5.3", "tarn": "^3.0.2", "uuid": "^10.0.0", "zod": "^3.23.8" @@ -1289,19 +1289,18 @@ } }, "node_modules/@puppeteer/browsers": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.2.3.tgz", - "integrity": "sha512-bJ0UBsk0ESOs6RFcLXOt99a3yTDcOKlzfjad+rhFwdaG1Lu/Wzq58GHYCDTlZ9z6mldf4g+NTb+TXEfe0PpnsQ==", - "license": "Apache-2.0", - "dependencies": { - "debug": "4.3.4", - "extract-zip": "2.0.1", - "progress": "2.0.3", - "proxy-agent": "6.4.0", - "semver": "7.6.0", - "tar-fs": "3.0.5", - "unbzip2-stream": "1.4.3", - "yargs": "17.7.2" + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", + "integrity": "sha512-x8J1csfIygOwf6D6qUAZ0ASk3z63zPb7wkNeHRerCMh82qWKUrOgkuP005AJC8lDL6/evtXETGEJVcwykKT4/g==", + "dependencies": { + "debug": "^4.3.6", + "extract-zip": "^2.0.1", + "progress": "^2.0.3", + "proxy-agent": "^6.4.0", + "semver": "^7.6.3", + "tar-fs": "^3.0.6", + "unbzip2-stream": "^1.4.3", + "yargs": "^17.7.2" }, "bin": { "browsers": "lib/cjs/main-cli.js" @@ -1310,43 +1309,10 @@ "node": ">=18" } }, - "node_modules/@puppeteer/browsers/node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", - "license": "MIT", - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/@puppeteer/browsers/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@puppeteer/browsers/node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "license": "ISC", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", + "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", "bin": { "semver": "bin/semver.js" }, @@ -1354,12 +1320,6 @@ "node": ">=10" } }, - "node_modules/@puppeteer/browsers/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC" - }, "node_modules/@rollup/plugin-terser": { "version": "0.4.4", "resolved": "https://registry.npmjs.org/@rollup/plugin-terser/-/plugin-terser-0.4.4.tgz", @@ -1384,224 +1344,208 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", - "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", + "integrity": "sha512-Q6HJd7Y6xdB48x8ZNVDOqsbh2uByBhgK8PiQgPhwkIw/HC/YX5Ghq2mQY5sRMZWHb3VsFkWooUVOZHKr7DmDIA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", - "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.24.0.tgz", + "integrity": "sha512-ijLnS1qFId8xhKjT81uBHuuJp2lU4x2yxa4ctFPtG+MqEE6+C5f/+X/bStmxapgmwLwiL3ih122xv8kVARNAZA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", - "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.24.0.tgz", + "integrity": "sha512-bIv+X9xeSs1XCk6DVvkO+S/z8/2AMt/2lMqdQbMrmVpgFvXlmde9mLcbQpztXm1tajC3raFDqegsH18HQPMYtA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", - "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.24.0.tgz", + "integrity": "sha512-X6/nOwoFN7RT2svEQWUsW/5C/fYMBe4fnLK9DQk4SX4mgVBiTA9h64kjUYPvGQ0F/9xwJ5U5UfTbl6BEjaQdBQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", - "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.24.0.tgz", + "integrity": "sha512-0KXvIJQMOImLCVCz9uvvdPgfyWo93aHHp8ui3FrtOP57svqrF/roSSR5pjqL2hcMp0ljeGlU4q9o/rQaAQ3AYA==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", - "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.24.0.tgz", + "integrity": "sha512-it2BW6kKFVh8xk/BnHfakEeoLPv8STIISekpoF+nBgWM4d55CZKc7T4Dx1pEbTnYm/xEKMgy1MNtYuoA8RFIWw==", "cpu": [ "arm" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", - "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.24.0.tgz", + "integrity": "sha512-i0xTLXjqap2eRfulFVlSnM5dEbTVque/3Pi4g2y7cxrs7+a9De42z4XxKLYJ7+OhE3IgxvfQM7vQc43bwTgPwA==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", - "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.24.0.tgz", + "integrity": "sha512-9E6MKUJhDuDh604Qco5yP/3qn3y7SLXYuiC0Rpr89aMScS2UAmK1wHP2b7KAa1nSjWJc/f/Lc0Wl1L47qjiyQw==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", - "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.24.0.tgz", + "integrity": "sha512-2XFFPJ2XMEiF5Zi2EBf4h73oR1V/lycirxZxHZNc93SqDN/IWhYYSYj8I9381ikUFXZrz2v7r2tOVk2NBwxrWw==", "cpu": [ "ppc64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", - "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.24.0.tgz", + "integrity": "sha512-M3Dg4hlwuntUCdzU7KjYqbbd+BLq3JMAOhCKdBE3TcMGMZbKkDdJ5ivNdehOssMCIokNHFOsv7DO4rlEOfyKpg==", "cpu": [ "riscv64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", - "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.24.0.tgz", + "integrity": "sha512-mjBaoo4ocxJppTorZVKWFpy1bfFj9FeCMJqzlMQGjpNPY9JwQi7OuS1axzNIk0nMX6jSgy6ZURDZ2w0QW6D56g==", "cpu": [ "s390x" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", - "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.24.0.tgz", + "integrity": "sha512-ZXFk7M72R0YYFN5q13niV0B7G8/5dcQ9JDp8keJSfr3GoZeXEoMHP/HlvqROA3OMbMdfr19IjCeNAnPUG93b6A==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", - "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.24.0.tgz", + "integrity": "sha512-w1i+L7kAXZNdYl+vFvzSZy8Y1arS7vMgIy8wusXJzRrPyof5LAb02KGr1PD2EkRcl73kHulIID0M501lN+vobQ==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", - "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.24.0.tgz", + "integrity": "sha512-VXBrnPWgBpVDCVY6XF3LEW0pOU51KbaHhccHw6AS6vBWIC60eqsH19DAeeObl+g8nKAz04QFdl/Cefta0xQtUQ==", "cpu": [ "arm64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", - "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.24.0.tgz", + "integrity": "sha512-xrNcGDU0OxVcPTH/8n/ShH4UevZxKIO6HJFK0e15XItZP2UcaiLFd5kiX7hJnqCbSztUF8Qot+JWBC/QXRPYWQ==", "cpu": [ "ia32" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", - "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.24.0.tgz", + "integrity": "sha512-fbMkAF7fufku0N2dE5TBXcNlg0pt0cJue4xBRE2Qc5Vqikxr4VCgKj/ht6SMdFcOacVA9rqF70APJ8RN/4vMJw==", "cpu": [ "x64" ], "dev": true, - "license": "MIT", "optional": true, "os": [ "win32" @@ -1637,8 +1581,7 @@ "node_modules/@tootallnate/quickjs-emscripten": { "version": "0.23.0", "resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz", - "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==", - "license": "MIT" + "integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==" }, "node_modules/@types/babel__core": { "version": "7.20.5", @@ -1686,11 +1629,10 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", - "dev": true, - "license": "MIT" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", + "dev": true }, "node_modules/@types/graceful-fs": { "version": "4.1.9", @@ -1774,7 +1716,6 @@ "version": "2.10.3", "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz", "integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==", - "license": "MIT", "optional": true, "dependencies": { "@types/node": "*" @@ -2061,7 +2002,6 @@ "version": "0.13.4", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz", "integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==", - "license": "MIT", "dependencies": { "tslib": "^2.0.1" }, @@ -2092,10 +2032,9 @@ } }, "node_modules/b4a": { - "version": "1.6.6", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz", - "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==", - "license": "Apache-2.0" + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==" }, "node_modules/babel-jest": { "version": "29.7.0", @@ -2218,17 +2157,15 @@ "license": "MIT" }, "node_modules/bare-events": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.4.2.tgz", - "integrity": "sha512-qMKFd2qG/36aA4GwvKq8MxnPgCQAmBWmSyLWsJcbn8v03wvIPQ/hG1Ms8bPzndZxMDoHpxez5VOS+gC9Yi24/Q==", - "license": "Apache-2.0", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", + "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", "optional": true }, "node_modules/bare-fs": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.1.tgz", - "integrity": "sha512-W/Hfxc/6VehXlsgFtbB5B4xFcsCl+pAh30cYhoFyXErf6oGrwjh8SwiPAdHgpmWonKuYpZgGywN0SXt7dgsADA==", - "license": "Apache-2.0", + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-2.3.5.tgz", + "integrity": "sha512-SlE9eTxifPDJrT6YgemQ1WGFleevzwY+XAP1Xqgl56HtcrisC2CHCZ2tq6dBpcH2TnNxwUEUGhweo+lrQtYuiw==", "optional": true, "dependencies": { "bare-events": "^2.0.0", @@ -2237,30 +2174,28 @@ } }, "node_modules/bare-os": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.0.tgz", - "integrity": "sha512-v8DTT08AS/G0F9xrhyLtepoo9EJBJ85FRSMbu1pQUlAf6A8T0tEEQGMVObWeqpjhSPXsE0VGlluFBJu2fdoTNg==", - "license": "Apache-2.0", + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/bare-os/-/bare-os-2.4.4.tgz", + "integrity": "sha512-z3UiI2yi1mK0sXeRdc4O1Kk8aOa/e+FNWZcTiPB/dfTWyLypuE99LibgRaQki914Jq//yAWylcAt+mknKdixRQ==", "optional": true }, "node_modules/bare-path": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/bare-path/-/bare-path-2.1.3.tgz", "integrity": "sha512-lh/eITfU8hrj9Ru5quUp0Io1kJWIk1bTjzo7JH1P5dWmQ2EL4hFUlfI8FonAhSlgIfhn63p84CDY/x+PisgcXA==", - "license": "Apache-2.0", "optional": true, "dependencies": { "bare-os": "^2.1.0" } }, "node_modules/bare-stream": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.1.3.tgz", - "integrity": "sha512-tiDAH9H/kP+tvNO5sczyn9ZAA7utrSMobyDchsnyyXBuUe2FSQWbxhtuHB8jwpHYYevVo2UJpcmvvjrbHboUUQ==", - "license": "Apache-2.0", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.3.0.tgz", + "integrity": "sha512-pVRWciewGUeCyKEuRxwv06M079r+fRjAQjBEK2P6OYGrO43O+Z0LrPZZEjlc4mB6C2RpZ9AxJ1s7NLEtOHO6eA==", "optional": true, "dependencies": { - "streamx": "^2.18.0" + "b4a": "^1.6.6", + "streamx": "^2.20.0" } }, "node_modules/base64-js": { @@ -2280,14 +2215,12 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "MIT" + ] }, "node_modules/basic-ftp": { "version": "5.0.5", "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", - "license": "MIT", "engines": { "node": ">=10.0.0" } @@ -2306,10 +2239,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", - "license": "MIT", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -2319,7 +2251,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -2333,7 +2265,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -2341,8 +2272,7 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/brace-expansion": { "version": "1.1.11", @@ -2429,7 +2359,6 @@ "url": "https://feross.org/support" } ], - "license": "MIT", "dependencies": { "base64-js": "^1.3.1", "ieee754": "^1.1.13" @@ -2439,7 +2368,6 @@ "version": "0.2.13", "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", - "license": "MIT", "engines": { "node": "*" } @@ -2465,7 +2393,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -2595,10 +2522,9 @@ } }, "node_modules/chromium-bidi": { - "version": "0.5.24", - "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.5.24.tgz", - "integrity": "sha512-5xQNN2SVBdZv4TxeMLaI+PelrnZsHDhn8h2JtyriLr+0qHcZS8BMuo93qN6J1VmtmrgYP+rmcLHcbpnA8QJh+w==", - "license": "Apache-2.0", + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-0.8.0.tgz", + "integrity": "sha512-uJydbGdTw0DEUjhoogGveneJVWX/9YuqkWePzMmkBYwtdAqo5d3J/ovNKFr+/2hWXYmYCr6it8mSSTIj6SS6Ug==", "dependencies": { "mitt": "3.0.1", "urlpattern-polyfill": "10.0.0", @@ -2836,7 +2762,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2849,10 +2774,9 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "license": "MIT", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -2967,7 +2891,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz", "integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==", - "license": "MIT", "engines": { "node": ">= 14" } @@ -3040,12 +2963,11 @@ } }, "node_modules/debug": { - "version": "4.3.5", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", - "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", - "license": "MIT", + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -3133,7 +3055,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz", "integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==", - "license": "MIT", "dependencies": { "ast-types": "^0.13.4", "escodegen": "^2.1.0", @@ -3156,7 +3077,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -3165,7 +3085,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", - "license": "MIT", "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -3182,10 +3101,9 @@ } }, "node_modules/devtools-protocol": { - "version": "0.0.1299070", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1299070.tgz", - "integrity": "sha512-+qtL3eX50qsJ7c+qVyagqi7AWMoQCBGNfoyJZMwm/NSXVqLYbuitrWEEIzxfUmTNy7//Xe8yhMmQ+elj3uAqSg==", - "license": "BSD-3-Clause" + "version": "0.0.1342118", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1342118.tgz", + "integrity": "sha512-75fMas7PkYNDTmDyb6PRJCH7ILmHLp+BhrZGeMsa4bCh40DTxgCz2NRy5UDzII4C5KuD0oBMZ9vXKhEl6UD/3w==" }, "node_modules/diff-sequences": { "version": "29.6.3", @@ -3231,8 +3149,7 @@ "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", - "license": "MIT" + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { "version": "1.4.816", @@ -3262,10 +3179,9 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "license": "MIT", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -3274,7 +3190,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "license": "MIT", "dependencies": { "once": "^1.4.0" } @@ -3459,8 +3374,7 @@ "node_modules/escape-html": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", - "license": "MIT" + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" }, "node_modules/escape-string-regexp": { "version": "4.0.0", @@ -3479,7 +3393,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", - "license": "BSD-2-Clause", "dependencies": { "esprima": "^4.0.1", "estraverse": "^5.2.0", @@ -3810,7 +3723,6 @@ "version": "1.8.1", "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3873,37 +3785,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", - "license": "MIT", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -3948,7 +3859,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", - "license": "BSD-2-Clause", "dependencies": { "debug": "^4.1.1", "get-stream": "^5.1.0", @@ -3968,7 +3878,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "license": "MIT", "dependencies": { "pump": "^3.0.0" }, @@ -3996,8 +3905,7 @@ "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", - "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", - "license": "MIT" + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==" }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", @@ -4037,7 +3945,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", - "license": "MIT", "dependencies": { "pend": "~1.2.0" } @@ -4069,13 +3976,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", - "license": "MIT", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -4090,7 +3996,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -4098,8 +4003,7 @@ "node_modules/finalhandler/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, "node_modules/find-up": { "version": "5.0.0", @@ -4177,7 +4081,6 @@ "version": "0.5.2", "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -4186,7 +4089,6 @@ "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "license": "MIT", "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -4352,7 +4254,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.3.tgz", "integrity": "sha512-BzUrJBS9EcUb4cFol8r4W3v1cPsSyajLSthNkz5BxbpDcHN5tIrM10E2eNvfnvBn3DaT3DUgx0OpsBKkaOpanw==", - "license": "MIT", "dependencies": { "basic-ftp": "^5.0.2", "data-uri-to-buffer": "^6.0.2", @@ -4563,7 +4464,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", - "license": "MIT", "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", @@ -4631,7 +4531,6 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -4656,8 +4555,7 @@ "type": "consulting", "url": "https://feross.org/support" } - ], - "license": "BSD-3-Clause" + ] }, "node_modules/ignore": { "version": "5.3.1", @@ -4759,7 +4657,6 @@ "version": "9.0.5", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", - "license": "MIT", "dependencies": { "jsbn": "1.1.0", "sprintf-js": "^1.1.3" @@ -5826,8 +5723,7 @@ "node_modules/jsbn": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", - "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==", - "license": "MIT" + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, "node_modules/jsdom": { "version": "24.1.0", @@ -5926,7 +5822,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "license": "MIT", "dependencies": { "universalify": "^2.0.0" }, @@ -6389,10 +6284,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "license": "MIT" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -6411,11 +6308,10 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, - "license": "MIT", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -6428,7 +6324,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "license": "MIT", "bin": { "mime": "cli.js" }, @@ -6492,8 +6387,7 @@ "node_modules/mitt": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz", - "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==", - "license": "MIT" + "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==" }, "node_modules/mkdirp": { "version": "0.5.6", @@ -6508,10 +6402,9 @@ } }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "license": "MIT" + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" }, "node_modules/multer": { "version": "1.4.5-lts.1", @@ -6551,7 +6444,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/netmask/-/netmask-2.0.2.tgz", "integrity": "sha512-dBpDMdxv9Irdq66304OLfEmQ9tbNRFnFTuZiLo+bD+r332bBmMJ8GBLXklIXXgxd3+v9+KUnZaUR5PJMa75Gsg==", - "license": "MIT", "engines": { "node": ">= 0.4.0" } @@ -6770,7 +6662,6 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "license": "MIT", "dependencies": { "ee-first": "1.1.1" }, @@ -6867,7 +6758,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.0.2.tgz", "integrity": "sha512-BFi3vZnO9X5Qt6NRz7ZOaPja3ic0PhlsmCRYLOpN11+mWBCR6XJDqW5RF3j8jm4WGGQZtBA+bTfxYzeKW73eHg==", - "license": "MIT", "dependencies": { "@tootallnate/quickjs-emscripten": "^0.23.0", "agent-base": "^7.0.2", @@ -6886,7 +6776,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz", "integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==", - "license": "MIT", "dependencies": { "degenerator": "^5.0.0", "netmask": "^2.0.2" @@ -6941,7 +6830,6 @@ "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -6984,16 +6872,14 @@ "license": "MIT" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "license": "MIT" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/pend": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", - "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", - "license": "MIT" + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==" }, "node_modules/picocolors": { "version": "1.0.1", @@ -7193,7 +7079,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", - "license": "MIT", "engines": { "node": ">=0.4.0" } @@ -7228,7 +7113,6 @@ "version": "6.4.0", "resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.4.0.tgz", "integrity": "sha512-u0piLU+nCOHMgGjRbimiXmA9kM/L9EHh3zL81xCdp7m+Y2pHIsnmbdDoEDoAz5geaonNR6q6+yOPQs6n4T6sBQ==", - "license": "MIT", "dependencies": { "agent-base": "^7.0.2", "debug": "^4.3.4", @@ -7247,7 +7131,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "license": "ISC", "engines": { "node": ">=12" } @@ -7255,8 +7138,7 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "license": "MIT" + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/psl": { "version": "1.9.0", @@ -7272,10 +7154,9 @@ "license": "MIT" }, "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "license": "MIT", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", "dependencies": { "end-of-stream": "^1.1.0", "once": "^1.3.1" @@ -7291,35 +7172,36 @@ } }, "node_modules/puppeteer": { - "version": "22.12.1", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-22.12.1.tgz", - "integrity": "sha512-1GxY8dnEnHr1SLzdSDr0FCjM6JQfAh2E2I/EqzeF8a58DbGVk9oVjj4lFdqNoVbpgFSpAbz7VER9St7S1wDpNg==", + "version": "23.5.3", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-23.5.3.tgz", + "integrity": "sha512-FghmfBsr/UUpe48OiCg1gV3W4vVfQJKjQehbF07SjnQvEpWcvPTah1nykfGWdOQQ1ydJPIXcajzWN7fliCU3zw==", "hasInstallScript": true, - "license": "Apache-2.0", "dependencies": { - "@puppeteer/browsers": "2.2.3", + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.8.0", "cosmiconfig": "^9.0.0", - "devtools-protocol": "0.0.1299070", - "puppeteer-core": "22.12.1" + "devtools-protocol": "0.0.1342118", + "puppeteer-core": "23.5.3", + "typed-query-selector": "^2.12.0" }, "bin": { - "puppeteer": "lib/esm/puppeteer/node/cli.js" + "puppeteer": "lib/cjs/puppeteer/node/cli.js" }, "engines": { "node": ">=18" } }, "node_modules/puppeteer-core": { - "version": "22.12.1", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-22.12.1.tgz", - "integrity": "sha512-XmqeDPVdC5/3nGJys1jbgeoZ02wP0WV1GBlPtr/ULRbGXJFuqgXMcKQ3eeNtFpBzGRbpeoCGWHge1ZWKWl0Exw==", - "license": "Apache-2.0", + "version": "23.5.3", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-23.5.3.tgz", + "integrity": "sha512-V58MZD/B3CwkYsqSEQlHKbavMJptF04fzhMdUpiCRCmUVhwZNwSGEPhaiZ1f8I3ABQUirg3VNhXVB6Z1ubHXtQ==", "dependencies": { - "@puppeteer/browsers": "2.2.3", - "chromium-bidi": "0.5.24", - "debug": "^4.3.5", - "devtools-protocol": "0.0.1299070", - "ws": "^8.17.1" + "@puppeteer/browsers": "2.4.0", + "chromium-bidi": "0.8.0", + "debug": "^4.3.7", + "devtools-protocol": "0.0.1342118", + "typed-query-selector": "^2.12.0", + "ws": "^8.18.0" }, "engines": { "node": ">=18" @@ -7343,12 +7225,11 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", - "license": "BSD-3-Clause", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -7387,8 +7268,7 @@ "node_modules/queue-tick": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", - "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", - "license": "MIT" + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==" }, "node_modules/randombytes": { "version": "2.1.0", @@ -7404,7 +7284,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", - "license": "MIT", "engines": { "node": ">= 0.6" } @@ -7413,7 +7292,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", - "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -7612,13 +7490,12 @@ } }, "node_modules/rollup": { - "version": "4.18.0", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", - "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", + "version": "4.24.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", + "integrity": "sha512-DOmrlGSXNk1DM0ljiQA+i+o0rSLhtii1je5wgk60j49d1jHT5YYttBv1iWOnYSTG+fZZESUOSNiAl89SIet+Cg==", "dev": true, - "license": "MIT", "dependencies": { - "@types/estree": "1.0.5" + "@types/estree": "1.0.6" }, "bin": { "rollup": "dist/bin/rollup" @@ -7628,22 +7505,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.18.0", - "@rollup/rollup-android-arm64": "4.18.0", - "@rollup/rollup-darwin-arm64": "4.18.0", - "@rollup/rollup-darwin-x64": "4.18.0", - "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", - "@rollup/rollup-linux-arm-musleabihf": "4.18.0", - "@rollup/rollup-linux-arm64-gnu": "4.18.0", - "@rollup/rollup-linux-arm64-musl": "4.18.0", - "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", - "@rollup/rollup-linux-riscv64-gnu": "4.18.0", - "@rollup/rollup-linux-s390x-gnu": "4.18.0", - "@rollup/rollup-linux-x64-gnu": "4.18.0", - "@rollup/rollup-linux-x64-musl": "4.18.0", - "@rollup/rollup-win32-arm64-msvc": "4.18.0", - "@rollup/rollup-win32-ia32-msvc": "4.18.0", - "@rollup/rollup-win32-x64-msvc": "4.18.0", + "@rollup/rollup-android-arm-eabi": "4.24.0", + "@rollup/rollup-android-arm64": "4.24.0", + "@rollup/rollup-darwin-arm64": "4.24.0", + "@rollup/rollup-darwin-x64": "4.24.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.24.0", + "@rollup/rollup-linux-arm-musleabihf": "4.24.0", + "@rollup/rollup-linux-arm64-gnu": "4.24.0", + "@rollup/rollup-linux-arm64-musl": "4.24.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.24.0", + "@rollup/rollup-linux-riscv64-gnu": "4.24.0", + "@rollup/rollup-linux-s390x-gnu": "4.24.0", + "@rollup/rollup-linux-x64-gnu": "4.24.0", + "@rollup/rollup-linux-x64-musl": "4.24.0", + "@rollup/rollup-win32-arm64-msvc": "4.24.0", + "@rollup/rollup-win32-ia32-msvc": "4.24.0", + "@rollup/rollup-win32-x64-msvc": "4.24.0", "fsevents": "~2.3.2" } }, @@ -7770,10 +7647,9 @@ } }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", - "license": "MIT", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -7797,7 +7673,6 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -7805,14 +7680,15 @@ "node_modules/send/node_modules/debug/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "license": "MIT" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } }, "node_modules/serialize-javascript": { "version": "6.0.2", @@ -7825,15 +7701,14 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", - "license": "MIT", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -7875,8 +7750,7 @@ "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", - "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", - "license": "ISC" + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, "node_modules/shebang-command": { "version": "2.0.0", @@ -8002,7 +7876,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "license": "MIT", "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -8019,7 +7892,6 @@ "version": "2.8.3", "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz", "integrity": "sha512-l5x7VUUWbjVFbafGLxPWkYsHIhEvmF85tbIeFZWc8ZPtoMyybuEhL7Jye/ooC4/d48FgOjSJXgsF/AJPYCW8Zw==", - "license": "MIT", "dependencies": { "ip-address": "^9.0.5", "smart-buffer": "^4.2.0" @@ -8033,7 +7905,6 @@ "version": "8.0.4", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.4.tgz", "integrity": "sha512-GNAq/eg8Udq2x0eNiFkr9gRg5bA7PXEWagQdeRX4cPSG+X/8V38v637gim9bjFptMk1QWsCTr0ttrJEiXbNnRw==", - "license": "MIT", "dependencies": { "agent-base": "^7.1.1", "debug": "^4.3.4", @@ -8067,8 +7938,7 @@ "node_modules/sprintf-js": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", - "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==", - "license": "BSD-3-Clause" + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" }, "node_modules/stack-utils": { "version": "2.0.6", @@ -8097,7 +7967,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8111,10 +7980,9 @@ } }, "node_modules/streamx": { - "version": "2.18.0", - "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.18.0.tgz", - "integrity": "sha512-LLUC1TWdjVdn1weXGcSxyTR3T4+acB6tVGXT95y0nGbca4t4o/ng1wKAGTljm9VicuCVLvRlqFYXYy5GwgM7sQ==", - "license": "MIT", + "version": "2.20.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.20.1.tgz", + "integrity": "sha512-uTa0mU6WUC65iUvzKH4X9hEdvSW7rbPxPtwfWiLMSj3qTdQbAiUboZTxauKfpFuGIGa1C2BYijZ7wgdUXICJhA==", "dependencies": { "fast-fifo": "^1.3.2", "queue-tick": "^1.0.1", @@ -8357,10 +8225,9 @@ } }, "node_modules/tar-fs": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.5.tgz", - "integrity": "sha512-JOgGAmZyMgbqpLwct7ZV8VzkEB6pxXFBVErLtb+XCOqzc6w1xiWKI9GVd6bwk68EX7eJ4DWmfXVmq8K2ziZTGg==", - "license": "MIT", + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.6.tgz", + "integrity": "sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==", "dependencies": { "pump": "^3.0.0", "tar-stream": "^3.1.5" @@ -8374,7 +8241,6 @@ "version": "3.1.7", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz", "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==", - "license": "MIT", "dependencies": { "b4a": "^1.6.4", "fast-fifo": "^1.2.0", @@ -8443,10 +8309,9 @@ } }, "node_modules/text-decoder": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.1.0.tgz", - "integrity": "sha512-TmLJNj6UgX8xcUZo4UDStGQtDiTzF7BzWlzn9g7UWrjkpHr5uJTK1ld16wZ3LXb2vb6jH8qU89dW5whuMdXYdw==", - "license": "Apache-2.0", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.0.tgz", + "integrity": "sha512-n1yg1mOj9DNpk3NeZOx7T6jchTbyJS3i3cucbNN6FcdPriMZx7NsgrGpWWdWZZGxD7ES1XB+3uoqHMgOKaN+fg==", "dependencies": { "b4a": "^1.6.4" } @@ -8461,8 +8326,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "license": "MIT" + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/tmpl": { "version": "1.0.5", @@ -8498,7 +8362,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", - "license": "MIT", "engines": { "node": ">=0.6" } @@ -8717,6 +8580,11 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typed-query-selector": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.0.tgz", + "integrity": "sha512-SbklCd1F0EiZOyPiW192rrHZzZ5sBijB6xM+cpmrwDqObvdtunOHHIk9fCGsoK5JVIYXoyEp4iEdE3upFH3PAg==" + }, "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", @@ -8743,7 +8611,6 @@ "version": "1.4.3", "resolved": "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.4.3.tgz", "integrity": "sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==", - "license": "MIT", "dependencies": { "buffer": "^5.2.1", "through": "^2.3.8" @@ -8767,7 +8634,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "license": "MIT", "engines": { "node": ">= 10.0.0" } @@ -8776,7 +8642,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", - "license": "MIT", "engines": { "node": ">= 0.8" } @@ -8835,8 +8700,7 @@ "node_modules/urlpattern-polyfill": { "version": "10.0.0", "resolved": "https://registry.npmjs.org/urlpattern-polyfill/-/urlpattern-polyfill-10.0.0.tgz", - "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==", - "license": "MIT" + "integrity": "sha512-H/A06tKD7sS1O1X2SshBVeA5FLycRpjqiBeqGKmBwBDBy28EnRjORxTNe269KSSr5un5qyWi1iL61wLxpd+ZOg==" }, "node_modules/util-deprecate": { "version": "1.0.2", @@ -9244,7 +9108,6 @@ "version": "2.10.0", "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", - "license": "MIT", "dependencies": { "buffer-crc32": "~0.2.3", "fd-slicer": "~1.1.0" diff --git a/package.json b/package.json index 1ece8de2..f08781a5 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "author": "Highsoft AS (http://www.highcharts.com/about)", "license": "MIT", "type": "module", - "version": "4.0.2", + "version": "4.0.3", "main": "./dist/index.esm.js", "engines": { "node": ">=18.12.0" @@ -72,7 +72,7 @@ "jsdom": "^24.1.0", "multer": "^1.4.5-lts.1", "prompts": "^2.4.2", - "puppeteer": "^22.12.1", + "puppeteer": "^23.5.3", "tarn": "^3.0.2", "uuid": "^10.0.0", "zod": "^3.23.8" diff --git a/public/illo_mission.jpg b/public/illo_mission.jpg new file mode 100644 index 00000000..3090c00b Binary files /dev/null and b/public/illo_mission.jpg differ diff --git a/public/index.html b/public/index.html index 6c2b6544..da6ca9bf 100644 --- a/public/index.html +++ b/public/index.html @@ -11,11 +11,16 @@ - - + + + src="https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.20.2/mode/javascript/javascript.min.js" + integrity="sha256-VCI9wgJK81jD+WoGeiVQXSS7MMWqjRbZQ446hRcLmBU=" crossorigin="anonymous"> + + + diff --git a/tests/unit/cache.test.js b/tests/unit/cache.test.js index 8086706c..31676e8a 100644 --- a/tests/unit/cache.test.js +++ b/tests/unit/cache.test.js @@ -1,4 +1,3 @@ -// cacheManager.test.js import { extractVersion, extractModuleName } from '../../lib/cache'; describe('extractVersion', () => {