diff --git a/.env.sample b/.env.sample index 6d68e389..6272b91c 100644 --- a/.env.sample +++ b/.env.sample @@ -72,6 +72,7 @@ OTHER_NODE_ENV = production OTHER_LISTEN_TO_PROCESS_EXITS = true OTHER_NO_LOGO = false OTHER_HARD_RESET_PAGE = false +OTHER_BROWSER_SHELL_MODE = true # DEBUG CONFIG DEBUG_ENABLE = false diff --git a/.puppeteerrc.cjs b/.puppeteerrc.cjs index 58b52d10..c83cc46f 100644 --- a/.puppeteerrc.cjs +++ b/.puppeteerrc.cjs @@ -1,8 +1,8 @@ -const {join} = require('path'); +const { join } = require('path'); /** * @type {import("puppeteer").Configuration} */ module.exports = { - cacheDirectory: join(__dirname, 'node_modules', '.puppeteer-cache'), + cacheDirectory: join(__dirname, 'node_modules', '.puppeteer-cache') }; diff --git a/CHANGELOG.md b/CHANGELOG.md index 3af17924..a9bddb35 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -20,7 +20,8 @@ _Enhancements:_ - Optimized code by reducing evaluate function calls to enhance performance and minimize jumping between NodeJS and browser processes. - Optimized and moved chart creation initialization scripts from the HTML template to a separate module named `highcharts.js`. - Optimized the `clearPage` function to ensure content cleaning is only performed once, during resource release. -- Introduced `hardResetPage` option for resetting the page's content (including Highcharts scripts) each time the page is released to the pool (defaulting to `false`). +- Introduced the `hardResetPage` option for resetting the page's content (including Highcharts scripts) each time the page is released to the pool (defaulting to `false`). +- Introduced the `browserShellMode` option for controlling the mode in which the browser runs (new or old, `shell` mode). - Optimized creating and acquiring pages from the pool. - Optimized adding and releasing additional JS and CSS resources. - Made corrections for gracefully shutting down resources, including running servers, ongoing intervals, browser instance, created pages, and workers pool. diff --git a/README.md b/README.md index aea6a8cd..e9cf105c 100644 --- a/README.md +++ b/README.md @@ -256,7 +256,8 @@ The format, along with its default values, is as follows (using the recommended "nodeEnv": "production", "listenToProcessExits": true, "noLogo": false, - "hardResetPage": false + "hardResetPage": false, + "browserShellMode": true }, "debug": { "enable": false, @@ -291,11 +292,11 @@ These variables are set in your environment and take precedence over options fro ### Export Config -- `EXPORT_TYPE`: The format of the file to export to. Can be _jpeg_, _png_, _pdf_ or _svg_ (defaults to `png`). -- `EXPORT_CONSTR`: The constructor to use. Can be _chart_, _stockChart_, _mapChart_ or _ganttChart_ (defaults to `chart`). +- `EXPORT_TYPE`: The format of the file to export to. Can be **jpeg**, **png**, **pdf** or **svg** (defaults to `png`). +- `EXPORT_CONSTR`: The constructor to use. Can be **chart**, **stockChart**, **mapChart** or **ganttChart** (defaults to `chart`). - `EXPORT_DEFAULT_HEIGHT`: The default height of the exported chart. Used when not found any value set (defaults to `400`). - `EXPORT_DEFAULT_WIDTH`: The default width of the exported chart. Used when not found any value set (defaults to `600`). -- `EXPORT_DEFAULT_SCALE`: The default scale of the exported chart. Ranges between _0.1_ and _5.0_ (defaults to `1`). +- `EXPORT_DEFAULT_SCALE`: The default scale of the exported chart. Ranges between **0.1** and **5.0** (defaults to `1`). - `EXPORT_RASTERIZATION_TIMEOUT`: The specified duration, in milliseconds, to wait for rendering a webpage (defaults to `1500`). ### Custom Logic Config @@ -305,7 +306,7 @@ These variables are set in your environment and take precedence over options fro ### Server Config -- `SERVER_ENABLE`: If set to true, the server starts on 0.0.0.0 (defaults to `false`). +- `SERVER_ENABLE`: If set to **true**, the server starts on 0.0.0.0 (defaults to `false`). - `SERVER_HOST`: The hostname of the server. Additionally, it starts a server listening on the provided hostname (defaults to `0.0.0.0`). - `SERVER_PORT`: The port to be used for the server when enabled (defaults to `7801`). - `SERVER_BENCHMARKING`: Indicates whether to display a message with the duration, in milliseconds, of specific actions that occur on the server while serving a request (defaults to `false`). @@ -322,14 +323,14 @@ These variables are set in your environment and take precedence over options fro - `SERVER_RATE_LIMITING_MAX_REQUESTS`: The maximum number of requests allowed in one minute (defaults to `10`). - `SERVER_RATE_LIMITING_WINDOW`: The time window, in minutes, for the rate limiting (defaults to `1`). - `SERVER_RATE_LIMITING_DELAY`: The delay duration for each successive request before reaching the maximum limit (defaults to `0`). -- `SERVER_RATE_LIMITING_TRUST_PROXY`: Set this to true if the server is behind a load balancer (defaults to `false`). -- `SERVER_RATE_LIMITING_SKIP_KEY`: Allows bypassing the rate limiter and should be provided with the _skipToken_ argument (defaults to ``). -- `SERVER_RATE_LIMITING_SKIP_TOKEN`: Allows bypassing the rate limiter and should be provided with the _skipKey_ argument (defaults to ``). +- `SERVER_RATE_LIMITING_TRUST_PROXY`: Set this to **true** if the server is behind a load balancer (defaults to `false`). +- `SERVER_RATE_LIMITING_SKIP_KEY`: Allows bypassing the rate limiter and should be provided with the `skipToken` argument (defaults to ``). +- `SERVER_RATE_LIMITING_SKIP_TOKEN`: Allows bypassing the rate limiter and should be provided with the `skipKey` argument (defaults to ``). ### Server SSL Config - `SERVER_SSL_ENABLE`: Enables or disables the SSL protocol (defaults to `false`). -- `SERVER_SSL_FORCE`: If set to true, the server is forced to serve only over HTTPS (defaults to `false`). +- `SERVER_SSL_FORCE`: If set to **true**, the server is forced to serve only over HTTPS (defaults to `false`). - `SERVER_SSL_PORT`: The port on which to run the SSL server (defaults to `443`). - `SERVER_SSL_CERT_PATH`: The path to the SSL certificate/key file (defaults to ``). @@ -348,8 +349,8 @@ These variables are set in your environment and take precedence over options fro ### Logging Config -- `LOGGING_LEVEL`: The logging level to be used. Can be _0_ - silent, _1_ - error, _2_ - warning, _3_ - notice, _4_ - verbose or _5_ benchmark (defaults to `4`). -- `LOGGING_FILE`: The name of a log file. The _logDest_ option also needs to be set to enable file logging (defaults to `highcharts-export-server.log`). +- `LOGGING_LEVEL`: The logging level to be used. Can be **0** - silent, **1** - error, **2** - warning, **3** - notice, **4** - verbose or **5** benchmark (defaults to `4`). +- `LOGGING_FILE`: The name of a log file. The `logDest` option also needs to be set to enable file logging (defaults to `highcharts-export-server.log`). - `LOGGING_DEST`: The path to store log files. This also enables file logging (defaults to `log/`). ### UI Config @@ -363,6 +364,7 @@ These variables are set in your environment and take precedence over options fro - `OTHER_LISTEN_TO_PROCESS_EXITS`: Decides whether or not to attach _process.exit_ handlers (defaults to `true`). - `OTHER_NO_LOGO`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `OTHER_HARD_RESET_PAGE`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). +- `OTHER_BROWSER_SHELL_MODE`: Decides whether to enable older but much more performant _shell_ mode for the browser (defaults to `true`). ### Debugging Config - `DEBUG_ENABLE`: Enables or disables debug mode for the underlying browser (defaults to `false`). @@ -380,18 +382,18 @@ To supply command line arguments, add them as flags when running the application _Available options:_ -- `--infile`: The input file should include a name and a type (_.json_ or _.svg_) and must be a correctly formatted JSON or SVG file (defaults to `false`). +- `--infile`: The input file should include a name and a type (**.json** or **.svg**) and must be a correctly formatted JSON or SVG file (defaults to `false`). - `--instr`: An input in a form of a stringified JSON or SVG file. Overrides the `--infile` option (defaults to `false`). - `--options`: An alias for the `--instr` option (defaults to `false`). -- `--outfile`: The output filename, accompanied by a type (_jpeg_, _png_, _pdf_, or _svg_). Ignores the `--type` flag (defaults to `false`). -- `--type`: The format of the file to export to. Can be _jpeg_, _png_, _pdf_, or _svg_ (defaults to `png`). -- `--constr`: The constructor to use. Can be _chart_, _stockChart_, _mapChart_ or _ganttChart_ (defaults to `chart`). +- `--outfile`: The output filename, accompanied by a type (**jpeg**, **png**, **pdf**, or **svg**). Ignores the `--type` flag (defaults to `false`). +- `--type`: The format of the file to export to. Can be **jpeg**, **png**, **pdf**, or **svg** (defaults to `png`). +- `--constr`: The constructor to use. Can be **chart**, **stockChart**, **mapChart** or **ganttChart** (defaults to `chart`). - `--height`: The height of the exported chart. Overrides the option in the chart settings (defaults to `400`). - `--width`: The width of the exported chart. Overrides the option in the chart settings (defaults to `600`). -- `--scale`: The scale of the exported chart. Ranges between _0.1_ and _5.0_ (defaults to `1`). +- `--scale`: The scale of the exported chart. Ranges between **0.1** and **5.0** (defaults to `1`). - `--globalOptions`: Either a stringified JSON or a filename containing global options to be passed into the `Highcharts.setOptions` (defaults to `false`). - `--themeOptions`: Either a stringified JSON or a filename containing theme options to be passed into the `Highcharts.setOptions` (defaults to `false`). -- `--batch`: Initiates a batch job with a string containing input/output pairs: "in=out;in=out;.." (defaults to `false`). +- `--batch`: Initiates a batch job with a string containing input/output pairs: **"in=out;in=out;.."** (defaults to `false`). - `--rasterizationTimeout`: The specified duration, in milliseconds, to wait for rendering a webpage (defaults to `1500`). - `--allowCodeExecution`: Controls whether the execution of arbitrary code is allowed during the exporting process (defaults to `false`). - `--allowFileResources`: Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server (defaults to `false`). @@ -400,7 +402,7 @@ _Available options:_ - `--resources`: Additional resources in the form of a stringified JSON. It may contain `files` (array of JS filenames), `js` (stringified JS), and `css` (stringified CSS) sections (defaults to `false`). - `--loadConfig`: A file containing a pre-defined configuration to use (defaults to `false`). - `--createConfig`: Enables setting options through a prompt and saving them in a provided config file (defaults to `false`). -- `--enableServer`: If set to true, the server starts on 0.0.0.0 (defaults to `false`). +- `--enableServer`: If set to **true**, the server starts on 0.0.0.0 (defaults to `false`). - `--host`: The hostname of the server. Additionally, it starts a server listening on the provided hostname (defaults to `0.0.0.0`). - `--port`: The port to be used for the server when enabled (defaults to `7801`). - `--serverBenchmarking`: Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request (defaults to `false`). @@ -411,11 +413,11 @@ _Available options:_ - `--maxRequests`: The maximum number of requests allowed in one minute (defaults to `10`). - `--window`: The time window, in minutes, for the rate limiting (defaults to `1`). - `--delay`: The delay duration for each successive request before reaching the maximum limit (defaults to `0`). -- `--trustProxy`: Set this to true if the server is behind a load balancer (defaults to `false`). +- `--trustProxy`: Set this to **true** if the server is behind a load balancer (defaults to `false`). - `--skipKey`: Allows bypassing the rate limiter and should be provided with the `--skipToken` argument (defaults to ``). - `--skipToken`: Allows bypassing the rate limiter and should be provided with the `--skipKey` argument (defaults to ``). - `--enableSsl`: Enables or disables the SSL protocol (defaults to `false`). -- `--sslForce`: If set to true, the server is forced to serve only over HTTPS (defaults to `false`). +- `--sslForce`: If set to **true**, the server is forced to serve only over HTTPS (defaults to `false`). - `--sslPort`: The port on which to run the SSL server (defaults to `443`). - `--certPath`: The path to the SSL certificate/key file (defaults to ``). - `--minWorkers`: The number of minimum and initial pool workers to spawn (defaults to `4`). @@ -428,15 +430,16 @@ _Available options:_ - `--createRetryInterval`: The duration, in milliseconds, to wait before retrying the create process in case of a failure (defaults to `200`). - `--reaperInterval`: The duration, in milliseconds, after which the check for idle resources to destroy is triggered (defaults to `1000`). - `--poolBenchmarking`: Indicate whether to show statistics for the pool of resources or not (defaults to `false`). -- `--logLevel`: The logging level to be used. Can be _0_ - silent, _1_ - error, _2_ - warning, _3_ - notice, _4_ - verbose or _5_ - benchmark (defaults to `4`). +- `--logLevel`: The logging level to be used. Can be **0** - silent, **1** - error, **2** - warning, **3** - notice, **4** - verbose or **5** - benchmark (defaults to `4`). - `--logFile`: The name of a log file. The `--logDest` option also needs to be set to enable file logging (defaults to `highcharts-export-server.log`). - `--logDest`: The path to store log files. This also enables file logging (defaults to `log/`). - `--enableUi`: Enables or disables the user interface (UI) for the Export Server (defaults to `false`). - `--uiRoute`: The endpoint route to which the user interface (UI) should be attached (defaults to `/`). - `--nodeEnv`: The type of Node.js environment (defaults to `production`). -- `--listenToProcessExits`: Decides whether or not to attach process.exit handlers (defaults to `true`). +- `--listenToProcessExits`: Decides whether or not to attach _process.exit_ handlers (defaults to `true`). - `--noLogo`: Skip printing the logo on a startup. Will be replaced by a simple text (defaults to `false`). - `--hardResetPage`: Determines whether the page's content should be reset from scratch, including Highcharts scripts (defaults to `false`). +- `--browserShellMode`: Decides whether to enable older but much more performant _shell_ mode for the browser (defaults to `true`). - `--enableDebug`: Enables or disables debug mode for the underlying browser (defaults to `false`). - `--headless`: Controls the mode in which the browser is launched when in the debug mode (defaults to `true`). - `--devtools`: Decides whether to enable DevTools when the browser is in a headful state (defaults to `false`). @@ -476,8 +479,8 @@ The server accepts the following arguments in a POST request body: - `options`: An alias for the `infile` option. - `data`: Another alias for the `infile` option. - `svg`: A string containing SVG representation to render as a chart. -- `type`: The format of an exported chart (can be _png_, _jpeg_, _pdf_ or _svg_). Mimetypes can also be used. -- `constr`: The constructor to use (can be _chart_, _stockChart_, _mapChart_ or _ganttChart_). +- `type`: The format of an exported chart (can be **png**, **jpeg**, **pdf** or **svg**). Mimetypes can also be used. +- `constr`: The constructor to use (can be **chart**, **stockChart**, **mapChart** or **ganttChart**). - `height`: The height of the exported chart. - `width`: The width of the exported chart. - `scale`: The scale factor of the exported chart. Use it to improve resolution in PNG and JPEG, for example setting scale to 2 on a 600px chart will result in a 1200px output. @@ -485,9 +488,9 @@ The server accepts the following arguments in a POST request body: - `themeOptions`: Either a JSON or a stringified JSON with theme options to be passed into `Highcharts.setOptions`. - `resources`: Additional resources in the form of a JSON or a stringified JSON. It may contain `files` (array of JS filenames), `js` (stringified JS), and `css` (stringified CSS) sections. - `callback`: Stringified JavaScript function to execute in the Highcharts constructor. -- `customCode`: Custom code to be executed before the chart initialization. This can be a function, code wrapped within a function, or a filename with the _.js_ extension. Both `allowFileResources` and `allowCodeExecution` must be set to _true_ for the option to be considered. -- `b64`: Boolean flag, set to true to receive the chart in the _base64_ format instead of the _binary_. -- `noDownload`: Boolean flag, set to true to exclude attachment headers from the response. +- `customCode`: Custom code to be executed before the chart initialization. This can be a function, code wrapped within a function, or a filename with the _.js_ extension. Both `allowFileResources` and `allowCodeExecution` must be set to **true** for the option to be considered. +- `b64`: Boolean flag, set to **true** to receive the chart in the _base64_ format instead of the _binary_. +- `noDownload`: Boolean flag, set to **true** to exclude attachment headers from the response. The server responds to `application/json`, `multipart/form-data`, and URL encoded requests. @@ -499,7 +502,7 @@ It is recommended to run the server using [pm2](https://www.npmjs.com/package/pm - POST - `/`: An endpoint for exporting charts. - - `/:filename` - An endpoint for exporting charts with a specified filename parameter to save the chart to. The file will be downloaded with the _{filename}.{type}_ name (the `noDownload` must be set to _false_). + - `/:filename` - An endpoint for exporting charts with a specified filename parameter to save the chart to. The file will be downloaded with the _{filename}.{type}_ name (the `noDownload` must be set to **false**). - `/change_hc_version/:newVersion`: An authenticated endpoint allowing the modification of the Highcharts version on the server through the use of a token. - GET @@ -583,12 +586,13 @@ This package supports both CommonJS and ES modules. - `server`: The server instance which offers the following functions: - `async startServer(serverConfig)`: The same as `startServer` described below. + - `{Object} serverConfig`: The server configuration object. - `closeServers()`: Closes all servers associated with Express app instance. - `getServers()`: Get all servers associated with Express app instance. - - `enableRateLimiting(options)`: Enable rate limiting for the server. + - `enableRateLimiting(limitConfig)`: Enable rate limiting for the server. - `{Object} limitConfig`: Configuration object for rate limiting. - `getExpress()`: Get the Express instance. @@ -638,8 +642,8 @@ This package supports both CommonJS and ES modules. - `log(...args)`: Logs a message. Accepts a variable amount of arguments. Arguments after `level` will be passed directly to console.log, and/or will be joined and appended to the log file. - `{any} args`: An array of arguments where the first is the log level and the rest are strings to build a message with. -- `logWithStack(level, error, customMessage)`: Logs an error message with its stack trace. Optionally, a custom message can be provided. - - `{number} level`: The log level. +- `logWithStack(newLevel, error, customMessage)`: Logs an error message with its stack trace. Optionally, a custom message can be provided. + - `{number} newLevel`: The log level. - `{Error} error`: The error object. - `{string} customMessage`: An optional custom message to be logged along with the error. @@ -657,7 +661,7 @@ This package supports both CommonJS and ES modules. - `{string} configFileName`: The name of the configuration file. - `printLogo(noLogo)`: Prints the Highcharts Export Server logo and version information. - - `{boolean} noLogo`: If true, only prints version information without the logo. + - `{boolean} noLogo`: If **true**, only prints version information without the logo. - `printUsage()`: Prints the usage information for CLI arguments. If required, it can list properties recursively. @@ -814,7 +818,7 @@ Version 4.0.0 introduced a new mode that allows debugging the Puppeteer browser ## Launching -Setting the `--enableDebug` to `true` passes all debug options to the `puppeteer.launch()` function on startup. Together with the `--headless` option set to `false`, it launches the browser in a headful state providing a full version of the browser with a graphical user interface (GUI). While this serves as the minimal configuration to simply display the browser, Puppeteer offers additional options. Here is the full list: +Setting the `--enableDebug` to **true** passes all debug options to the `puppeteer.launch()` function on startup. Together with the `--headless` option set to **false**, it launches the browser in a headful state providing a full version of the browser with a graphical user interface (GUI). While this serves as the minimal configuration to simply display the browser, Puppeteer offers additional options. Here is the full list: - `--enableDebug`: Enables passing debug options to the `puppeteer.launch()`. - `--headless`: Sets the browser's state. @@ -828,7 +832,7 @@ Setting the `--enableDebug` to `true` passes all debug options to the `puppeteer There are two main ways to debug code: -- By adding a `debugger` statement within any client-side code (e.g., inside a `page.evaluate` callback). With the `--devtools` option set to `true`, the code execution will stop automatically. +- By adding a `debugger` statement within any client-side code (e.g., inside a `page.evaluate` callback). With the `--devtools` option set to **true**, the code execution will stop automatically. - By running the export server with the `--inspect-brk=` flag, and adding a `debugger` statement within any server-side code. Subsequently, navigate to `chrome://inspect/`, input the server's IP address and port (e.g., `localhost:9229`) in the Configure section. Clicking 'inspect' initiates debugging of the server-side code. @@ -838,9 +842,9 @@ For more details, refer to the [Puppeteer debugging guide](https://pptr.dev/guid ## Additional Notes -- Ensure to set the `--headless` to `false` when the `--devtools` is set to `true`. Otherwise, there's a possibility that while DevTools may be recognized as enabled, the browser won't be displayed. Moreover, if a `debugger` is caught within the browser, it might lead to the entire debugging process getting stuck. In such scenarios, you can set the IP address and port (using the value of the `--debuggingPort` option) the same way as described in the section for debugging server-side code. This allows you to access DevTools and resume code execution. +- Ensure to set the `--headless` to **false** when the `--devtools` is set to **true**. Otherwise, there's a possibility that while DevTools may be recognized as enabled, the browser won't be displayed. Moreover, if a `debugger` is caught within the browser, it might lead to the entire debugging process getting stuck. In such scenarios, you can set the IP address and port (using the value of the `--debuggingPort` option) the same way as described in the section for debugging server-side code. This allows you to access DevTools and resume code execution. -- When using the `--listenToConsole` and `--dumpio` options, be aware that the server's console may become 'polluted' with messages from the browser. If you prefer to avoid this, simply set both options to false. +- When using the `--listenToConsole` and `--dumpio` options, be aware that the server's console may become 'polluted' with messages from the browser. If you prefer to avoid this, simply set both options to **false**. # Performance Notice diff --git a/dist/index.cjs b/dist/index.cjs index 62ca7e1c..b6ad5f78 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"),u=require("puppeteer"),h=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","export-data","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","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"],indicators:["indicators-all"]},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:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],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 logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},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."}},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 the --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:w.logging.dest.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}],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:_(),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(),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),A=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:A[0]},{title:"warning",color:A[1]},{title:"notice",color:A[2]},{title:"verbose",color:A[3]},{title:"benchmark",color:A[4]}],listeners:[]};for(const[e,t]of Object.entries(w.logging))N[e]=t.value;const P=(t,r)=>{N.toFile&&(N.pathCreated||(!e.existsSync(N.dest)&&e.mkdirSync(N.dest),N.pathCreated=!0),e.appendFile(`${N.dest}${N.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},H=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=N;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;N.listeners.forEach((e=>{e(s,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,s)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=N;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];N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[e-1].color]].concat([o[A[e-1]],"\n",a])),N.listeners.forEach((e=>{e(n,l.join(" "))})),P(l,n)},U=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},D=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},j=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),G=(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"},F=(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(j,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,u=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!==u?(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(j,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(j,J().highcharts.cachePath),ce=()=>oe.hcVersion;function pe(){Highcharts.animObject=function(){return{duration:0}}}async function ue(e,t,r){window._displayErrors=r;const{getOptions:o,merge:i,setOptions:s,wrap:n}=Highcharts;Highcharts.setOptionsObj=i(!1,{},o()),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,u=JSON.parse(t.export.globalOptions);u&&s(u),Highcharts[t.export.constr||"chart"]("container",c,p);const h=o();for(const e in h)"function"!=typeof h[e]&&delete h[e];s(Highcharts.setOptionsObj),Highcharts.setOptionsObj={}}const he=e.readFileSync(j+"/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(he,{waitUntil:"domcontentloaded"}),await e.addScriptTag({path:`${le()}/sources.js`}),await e.evaluate(pe)}const ve=async(e,t,r,o)=>e.evaluate(ue,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(j,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),u=Math.ceil(c.chartWidth||n.width),{x:h,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:u,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:u,height:p,x:h,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,u,"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{enable:t,...r}=J().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!de){let e=0;const r=async()=>{try{H(3,`[browser] Attempting to get a browser instance (try ${++e}).`),de=await u.launch(o)}catch(t){if($(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;H(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&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 h.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):Ne(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'."))},Ae=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},Ne=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=F(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=F(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=G(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,...Ae(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,Ne(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."),Ne(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ne(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=[],Ue=()=>{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)},je=(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 Ge=(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 Fe 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 Fe("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 Fe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Fe("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 Fe(`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=G(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Fe("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 Fe("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=Xe(Ve,e,t,{id:a,uniqueId:i,type:l,body:n}),!0!==u)return t.send(u);let h=!1;e.socket.on("close",(()=>{h=!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 Fe("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.`),h)return H(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;if(!c||!c.result)throw new Fe(`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(j,"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:`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)&&Ge(et,r.rateLimiting),et.use(m.static(t.posix.join(j,"public"))),Qe(et),(e=>{e.post("/",ze),e.post("/:filename",ze)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(j,"public","index.html"))}))})(et),Me(et),(e=>{e.use(De),e.use(je)})(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=>Ge(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([Ue(),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=>{U(e&&parseInt(e.level)),e&&e.dest&&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:U,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(j,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(j+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:V};module.exports=lt; -//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZGVidWc6IHtcclxuICAgIGVuYWJsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0VOQUJMRScsXHJcbiAgICAgIGNsaU5hbWU6ICdlbmFibGVEZWJ1ZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyBvciBkaXNhYmxlcyBkZWJ1ZyBtb2RlIGZvciB0aGUgdW5kZXJseWluZyBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBoZWFkbGVzczoge1xyXG4gICAgICB2YWx1ZTogdHJ1ZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfSEVBRExFU1MnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ29udHJvbHMgdGhlIG1vZGUgaW4gd2hpY2ggdGhlIGJyb3dzZXIgaXMgbGF1bmNoZWQgd2hlbiBpbiB0aGUgZGVidWcgbW9kZS4nXHJcbiAgICB9LFxyXG4gICAgZGV2dG9vbHM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERVZUT09MUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIERldlRvb2xzIHdoZW4gdGhlIGJyb3dzZXIgaXMgaW4gYSBoZWFkZnVsIHN0YXRlLidcclxuICAgIH0sXHJcbiAgICBsaXN0ZW5Ub0NvbnNvbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19MSVNURU5fVE9fQ09OU09MRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdEZWNpZGVzIHdoZXRoZXIgdG8gZW5hYmxlIGEgbGlzdGVuZXIgZm9yIGNvbnNvbGUgbWVzc2FnZXMgc2VudCBmcm9tIHRoZSBicm93c2VyLidcclxuICAgIH0sXHJcbiAgICBkdW1waW86IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19EVU1QSU8nLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnUmVkaXJlY3RzIGJyb3dzZXIgcHJvY2VzcyBzdGRvdXQgYW5kIHN0ZGVyciB0byBwcm9jZXNzLnN0ZG91dCBhbmQgcHJvY2Vzcy5zdGRlcnIuJ1xyXG4gICAgfSxcclxuICAgIHNsb3dNbzoge1xyXG4gICAgICB2YWx1ZTogMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19TTE9XX01PJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1Nsb3dzIGRvd24gUHVwcGV0ZWVyIG9wZXJhdGlvbnMgYnkgdGhlIHNwZWNpZmllZCBudW1iZXIgb2YgbWlsbGlzZWNvbmRzLidcclxuICAgIH0sXHJcbiAgICBkZWJ1Z2dpbmdQb3J0OiB7XHJcbiAgICAgIHZhbHVlOiA5MjIyLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0RFQlVHR0lOR19QT1JUJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdTcGVjaWZpZXMgdGhlIGRlYnVnZ2luZyBwb3J0LidcclxuICAgIH1cclxuICB9XHJcbn07XHJcblxyXG4vLyBUaGUgY29uZmlnIGRlc2NyaXB0aW9ucyBvYmplY3QgZm9yIHRoZSBwcm9tcHRzIGZ1bmN0aW9uYWxpdHkuIEl0IGNvbnRhaW5zXHJcbi8vIGluZm9ybWF0aW9uIGxpa2U6XHJcbi8vICogVHlwZSBvZiBhIHByb21wdFxyXG4vLyAqIE5hbWUgb2YgYW4gb3B0aW9uXHJcbi8vICogU2hvcnQgZGVzY3JpcHRpb24gb2YgYSBjaG9zZW4gb3B0aW9uXHJcbi8vICogSW5pdGlhbCB2YWx1ZVxyXG5leHBvcnQgY29uc3QgcHJvbXB0c0NvbmZpZyA9IHtcclxuICBwdXBwZXRlZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ2xpc3QnLFxyXG4gICAgICBuYW1lOiAnYXJncycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgYXJndW1lbnRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wdXBwZXRlZXIuYXJncy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9XHJcbiAgXSxcclxuICBoaWdoY2hhcnRzOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3ZlcnNpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnSGlnaGNoYXJ0cyB2ZXJzaW9uJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLnZlcnNpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NkblVSTCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgVVJMIG9mIENETicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jZG5VUkwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb3JlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgY29yZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNvcmVTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnbW9kdWxlU2NyaXB0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdBdmFpbGFibGUgbW9kdWxlIHNjcmlwdHMnLFxyXG4gICAgICBpbnN0cnVjdGlvbnM6ICdTcGFjZTogU2VsZWN0IHNwZWNpZmljLCBBOiBTZWxlY3QgYWxsLCBFbnRlcjogQ29uZmlybS4nLFxyXG4gICAgICBjaG9pY2VzOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMubW9kdWxlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2luZGljYXRvclNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGluZGljYXRvciBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmluZGljYXRvclNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2N1c3RvbVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQ3VzdG9tIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY3VzdG9tU2NyaXB0cy52YWx1ZS5qb2luKCcsJyksXHJcbiAgICAgIHNlcGFyYXRvcjogJywnXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2ZvcmNlRmV0Y2gnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2UgcmUtZmV0Y2ggdGhlIHNjcmlwdHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuZm9yY2VGZXRjaC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnY2FjaGVQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2FjaGVQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBleHBvcnQ6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICd0eXBlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGV4cG9ydCBmaWxlIHR5cGUnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC50eXBlLnZhbHVlfWAsXHJcbiAgICAgIGluaXRpYWw6IDAsXHJcbiAgICAgIGNob2ljZXM6IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ2NvbnN0cicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBjb25zdHJ1Y3RvciBmb3IgSGlnaGNoYXJ0cycsXHJcbiAgICAgIGhpbnQ6IGBEZWZhdWx0OiAke2RlZmF1bHRDb25maWcuZXhwb3J0LmNvbnN0ci52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ2NoYXJ0JywgJ3N0b2NrQ2hhcnQnLCAnbWFwQ2hhcnQnLCAnZ2FudHRDaGFydCddXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRIZWlnaHQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgaGVpZ2h0IG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRIZWlnaHQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFdpZHRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHdpZHRoIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRXaWR0aC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0U2NhbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgZmFsbGJhY2sgc2NhbGUgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5leHBvcnQuZGVmYXVsdFNjYWxlLnZhbHVlLFxyXG4gICAgICBtaW46IDAuMSxcclxuICAgICAgbWF4OiA1XHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Jhc3Rlcml6YXRpb25UaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSByZW5kZXJpbmcgd2VicGFnZSB0aW1lb3V0IGluIG1pbGxpc2Vjb25kcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LnJhc3Rlcml6YXRpb25UaW1lb3V0LnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBjdXN0b21Mb2dpYzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93Q29kZUV4ZWN1dGlvbicsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZXhlY3V0aW9uIG9mIGN1c3RvbSBjb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb24udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnYWxsb3dGaWxlUmVzb3VyY2VzJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBmaWxlIHJlc291cmNlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBzZXJ2ZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnU3RhcnRzIHRoZSBzZXJ2ZXIgb24gMC4wLjAuMCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXJ2ZXIgaG9zdG5hbWUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3BvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgc2VydmVyIGJlbmNobWFya2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncHJveHkuaG9zdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaG9zdCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5Lmhvc3QudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBvZiB0aGUgcHJveHkgc2VydmVyIHRvIHVzZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnByb3h5LnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncHJveHkudGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdGltZW91dCBmb3IgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS50aW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5lbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHJhdGUgbGltaXRpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5tYXhSZXF1ZXN0cycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSByZXF1ZXN0cyBhbGxvd2VkIHBlciBtaW51dGUnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLndpbmRvdycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmF0ZS1saW1pdGluZyB0aW1lIHdpbmRvdyBpbiBtaW51dGVzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLndpbmRvdy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZGVsYXknLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgZGVsYXkgZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5kZWxheS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcudHJ1c3RQcm94eScsXHJcbiAgICAgIG1lc3NhZ2U6ICdTZXQgdG8gdHJ1ZSBpZiBiZWhpbmQgYSBsb2FkIGJhbGFuY2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnRydXN0UHJveHkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwS2V5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcFRva2VuIGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBLZXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy5za2lwVG9rZW4nLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgd2hlbiBwcm92aWRlZCB3aXRoIHRoZSBza2lwS2V5IGFyZ3VtZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLnNraXBUb2tlbi52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBTU0wgcHJvdG9jb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ3NzbC5mb3JjZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdGb3JjZSBzZXJ2aW5nIG9ubHkgb3ZlciBIVFRQUycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnNzbC5mb3JjZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdzc2wucG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdTU0wgc2VydmVyIHBvcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnc3NsLmNlcnRQYXRoJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGZpbmQgdGhlIFNTTCBjZXJ0aWZpY2F0ZS9rZXknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuY2VydFBhdGgudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHBvb2w6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdtaW5Xb3JrZXJzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBpbml0aWFsIG51bWJlciBvZiB3b3JrZXJzIHRvIHNwYXduJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLm1pbldvcmtlcnMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWF4V29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbWF4aW11bSBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5tYXhXb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3dvcmtMaW1pdCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSBwaWVjZXMgb2Ygd29yayB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgYSBQdXBwZXRlZXIgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC53b3JrTGltaXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnYWNxdWlyZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYWNxdWlyZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnY3JlYXRlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyB0byB3YWl0IGZvciBjcmVhdGluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVRpbWVvdXQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVzdHJveVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgZGVzdHJveWluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmRlc3Ryb3lUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2lkbGVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIGFmdGVyIGFuIGlkbGUgcmVzb3VyY2UgaXMgZGVzdHJveWVkJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmlkbGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVJldHJ5SW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmV0cnkgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIGEgY3JlYXRlIHByb2Nlc3MgZmFpbHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuY3JlYXRlUmV0cnlJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyZWFwZXJJbnRlcnZhbCcsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ1RoZSByZWFwZXIgaW50ZXJ2YWwgaW4gbWlsbGlzZWNvbmRzIGFmdGVyIHRyaWdnZXJpbmcgdGhlIGNoZWNrIGZvciBpZGxlIHJlc291cmNlcyB0byBkZXN0cm95JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLnJlYXBlckludGVydmFsLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2JlbmNobWFya2luZycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgYmVuY2htYXJraW5nIGZvciBhIHJlc291cmNlIHBvb2wnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wuYmVuY2htYXJraW5nLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBsb2dnaW5nOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbGV2ZWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgbG9nIGxldmVsICgwOiBzaWxlbnQsIDE6IGVycm9yLCAyOiB3YXJuaW5nLCAzOiBub3RpY2UsIDQ6IHZlcmJvc2UsIDU6IGJlbmNobWFyayknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcubGV2ZWwudmFsdWUsXHJcbiAgICAgIHJvdW5kOiAwLFxyXG4gICAgICBtaW46IDAsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZmlsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIGxvZyBmaWxlIG5hbWUuIFNldCB3aXRoIHRoZSAtLWxvZ0Rlc3QgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcubG9nZ2luZy5maWxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdkZXN0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwYXRoIHRvIGxvZyBmaWxlcy4gRW5hYmxlcyBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZGVzdC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgdWk6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdlbmFibGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIFVJIGZvciB0aGUgZXhwb3J0IHNlcnZlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcudWkuZW5hYmxlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyb3V0ZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdBIHJvdXRlIHRvIGF0dGFjaCB0aGUgVUknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLnJvdXRlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBvdGhlcjogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdub2RlRW52JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vZGVFbnYudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Qcm9jZXNzRXhpdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIGZhbHNlIHRvIHNraXAgYXR0YWNoaW5nIHByb2Nlc3MuZXhpdCBoYW5kbGVycycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcub3RoZXIubGlzdGVuVG9Qcm9jZXNzRXhpdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbm9Mb2dvJyxcclxuICAgICAgbWVzc2FnZTogJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gc3RhcnR1cC4gUmVwbGFjZWQgYnkgc2ltcGxlIHRleHQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLm5vTG9nby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoYXJkUmVzZXRQYWdlJyxcclxuICAgICAgbWVzc2FnZTogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHknLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmhhcmRSZXNldFBhZ2UudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIGRlYnVnOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIGJyb3dzZXIgaW5zdGFuY2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdoZWFkbGVzcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbW9kZSBzZXR0aW5nIGZvciB0aGUgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuaGVhZGxlc3MudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZGV2dG9vbHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIERldlRvb2xzIGZvciB0aGUgaGVhZGZ1bCBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZXZ0b29scy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdsaXN0ZW5Ub0NvbnNvbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGV2ZW50IGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIGZyb20gdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmxpc3RlblRvQ29uc29sZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdkdW1waW8nLFxyXG4gICAgICBtZXNzYWdlOiAnUmVkaXJlY3RzIHRoZSBicm93c2VyIHN0ZG91dCBhbmQgc3RkZXJyIHRvIE5vZGVKUyBwcm9jZXNzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kdW1waW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc2xvd01vJyxcclxuICAgICAgbWVzc2FnZTogJ1B1cHBldGVlciBvcGVyYXRpb25zIHNsb3cgZG93biBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLnNsb3dNby52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWJ1Z2dpbmdQb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBwb3J0IG51bWJlciBmb3IgZGVidWdnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5kZWJ1Z2dpbmdQb3J0LnZhbHVlXHJcbiAgICB9XHJcbiAgXVxyXG59O1xyXG5cclxuLy8gQWJzb2x1dGUgcHJvcHMgdGhhdCwgaW4gY2FzZSBvZiBtZXJnaW5nIHJlY3Vyc2l2ZWx5LCBuZWVkIHRvIGJlIGZvcmNlIG1lcmdlZFxyXG5leHBvcnQgY29uc3QgYWJzb2x1dGVQcm9wcyA9IFtcclxuICAnb3B0aW9ucycsXHJcbiAgJ2dsb2JhbE9wdGlvbnMnLFxyXG4gICd0aGVtZU9wdGlvbnMnLFxyXG4gICdyZXNvdXJjZXMnLFxyXG4gICdwYXlsb2FkJ1xyXG5dO1xyXG5cclxuLy8gQXJndW1lbnQgbmVzdGluZyBsZXZlbCBvZiBhbGwgZXhwb3J0IHNlcnZlciBvcHRpb25zXHJcbmV4cG9ydCBjb25zdCBuZXN0ZWRBcmdzID0ge307XHJcblxyXG4vKipcclxuICogUmVjdXJzaXZlbHkgY3JlYXRlcyBhIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHMgZnJvbSBhbiBvYmplY3QuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmogLSBUaGUgb2JqZWN0IGNvbnRhaW5pbmcgbmVzdGVkIGFyZ3VtZW50cy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByb3BDaGFpbiAtIFRoZSBjdXJyZW50IGNoYWluIG9mIG5lc3RlZCBwcm9wZXJ0aWVzXHJcbiAqICh1c2VkIGludGVybmFsbHkgZHVyaW5nIHJlY3Vyc2lvbikuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVOZXN0ZWRBcmdzID0gKG9iaiwgcHJvcENoYWluID0gJycpID0+IHtcclxuICBPYmplY3Qua2V5cyhvYmopLmZvckVhY2goKGspID0+IHtcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGspKSB7XHJcbiAgICAgIGNvbnN0IGVudHJ5ID0gb2JqW2tdO1xyXG4gICAgICBpZiAodHlwZW9mIGVudHJ5LnZhbHVlID09PSAndW5kZWZpbmVkJykge1xyXG4gICAgICAgIC8vIEdvIGRlZXBlciBpbiB0aGUgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIGNyZWF0ZU5lc3RlZEFyZ3MoZW50cnksIGAke3Byb3BDaGFpbn0uJHtrfWApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIENyZWF0ZSB0aGUgY2hhaW4gb2YgbmVzdGVkIGFyZ3VtZW50c1xyXG4gICAgICAgIG5lc3RlZEFyZ3NbZW50cnkuY2xpTmFtZSB8fCBrXSA9IGAke3Byb3BDaGFpbn0uJHtrfWAuc3Vic3RyaW5nKDEpO1xyXG5cclxuICAgICAgICAvLyBTdXBwb3J0IGZvciB0aGUgbGVnYWN5LCBQaGFudG9tSlMgcHJvcGVydGllcyBuYW1lc1xyXG4gICAgICAgIGlmIChlbnRyeS5sZWdhY3lOYW1lICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICAgIG5lc3RlZEFyZ3NbZW50cnkubGVnYWN5TmFtZV0gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9KTtcclxufTtcclxuXHJcbmNyZWF0ZU5lc3RlZEFyZ3MoZGVmYXVsdENvbmZpZyk7XHJcbiIsIi8qKlxyXG4gKiBAZmlsZW92ZXJ2aWV3XHJcbiAqIFRoaXMgZmlsZSBpcyByZXNwb25zaWJsZSBmb3IgcGFyc2luZyB0aGUgZW52aXJvbm1lbnQgdmFyaWFibGVzIHdpdGggdGhlICd6b2QnXHJcbiAqIGxpYnJhcnkuIFRoZSBwYXJzZWQgZW52aXJvbm1lbnQgdmFyaWFibGVzIGFyZSB0aGVuIGV4cG9ydGVkIHRvIGJlIHVzZWRcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIFwiZW52c1wiLiBXZSBzaG91bGQgbm90IHVzZSBwcm9jZXNzLmVudiBkaXJlY3RseVxyXG4gKiBpbiB0aGUgYXBwbGljYXRpb24gYXMgdGhlc2Ugd291bGQgbm90IGJlIHBhcnNlZCBwcm9wZXJseS5cclxuICpcclxuICogVGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgcGFyc2VkIGFuZCB2YWxpZGF0ZWQgb25seSBvbmNlIHdoZW5cclxuICogdGhlIGFwcGxpY2F0aW9uIHN0YXJ0cy4gV2Ugc2hvdWxkIHdyaXRlIGEgY3VzdG9tIHZhbGlkYXRvciBvciBhIHRyYW5zZm9ybWVyXHJcbiAqIGZvciBlYWNoIG9mIHRoZSBvcHRpb25zLlxyXG4gKi9cclxuXHJcbmltcG9ydCBkb3RlbnYgZnJvbSAnZG90ZW52JztcclxuaW1wb3J0IHsgeiB9IGZyb20gJ3pvZCc7XHJcblxyXG5pbXBvcnQgeyBzY3JpcHRzTmFtZXMgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIExvYWQgLmVudiBpbnRvIGVudmlyb25tZW50IHZhcmlhYmxlc1xyXG5kb3RlbnYuY29uZmlnKCk7XHJcblxyXG4vLyBPYmplY3Qgd2l0aCBjdXN0b20gdmFsaWRhdG9ycyBhbmQgdHJhbnNmb3JtZXJzLCB0byBhdm9pZCByZXBldGl0aW9uXHJcbi8vIGluIHRoZSBDb25maWcgb2JqZWN0XHJcbmNvbnN0IHYgPSB7XHJcbiAgLy8gU3BsaXRzIHN0cmluZyB2YWx1ZSBpbnRvIGVsZW1lbnRzIGluIGFuIGFycmF5LCB0cmltcyBldmVyeSBlbGVtZW50LCBjaGVja3NcclxuICAvLyBpZiBhbiBhcnJheSBpcyBjb3JyZWN0LCBpZiBpdCBpcyBlbXB0eSwgYW5kIGlmIGl0IGlzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIGFycmF5OiAoZmlsdGVyQXJyYXkpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT5cclxuICAgICAgICB2YWx1ZVxyXG4gICAgICAgICAgLnNwbGl0KCcsJylcclxuICAgICAgICAgIC5tYXAoKHZhbHVlKSA9PiB2YWx1ZS50cmltKCkpXHJcbiAgICAgICAgICAuZmlsdGVyKCh2YWx1ZSkgPT4gZmlsdGVyQXJyYXkuaW5jbHVkZXModmFsdWUpKVxyXG4gICAgICApXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUubGVuZ3RoID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIG9ubHkgdHJ1ZSwgZmFsc2UgYW5kIGNvcnJlY3RseSBwYXJzZSB0aGUgdmFsdWUgdG8gYm9vbGVhblxyXG4gIC8vIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgYm9vbGVhbjogKCkgPT5cclxuICAgIHpcclxuICAgICAgLmVudW0oWyd0cnVlJywgJ2ZhbHNlJywgJyddKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlID09PSAndHJ1ZScgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gQWxsb3dzIHBhc3NlZCB2YWx1ZXMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWUgd2lsbFxyXG4gIC8vIGJlIHVuZGVmaW5lZFxyXG4gIGVudW06ICh2YWx1ZXMpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsuLi52YWx1ZXMsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBUcmltcyB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjaGVja3MgaWYgaXQgaXMgZW1wdHkgb3IgY29udGFpbnMgc3RyaW5naWZpZWRcclxuICAvLyB2YWx1ZXMgc3VjaCBhcyBmYWxzZSwgdW5kZWZpbmVkLCBudWxsLCBOYU4sIGlmIGl0IGRvZXMsIHJldHVybnMgdW5kZWZpbmVkXHJcbiAgc3RyaW5nOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgICFbJ2ZhbHNlJywgJ3VuZGVmaW5lZCcsICdudWxsJywgJ05hTiddLmluY2x1ZGVzKHZhbHVlKSB8fFxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgc3RyaW5nIGNvbnRhaW5zIGZvcmJpZGRlbiB2YWx1ZXMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwb3NpdGl2ZSBudW1iZXJzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBwb3NpdGl2ZU51bTogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICB2YWx1ZSA9PT0gJycgfHwgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiYgcGFyc2VGbG9hdCh2YWx1ZSkgPiAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgcG9zaXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBub24tbmVnYXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZVxyXG4gIC8vIHdpbGwgYmUgdW5kZWZpbmVkXHJcbiAgbm9uTmVnYXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID49IDApLFxyXG4gICAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICAgIG1lc3NhZ2U6IGBUaGUgdmFsdWUgbXVzdCBiZSBudW1lcmljIGFuZCBub24tbmVnYXRpdmUsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgICAgfSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSlcclxufTtcclxuXHJcbmV4cG9ydCBjb25zdCBDb25maWcgPSB6Lm9iamVjdCh7XHJcbiAgLy8gaGlnaGNoYXJ0c1xyXG4gIEhJR0hDSEFSVFNfVkVSU0lPTjogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+IC9eKGxhdGVzdHxcXGQrKFxcLlxcZCspezAsMn0pJC8udGVzdCh2YWx1ZSkgfHwgdmFsdWUgPT09ICcnLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEhJR0hDSEFSVFNfVkVSU0lPTiBtdXN0IGJlICdsYXRlc3QnLCBhIG1ham9yIHZlcnNpb24sIG9yIGluIHRoZSBmb3JtIFhYLllZLlpaLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ0ROX1VSTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUuc3RhcnRzV2l0aCgnaHR0cHM6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHA6Ly8nKSB8fFxyXG4gICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBISUdIQ0hBUlRTX0NETl9VUkwuIEl0IHNob3VsZCBzdGFydCB3aXRoIGh0dHA6Ly8gb3IgaHR0cHM6Ly8sIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcbiAgSElHSENIQVJUU19DT1JFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmNvcmUpLFxyXG4gIEhJR0hDSEFSVFNfTU9EVUxFX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLm1vZHVsZXMpLFxyXG4gIEhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFM6IHYuYXJyYXkoc2NyaXB0c05hbWVzLmluZGljYXRvcnMpLFxyXG4gIEhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0g6IHYuYm9vbGVhbigpLFxyXG4gIEhJR0hDSEFSVFNfQ0FDSEVfUEFUSDogdi5zdHJpbmcoKSxcclxuICBISUdIQ0hBUlRTX0FETUlOX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBleHBvcnRcclxuICBFWFBPUlRfVFlQRTogdi5lbnVtKFsnanBlZycsICdwbmcnLCAncGRmJywgJ3N2ZyddKSxcclxuICBFWFBPUlRfQ09OU1RSOiB2LmVudW0oWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXSksXHJcbiAgRVhQT1JUX0RFRkFVTFRfSEVJR0hUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfV0lEVEg6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfREVGQVVMVF9TQ0FMRTogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuXHJcbiAgLy8gY3VzdG9tXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OOiB2LmJvb2xlYW4oKSxcclxuICBDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVM6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXJcclxuICBTRVJWRVJfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9CRU5DSE1BUktJTkc6IHYuYm9vbGVhbigpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcHJveHlcclxuICBTRVJWRVJfUFJPWFlfSE9TVDogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUFJPWFlfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9QUk9YWV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIHNlcnZlciByYXRlIGxpbWl0aW5nXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1c6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWTogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX0tFWTogdi5zdHJpbmcoKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBzZXJ2ZXIgc3NsXHJcbiAgU0VSVkVSX1NTTF9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfRk9SQ0U6IHYuYm9vbGVhbigpLFxyXG4gIFNFUlZFUl9TU0xfUE9SVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIFNFUlZFUl9TU0xfQ0VSVF9QQVRIOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBwb29sXHJcbiAgUE9PTF9NSU5fV09SS0VSUzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfTUFYX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1dPUktfTElNSVQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBQT09MX0FDUVVJUkVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0RFU1RST1lfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfSURMRV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX1JFQVBFUl9JTlRFUlZBTDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gbG9nZ2VyXHJcbiAgTE9HR0lOR19MRVZFTDogelxyXG4gICAgLnN0cmluZygpXHJcbiAgICAudHJpbSgpXHJcbiAgICAucmVmaW5lKFxyXG4gICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWUgPT09ICcnIHx8XHJcbiAgICAgICAgKCFpc05hTihwYXJzZUZsb2F0KHZhbHVlKSkgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpID49IDAgJiZcclxuICAgICAgICAgIHBhcnNlRmxvYXQodmFsdWUpIDw9IDUpLFxyXG4gICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgbWVzc2FnZTogYEludmFsaWQgdmFsdWUgZm9yIExPR0dJTkdfTEVWRUwuIFdlIG9ubHkgYWNjZXB0IHZhbHVlcyBmcm9tIDAgdG8gNSBhcyBsb2dnaW5nIGxldmVscywgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gcGFyc2VGbG9hdCh2YWx1ZSkgOiB1bmRlZmluZWQpKSxcclxuICBMT0dHSU5HX0ZJTEU6IHYuc3RyaW5nKCksXHJcbiAgTE9HR0lOR19ERVNUOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyB1aVxyXG4gIFVJX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgVUlfUk9VVEU6IHYuc3RyaW5nKCksXHJcblxyXG4gIC8vIG90aGVyXHJcbiAgT1RIRVJfTk9ERV9FTlY6IHYuZW51bShbJ2RldmVsb3BtZW50JywgJ3Byb2R1Y3Rpb24nLCAndGVzdCddKSxcclxuICBPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfTk9fTE9HTzogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfSEFSRF9SRVNFVF9QQUdFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xyXG5cclxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xyXG5cclxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZSxcclxuICBoaWdoY2hhcnRzLFxyXG4gIHZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cclxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xyXG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XHJcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsICd1dGY4Jyk7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1ZyB9ID0gZ2V0T3B0aW9ucygpLmRlYnVnO1xyXG4gIGNvbnN0IGxhdW5jaE9wdGlvbnMgPSB7XHJcbiAgICBoZWFkbGVzczogJ3NoZWxsJyxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWcpXHJcbiAgfTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgYnJvd3NlclxyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgbGV0IHRyeUNvdW50ID0gMDtcclxuXHJcbiAgICBjb25zdCBvcGVuID0gYXN5bmMgKCkgPT4ge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2Jyb3dzZXJdIEF0dGVtcHRpbmcgdG8gZ2V0IGEgYnJvd3NlciBpbnN0YW5jZSAodHJ5ICR7Kyt0cnlDb3VudH0pLmBcclxuICAgICAgICApO1xyXG4gICAgICAgIGJyb3dzZXIgPSBhd2FpdCBwdXBwZXRlZXIubGF1bmNoKGxhdW5jaE9wdGlvbnMpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDEsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgICdbYnJvd3Nlcl0gRmFpbGVkIHRvIGxhdW5jaCBhIGJyb3dzZXIgaW5zdGFuY2UuJ1xyXG4gICAgICAgICk7XHJcblxyXG4gICAgICAgIC8vIFJldHJ5IHRvIGxhdW5jaCBicm93c2VyIHVudGlsIHJlYWNoaW5nIG1heCBhdHRlbXB0c1xyXG4gICAgICAgIGlmICh0cnlDb3VudCA8IDI1KSB7XHJcbiAgICAgICAgICBsb2coMywgYFticm93c2VyXSBSZXRyeSB0byBvcGVuIGEgYnJvd3NlciAoJHt0cnlDb3VudH0gb3V0IG9mIDI1KS5gKTtcclxuICAgICAgICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgNDAwMCkpO1xyXG4gICAgICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICB0aHJvdyBlcnJvcjtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgIH07XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgYXdhaXQgb3BlbigpO1xyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIHNldFBhZ2VFdmVudHMocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKCFwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXHJcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcclxuICogYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXHJcbiAqIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcclxuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxyXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAvLyBleHBvcnRzXHJcbiAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xyXG4gICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICBdKSB7XHJcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXHJcbiAqL1xyXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cclxuICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcclxuICBwYWdlLFxyXG4gIGhlaWdodCxcclxuICB3aWR0aCxcclxuICBlbmNvZGluZyxcclxuICByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4pID0+IHtcclxuICBhd2FpdCBwYWdlLmVtdWxhdGVNZWRpYVR5cGUoJ3NjcmVlbicpO1xyXG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5wZGYoe1xyXG4gICAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgZW5jb2RpbmdcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcclxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxyXG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxyXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCksIHtcclxuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcclxuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNoYXJ0OiB7XHJcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzID0gYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XHJcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcclxuICBleHBvcnRBdHRlbXB0czogMCxcclxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXHJcbiAgdGltZVNwZW50OiAwLFxyXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxyXG4gIHNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKiovXHJcblxyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXHJcbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXHJcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XHJcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRJbnRlcnZhbCxcclxuICBjbGVhckFsbEludGVydmFsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlVmVyc2lvbiwgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogdmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCB7IHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgIHJlcy5zZW5kKHtcclxuICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICB1cHRpbWU6XHJcbiAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IHZlcnNpb24oKSxcclxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXHJcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXHJcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxyXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXHJcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFBvb2xcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJkZWJ1ZyIsImhlYWRsZXNzIiwiZGV2dG9vbHMiLCJsaXN0ZW5Ub0NvbnNvbGUiLCJkdW1waW8iLCJzbG93TW8iLCJkZWJ1Z2dpbmdQb3J0IiwicHJvbXB0c0NvbmZpZyIsIm5hbWUiLCJtZXNzYWdlIiwiaW5pdGlhbCIsImpvaW4iLCJzZXBhcmF0b3IiLCJpbnN0cnVjdGlvbnMiLCJjaG9pY2VzIiwiaGludCIsIm1pbiIsIm1heCIsInJvdW5kIiwiYWJzb2x1dGVQcm9wcyIsIm5lc3RlZEFyZ3MiLCJjcmVhdGVOZXN0ZWRBcmdzIiwib2JqIiwicHJvcENoYWluIiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJrIiwiaW5jbHVkZXMiLCJlbnRyeSIsInN1YnN0cmluZyIsInVuZGVmaW5lZCIsImRvdGVudiIsImNvbmZpZyIsInYiLCJmaWx0ZXJBcnJheSIsInoiLCJzdHJpbmciLCJ0cmFuc2Zvcm0iLCJzcGxpdCIsIm1hcCIsInRyaW0iLCJmaWx0ZXIiLCJsZW5ndGgiLCJlbnVtIiwidmFsdWVzIiwicmVmaW5lIiwiaXNOYU4iLCJwYXJzZUZsb2F0IiwiZW52cyIsIm9iamVjdCIsIkhJR0hDSEFSVFNfVkVSU0lPTiIsInRlc3QiLCJISUdIQ0hBUlRTX0NETl9VUkwiLCJzdGFydHNXaXRoIiwiSElHSENIQVJUU19DT1JFX1NDUklQVFMiLCJISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTIiwiSElHSENIQVJUU19JTkRJQ0FUT1JfU0NSSVBUUyIsIkhJR0hDSEFSVFNfRk9SQ0VfRkVUQ0giLCJISUdIQ0hBUlRTX0NBQ0hFX1BBVEgiLCJISUdIQ0hBUlRTX0FETUlOX1RPS0VOIiwiRVhQT1JUX1RZUEUiLCJFWFBPUlRfQ09OU1RSIiwiRVhQT1JUX0RFRkFVTFRfSEVJR0hUIiwiRVhQT1JUX0RFRkFVTFRfV0lEVEgiLCJFWFBPUlRfREVGQVVMVF9TQ0FMRSIsIkVYUE9SVF9SQVNURVJJWkFUSU9OX1RJTUVPVVQiLCJDVVNUT01fTE9HSUNfQUxMT1dfQ09ERV9FWEVDVVRJT04iLCJDVVNUT01fTE9HSUNfQUxMT1dfRklMRV9SRVNPVVJDRVMiLCJTRVJWRVJfRU5BQkxFIiwiU0VSVkVSX0hPU1QiLCJTRVJWRVJfUE9SVCIsIlNFUlZFUl9CRU5DSE1BUktJTkciLCJTRVJWRVJfUFJPWFlfSE9TVCIsIlNFUlZFUl9QUk9YWV9QT1JUIiwiU0VSVkVSX1BST1hZX1RJTUVPVVQiLCJTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUiLCJTRVJWRVJfUkFURV9MSU1JVElOR19NQVhfUkVRVUVTVFMiLCJTRVJWRVJfUkFURV9MSU1JVElOR19XSU5ET1ciLCJTRVJWRVJfUkFURV9MSU1JVElOR19ERUxBWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1RSVVNUX1BST1hZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19TS0lQX1RPS0VOIiwiU0VSVkVSX1NTTF9FTkFCTEUiLCJTRVJWRVJfU1NMX0ZPUkNFIiwiU0VSVkVSX1NTTF9QT1JUIiwiU0VSVkVSX1NTTF9DRVJUX1BBVEgiLCJQT09MX01JTl9XT1JLRVJTIiwiUE9PTF9NQVhfV09SS0VSUyIsIlBPT0xfV09SS19MSU1JVCIsIlBPT0xfQUNRVUlSRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfVElNRU9VVCIsIlBPT0xfREVTVFJPWV9USU1FT1VUIiwiUE9PTF9JRExFX1RJTUVPVVQiLCJQT09MX0NSRUFURV9SRVRSWV9JTlRFUlZBTCIsIlBPT0xfUkVBUEVSX0lOVEVSVkFMIiwiUE9PTF9CRU5DSE1BUktJTkciLCJMT0dHSU5HX0xFVkVMIiwiTE9HR0lOR19GSUxFIiwiTE9HR0lOR19ERVNUIiwiVUlfRU5BQkxFIiwiVUlfUk9VVEUiLCJPVEhFUl9OT0RFX0VOViIsIk9USEVSX0xJU1RFTl9UT19QUk9DRVNTX0VYSVRTIiwiT1RIRVJfTk9fTE9HTyIsIk9USEVSX0hBUkRfUkVTRVRfUEFHRSIsIkRFQlVHX0VOQUJMRSIsIkRFQlVHX0hFQURMRVNTIiwiREVCVUdfREVWVE9PTFMiLCJERUJVR19MSVNURU5fVE9fQ09OU09MRSIsIkRFQlVHX0RVTVBJTyIsIkRFQlVHX1NMT1dfTU8iLCJERUJVR19ERUJVR0dJTkdfUE9SVCIsInBhcnRpYWwiLCJwYXJzZSIsInByb2Nlc3MiLCJlbnYiLCJjb2xvcnMiLCJ0b0NvbnNvbGUiLCJ0b0ZpbGUiLCJwYXRoQ3JlYXRlZCIsImxldmVsc0Rlc2MiLCJ0aXRsZSIsImNvbG9yIiwibGlzdGVuZXJzIiwia2V5Iiwib3B0aW9uIiwiZW50cmllcyIsImxvZ1RvRmlsZSIsInRleHRzIiwicHJlZml4IiwiZXhpc3RzU3luYyIsIm1rZGlyU3luYyIsImFwcGVuZEZpbGUiLCJjb25jYXQiLCJlcnJvciIsImNvbnNvbGUiLCJsb2ciLCJuZXdMZXZlbCIsIkRhdGUiLCJ0b1N0cmluZyIsImZuIiwiYXBwbHkiLCJsb2dXaXRoU3RhY2siLCJjdXN0b21NZXNzYWdlIiwibWFpbk1lc3NhZ2UiLCJzdGFja01lc3NhZ2UiLCJzdGFjayIsInNsaWNlIiwic2V0TG9nTGV2ZWwiLCJlbmFibGVGaWxlTG9nZ2luZyIsImxvZ0Rlc3QiLCJsb2dGaWxlIiwiZW5kc1dpdGgiLCJfX2Rpcm5hbWUiLCJmaWxlVVJMVG9QYXRoIiwiVVJMIiwiZG9jdW1lbnQiLCJyZXF1aXJlIiwicGF0aFRvRmlsZVVSTCIsIl9fZmlsZW5hbWUiLCJocmVmIiwiX2RvY3VtZW50Q3VycmVudFNjcmlwdCIsInNyYyIsImJhc2VVUkkiLCJmaXhUeXBlIiwiZm9ybWF0cyIsIm91dFR5cGUiLCJwb3AiLCJmaW5kIiwidCIsImhhbmRsZVJlc291cmNlcyIsImFsbG93ZWRQcm9wcyIsImhhbmRsZWRSZXNvdXJjZXMiLCJjb3JyZWN0UmVzb3VyY2VzIiwiaXNDb3JyZWN0SlNPTiIsInJlYWRGaWxlU3luYyIsImZpbGVzIiwicHJvcE5hbWUiLCJpdGVtIiwiZGF0YSIsInBhcnNlZERhdGEiLCJKU09OIiwic3RyaW5naWZ5IiwiZGVlcENvcHkiLCJjb3B5IiwiQXJyYXkiLCJpc0FycmF5IiwicHJvdG90eXBlIiwiaGFzT3duUHJvcGVydHkiLCJjYWxsIiwib3B0aW9uc1N0cmluZ2lmeSIsImFsbG93RnVuY3Rpb25zIiwicmVwbGFjZUFsbCIsInByaW50VXNhZ2UiLCJib2xkIiwieWVsbG93IiwiY3ljbGVDYXRlZ29yaWVzIiwiZGVzY05hbWUiLCJncmVlbiIsImkiLCJibHVlIiwiY2F0ZWdvcnkiLCJ0b1VwcGVyQ2FzZSIsInJlZCIsInRvQm9vbGVhbiIsIndyYXBBcm91bmQiLCJyZXBsYWNlIiwibWVhc3VyZVRpbWUiLCJzdGFydCIsImhydGltZSIsImJpZ2ludCIsIk51bWJlciIsImdlbmVyYWxPcHRpb25zIiwiZ2V0T3B0aW9ucyIsIm1lcmdlQ29uZmlnT3B0aW9ucyIsIm5ld09wdGlvbnMiLCJtZXJnZWRPcHRpb25zIiwidXBkYXRlRGVmYXVsdENvbmZpZyIsImNvbmZpZ09iaiIsImN1c3RvbU9iaiIsImN1c3RvbVZhbHVlIiwiaW5pdE9wdGlvbnMiLCJpdGVtcyIsInJlY3Vyc2l2ZVByb3BzIiwib2JqZWN0VG9VcGRhdGUiLCJuZXN0ZWROYW1lcyIsInNoaWZ0IiwiYXNzaWduIiwiYXN5bmMiLCJmZXRjaCIsInVybCIsInJlcXVlc3RPcHRpb25zIiwiUHJvbWlzZSIsInJlc29sdmUiLCJyZWplY3QiLCJwcm90b2NvbCIsImh0dHBzIiwiaHR0cCIsImdldFByb3RvY29sIiwiZ2V0IiwicmVzIiwib24iLCJjaHVuayIsInRleHQiLCJFeHBvcnRFcnJvciIsIkVycm9yIiwiY29uc3RydWN0b3IiLCJzdXBlciIsInRoaXMiLCJzZXRFcnJvciIsInN0YXR1c0NvZGUiLCJjYWNoZSIsImFjdGl2ZU1hbmlmZXN0Iiwic291cmNlcyIsImhjVmVyc2lvbiIsImV4dHJhY3RWZXJzaW9uIiwiaW5kZXhPZiIsImZldGNoQW5kUHJvY2Vzc1NjcmlwdCIsInNjcmlwdCIsImZldGNoZWRNb2R1bGVzIiwic2hvdWxkVGhyb3dFcnJvciIsInJlc3BvbnNlIiwidXBkYXRlQ2FjaGUiLCJoaWdoY2hhcnRzT3B0aW9ucyIsInByb3h5T3B0aW9ucyIsInNvdXJjZVBhdGgiLCJwcm94eUFnZW50IiwicHJveHlIb3N0IiwicHJveHlQb3J0IiwiSHR0cHNQcm94eUFnZW50IiwiYWdlbnQiLCJhbGxGZXRjaFByb21pc2VzIiwiYWxsIiwiZmV0Y2hTY3JpcHRzIiwiYyIsIm0iLCJ3cml0ZUZpbGVTeW5jIiwiY2hlY2tBbmRVcGRhdGVDYWNoZSIsIm1hbmlmZXN0UGF0aCIsInJlcXVlc3RVcGRhdGUiLCJtYW5pZmVzdCIsIm1vZHVsZU1hcCIsIm51bWJlck9mTW9kdWxlcyIsInNvbWUiLCJtb2R1bGVOYW1lIiwibmV3TWFuaWZlc3QiLCJzYXZlQ29uZmlnVG9NYW5pZmVzdCIsImdldENhY2hlUGF0aCIsInNldHVwSGlnaGNoYXJ0cyIsIkhpZ2hjaGFydHMiLCJhbmltT2JqZWN0IiwiZHVyYXRpb24iLCJ0cmlnZ2VyRXhwb3J0IiwiY2hhcnRPcHRpb25zIiwiZGlzcGxheUVycm9ycyIsIl9kaXNwbGF5RXJyb3JzIiwibWVyZ2UiLCJzZXRPcHRpb25zIiwid3JhcCIsInNldE9wdGlvbnNPYmoiLCJGdW5jdGlvbiIsImNoYXJ0IiwiYW5pbWF0aW9uIiwic3RySW5qIiwiaXNSZW5kZXJDb21wbGV0ZSIsIkNoYXJ0IiwicHJvY2VlZCIsInVzZXJPcHRpb25zIiwiY2IiLCJleHBvcnRpbmciLCJlbmFibGVkIiwicGxvdE9wdGlvbnMiLCJzZXJpZXMiLCJsYWJlbCIsInRvb2x0aXAiLCJvbkhpZ2hjaGFydHNSZW5kZXIiLCJhZGRFdmVudCIsIlNlcmllcyIsImZpbmFsT3B0aW9ucyIsImZpbmFsQ2FsbGJhY2siLCJkZWZhdWx0T3B0aW9ucyIsInByb3AiLCJ0ZW1wbGF0ZSIsImJyb3dzZXIiLCJuZXdQYWdlIiwicGFnZSIsInNldENhY2hlRW5hYmxlZCIsInNldFBhZ2VDb250ZW50IiwiJGV2YWwiLCJlbGVtZW50IiwiZXJyb3JNZXNzYWdlIiwiaW5uZXJIVE1MIiwic2V0UGFnZUV2ZW50cyIsImNsZWFyUGFnZVJlc291cmNlcyIsImluamVjdGVkUmVzb3VyY2VzIiwicmVzb3VyY2UiLCJkaXNwb3NlIiwiZXZhbHVhdGUiLCJvbGRDaGFydHMiLCJjaGFydHMiLCJvbGRDaGFydCIsImRlc3Ryb3kiLCJzY3JpcHRzVG9SZW1vdmUiLCJnZXRFbGVtZW50c0J5VGFnTmFtZSIsInN0eWxlc1RvUmVtb3ZlIiwibGlua3NUb1JlbW92ZSIsInJlbW92ZSIsInNldENvbnRlbnQiLCJ3YWl0VW50aWwiLCJhZGRTY3JpcHRUYWciLCJwYXRoIiwic2V0QXNDb25maWciLCJwdXBwZXRlZXJFeHBvcnQiLCJleHBvcnRPcHRpb25zIiwiZGVidWdnZXIiLCJpc1NWRyIsInN2Z1RlbXBsYXRlIiwiaW5qZWN0ZWRKcyIsImpzIiwicHVzaCIsImNvbnRlbnQiLCJpc0xvY2FsIiwianNSZXNvdXJjZSIsImluamVjdGVkQ3NzIiwiY3NzIiwiY3NzSW1wb3J0cyIsIm1hdGNoIiwiY3NzSW1wb3J0UGF0aCIsImNzc1Jlc291cmNlIiwiYWRkU3R5bGVUYWciLCJhZGRQYWdlUmVzb3VyY2VzIiwic2l6ZSIsInN2Z0VsZW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiY2hhcnRIZWlnaHQiLCJiYXNlVmFsIiwiY2hhcnRXaWR0aCIsImJvZHkiLCJzdHlsZSIsInpvb20iLCJtYXJnaW4iLCJ2aWV3cG9ydEhlaWdodCIsIk1hdGgiLCJjZWlsIiwidmlld3BvcnRXaWR0aCIsIngiLCJ5IiwiZ2V0Qm91bmRpbmdDbGllbnRSZWN0IiwidHJ1bmMiLCJnZXRDbGlwUmVnaW9uIiwic2V0Vmlld3BvcnQiLCJkZXZpY2VTY2FsZUZhY3RvciIsIm91dGVySFRNTCIsImNyZWF0ZVNWRyIsImVuY29kaW5nIiwiY2xpcCIsInJhY2UiLCJzY3JlZW5zaG90IiwiY2FwdHVyZUJleW9uZFZpZXdwb3J0IiwiZnVsbFBhZ2UiLCJvcHRpbWl6ZUZvclNwZWVkIiwicXVhbGl0eSIsIm9taXRCYWNrZ3JvdW5kIiwiX3Jlc29sdmUiLCJzZXRUaW1lb3V0IiwiY3JlYXRlSW1hZ2UiLCJlbXVsYXRlTWVkaWFUeXBlIiwicGRmIiwiY3JlYXRlUERGIiwic3RhdHMiLCJwZXJmb3JtZWRFeHBvcnRzIiwiZXhwb3J0QXR0ZW1wdHMiLCJleHBvcnRGcm9tU3ZnQXR0ZW1wdHMiLCJ0aW1lU3BlbnQiLCJkcm9wcGVkRXhwb3J0cyIsInNwZW50QXZlcmFnZSIsInBvb2xDb25maWciLCJmYWN0b3J5IiwiY3JlYXRlIiwiaWQiLCJ1dWlkIiwic3RhcnREYXRlIiwiZ2V0VGltZSIsImlzQ2xvc2VkIiwid29ya0NvdW50IiwicmFuZG9tIiwidmFsaWRhdGUiLCJ3b3JrZXJIYW5kbGUiLCJjbG9zZSIsImluaXRQb29sIiwicHVwcGV0ZWVyQXJncyIsImVuYWJsZWREZWJ1ZyIsImxhdW5jaE9wdGlvbnMiLCJ1c2VyRGF0YURpciIsImhhbmRsZVNJR0lOVCIsImhhbmRsZVNJR1RFUk0iLCJoYW5kbGVTSUdIVVAiLCJ3YWl0Rm9ySW5pdGlhbFBhZ2UiLCJkZWZhdWx0Vmlld3BvcnQiLCJ0cnlDb3VudCIsIm9wZW4iLCJsYXVuY2giLCJjcmVhdGVCcm93c2VyIiwicGFyc2VJbnQiLCJQb29sIiwiYWNxdWlyZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVUaW1lb3V0TWlsbGlzIiwiZGVzdHJveVRpbWVvdXRNaWxsaXMiLCJpZGxlVGltZW91dE1pbGxpcyIsImNyZWF0ZVJldHJ5SW50ZXJ2YWxNaWxsaXMiLCJyZWFwSW50ZXJ2YWxNaWxsaXMiLCJwcm9wYWdhdGVDcmVhdGVFcnJvciIsImhhcmRSZXNldCIsImdvdG8iLCJjbGVhclBhZ2UiLCJldmVudElkIiwiaW5pdGlhbFJlc291cmNlcyIsImFjcXVpcmUiLCJwcm9taXNlIiwicmVsZWFzZSIsImtpbGxQb29sIiwid29ya2VyIiwidXNlZCIsImRlc3Ryb3llZCIsImNvbm5lY3RlZCIsImNsb3NlQnJvd3NlciIsInBvc3RXb3JrIiwiZ2V0UG9vbEluZm8iLCJhY3F1aXJlQ291bnRlciIsInBheWxvYWQiLCJyZXF1ZXN0SWQiLCJ3b3JrU3RhcnQiLCJleHBvcnRDb3VudGVyIiwicmVzdWx0IiwiZXhwb3J0VGltZSIsImdldFBvb2xJbmZvSlNPTiIsIm51bUZyZWUiLCJudW1Vc2VkIiwiYXZhaWxhYmxlIiwicGVuZGluZyIsIm51bVBlbmRpbmdBY3F1aXJlcyIsInBvb2wkMSIsInN0YXJ0RXhwb3J0Iiwic2V0dGluZ3MiLCJlbmRDYWxsYmFjayIsInN2ZyIsImluaXRFeHBvcnRTZXR0aW5ncyIsImV4cG9ydEFzU3RyaW5nIiwiaW5wdXQiLCJKU0RPTSIsIkRPTVB1cmlmeSIsInNhbml0aXplIiwiQUREX1RBR1MiLCJkb1N0cmFpZ2h0SW5qZWN0IiwiZG9FeHBvcnQiLCJmaW5kQ2hhcnRTaXplIiwicHJlY2lzaW9uIiwibXVsdGlwbGllciIsInBvdyIsInJvdW5kTnVtYmVyIiwic291cmNlSGVpZ2h0Iiwic291cmNlV2lkdGgiLCJwYXJhbSIsImNoYXJ0SnNvbiIsImN1c3RvbUxvZ2ljT3B0aW9ucyIsImFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCIsIm9wdGlvbnNOYW1lIiwic3RyaW5nVG9FeHBvcnQiLCJjaGFydEpTT04iLCJpbnRlcnZhbElkcyIsImNsZWFyQWxsSW50ZXJ2YWxzIiwiY2xlYXJJbnRlcnZhbCIsImxvZ0Vycm9yTWlkZGxld2FyZSIsInJlcSIsIm5leHQiLCJyZXR1cm5FcnJvck1pZGRsZXdhcmUiLCJzdENvZGUiLCJzdGF0dXMiLCJqc29uIiwicmF0ZUxpbWl0IiwiYXBwIiwibGltaXRDb25maWciLCJtc2ciLCJyYXRlT3B0aW9ucyIsImxpbWl0ZXIiLCJ3aW5kb3dNcyIsImRlbGF5TXMiLCJoYW5kbGVyIiwicmVxdWVzdCIsImZvcm1hdCIsInNlbmQiLCJkZWZhdWx0Iiwic2tpcCIsInF1ZXJ5IiwiYWNjZXNzX3Rva2VuIiwidXNlIiwiSHR0cEVycm9yIiwic2V0U3RhdHVzIiwidlN3aXRjaFJvdXRlIiwicG9zdCIsImFkbWluVG9rZW4iLCJ0b2tlbiIsIm5ld1ZlcnNpb24iLCJwYXJhbXMiLCJ1cGRhdGVWZXJzaW9uIiwicmV2ZXJzZWRNaW1lIiwicG5nIiwianBlZyIsImdpZiIsInJlcXVlc3RzQ291bnRlciIsImJlZm9yZVJlcXVlc3QiLCJhZnRlclJlcXVlc3QiLCJkb0NhbGxiYWNrcyIsImNhbGxiYWNrcyIsInVuaXF1ZUlkIiwiY2FsbFJlc3BvbnNlIiwiZXhwb3J0SGFuZGxlciIsInN0b3BDb3VudGVyIiwiaGVhZGVycyIsImNvbm5lY3Rpb24iLCJyZW1vdGVBZGRyZXNzIiwiY29ubmVjdGlvbkFib3J0ZWQiLCJzb2NrZXQiLCJ0b0xvd2VyQ2FzZSIsInN1YnN0ciIsImI2NCIsIm5vRG93bmxvYWQiLCJwYXR0ZXJuIiwiaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCIsImluZm8iLCJyZW1vdmVBbGxMaXN0ZW5lcnMiLCJCdWZmZXIiLCJmcm9tIiwiaGVhZGVyIiwiYXR0YWNobWVudCIsImZpbGVuYW1lIiwicGtnRmlsZSIsInBhdGhlciIsInNlcnZlclN0YXJ0VGltZSIsInN1Y2Nlc3NSYXRlcyIsImFkZEhlYWx0aFJvdXRlcyIsInNldEludGVydmFsIiwic3VjY2Vzc1JhdGlvIiwiXyIsInBlcmlvZCIsIm1vdmluZ0F2ZXJhZ2UiLCJyZWR1Y2UiLCJhIiwiYiIsImJvb3RUaW1lIiwidXB0aW1lIiwiZmxvb3IiLCJoaWdoY2hhcnRzVmVyc2lvbiIsImF2ZXJhZ2VQcm9jZXNzaW5nVGltZSIsImZhaWxlZEV4cG9ydHMiLCJzdWNlc3NSYXRpbyIsInRvRml4ZWQiLCJzdmdFeHBvcnRBdHRlbXB0cyIsImpzb25FeHBvcnRBdHRlbXB0cyIsImFjdGl2ZVNlcnZlcnMiLCJNYXAiLCJleHByZXNzIiwiZGlzYWJsZSIsImNvcnMiLCJzdG9yYWdlIiwibXVsdGVyIiwibWVtb3J5U3RvcmFnZSIsInVwbG9hZCIsImxpbWl0cyIsImZpZWxkU2l6ZSIsImxpbWl0IiwidXJsZW5jb2RlZCIsImV4dGVuZGVkIiwibm9uZSIsImF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMiLCJzdGFydFNlcnZlciIsInNlcnZlckNvbmZpZyIsImh0dHBTZXJ2ZXIiLCJjcmVhdGVTZXJ2ZXIiLCJsaXN0ZW4iLCJzZXQiLCJjZXJ0IiwiZnNQcm9taXNlcyIsInJlYWRGaWxlIiwicG9zaXgiLCJodHRwc1NlcnZlciIsIk5hTiIsInN0YXRpYyIsImhlYWx0aFJvdXRlIiwiZXhwb3J0Um91dGVzIiwic2VuZEZpbGUiLCJ1aVJvdXRlIiwiZXJyb3JIYW5kbGVyIiwiY2xvc2VTZXJ2ZXJzIiwiZGVsZXRlIiwiZ2V0U2VydmVycyIsImVuYWJsZVJhdGVMaW1pdGluZyIsImdldEV4cHJlc3MiLCJnZXRBcHAiLCJtaWRkbGV3YXJlcyIsInNodXRkb3duQ2xlYW5VcCIsImV4aXRDb2RlIiwiYWxsU2V0dGxlZCIsImV4aXQiLCJpbmRleCIsImluaXRFeHBvcnQiLCJpbml0TG9nZ2luZyIsImNvZGUiLCJzaW5nbGVFeHBvcnQiLCJiYXRjaEV4cG9ydCIsImJhdGNoRnVuY3Rpb25zIiwicGFpciIsImNvbmZpZ0luZGV4IiwiZmluZEluZGV4IiwiYXJnIiwiZmlsZU5hbWUiLCJsb2FkQ29uZmlnRmlsZSIsInNob3dVc2FnZSIsInByb3BlcnRpZXNDaGFpbiIsImFyZ3VtZW50VHlwZSIsInBhaXJBcmd1bWVudFZhbHVlIiwibWFwVG9OZXdDb25maWciLCJvbGRPcHRpb25zIiwibWFudWFsQ29uZmlnIiwiY29uZmlnRmlsZU5hbWUiLCJjb25maWdGaWxlIiwiY2hvaWNlIiwicHJvbXB0cyIsIm9uU3VibWl0IiwicCIsImNhdGVnb3JpZXMiLCJxdWVzdGlvbnNDb3VudGVyIiwiYWxsUXVlc3Rpb25zIiwic2VjdGlvbiIsInByb21wdCIsImFuc3dlciIsIm1vZHVsZSIsInByb21pc2VzIiwid3JpdGVGaWxlIiwicHJpbnRMb2dvIiwicGFja2FnZVZlcnNpb24iXSwibWFwcGluZ3MiOiIrY0FlTyxNQUFNQSxFQUFlLENBQzFCQyxLQUFNLENBQUMsYUFBYyxrQkFBbUIsaUJBQ3hDQyxRQUFTLENBQ1AsUUFDQSxNQUNBLFFBQ0EsWUFDQSxjQUNBLHVCQUNBLGdCQUVBLGVBQ0EsUUFDQSxPQUNBLGFBQ0EsbUJBQ0EsZUFDQSxjQUNB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 +"use strict";require("colors");var e=require("fs"),t=require("path"),r=require("https-proxy-agent"),o=require("prompts"),i=require("dotenv"),s=require("zod"),n=require("url"),a=require("http"),l=require("https"),c=require("tarn"),p=require("uuid"),h=require("puppeteer"),u=require("jsdom"),d=require("dompurify"),g=require("cors"),m=require("express"),f=require("multer"),v=require("express-rate-limit"),y="undefined"!=typeof document?document.currentScript:null;const b={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","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","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"],indicators:["indicators-all"]},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:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],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 logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},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 the --logDest to enable file logging",initial:w.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:w.logging.dest.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:_(),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),A=["red","yellow","blue","gray","green"];let N={toConsole:!0,toFile:!1,pathCreated:!1,levelsDesc:[{title:"error",color:A[0]},{title:"warning",color:A[1]},{title:"notice",color:A[2]},{title:"verbose",color:A[3]},{title:"benchmark",color:A[4]}],listeners:[]};for(const[e,t]of Object.entries(w.logging))N[e]=t.value;const P=(t,r)=>{N.toFile&&(N.pathCreated||(!e.existsSync(N.dest)&&e.mkdirSync(N.dest),N.pathCreated=!0),e.appendFile(`${N.dest}${N.file}`,[r].concat(t).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),N.toFile=!1)})))},H=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=N;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;N.listeners.forEach((e=>{e(s,r.join(" "))})),N.toConsole&&console.log.apply(void 0,[s.toString()[N.levelsDesc[t-1].color]].concat(r)),P(r,s)},$=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=N;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];N.toConsole&&console.log.apply(void 0,[n.toString()[N.levelsDesc[e-1].color]].concat([o[A[e-1]],"\n",a])),N.listeners.forEach((e=>{e(n,l.join(" "))})),P(l,n)},D=e=>{e>=0&&e<=N.levelsDesc.length&&(N.level=e)},U=(e,t)=>{if(N={...N,dest:e||N.dest,file:t||N.file,toFile:!0},0===N.dest.length)return H(1,"[logger] File logging initialization: no path supplied.");N.dest.endsWith("/")||(N.dest+="/")},j=n.fileURLToPath(new URL("../.","undefined"==typeof document?require("url").pathToFileURL(__filename).href:y&&y.src||new URL("index.cjs",document.baseURI).href)),G=(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"},F=(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(j,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(j,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(j,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(j+"/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(j,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):Ne(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'."))},Ae=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},Ne=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=F(t.customLogic.resources,B(t.customLogic.allowFileResources));else if(!t.customLogic.resources)try{const r=e.readFileSync("resources.json","utf8");t.customLogic.resources=F(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=G(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,...Ae(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,Ne(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."),Ne(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ne(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=[],De=()=>{H(4,"[server] Clearing all registered intervals.");for(const e of $e)clearInterval(e)},Ue=(e,t,r,o)=>{$(1,e),"development"!==C.OTHER_NODE_ENV&&delete e.stack,o(e)},je=(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 Ge=(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 Fe 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 Fe("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 Fe("Invalid or missing token: Set the token in the hc-auth header.",401);const i=e.params.newVersion;if(!i)throw new Fe("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 Fe(`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=G(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).length)throw new Fe("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 Fe("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 Fe("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 Fe(`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(j,"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:`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)&&Ge(et,r.rateLimiting),et.use(m.static(t.posix.join(j,"public"))),Qe(et),(e=>{e.post("/",ze),e.post("/:filename",ze)})(et),(e=>{!!e&&e.get("/",((e,r)=>{r.sendFile(t.join(j,"public","index.html"))}))})(et),Me(et),(e=>{e.use(Ue),e.use(je)})(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=>Ge(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([De(),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=>{D(e&&parseInt(e.level)),e&&e.dest&&U(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:D,enableFileLogging:U,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(j,"package.json"))).version;r?console.log(`Starting Highcharts Export Server v${o}...`):console.log(e.readFileSync(j+"/msg/startup.msg").toString().bold.yellow,`v${o}\n`.bold)},printUsage:V};module.exports=lt; +//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguY2pzIiwic291cmNlcyI6WyIuLi9saWIvc2NoZW1hcy9jb25maWcuanMiLCIuLi9saWIvZW52cy5qcyIsIi4uL2xpYi9sb2dnZXIuanMiLCIuLi9saWIvdXRpbHMuanMiLCIuLi9saWIvY29uZmlnLmpzIiwiLi4vbGliL2ZldGNoLmpzIiwiLi4vbGliL2Vycm9ycy9FeHBvcnRFcnJvci5qcyIsIi4uL2xpYi9jYWNoZS5qcyIsIi4uL2xpYi9oaWdoY2hhcnRzLmpzIiwiLi4vbGliL2Jyb3dzZXIuanMiLCIuLi9saWIvZXhwb3J0LmpzIiwiLi4vdGVtcGxhdGVzL3N2Z19leHBvcnQvc3ZnX2V4cG9ydC5qcyIsIi4uL2xpYi9wb29sLmpzIiwiLi4vbGliL2NoYXJ0LmpzIiwiLi4vbGliL3Nhbml0aXplLmpzIiwiLi4vbGliL2ludGVydmFscy5qcyIsIi4uL2xpYi9zZXJ2ZXIvZXJyb3IuanMiLCIuLi9saWIvc2VydmVyL3JhdGVfbGltaXQuanMiLCIuLi9saWIvZXJyb3JzL0h0dHBFcnJvci5qcyIsIi4uL2xpYi9zZXJ2ZXIvcm91dGVzL2NoYW5nZV9oY192ZXJzaW9uLmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvZXhwb3J0LmpzIiwiLi4vbGliL3NlcnZlci9yb3V0ZXMvaGVhbHRoLmpzIiwiLi4vbGliL3NlcnZlci9zZXJ2ZXIuanMiLCIuLi9saWIvc2VydmVyL3JvdXRlcy91aS5qcyIsIi4uL2xpYi9yZXNvdXJjZV9yZWxlYXNlLmpzIiwiLi4vbGliL2luZGV4LmpzIl0sInNvdXJjZXNDb250ZW50IjpbIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuLy8gUG9zc2libGUgbmFtZXMgZm9yIEhpZ2hjaGFydHMgc2NyaXB0c1xyXG5leHBvcnQgY29uc3Qgc2NyaXB0c05hbWVzID0ge1xyXG4gIGNvcmU6IFsnaGlnaGNoYXJ0cycsICdoaWdoY2hhcnRzLW1vcmUnLCAnaGlnaGNoYXJ0cy0zZCddLFxyXG4gIG1vZHVsZXM6IFtcclxuICAgICdzdG9jaycsXHJcbiAgICAnbWFwJyxcclxuICAgICdnYW50dCcsXHJcbiAgICAnZXhwb3J0aW5nJyxcclxuICAgICdleHBvcnQtZGF0YScsXHJcbiAgICAncGFyYWxsZWwtY29vcmRpbmF0ZXMnLFxyXG4gICAgJ2FjY2Vzc2liaWxpdHknLFxyXG4gICAgLy8gJ2Fubm90YXRpb25zLWFkdmFuY2VkJyxcclxuICAgICdib29zdC1jYW52YXMnLFxyXG4gICAgJ2Jvb3N0JyxcclxuICAgICdkYXRhJyxcclxuICAgICdkYXRhLXRvb2xzJyxcclxuICAgICdkcmFnZ2FibGUtcG9pbnRzJyxcclxuICAgICdzdGF0aWMtc2NhbGUnLFxyXG4gICAgJ2Jyb2tlbi1heGlzJyxcclxuICAgICdoZWF0bWFwJyxcclxuICAgICd0aWxlbWFwJyxcclxuICAgICd0aWxlZHdlYm1hcCcsXHJcbiAgICAndGltZWxpbmUnLFxyXG4gICAgJ3RyZWVtYXAnLFxyXG4gICAgJ3RyZWVncmFwaCcsXHJcbiAgICAnaXRlbS1zZXJpZXMnLFxyXG4gICAgJ2RyaWxsZG93bicsXHJcbiAgICAnaGlzdG9ncmFtLWJlbGxjdXJ2ZScsXHJcbiAgICAnYnVsbGV0JyxcclxuICAgICdmdW5uZWwnLFxyXG4gICAgJ2Z1bm5lbDNkJyxcclxuICAgICdnZW9oZWF0bWFwJyxcclxuICAgICdweXJhbWlkM2QnLFxyXG4gICAgJ25ldHdvcmtncmFwaCcsXHJcbiAgICAnb3ZlcmxhcHBpbmctZGF0YWxhYmVscycsXHJcbiAgICAncGFyZXRvJyxcclxuICAgICdwYXR0ZXJuLWZpbGwnLFxyXG4gICAgJ3BpY3RvcmlhbCcsXHJcbiAgICAncHJpY2UtaW5kaWNhdG9yJyxcclxuICAgICdzYW5rZXknLFxyXG4gICAgJ2FyYy1kaWFncmFtJyxcclxuICAgICdkZXBlbmRlbmN5LXdoZWVsJyxcclxuICAgICdzZXJpZXMtbGFiZWwnLFxyXG4gICAgJ3NvbGlkLWdhdWdlJyxcclxuICAgICdzb25pZmljYXRpb24nLFxyXG4gICAgLy8gJ3N0b2NrLXRvb2xzJyxcclxuICAgICdzdHJlYW1ncmFwaCcsXHJcbiAgICAnc3VuYnVyc3QnLFxyXG4gICAgJ3ZhcmlhYmxlLXBpZScsXHJcbiAgICAndmFyaXdpZGUnLFxyXG4gICAgJ3ZlY3RvcicsXHJcbiAgICAndmVubicsXHJcbiAgICAnd2luZGJhcmInLFxyXG4gICAgJ3dvcmRjbG91ZCcsXHJcbiAgICAneHJhbmdlJyxcclxuICAgICduby1kYXRhLXRvLWRpc3BsYXknLFxyXG4gICAgJ2RyYWctcGFuZXMnLFxyXG4gICAgJ2RlYnVnZ2VyJyxcclxuICAgICdkdW1iYmVsbCcsXHJcbiAgICAnbG9sbGlwb3AnLFxyXG4gICAgJ2N5bGluZGVyJyxcclxuICAgICdvcmdhbml6YXRpb24nLFxyXG4gICAgJ2RvdHBsb3QnLFxyXG4gICAgJ21hcmtlci1jbHVzdGVycycsXHJcbiAgICAnaG9sbG93Y2FuZGxlc3RpY2snLFxyXG4gICAgJ2hlaWtpbmFzaGknLFxyXG4gICAgJ2Zsb3dtYXAnXHJcbiAgXSxcclxuICBpbmRpY2F0b3JzOiBbJ2luZGljYXRvcnMtYWxsJ11cclxufTtcclxuXHJcbi8vIFRoaXMgaXMgdGhlIGNvbmZpZ3VyYXRpb24gb2JqZWN0IHdpdGggYWxsIG9wdGlvbnMgYW5kIHRoZWlyIGRlZmF1bHQgdmFsdWVzLFxyXG4vLyBhbHNvIGZyb20gdGhlIC5lbnYgZmlsZSBpZiBvbmUgZXhpc3RzXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0Q29uZmlnID0ge1xyXG4gIHB1cHBldGVlcjoge1xyXG4gICAgYXJnczoge1xyXG4gICAgICB2YWx1ZTogW1xyXG4gICAgICAgICctLWFsbG93LXJ1bm5pbmctaW5zZWN1cmUtY29udGVudCcsXHJcbiAgICAgICAgJy0tYXNoLW5vLW51ZGdlcycsXHJcbiAgICAgICAgJy0tYXV0b3BsYXktcG9saWN5PXVzZXItZ2VzdHVyZS1yZXF1aXJlZCcsXHJcbiAgICAgICAgJy0tYmxvY2stbmV3LXdlYi1jb250ZW50cycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1hY2NlbGVyYXRlZC0yZC1jYW52YXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtYmFja2dyb3VuZC1uZXR3b3JraW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWJhY2tncm91bmQtdGltZXItdGhyb3R0bGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1iYWNrZ3JvdW5kaW5nLW9jY2x1ZGVkLXdpbmRvd3MnLFxyXG4gICAgICAgICctLWRpc2FibGUtYnJlYWtwYWQnLFxyXG4gICAgICAgICctLWRpc2FibGUtY2hlY2tlci1pbWFnaW5nJyxcclxuICAgICAgICAnLS1kaXNhYmxlLWNsaWVudC1zaWRlLXBoaXNoaW5nLWRldGVjdGlvbicsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1jb21wb25lbnQtZXh0ZW5zaW9ucy13aXRoLWJhY2tncm91bmQtcGFnZXMnLFxyXG4gICAgICAgICctLWRpc2FibGUtY29tcG9uZW50LXVwZGF0ZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kZWZhdWx0LWFwcHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtZGV2LXNobS11c2FnZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1kb21haW4tcmVsaWFiaWxpdHknLFxyXG4gICAgICAgICctLWRpc2FibGUtZXh0ZW5zaW9ucycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1mZWF0dXJlcz1DYWxjdWxhdGVOYXRpdmVXaW5PY2NsdXNpb24sSW50ZXJlc3RGZWVkQ29udGVudFN1Z2dlc3Rpb25zLFdlYk9UUCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1oYW5nLW1vbml0b3InLFxyXG4gICAgICAgICctLWRpc2FibGUtaXBjLWZsb29kaW5nLXByb3RlY3Rpb24nLFxyXG4gICAgICAgICctLWRpc2FibGUtbG9nZ2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1ub3RpZmljYXRpb25zJyxcclxuICAgICAgICAnLS1kaXNhYmxlLW9mZmVyLXN0b3JlLXVubWFza2VkLXdhbGxldC1jYXJkcycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wb3B1cC1ibG9ja2luZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1wcmludC1wcmV2aWV3JyxcclxuICAgICAgICAnLS1kaXNhYmxlLXByb21wdC1vbi1yZXBvc3QnLFxyXG4gICAgICAgICctLWRpc2FibGUtcmVuZGVyZXItYmFja2dyb3VuZGluZycsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZWFyY2gtZW5naW5lLWNob2ljZS1zY3JlZW4nLFxyXG4gICAgICAgICctLWRpc2FibGUtc2Vzc2lvbi1jcmFzaGVkLWJ1YmJsZScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zZXR1aWQtc2FuZGJveCcsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zaXRlLWlzb2xhdGlvbi10cmlhbHMnLFxyXG4gICAgICAgICctLWRpc2FibGUtc3BlZWNoLWFwaScsXHJcbiAgICAgICAgJy0tZGlzYWJsZS1zeW5jJyxcclxuICAgICAgICAnLS1lbmFibGUtdW5zYWZlLXdlYmdwdScsXHJcbiAgICAgICAgJy0taGlkZS1jcmFzaC1yZXN0b3JlLWJ1YmJsZScsXHJcbiAgICAgICAgJy0taGlkZS1zY3JvbGxiYXJzJyxcclxuICAgICAgICAnLS1tZXRyaWNzLXJlY29yZGluZy1vbmx5JyxcclxuICAgICAgICAnLS1tdXRlLWF1ZGlvJyxcclxuICAgICAgICAnLS1uby1kZWZhdWx0LWJyb3dzZXItY2hlY2snLFxyXG4gICAgICAgICctLW5vLWZpcnN0LXJ1bicsXHJcbiAgICAgICAgJy0tbm8tcGluZ3MnLFxyXG4gICAgICAgICctLW5vLXNhbmRib3gnLFxyXG4gICAgICAgICctLW5vLXN0YXJ0dXAtd2luZG93JyxcclxuICAgICAgICAnLS1uby16eWdvdGUnLFxyXG4gICAgICAgICctLXBhc3N3b3JkLXN0b3JlPWJhc2ljJyxcclxuICAgICAgICAnLS1wcm9jZXNzLXBlci10YWInLFxyXG4gICAgICAgICctLXVzZS1tb2NrLWtleWNoYWluJ1xyXG4gICAgICBdLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0FyZ3VtZW50cyBhcnJheSB0byBzZW5kIHRvIFB1cHBldGVlci4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBoaWdoY2hhcnRzOiB7XHJcbiAgICB2ZXJzaW9uOiB7XHJcbiAgICAgIHZhbHVlOiAnbGF0ZXN0JyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX1ZFUlNJT04nLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgdXNlZC4nXHJcbiAgICB9LFxyXG4gICAgY2RuVVJMOiB7XHJcbiAgICAgIHZhbHVlOiAnaHR0cHM6Ly9jb2RlLmhpZ2hjaGFydHMuY29tLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DRE5fVVJMJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgQ0ROIFVSTCBmb3IgSGlnaGNoYXJ0cyBzY3JpcHRzIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGNvcmVTY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBzY3JpcHRzTmFtZXMuY29yZSxcclxuICAgICAgdHlwZTogJ3N0cmluZ1tdJyxcclxuICAgICAgZW52TGluazogJ0hJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgY29yZSBIaWdoY2hhcnRzIHNjcmlwdHMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIG1vZHVsZVNjcmlwdHM6IHtcclxuICAgICAgdmFsdWU6IHNjcmlwdHNOYW1lcy5tb2R1bGVzLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nW10nLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG1vZHVsZXMgb2YgSGlnaGNoYXJ0cyB0byBmZXRjaC4nXHJcbiAgICB9LFxyXG4gICAgaW5kaWNhdG9yU2NyaXB0czoge1xyXG4gICAgICB2YWx1ZTogc2NyaXB0c05hbWVzLmluZGljYXRvcnMsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgaW5kaWNhdG9ycyBvZiBIaWdoY2hhcnRzIHRvIGZldGNoLidcclxuICAgIH0sXHJcbiAgICBjdXN0b21TY3JpcHRzOiB7XHJcbiAgICAgIHZhbHVlOiBbXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC5qcy8yLjI5LjQvbW9tZW50Lm1pbi5qcycsXHJcbiAgICAgICAgJ2h0dHBzOi8vY2RuanMuY2xvdWRmbGFyZS5jb20vYWpheC9saWJzL21vbWVudC10aW1lem9uZS8wLjUuMzQvbW9tZW50LXRpbWV6b25lLXdpdGgtZGF0YS5taW4uanMnXHJcbiAgICAgIF0sXHJcbiAgICAgIHR5cGU6ICdzdHJpbmdbXScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnQWRkaXRpb25hbCBjdXN0b20gc2NyaXB0cyBvciBkZXBlbmRlbmNpZXMgdG8gZmV0Y2guJ1xyXG4gICAgfSxcclxuICAgIGZvcmNlRmV0Y2g6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBmbGFnIHRvIGRldGVybWluZSB3aGV0aGVyIHRvIHJlZmV0Y2ggYWxsIHNjcmlwdHMgYWZ0ZXIgZWFjaCBzZXJ2ZXIgcmVydW4uJ1xyXG4gICAgfSxcclxuICAgIGNhY2hlUGF0aDoge1xyXG4gICAgICB2YWx1ZTogJy5jYWNoZScsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnSElHSENIQVJUU19DQUNIRV9QQVRIJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHRoZSBjYWNoZSBkaXJlY3RvcnkuIEl0IGlzIHVzZWQgdG8gc3RvcmUgdGhlIEhpZ2hjaGFydHMgc2NyaXB0cyBhbmQgY3VzdG9tIHNjcmlwdHMuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgZXhwb3J0OiB7XHJcbiAgICBpbmZpbGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBpbnB1dCBmaWxlIHNob3VsZCBpbmNsdWRlIGEgbmFtZSBhbmQgYSB0eXBlIChqc29uIG9yIHN2ZykuIEl0IG11c3QgYmUgY29ycmVjdGx5IGZvcm1hdHRlZCBhcyBhIEpTT04gb3IgU1ZHIGZpbGUuJ1xyXG4gICAgfSxcclxuICAgIGluc3RyOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbnB1dCwgcHJvdmlkZWQgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OIG9yIFNWRyBmaWxlLCB3aWxsIG92ZXJyaWRlIHRoZSAtLWluZmlsZSBvcHRpb24uJ1xyXG4gICAgfSxcclxuICAgIG9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBbiBhbGlhcyBmb3IgdGhlIC0taW5zdHIgb3B0aW9uLidcclxuICAgIH0sXHJcbiAgICBvdXRmaWxlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgb3V0cHV0IGZpbGVuYW1lIGFsb25nIHdpdGggYSB0eXBlIChqcGVnLCBwbmcsIHBkZiwgb3Igc3ZnKS4gVGhpcyB3aWxsIGlnbm9yZSB0aGUgLS10eXBlIGZsYWcuJ1xyXG4gICAgfSxcclxuICAgIHR5cGU6IHtcclxuICAgICAgdmFsdWU6ICdwbmcnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9UWVBFJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgZmlsZSBleHBvcnQgZm9ybWF0LiBJdCBjYW4gYmUganBlZywgcG5nLCBwZGYsIG9yIHN2Zy4nXHJcbiAgICB9LFxyXG4gICAgY29uc3RyOiB7XHJcbiAgICAgIHZhbHVlOiAnY2hhcnQnLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9DT05TVFInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGNvbnN0cnVjdG9yIHRvIHVzZS4gQ2FuIGJlIGNoYXJ0LCBzdG9ja0NoYXJ0LCBtYXBDaGFydCwgb3IgZ2FudHRDaGFydC4nXHJcbiAgICB9LFxyXG4gICAgZGVmYXVsdEhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogNDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0VYUE9SVF9ERUZBVUxUX0hFSUdIVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICd0aGUgZGVmYXVsdCBoZWlnaHQgb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LiBVc2VkIHdoZW4gbm8gdmFsdWUgaXMgc2V0LidcclxuICAgIH0sXHJcbiAgICBkZWZhdWx0V2lkdGg6IHtcclxuICAgICAgdmFsdWU6IDYwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9XSURUSCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGRlZmF1bHRTY2FsZToge1xyXG4gICAgICB2YWx1ZTogMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfREVGQVVMVF9TQ0FMRScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZGVmYXVsdCBzY2FsZSBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQuIFVzZWQgd2hlbiBubyB2YWx1ZSBpcyBzZXQuJ1xyXG4gICAgfSxcclxuICAgIGhlaWdodDoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQsIG92ZXJyaWRpbmcgdGhlIG9wdGlvbiBpbiB0aGUgY2hhcnQgc2V0dGluZ3MuJ1xyXG4gICAgfSxcclxuICAgIHdpZHRoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgd2lkdGggb2YgdGhlIGV4cG9ydGVkIGNoYXJ0LCBvdmVycmlkaW5nIHRoZSBvcHRpb24gaW4gdGhlIGNoYXJ0IHNldHRpbmdzLidcclxuICAgIH0sXHJcbiAgICBzY2FsZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCwgb3ZlcnJpZGluZyB0aGUgb3B0aW9uIGluIHRoZSBjaGFydCBzZXR0aW5ncy4gUmFuZ2VzIGJldHdlZW4gMC4xIGFuZCA1LjAuJ1xyXG4gICAgfSxcclxuICAgIGdsb2JhbE9wdGlvbnM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VpdGhlciBhIHN0cmluZ2lmaWVkIEpTT04gb3IgYSBmaWxlbmFtZSBjb250YWluaW5nIG9wdGlvbnMgdG8gYmUgcGFzc2VkIGludG8gdGhlIEhpZ2hjaGFydHMuc2V0T3B0aW9ucy4nXHJcbiAgICB9LFxyXG4gICAgdGhlbWVPcHRpb25zOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdFaXRoZXIgYSBzdHJpbmdpZmllZCBKU09OIG9yIGEgZmlsZW5hbWUgY29udGFpbmluZyB0aGVtZSBvcHRpb25zIHRvIGJlIHBhc3NlZCBpbnRvIHRoZSBIaWdoY2hhcnRzLnNldE9wdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGJhdGNoOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdJbml0aWF0ZXMgYSBiYXRjaCBqb2Igd2l0aCBhIHN0cmluZyBjb250YWluaW5nIGlucHV0L291dHB1dCBwYWlyczogXCJpbj1vdXQ7aW49b3V0Oy4uLlwiLidcclxuICAgIH0sXHJcbiAgICByYXN0ZXJpemF0aW9uVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogMTUwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiBpbiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgcmVuZGVyaW5nIGEgd2VicGFnZS4nXHJcbiAgICB9XHJcbiAgfSxcclxuICBjdXN0b21Mb2dpYzoge1xyXG4gICAgYWxsb3dDb2RlRXhlY3V0aW9uOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHdoZXRoZXIgdGhlIGV4ZWN1dGlvbiBvZiBhcmJpdHJhcnkgY29kZSBpcyBhbGxvd2VkIGR1cmluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJ1xyXG4gICAgfSxcclxuICAgIGFsbG93RmlsZVJlc291cmNlczoge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0NVU1RPTV9MT0dJQ19BTExPV19GSUxFX1JFU09VUkNFUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdDb250cm9scyB0aGUgYWJpbGl0eSB0byBpbmplY3QgcmVzb3VyY2VzIGZyb20gdGhlIGZpbGVzeXN0ZW0uIFRoaXMgc2V0dGluZyBoYXMgbm8gZWZmZWN0IHdoZW4gcnVubmluZyBhcyBhIHNlcnZlci4nXHJcbiAgICB9LFxyXG4gICAgY3VzdG9tQ29kZToge1xyXG4gICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnQ3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBiZWZvcmUgY2hhcnQgaW5pdGlhbGl6YXRpb24uIEl0IGNhbiBiZSBhIGZ1bmN0aW9uLCBjb2RlIHdyYXBwZWQgd2l0aGluIGEgZnVuY3Rpb24sIG9yIGEgZmlsZW5hbWUgd2l0aCB0aGUgLmpzIGV4dGVuc2lvbi4nXHJcbiAgICB9LFxyXG4gICAgY2FsbGJhY2s6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0phdmFTY3JpcHQgY29kZSB0byBydW4gZHVyaW5nIGNvbnN0cnVjdGlvbi4gSXQgY2FuIGJlIGEgZnVuY3Rpb24gb3IgYSBmaWxlbmFtZSB3aXRoIHRoZSAuanMgZXh0ZW5zaW9uLidcclxuICAgIH0sXHJcbiAgICByZXNvdXJjZXM6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0FkZGl0aW9uYWwgcmVzb3VyY2UgaW4gdGhlIGZvcm0gb2YgYSBzdHJpbmdpZmllZCBKU09OLCB3aGljaCBtYXkgY29udGFpbiBmaWxlcywganMsIGFuZCBjc3Mgc2VjdGlvbnMuJ1xyXG4gICAgfSxcclxuICAgIGxvYWRDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgbGVnYWN5TmFtZTogJ2Zyb21GaWxlJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdBIGZpbGUgY29udGFpbmluZyBhIHByZS1kZWZpbmVkIGNvbmZpZ3VyYXRpb24gdG8gdXNlLidcclxuICAgIH0sXHJcbiAgICBjcmVhdGVDb25maWc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0VuYWJsZXMgc2V0dGluZyBvcHRpb25zIHRocm91Z2ggYSBwcm9tcHQgYW5kIHNhdmluZyB0aGVtIGluIGEgcHJvdmlkZWQgY29uZmlnIGZpbGUuJ1xyXG4gICAgfVxyXG4gIH0sXHJcbiAgc2VydmVyOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfRU5BQkxFJyxcclxuICAgICAgY2xpTmFtZTogJ2VuYWJsZVNlcnZlcicsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdXaGVuIHNldCB0byB0cnVlLCB0aGUgc2VydmVyIHN0YXJ0cyBvbiB0aGUgbG9jYWwgSVAgYWRkcmVzcyAwLjAuMC4wLidcclxuICAgIH0sXHJcbiAgICBob3N0OiB7XHJcbiAgICAgIHZhbHVlOiAnMC4wLjAuMCcsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0hPU1QnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGhvc3RuYW1lIG9mIHRoZSBzZXJ2ZXIuIEFkZGl0aW9uYWxseSwgaXQgc3RhcnRzIGEgc2VydmVyIG9uIHRoZSBwcm92aWRlZCBob3N0bmFtZS4nXHJcbiAgICB9LFxyXG4gICAgcG9ydDoge1xyXG4gICAgICB2YWx1ZTogNzgwMSxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdTRVJWRVJfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHNlcnZlciBwb3J0IHdoZW4gZW5hYmxlZC4nXHJcbiAgICB9LFxyXG4gICAgYmVuY2htYXJraW5nOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnU0VSVkVSX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdzZXJ2ZXJCZW5jaG1hcmtpbmcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnSW5kaWNhdGVzIHdoZXRoZXIgdG8gZGlzcGxheSB0aGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgb2Ygc3BlY2lmaWMgYWN0aW9ucyB0aGF0IG9jY3VyIG9uIHRoZSBzZXJ2ZXIgd2hpbGUgc2VydmluZyBhIHJlcXVlc3QuJ1xyXG4gICAgfSxcclxuICAgIHByb3h5OiB7XHJcbiAgICAgIGhvc3Q6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9IT1NUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlIb3N0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBob3N0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICBwb3J0OiB7XHJcbiAgICAgICAgdmFsdWU6IDgwODAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9QT1JUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlQb3J0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSBwb3J0IG9mIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlLCBpZiBpdCBleGlzdHMuJ1xyXG4gICAgICB9LFxyXG4gICAgICB0aW1lb3V0OiB7XHJcbiAgICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9QUk9YWV9USU1FT1VUJyxcclxuICAgICAgICBjbGlOYW1lOiAncHJveHlUaW1lb3V0JyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0aW1lb3V0IGZvciB0aGUgcHJveHkgc2VydmVyIHRvIHVzZSwgaWYgaXQgZXhpc3RzLidcclxuICAgICAgfVxyXG4gICAgfSxcclxuICAgIHJhdGVMaW1pdGluZzoge1xyXG4gICAgICBlbmFibGU6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19FTkFCTEUnLFxyXG4gICAgICAgIGNsaU5hbWU6ICdlbmFibGVSYXRlTGltaXRpbmcnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnRW5hYmxlcyByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgbWF4UmVxdWVzdHM6IHtcclxuICAgICAgICB2YWx1ZTogMTAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX01BWF9SRVFVRVNUUycsXHJcbiAgICAgICAgbGVnYWN5TmFtZTogJ3JhdGVMaW1pdCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgbWF4aW11bSBudW1iZXIgb2YgcmVxdWVzdHMgYWxsb3dlZCBpbiBvbmUgbWludXRlLidcclxuICAgICAgfSxcclxuICAgICAgd2luZG93OiB7XHJcbiAgICAgICAgdmFsdWU6IDEsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1dJTkRPVycsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgdGltZSB3aW5kb3csIGluIG1pbnV0ZXMsIGZvciB0aGUgcmF0ZSBsaW1pdGluZy4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGRlbGF5OiB7XHJcbiAgICAgICAgdmFsdWU6IDAsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX0RFTEFZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdUaGUgZGVsYXkgZHVyYXRpb24gZm9yIGVhY2ggc3VjY2Vzc2l2ZSByZXF1ZXN0IGJlZm9yZSByZWFjaGluZyB0aGUgbWF4aW11bSBsaW1pdC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHRydXN0UHJveHk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICAgIGVudkxpbms6ICdTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdTZXQgdGhpcyB0byB0cnVlIGlmIHRoZSBzZXJ2ZXIgaXMgYmVoaW5kIGEgbG9hZCBiYWxhbmNlci4nXHJcbiAgICAgIH0sXHJcbiAgICAgIHNraXBLZXk6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAgICdBbGxvd3MgYnlwYXNzaW5nIHRoZSByYXRlIGxpbWl0ZXIgYW5kIHNob3VsZCBiZSBwcm92aWRlZCB3aXRoIHRoZSBza2lwVG9rZW4gYXJndW1lbnQuJ1xyXG4gICAgICB9LFxyXG4gICAgICBza2lwVG9rZW46IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfVE9LRU4nLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciBhbmQgc2hvdWxkIGJlIHByb3ZpZGVkIHdpdGggdGhlIHNraXBLZXkgYXJndW1lbnQuJ1xyXG4gICAgICB9XHJcbiAgICB9LFxyXG4gICAgc3NsOiB7XHJcbiAgICAgIGVuYWJsZToge1xyXG4gICAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfRU5BQkxFJyxcclxuICAgICAgICBjbGlOYW1lOiAnZW5hYmxlU3NsJyxcclxuICAgICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgdGhlIFNTTCBwcm90b2NvbC4nXHJcbiAgICAgIH0sXHJcbiAgICAgIGZvcmNlOiB7XHJcbiAgICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgICBlbnZMaW5rOiAnU0VSVkVSX1NTTF9GT1JDRScsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbEZvcmNlJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsT25seScsXHJcbiAgICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgICAnV2hlbiBzZXQgdG8gdHJ1ZSwgdGhlIHNlcnZlciBpcyBmb3JjZWQgdG8gc2VydmUgb25seSBvdmVyIEhUVFBTLidcclxuICAgICAgfSxcclxuICAgICAgcG9ydDoge1xyXG4gICAgICAgIHZhbHVlOiA0NDMsXHJcbiAgICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfUE9SVCcsXHJcbiAgICAgICAgY2xpTmFtZTogJ3NzbFBvcnQnLFxyXG4gICAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIHBvcnQgb24gd2hpY2ggdG8gcnVuIHRoZSBTU0wgc2VydmVyLidcclxuICAgICAgfSxcclxuICAgICAgY2VydFBhdGg6IHtcclxuICAgICAgICB2YWx1ZTogZmFsc2UsXHJcbiAgICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgICAgZW52TGluazogJ1NFUlZFUl9TU0xfQ0VSVF9QQVRIJyxcclxuICAgICAgICBsZWdhY3lOYW1lOiAnc3NsUGF0aCcsXHJcbiAgICAgICAgZGVzY3JpcHRpb246ICdUaGUgcGF0aCB0byB0aGUgU1NMIGNlcnRpZmljYXRlL2tleSBmaWxlLidcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0sXHJcbiAgcG9vbDoge1xyXG4gICAgbWluV29ya2Vyczoge1xyXG4gICAgICB2YWx1ZTogNCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX01JTl9XT1JLRVJTJyxcclxuICAgICAgZGVzY3JpcHRpb246ICdUaGUgbnVtYmVyIG9mIG1pbmltdW0gYW5kIGluaXRpYWwgcG9vbCB3b3JrZXJzIHRvIHNwYXduLidcclxuICAgIH0sXHJcbiAgICBtYXhXb3JrZXJzOiB7XHJcbiAgICAgIHZhbHVlOiA4LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfTUFYX1dPUktFUlMnLFxyXG4gICAgICBsZWdhY3lOYW1lOiAnd29ya2VycycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnVGhlIG51bWJlciBvZiBtYXhpbXVtIHBvb2wgd29ya2VycyB0byBzcGF3bi4nXHJcbiAgICB9LFxyXG4gICAgd29ya0xpbWl0OiB7XHJcbiAgICAgIHZhbHVlOiA0MCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX1dPUktfTElNSVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIG51bWJlciBvZiB3b3JrIHBpZWNlcyB0aGF0IGNhbiBiZSBwZXJmb3JtZWQgYmVmb3JlIHJlc3RhcnRpbmcgdGhlIHdvcmtlciBwcm9jZXNzLidcclxuICAgIH0sXHJcbiAgICBhY3F1aXJlVGltZW91dDoge1xyXG4gICAgICB2YWx1ZTogNTAwMCxcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0FDUVVJUkVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgYWNxdWlyaW5nIGEgcmVzb3VyY2UuJ1xyXG4gICAgfSxcclxuICAgIGNyZWF0ZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9DUkVBVEVfVElNRU9VVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZHVyYXRpb24sIGluIG1pbGxpc2Vjb25kcywgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgZGVzdHJveVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDUwMDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnUE9PTF9ERVNUUk9ZX1RJTUVPVVQnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnVGhlIGR1cmF0aW9uLCBpbiBtaWxsaXNlY29uZHMsIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZS4nXHJcbiAgICB9LFxyXG4gICAgaWRsZVRpbWVvdXQ6IHtcclxuICAgICAgdmFsdWU6IDMwMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfSURMRV9USU1FT1VUJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZC4nXHJcbiAgICB9LFxyXG4gICAgY3JlYXRlUmV0cnlJbnRlcnZhbDoge1xyXG4gICAgICB2YWx1ZTogMjAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCB0byB3YWl0IGJlZm9yZSByZXRyeWluZyB0aGUgY3JlYXRlIHByb2Nlc3MgaW4gY2FzZSBvZiBhIGZhaWx1cmUuJ1xyXG4gICAgfSxcclxuICAgIHJlYXBlckludGVydmFsOiB7XHJcbiAgICAgIHZhbHVlOiAxMDAwLFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ1BPT0xfUkVBUEVSX0lOVEVSVkFMJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBkdXJhdGlvbiwgaW4gbWlsbGlzZWNvbmRzLCBhZnRlciB3aGljaCB0aGUgY2hlY2sgZm9yIGlkbGUgcmVzb3VyY2VzIHRvIGRlc3Ryb3kgaXMgdHJpZ2dlcmVkLidcclxuICAgIH0sXHJcbiAgICBiZW5jaG1hcmtpbmc6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdQT09MX0JFTkNITUFSS0lORycsXHJcbiAgICAgIGNsaU5hbWU6ICdwb29sQmVuY2htYXJraW5nJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0luZGljYXRlIHdoZXRoZXIgdG8gc2hvdyBzdGF0aXN0aWNzIGZvciB0aGUgcG9vbCBvZiByZXNvdXJjZXMgb3Igbm90LidcclxuICAgIH1cclxuICB9LFxyXG4gIGxvZ2dpbmc6IHtcclxuICAgIGxldmVsOiB7XHJcbiAgICAgIHZhbHVlOiA0LFxyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfTEVWRUwnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nTGV2ZWwnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSBsb2dnaW5nIGxldmVsIHRvIGJlIHVzZWQuJ1xyXG4gICAgfSxcclxuICAgIGZpbGU6IHtcclxuICAgICAgdmFsdWU6ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJyxcclxuICAgICAgdHlwZTogJ3N0cmluZycsXHJcbiAgICAgIGVudkxpbms6ICdMT0dHSU5HX0ZJTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnbG9nRmlsZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgbmFtZSBvZiBhIGxvZyBmaWxlLiBUaGUgbG9nRGVzdCBvcHRpb24gYWxzbyBuZWVkcyB0byBiZSBzZXQgdG8gZW5hYmxlIGZpbGUgbG9nZ2luZy4nXHJcbiAgICB9LFxyXG4gICAgZGVzdDoge1xyXG4gICAgICB2YWx1ZTogJ2xvZy8nLFxyXG4gICAgICB0eXBlOiAnc3RyaW5nJyxcclxuICAgICAgZW52TGluazogJ0xPR0dJTkdfREVTVCcsXHJcbiAgICAgIGNsaU5hbWU6ICdsb2dEZXN0JyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1RoZSBwYXRoIHRvIHN0b3JlIGxvZyBmaWxlcy4gVGhpcyBhbHNvIGVuYWJsZXMgZmlsZSBsb2dnaW5nLidcclxuICAgIH1cclxuICB9LFxyXG4gIHVpOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdVSV9FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlVWknLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRW5hYmxlcyBvciBkaXNhYmxlcyB0aGUgdXNlciBpbnRlcmZhY2UgKFVJKSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXIuJ1xyXG4gICAgfSxcclxuICAgIHJvdXRlOiB7XHJcbiAgICAgIHZhbHVlOiAnLycsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnVUlfUk9VVEUnLFxyXG4gICAgICBjbGlOYW1lOiAndWlSb3V0ZScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdUaGUgZW5kcG9pbnQgcm91dGUgdG8gd2hpY2ggdGhlIHVzZXIgaW50ZXJmYWNlIChVSSkgc2hvdWxkIGJlIGF0dGFjaGVkLidcclxuICAgIH1cclxuICB9LFxyXG4gIG90aGVyOiB7XHJcbiAgICBub2RlRW52OiB7XHJcbiAgICAgIHZhbHVlOiAncHJvZHVjdGlvbicsXHJcbiAgICAgIHR5cGU6ICdzdHJpbmcnLFxyXG4gICAgICBlbnZMaW5rOiAnT1RIRVJfTk9ERV9FTlYnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ1RoZSB0eXBlIG9mIE5vZGUuanMgZW52aXJvbm1lbnQuJ1xyXG4gICAgfSxcclxuICAgIGxpc3RlblRvUHJvY2Vzc0V4aXRzOiB7XHJcbiAgICAgIHZhbHVlOiB0cnVlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyB3aGV0aGVyIG9yIG5vdCB0byBhdHRhY2ggcHJvY2Vzcy5leGl0IGhhbmRsZXJzLidcclxuICAgIH0sXHJcbiAgICBub0xvZ286IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9OT19MT0dPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1NraXAgcHJpbnRpbmcgdGhlIGxvZ28gb24gYSBzdGFydHVwLiBXaWxsIGJlIHJlcGxhY2VkIGJ5IGEgc2ltcGxlIHRleHQuJ1xyXG4gICAgfSxcclxuICAgIGhhcmRSZXNldFBhZ2U6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdPVEhFUl9IQVJEX1JFU0VUX1BBR0UnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0RlY2lkZXMgaWYgdGhlIHBhZ2UgY29udGVudCBzaG91bGQgYmUgcmVzZXQgZW50aXJlbHkuJ1xyXG4gICAgfSxcclxuICAgIGJyb3dzZXJTaGVsbE1vZGU6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ09USEVSX0JST1dTRVJfU0hFTExfTU9ERScsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlLidcclxuICAgIH1cclxuICB9LFxyXG4gIGRlYnVnOiB7XHJcbiAgICBlbmFibGU6IHtcclxuICAgICAgdmFsdWU6IGZhbHNlLFxyXG4gICAgICB0eXBlOiAnYm9vbGVhbicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19FTkFCTEUnLFxyXG4gICAgICBjbGlOYW1lOiAnZW5hYmxlRGVidWcnLFxyXG4gICAgICBkZXNjcmlwdGlvbjogJ0VuYWJsZXMgb3IgZGlzYWJsZXMgZGVidWcgbW9kZSBmb3IgdGhlIHVuZGVybHlpbmcgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgaGVhZGxlc3M6IHtcclxuICAgICAgdmFsdWU6IHRydWUsXHJcbiAgICAgIHR5cGU6ICdib29sZWFuJyxcclxuICAgICAgZW52TGluazogJ0RFQlVHX0hFQURMRVNTJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ0NvbnRyb2xzIHRoZSBtb2RlIGluIHdoaWNoIHRoZSBicm93c2VyIGlzIGxhdW5jaGVkIHdoZW4gaW4gdGhlIGRlYnVnIG1vZGUuJ1xyXG4gICAgfSxcclxuICAgIGRldnRvb2xzOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfREVWVE9PTFMnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBEZXZUb29scyB3aGVuIHRoZSBicm93c2VyIGlzIGluIGEgaGVhZGZ1bCBzdGF0ZS4nXHJcbiAgICB9LFxyXG4gICAgbGlzdGVuVG9Db25zb2xlOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfTElTVEVOX1RPX0NPTlNPTEUnLFxyXG4gICAgICBkZXNjcmlwdGlvbjpcclxuICAgICAgICAnRGVjaWRlcyB3aGV0aGVyIHRvIGVuYWJsZSBhIGxpc3RlbmVyIGZvciBjb25zb2xlIG1lc3NhZ2VzIHNlbnQgZnJvbSB0aGUgYnJvd3Nlci4nXHJcbiAgICB9LFxyXG4gICAgZHVtcGlvOiB7XHJcbiAgICAgIHZhbHVlOiBmYWxzZSxcclxuICAgICAgdHlwZTogJ2Jvb2xlYW4nLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfRFVNUElPJyxcclxuICAgICAgZGVzY3JpcHRpb246XHJcbiAgICAgICAgJ1JlZGlyZWN0cyBicm93c2VyIHByb2Nlc3Mgc3Rkb3V0IGFuZCBzdGRlcnIgdG8gcHJvY2Vzcy5zdGRvdXQgYW5kIHByb2Nlc3Muc3RkZXJyLidcclxuICAgIH0sXHJcbiAgICBzbG93TW86IHtcclxuICAgICAgdmFsdWU6IDAsXHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBlbnZMaW5rOiAnREVCVUdfU0xPV19NTycsXHJcbiAgICAgIGRlc2NyaXB0aW9uOlxyXG4gICAgICAgICdTbG93cyBkb3duIFB1cHBldGVlciBvcGVyYXRpb25zIGJ5IHRoZSBzcGVjaWZpZWQgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcy4nXHJcbiAgICB9LFxyXG4gICAgZGVidWdnaW5nUG9ydDoge1xyXG4gICAgICB2YWx1ZTogOTIyMixcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIGVudkxpbms6ICdERUJVR19ERUJVR0dJTkdfUE9SVCcsXHJcbiAgICAgIGRlc2NyaXB0aW9uOiAnU3BlY2lmaWVzIHRoZSBkZWJ1Z2dpbmcgcG9ydC4nXHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLy8gVGhlIGNvbmZpZyBkZXNjcmlwdGlvbnMgb2JqZWN0IGZvciB0aGUgcHJvbXB0cyBmdW5jdGlvbmFsaXR5LiBJdCBjb250YWluc1xyXG4vLyBpbmZvcm1hdGlvbiBsaWtlOlxyXG4vLyAqIFR5cGUgb2YgYSBwcm9tcHRcclxuLy8gKiBOYW1lIG9mIGFuIG9wdGlvblxyXG4vLyAqIFNob3J0IGRlc2NyaXB0aW9uIG9mIGEgY2hvc2VuIG9wdGlvblxyXG4vLyAqIEluaXRpYWwgdmFsdWVcclxuZXhwb3J0IGNvbnN0IHByb21wdHNDb25maWcgPSB7XHJcbiAgcHVwcGV0ZWVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdsaXN0JyxcclxuICAgICAgbmFtZTogJ2FyZ3MnLFxyXG4gICAgICBtZXNzYWdlOiAnUHVwcGV0ZWVyIGFyZ3VtZW50cycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucHVwcGV0ZWVyLmFyZ3MudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfVxyXG4gIF0sXHJcbiAgaGlnaGNoYXJ0czogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICd2ZXJzaW9uJyxcclxuICAgICAgbWVzc2FnZTogJ0hpZ2hjaGFydHMgdmVyc2lvbicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy52ZXJzaW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdjZG5VUkwnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIFVSTCBvZiBDRE4nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmhpZ2hjaGFydHMuY2RuVVJMLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbXVsdGlzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAnY29yZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIGNvcmUgc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5jb3JlU2NyaXB0cy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ211bHRpc2VsZWN0JyxcclxuICAgICAgbmFtZTogJ21vZHVsZVNjcmlwdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnQXZhaWxhYmxlIG1vZHVsZSBzY3JpcHRzJyxcclxuICAgICAgaW5zdHJ1Y3Rpb25zOiAnU3BhY2U6IFNlbGVjdCBzcGVjaWZpYywgQTogU2VsZWN0IGFsbCwgRW50ZXI6IENvbmZpcm0uJyxcclxuICAgICAgY2hvaWNlczogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLm1vZHVsZVNjcmlwdHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdpbmRpY2F0b3JTY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0F2YWlsYWJsZSBpbmRpY2F0b3Igc2NyaXB0cycsXHJcbiAgICAgIGluc3RydWN0aW9uczogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGNob2ljZXM6IGRlZmF1bHRDb25maWcuaGlnaGNoYXJ0cy5pbmRpY2F0b3JTY3JpcHRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbGlzdCcsXHJcbiAgICAgIG5hbWU6ICdjdXN0b21TY3JpcHRzJyxcclxuICAgICAgbWVzc2FnZTogJ0N1c3RvbSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmN1c3RvbVNjcmlwdHMudmFsdWUuam9pbignLCcpLFxyXG4gICAgICBzZXBhcmF0b3I6ICcsJ1xyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdmb3JjZUZldGNoJyxcclxuICAgICAgbWVzc2FnZTogJ0ZvcmNlIHJlLWZldGNoIHRoZSBzY3JpcHRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmZvcmNlRmV0Y2gudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2NhY2hlUGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byB0aGUgY2FjaGUgZGlyZWN0b3J5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5oaWdoY2hhcnRzLmNhY2hlUGF0aC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgZXhwb3J0OiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdzZWxlY3QnLFxyXG4gICAgICBuYW1lOiAndHlwZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBleHBvcnQgZmlsZSB0eXBlJyxcclxuICAgICAgaGludDogYERlZmF1bHQ6ICR7ZGVmYXVsdENvbmZpZy5leHBvcnQudHlwZS52YWx1ZX1gLFxyXG4gICAgICBpbml0aWFsOiAwLFxyXG4gICAgICBjaG9pY2VzOiBbJ3BuZycsICdqcGVnJywgJ3BkZicsICdzdmcnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3NlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjb25zdHInLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGRlZmF1bHQgY29uc3RydWN0b3IgZm9yIEhpZ2hjaGFydHMnLFxyXG4gICAgICBoaW50OiBgRGVmYXVsdDogJHtkZWZhdWx0Q29uZmlnLmV4cG9ydC5jb25zdHIudmFsdWV9YCxcclxuICAgICAgaW5pdGlhbDogMCxcclxuICAgICAgY2hvaWNlczogWydjaGFydCcsICdzdG9ja0NoYXJ0JywgJ21hcENoYXJ0JywgJ2dhbnR0Q2hhcnQnXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdkZWZhdWx0SGVpZ2h0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIGhlaWdodCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0SGVpZ2h0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2RlZmF1bHRXaWR0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgZGVmYXVsdCBmYWxsYmFjayB3aWR0aCBvZiB0aGUgZXhwb3J0ZWQgY2hhcnQnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5kZWZhdWx0V2lkdGgudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVmYXVsdFNjYWxlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBkZWZhdWx0IGZhbGxiYWNrIHNjYWxlIG9mIHRoZSBleHBvcnRlZCBjaGFydCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZXhwb3J0LmRlZmF1bHRTY2FsZS52YWx1ZSxcclxuICAgICAgbWluOiAwLjEsXHJcbiAgICAgIG1heDogNVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXN0ZXJpemF0aW9uVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcmVuZGVyaW5nIHdlYnBhZ2UgdGltZW91dCBpbiBtaWxsaXNlY29uZHMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmV4cG9ydC5yYXN0ZXJpemF0aW9uVGltZW91dC52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgY3VzdG9tTG9naWM6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdhbGxvd0NvZGVFeGVjdXRpb24nLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGV4ZWN1dGlvbiBvZiBjdXN0b20gY29kZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuY3VzdG9tTG9naWMuYWxsb3dDb2RlRXhlY3V0aW9uLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2FsbG93RmlsZVJlc291cmNlcycsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgZmlsZSByZXNvdXJjZXMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgc2VydmVyOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ1N0YXJ0cyB0aGUgc2VydmVyIG9uIDAuMC4wLjAnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2hvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnU2VydmVyIGhvc3RuYW1lJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuaG9zdC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdwb3J0JyxcclxuICAgICAgbWVzc2FnZTogJ1NlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucG9ydC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIHNlcnZlciBiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5iZW5jaG1hcmtpbmcudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3Byb3h5Lmhvc3QnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIGhvc3Qgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5ob3N0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHBvcnQgb2YgdGhlIHByb3h5IHNlcnZlciB0byB1c2UnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5wcm94eS5wb3J0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Byb3h5LnRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHRpbWVvdXQgZm9yIHRoZSBwcm94eSBzZXJ2ZXIgdG8gdXNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucHJveHkudGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSByYXRlIGxpbWl0aW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcubWF4UmVxdWVzdHMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gcmVxdWVzdHMgYWxsb3dlZCBwZXIgbWludXRlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIucmF0ZUxpbWl0aW5nLm1heFJlcXVlc3RzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3JhdGVMaW1pdGluZy53aW5kb3cnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIHJhdGUtbGltaXRpbmcgdGltZSB3aW5kb3cgaW4gbWludXRlcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy53aW5kb3cudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLmRlbGF5JyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGRlbGF5IGZvciBlYWNoIHN1Y2Nlc3NpdmUgcmVxdWVzdCBiZWZvcmUgcmVhY2hpbmcgdGhlIG1heGltdW0nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5yYXRlTGltaXRpbmcuZGVsYXkudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAncmF0ZUxpbWl0aW5nLnRydXN0UHJveHknLFxyXG4gICAgICBtZXNzYWdlOiAnU2V0IHRvIHRydWUgaWYgYmVoaW5kIGEgbG9hZCBiYWxhbmNlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy50cnVzdFByb3h5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcEtleScsXHJcbiAgICAgIG1lc3NhZ2U6XHJcbiAgICAgICAgJ0FsbG93cyBieXBhc3NpbmcgdGhlIHJhdGUgbGltaXRlciB3aGVuIHByb3ZpZGVkIHdpdGggdGhlIHNraXBUb2tlbiBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwS2V5LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndGV4dCcsXHJcbiAgICAgIG5hbWU6ICdyYXRlTGltaXRpbmcuc2tpcFRva2VuJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnQWxsb3dzIGJ5cGFzc2luZyB0aGUgcmF0ZSBsaW1pdGVyIHdoZW4gcHJvdmlkZWQgd2l0aCB0aGUgc2tpcEtleSBhcmd1bWVudCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuc2VydmVyLnJhdGVMaW1pdGluZy5za2lwVG9rZW4udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnc3NsLmVuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGUgU1NMIHByb3RvY29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdzc2wuZm9yY2UnLFxyXG4gICAgICBtZXNzYWdlOiAnRm9yY2Ugc2VydmluZyBvbmx5IG92ZXIgSFRUUFMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnNlcnZlci5zc2wuZm9yY2UudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnc3NsLnBvcnQnLFxyXG4gICAgICBtZXNzYWdlOiAnU1NMIHNlcnZlciBwb3J0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLnBvcnQudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ3NzbC5jZXJ0UGF0aCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBmaW5kIHRoZSBTU0wgY2VydGlmaWNhdGUva2V5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5zZXJ2ZXIuc3NsLmNlcnRQYXRoLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBwb29sOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnbWluV29ya2VycycsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgaW5pdGlhbCBudW1iZXIgb2Ygd29ya2VycyB0byBzcGF3bicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5taW5Xb3JrZXJzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ21heFdvcmtlcnMnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1heGltdW0gbnVtYmVyIG9mIHdvcmtlcnMgdG8gc3Bhd24nLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wubWF4V29ya2Vycy52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICd3b3JrTGltaXQnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcGllY2VzIG9mIHdvcmsgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIGJlZm9yZSByZXN0YXJ0aW5nIGEgUHVwcGV0ZWVyIHByb2Nlc3MnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnBvb2wud29ya0xpbWl0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2FjcXVpcmVUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGFjcXVpcmluZyBhIHJlc291cmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmFjcXVpcmVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2NyZWF0ZVRpbWVvdXQnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG51bWJlciBvZiBtaWxsaXNlY29uZHMgdG8gd2FpdCBmb3IgY3JlYXRpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5jcmVhdGVUaW1lb3V0LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2Rlc3Ryb3lUaW1lb3V0JyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBudW1iZXIgb2YgbWlsbGlzZWNvbmRzIHRvIHdhaXQgZm9yIGRlc3Ryb3lpbmcgYSByZXNvdXJjZScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5kZXN0cm95VGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdpZGxlVGltZW91dCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgbnVtYmVyIG9mIG1pbGxpc2Vjb25kcyBhZnRlciBhbiBpZGxlIHJlc291cmNlIGlzIGRlc3Ryb3llZCcsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5pZGxlVGltZW91dC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ251bWJlcicsXHJcbiAgICAgIG5hbWU6ICdjcmVhdGVSZXRyeUludGVydmFsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIHJldHJ5IGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciBhIGNyZWF0ZSBwcm9jZXNzIGZhaWxzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmNyZWF0ZVJldHJ5SW50ZXJ2YWwudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAncmVhcGVySW50ZXJ2YWwnLFxyXG4gICAgICBtZXNzYWdlOlxyXG4gICAgICAgICdUaGUgcmVhcGVyIGludGVydmFsIGluIG1pbGxpc2Vjb25kcyBhZnRlciB0cmlnZ2VyaW5nIHRoZSBjaGVjayBmb3IgaWRsZSByZXNvdXJjZXMgdG8gZGVzdHJveScsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcucG9vbC5yZWFwZXJJbnRlcnZhbC52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RvZ2dsZScsXHJcbiAgICAgIG5hbWU6ICdiZW5jaG1hcmtpbmcnLFxyXG4gICAgICBtZXNzYWdlOiAnRW5hYmxlIGJlbmNobWFya2luZyBmb3IgYSByZXNvdXJjZSBwb29sJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5wb29sLmJlbmNobWFya2luZy52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgbG9nZ2luZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ2xldmVsJyxcclxuICAgICAgbWVzc2FnZTpcclxuICAgICAgICAnVGhlIGxvZyBsZXZlbCAoMDogc2lsZW50LCAxOiBlcnJvciwgMjogd2FybmluZywgMzogbm90aWNlLCA0OiB2ZXJib3NlLCA1OiBiZW5jaG1hcmspJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmxldmVsLnZhbHVlLFxyXG4gICAgICByb3VuZDogMCxcclxuICAgICAgbWluOiAwLFxyXG4gICAgICBtYXg6IDVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0ZXh0JyxcclxuICAgICAgbmFtZTogJ2ZpbGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSBsb2cgZmlsZSBuYW1lLiBTZXQgd2l0aCB0aGUgLS1sb2dEZXN0IHRvIGVuYWJsZSBmaWxlIGxvZ2dpbmcnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmxvZ2dpbmcuZmlsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnZGVzdCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcGF0aCB0byBsb2cgZmlsZXMuIEVuYWJsZXMgZmlsZSBsb2dnaW5nJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5sb2dnaW5nLmRlc3QudmFsdWVcclxuICAgIH1cclxuICBdLFxyXG4gIHVpOiBbXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZW5hYmxlJyxcclxuICAgICAgbWVzc2FnZTogJ0VuYWJsZSBVSSBmb3IgdGhlIGV4cG9ydCBzZXJ2ZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLnVpLmVuYWJsZS52YWx1ZVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAncm91dGUnLFxyXG4gICAgICBtZXNzYWdlOiAnQSByb3V0ZSB0byBhdHRhY2ggdGhlIFVJJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy51aS5yb3V0ZS52YWx1ZVxyXG4gICAgfVxyXG4gIF0sXHJcbiAgb3RoZXI6IFtcclxuICAgIHtcclxuICAgICAgdHlwZTogJ3RleHQnLFxyXG4gICAgICBuYW1lOiAnbm9kZUVudicsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgdHlwZSBvZiBOb2RlLmpzIGVudmlyb25tZW50JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub2RlRW52LnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2xpc3RlblRvUHJvY2Vzc0V4aXRzJyxcclxuICAgICAgbWVzc2FnZTogJ1NldCB0byBmYWxzZSB0byBza2lwIGF0dGFjaGluZyBwcm9jZXNzLmV4aXQgaGFuZGxlcnMnLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLm90aGVyLmxpc3RlblRvUHJvY2Vzc0V4aXRzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ25vTG9nbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdTa2lwIHByaW50aW5nIHRoZSBsb2dvIG9uIHN0YXJ0dXAuIFJlcGxhY2VkIGJ5IHNpbXBsZSB0ZXh0JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5ub0xvZ28udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGFyZFJlc2V0UGFnZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdEZWNpZGVzIGlmIHRoZSBwYWdlIGNvbnRlbnQgc2hvdWxkIGJlIHJlc2V0IGVudGlyZWx5JyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5oYXJkUmVzZXRQYWdlLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2Jyb3dzZXJTaGVsbE1vZGUnLFxyXG4gICAgICBtZXNzYWdlOiAnRGVjaWRlcyBpZiB0aGUgYnJvd3NlciBydW5zIGluIHRoZSBzaGVsbCBtb2RlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5vdGhlci5icm93c2VyU2hlbGxNb2RlLnZhbHVlXHJcbiAgICB9XHJcbiAgXSxcclxuICBkZWJ1ZzogW1xyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2VuYWJsZScsXHJcbiAgICAgIG1lc3NhZ2U6ICdFbmFibGVzIGRlYnVnIG1vZGUgZm9yIHRoZSBicm93c2VyIGluc3RhbmNlJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5lbmFibGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnaGVhZGxlc3MnLFxyXG4gICAgICBtZXNzYWdlOiAnVGhlIG1vZGUgc2V0dGluZyBmb3IgdGhlIGJyb3dzZXInLFxyXG4gICAgICBpbml0aWFsOiBkZWZhdWx0Q29uZmlnLmRlYnVnLmhlYWRsZXNzLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAndG9nZ2xlJyxcclxuICAgICAgbmFtZTogJ2RldnRvb2xzJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBEZXZUb29scyBmb3IgdGhlIGhlYWRmdWwgYnJvd3NlcicsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGV2dG9vbHMudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnbGlzdGVuVG9Db25zb2xlJyxcclxuICAgICAgbWVzc2FnZTogJ1RoZSBldmVudCBsaXN0ZW5lciBmb3IgY29uc29sZSBtZXNzYWdlcyBmcm9tIHRoZSBicm93c2VyJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5saXN0ZW5Ub0NvbnNvbGUudmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICd0b2dnbGUnLFxyXG4gICAgICBuYW1lOiAnZHVtcGlvJyxcclxuICAgICAgbWVzc2FnZTogJ1JlZGlyZWN0cyB0aGUgYnJvd3NlciBzdGRvdXQgYW5kIHN0ZGVyciB0byBOb2RlSlMgcHJvY2VzcycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZHVtcGlvLnZhbHVlXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0eXBlOiAnbnVtYmVyJyxcclxuICAgICAgbmFtZTogJ3Nsb3dNbycsXHJcbiAgICAgIG1lc3NhZ2U6ICdQdXBwZXRlZXIgb3BlcmF0aW9ucyBzbG93IGRvd24gaW4gbWlsbGlzZWNvbmRzJyxcclxuICAgICAgaW5pdGlhbDogZGVmYXVsdENvbmZpZy5kZWJ1Zy5zbG93TW8udmFsdWVcclxuICAgIH0sXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdudW1iZXInLFxyXG4gICAgICBuYW1lOiAnZGVidWdnaW5nUG9ydCcsXHJcbiAgICAgIG1lc3NhZ2U6ICdUaGUgcG9ydCBudW1iZXIgZm9yIGRlYnVnZ2luZycsXHJcbiAgICAgIGluaXRpYWw6IGRlZmF1bHRDb25maWcuZGVidWcuZGVidWdnaW5nUG9ydC52YWx1ZVxyXG4gICAgfVxyXG4gIF1cclxufTtcclxuXHJcbi8vIEFic29sdXRlIHByb3BzIHRoYXQsIGluIGNhc2Ugb2YgbWVyZ2luZyByZWN1cnNpdmVseSwgbmVlZCB0byBiZSBmb3JjZSBtZXJnZWRcclxuZXhwb3J0IGNvbnN0IGFic29sdXRlUHJvcHMgPSBbXHJcbiAgJ29wdGlvbnMnLFxyXG4gICdnbG9iYWxPcHRpb25zJyxcclxuICAndGhlbWVPcHRpb25zJyxcclxuICAncmVzb3VyY2VzJyxcclxuICAncGF5bG9hZCdcclxuXTtcclxuXHJcbi8vIEFyZ3VtZW50IG5lc3RpbmcgbGV2ZWwgb2YgYWxsIGV4cG9ydCBzZXJ2ZXIgb3B0aW9uc1xyXG5leHBvcnQgY29uc3QgbmVzdGVkQXJncyA9IHt9O1xyXG5cclxuLyoqXHJcbiAqIFJlY3Vyc2l2ZWx5IGNyZWF0ZXMgYSBjaGFpbiBvZiBuZXN0ZWQgYXJndW1lbnRzIGZyb20gYW4gb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIC0gVGhlIG9iamVjdCBjb250YWluaW5nIG5lc3RlZCBhcmd1bWVudHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBUaGUgY3VycmVudCBjaGFpbiBvZiBuZXN0ZWQgcHJvcGVydGllc1xyXG4gKiAodXNlZCBpbnRlcm5hbGx5IGR1cmluZyByZWN1cnNpb24pLlxyXG4gKi9cclxuY29uc3QgY3JlYXRlTmVzdGVkQXJncyA9IChvYmosIHByb3BDaGFpbiA9ICcnKSA9PiB7XHJcbiAgT2JqZWN0LmtleXMob2JqKS5mb3JFYWNoKChrKSA9PiB7XHJcbiAgICBpZiAoIVsncHVwcGV0ZWVyJywgJ2hpZ2hjaGFydHMnXS5pbmNsdWRlcyhrKSkge1xyXG4gICAgICBjb25zdCBlbnRyeSA9IG9ialtrXTtcclxuICAgICAgaWYgKHR5cGVvZiBlbnRyeS52YWx1ZSA9PT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAvLyBHbyBkZWVwZXIgaW4gdGhlIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBjcmVhdGVOZXN0ZWRBcmdzKGVudHJ5LCBgJHtwcm9wQ2hhaW59LiR7a31gKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDcmVhdGUgdGhlIGNoYWluIG9mIG5lc3RlZCBhcmd1bWVudHNcclxuICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmNsaU5hbWUgfHwga10gPSBgJHtwcm9wQ2hhaW59LiR7a31gLnN1YnN0cmluZygxKTtcclxuXHJcbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgdGhlIGxlZ2FjeSwgUGhhbnRvbUpTIHByb3BlcnRpZXMgbmFtZXNcclxuICAgICAgICBpZiAoZW50cnkubGVnYWN5TmFtZSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgICBuZXN0ZWRBcmdzW2VudHJ5LmxlZ2FjeU5hbWVdID0gYCR7cHJvcENoYWlufS4ke2t9YC5zdWJzdHJpbmcoMSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn07XHJcblxyXG5jcmVhdGVOZXN0ZWRBcmdzKGRlZmF1bHRDb25maWcpO1xyXG4iLCIvKipcclxuICogQGZpbGVvdmVydmlld1xyXG4gKiBUaGlzIGZpbGUgaXMgcmVzcG9uc2libGUgZm9yIHBhcnNpbmcgdGhlIGVudmlyb25tZW50IHZhcmlhYmxlcyB3aXRoIHRoZSAnem9kJ1xyXG4gKiBsaWJyYXJ5LiBUaGUgcGFyc2VkIGVudmlyb25tZW50IHZhcmlhYmxlcyBhcmUgdGhlbiBleHBvcnRlZCB0byBiZSB1c2VkXHJcbiAqIGluIHRoZSBhcHBsaWNhdGlvbiBhcyBcImVudnNcIi4gV2Ugc2hvdWxkIG5vdCB1c2UgcHJvY2Vzcy5lbnYgZGlyZWN0bHlcclxuICogaW4gdGhlIGFwcGxpY2F0aW9uIGFzIHRoZXNlIHdvdWxkIG5vdCBiZSBwYXJzZWQgcHJvcGVybHkuXHJcbiAqXHJcbiAqIFRoZSBlbnZpcm9ubWVudCB2YXJpYWJsZXMgYXJlIHBhcnNlZCBhbmQgdmFsaWRhdGVkIG9ubHkgb25jZSB3aGVuXHJcbiAqIHRoZSBhcHBsaWNhdGlvbiBzdGFydHMuIFdlIHNob3VsZCB3cml0ZSBhIGN1c3RvbSB2YWxpZGF0b3Igb3IgYSB0cmFuc2Zvcm1lclxyXG4gKiBmb3IgZWFjaCBvZiB0aGUgb3B0aW9ucy5cclxuICovXHJcblxyXG5pbXBvcnQgZG90ZW52IGZyb20gJ2RvdGVudic7XHJcbmltcG9ydCB7IHogfSBmcm9tICd6b2QnO1xyXG5cclxuaW1wb3J0IHsgc2NyaXB0c05hbWVzIH0gZnJvbSAnLi9zY2hlbWFzL2NvbmZpZy5qcyc7XHJcblxyXG4vLyBMb2FkIC5lbnYgaW50byBlbnZpcm9ubWVudCB2YXJpYWJsZXNcclxuZG90ZW52LmNvbmZpZygpO1xyXG5cclxuLy8gT2JqZWN0IHdpdGggY3VzdG9tIHZhbGlkYXRvcnMgYW5kIHRyYW5zZm9ybWVycywgdG8gYXZvaWQgcmVwZXRpdGlvblxyXG4vLyBpbiB0aGUgQ29uZmlnIG9iamVjdFxyXG5jb25zdCB2ID0ge1xyXG4gIC8vIFNwbGl0cyBzdHJpbmcgdmFsdWUgaW50byBlbGVtZW50cyBpbiBhbiBhcnJheSwgdHJpbXMgZXZlcnkgZWxlbWVudCwgY2hlY2tzXHJcbiAgLy8gaWYgYW4gYXJyYXkgaXMgY29ycmVjdCwgaWYgaXQgaXMgZW1wdHksIGFuZCBpZiBpdCBpcywgcmV0dXJucyB1bmRlZmluZWRcclxuICBhcnJheTogKGZpbHRlckFycmF5KSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+XHJcbiAgICAgICAgdmFsdWVcclxuICAgICAgICAgIC5zcGxpdCgnLCcpXHJcbiAgICAgICAgICAubWFwKCh2YWx1ZSkgPT4gdmFsdWUudHJpbSgpKVxyXG4gICAgICAgICAgLmZpbHRlcigodmFsdWUpID0+IGZpbHRlckFycmF5LmluY2x1ZGVzKHZhbHVlKSlcclxuICAgICAgKVxyXG4gICAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlLmxlbmd0aCA/IHZhbHVlIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBvbmx5IHRydWUsIGZhbHNlIGFuZCBjb3JyZWN0bHkgcGFyc2UgdGhlIHZhbHVlIHRvIGJvb2xlYW5cclxuICAvLyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIGJvb2xlYW46ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5lbnVtKFsndHJ1ZScsICdmYWxzZScsICcnXSlcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA9PT0gJ3RydWUnIDogdW5kZWZpbmVkKSksXHJcblxyXG4gIC8vIEFsbG93cyBwYXNzZWQgdmFsdWVzIG9yIG5vIHZhbHVlIGluIHdoaWNoIGNhc2UgdGhlIHJldHVybmVkIHZhbHVlIHdpbGxcclxuICAvLyBiZSB1bmRlZmluZWRcclxuICBlbnVtOiAodmFsdWVzKSA9PlxyXG4gICAgelxyXG4gICAgICAuZW51bShbLi4udmFsdWVzLCAnJ10pXHJcbiAgICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuXHJcbiAgLy8gVHJpbXMgdGhlIHN0cmluZyB2YWx1ZSBhbmQgY2hlY2tzIGlmIGl0IGlzIGVtcHR5IG9yIGNvbnRhaW5zIHN0cmluZ2lmaWVkXHJcbiAgLy8gdmFsdWVzIHN1Y2ggYXMgZmFsc2UsIHVuZGVmaW5lZCwgbnVsbCwgTmFOLCBpZiBpdCBkb2VzLCByZXR1cm5zIHVuZGVmaW5lZFxyXG4gIHN0cmluZzogKCkgPT5cclxuICAgIHpcclxuICAgICAgLnN0cmluZygpXHJcbiAgICAgIC50cmltKClcclxuICAgICAgLnJlZmluZShcclxuICAgICAgICAodmFsdWUpID0+XHJcbiAgICAgICAgICAhWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nXS5pbmNsdWRlcyh2YWx1ZSkgfHxcclxuICAgICAgICAgIHZhbHVlID09PSAnJyxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHN0cmluZyBjb250YWlucyBmb3JiaWRkZW4gdmFsdWVzLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3MgcG9zaXRpdmUgbnVtYmVycyBvciBubyB2YWx1ZSBpbiB3aGljaCBjYXNlIHRoZSByZXR1cm5lZCB2YWx1ZSB3aWxsXHJcbiAgLy8gYmUgdW5kZWZpbmVkXHJcbiAgcG9zaXRpdmVOdW06ICgpID0+XHJcbiAgICB6XHJcbiAgICAgIC5zdHJpbmcoKVxyXG4gICAgICAudHJpbSgpXHJcbiAgICAgIC5yZWZpbmUoXHJcbiAgICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgICAgdmFsdWUgPT09ICcnIHx8ICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmIHBhcnNlRmxvYXQodmFsdWUpID4gMCksXHJcbiAgICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgICAgbWVzc2FnZTogYFRoZSB2YWx1ZSBtdXN0IGJlIG51bWVyaWMgYW5kIHBvc2l0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpLFxyXG5cclxuICAvLyBBbGxvd3Mgbm9uLW5lZ2F0aXZlIG51bWJlcnMgb3Igbm8gdmFsdWUgaW4gd2hpY2ggY2FzZSB0aGUgcmV0dXJuZWQgdmFsdWVcclxuICAvLyB3aWxsIGJlIHVuZGVmaW5lZFxyXG4gIG5vbk5lZ2F0aXZlTnVtOiAoKSA9PlxyXG4gICAgelxyXG4gICAgICAuc3RyaW5nKClcclxuICAgICAgLnRyaW0oKVxyXG4gICAgICAucmVmaW5lKFxyXG4gICAgICAgICh2YWx1ZSkgPT5cclxuICAgICAgICAgIHZhbHVlID09PSAnJyB8fCAoIWlzTmFOKHBhcnNlRmxvYXQodmFsdWUpKSAmJiBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwKSxcclxuICAgICAgICAodmFsdWUpID0+ICh7XHJcbiAgICAgICAgICBtZXNzYWdlOiBgVGhlIHZhbHVlIG11c3QgYmUgbnVtZXJpYyBhbmQgbm9uLW5lZ2F0aXZlLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICAgIH0pXHJcbiAgICAgIClcclxuICAgICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyBwYXJzZUZsb2F0KHZhbHVlKSA6IHVuZGVmaW5lZCkpXHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgQ29uZmlnID0gei5vYmplY3Qoe1xyXG4gIC8vIGhpZ2hjaGFydHNcclxuICBISUdIQ0hBUlRTX1ZFUlNJT046IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PiAvXihsYXRlc3R8XFxkKyhcXC5cXGQrKXswLDJ9KSQvLnRlc3QodmFsdWUpIHx8IHZhbHVlID09PSAnJyxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBISUdIQ0hBUlRTX1ZFUlNJT04gbXVzdCBiZSAnbGF0ZXN0JywgYSBtYWpvciB2ZXJzaW9uLCBvciBpbiB0aGUgZm9ybSBYWC5ZWS5aWiwgcmVjZWl2ZWQgJyR7dmFsdWV9J2BcclxuICAgICAgfSlcclxuICAgIClcclxuICAgIC50cmFuc2Zvcm0oKHZhbHVlKSA9PiAodmFsdWUgIT09ICcnID8gdmFsdWUgOiB1bmRlZmluZWQpKSxcclxuICBISUdIQ0hBUlRTX0NETl9VUkw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlLnN0YXJ0c1dpdGgoJ2h0dHBzOi8vJykgfHxcclxuICAgICAgICB2YWx1ZS5zdGFydHNXaXRoKCdodHRwOi8vJykgfHxcclxuICAgICAgICB2YWx1ZSA9PT0gJycsXHJcbiAgICAgICh2YWx1ZSkgPT4gKHtcclxuICAgICAgICBtZXNzYWdlOiBgSW52YWxpZCB2YWx1ZSBmb3IgSElHSENIQVJUU19DRE5fVVJMLiBJdCBzaG91bGQgc3RhcnQgd2l0aCBodHRwOi8vIG9yIGh0dHBzOi8vLCByZWNlaXZlZCAnJHt2YWx1ZX0nYFxyXG4gICAgICB9KVxyXG4gICAgKVxyXG4gICAgLnRyYW5zZm9ybSgodmFsdWUpID0+ICh2YWx1ZSAhPT0gJycgPyB2YWx1ZSA6IHVuZGVmaW5lZCkpLFxyXG4gIEhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5jb3JlKSxcclxuICBISUdIQ0hBUlRTX01PRFVMRV9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5tb2R1bGVzKSxcclxuICBISUdIQ0hBUlRTX0lORElDQVRPUl9TQ1JJUFRTOiB2LmFycmF5KHNjcmlwdHNOYW1lcy5pbmRpY2F0b3JzKSxcclxuICBISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIOiB2LmJvb2xlYW4oKSxcclxuICBISUdIQ0hBUlRTX0NBQ0hFX1BBVEg6IHYuc3RyaW5nKCksXHJcbiAgSElHSENIQVJUU19BRE1JTl9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gZXhwb3J0XHJcbiAgRVhQT1JUX1RZUEU6IHYuZW51bShbJ2pwZWcnLCAncG5nJywgJ3BkZicsICdzdmcnXSksXHJcbiAgRVhQT1JUX0NPTlNUUjogdi5lbnVtKFsnY2hhcnQnLCAnc3RvY2tDaGFydCcsICdtYXBDaGFydCcsICdnYW50dENoYXJ0J10pLFxyXG4gIEVYUE9SVF9ERUZBVUxUX0hFSUdIVDogdi5wb3NpdGl2ZU51bSgpLFxyXG4gIEVYUE9SVF9ERUZBVUxUX1dJRFRIOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgRVhQT1JUX0RFRkFVTFRfU0NBTEU6IHYucG9zaXRpdmVOdW0oKSxcclxuICBFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcblxyXG4gIC8vIGN1c3RvbVxyXG4gIENVU1RPTV9MT0dJQ19BTExPV19DT0RFX0VYRUNVVElPTjogdi5ib29sZWFuKCksXHJcbiAgQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyXHJcbiAgU0VSVkVSX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfQkVOQ0hNQVJLSU5HOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gc2VydmVyIHByb3h5XHJcbiAgU0VSVkVSX1BST1hZX0hPU1Q6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1BST1hZX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUFJPWFlfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG5cclxuICAvLyBzZXJ2ZXIgcmF0ZSBsaW1pdGluZ1xyXG4gIFNFUlZFUl9SQVRFX0xJTUlUSU5HX0VOQUJMRTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVk6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWTogdi5ib29sZWFuKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9LRVk6IHYuc3RyaW5nKCksXHJcbiAgU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTjogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gc2VydmVyIHNzbFxyXG4gIFNFUlZFUl9TU0xfRU5BQkxFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX0ZPUkNFOiB2LmJvb2xlYW4oKSxcclxuICBTRVJWRVJfU1NMX1BPUlQ6IHYucG9zaXRpdmVOdW0oKSxcclxuICBTRVJWRVJfU1NMX0NFUlRfUEFUSDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gcG9vbFxyXG4gIFBPT0xfTUlOX1dPUktFUlM6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX01BWF9XT1JLRVJTOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9XT1JLX0xJTUlUOiB2LnBvc2l0aXZlTnVtKCksXHJcbiAgUE9PTF9BQ1FVSVJFX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0NSRUFURV9USU1FT1VUOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9ERVNUUk9ZX1RJTUVPVVQ6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0lETEVfVElNRU9VVDogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIFBPT0xfQ1JFQVRFX1JFVFJZX0lOVEVSVkFMOiB2Lm5vbk5lZ2F0aXZlTnVtKCksXHJcbiAgUE9PTF9SRUFQRVJfSU5URVJWQUw6IHYubm9uTmVnYXRpdmVOdW0oKSxcclxuICBQT09MX0JFTkNITUFSS0lORzogdi5ib29sZWFuKCksXHJcblxyXG4gIC8vIGxvZ2dlclxyXG4gIExPR0dJTkdfTEVWRUw6IHpcclxuICAgIC5zdHJpbmcoKVxyXG4gICAgLnRyaW0oKVxyXG4gICAgLnJlZmluZShcclxuICAgICAgKHZhbHVlKSA9PlxyXG4gICAgICAgIHZhbHVlID09PSAnJyB8fFxyXG4gICAgICAgICghaXNOYU4ocGFyc2VGbG9hdCh2YWx1ZSkpICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA+PSAwICYmXHJcbiAgICAgICAgICBwYXJzZUZsb2F0KHZhbHVlKSA8PSA1KSxcclxuICAgICAgKHZhbHVlKSA9PiAoe1xyXG4gICAgICAgIG1lc3NhZ2U6IGBJbnZhbGlkIHZhbHVlIGZvciBMT0dHSU5HX0xFVkVMLiBXZSBvbmx5IGFjY2VwdCB2YWx1ZXMgZnJvbSAwIHRvIDUgYXMgbG9nZ2luZyBsZXZlbHMsIHJlY2VpdmVkICcke3ZhbHVlfSdgXHJcbiAgICAgIH0pXHJcbiAgICApXHJcbiAgICAudHJhbnNmb3JtKCh2YWx1ZSkgPT4gKHZhbHVlICE9PSAnJyA/IHBhcnNlRmxvYXQodmFsdWUpIDogdW5kZWZpbmVkKSksXHJcbiAgTE9HR0lOR19GSUxFOiB2LnN0cmluZygpLFxyXG4gIExPR0dJTkdfREVTVDogdi5zdHJpbmcoKSxcclxuXHJcbiAgLy8gdWlcclxuICBVSV9FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIFVJX1JPVVRFOiB2LnN0cmluZygpLFxyXG5cclxuICAvLyBvdGhlclxyXG4gIE9USEVSX05PREVfRU5WOiB2LmVudW0oWydkZXZlbG9wbWVudCcsICdwcm9kdWN0aW9uJywgJ3Rlc3QnXSksXHJcbiAgT1RIRVJfTElTVEVOX1RPX1BST0NFU1NfRVhJVFM6IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX05PX0xPR086IHYuYm9vbGVhbigpLFxyXG4gIE9USEVSX0hBUkRfUkVTRVRfUEFHRTogdi5ib29sZWFuKCksXHJcbiAgT1RIRVJfQlJPV1NFUl9TSEVMTF9NT0RFOiB2LmJvb2xlYW4oKSxcclxuXHJcbiAgLy8gZGVidWdnZXJcclxuICBERUJVR19FTkFCTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0hFQURMRVNTOiB2LmJvb2xlYW4oKSxcclxuICBERUJVR19ERVZUT09MUzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfTElTVEVOX1RPX0NPTlNPTEU6IHYuYm9vbGVhbigpLFxyXG4gIERFQlVHX0RVTVBJTzogdi5ib29sZWFuKCksXHJcbiAgREVCVUdfU0xPV19NTzogdi5ub25OZWdhdGl2ZU51bSgpLFxyXG4gIERFQlVHX0RFQlVHR0lOR19QT1JUOiB2LnBvc2l0aXZlTnVtKClcclxufSk7XHJcblxyXG5leHBvcnQgY29uc3QgZW52cyA9IENvbmZpZy5wYXJ0aWFsKCkucGFyc2UocHJvY2Vzcy5lbnYpO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFwcGVuZEZpbGUsIGV4aXN0c1N5bmMsIG1rZGlyU3luYyB9IGZyb20gJ2ZzJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuXHJcbi8vIFRoZSBhdmFpbGFibGUgY29sb3JzXHJcbmNvbnN0IGNvbG9ycyA9IFsncmVkJywgJ3llbGxvdycsICdibHVlJywgJ2dyYXknLCAnZ3JlZW4nXTtcclxuXHJcbi8vIFRoZSBkZWZhdWx0IGxvZ2dpbmcgY29uZmlnXHJcbmxldCBsb2dnaW5nID0ge1xyXG4gIC8vIEZsYWdzIGZvciBsb2dnaW5nIHN0YXR1c1xyXG4gIHRvQ29uc29sZTogdHJ1ZSxcclxuICB0b0ZpbGU6IGZhbHNlLFxyXG4gIHBhdGhDcmVhdGVkOiBmYWxzZSxcclxuICAvLyBMb2cgbGV2ZWxzXHJcbiAgbGV2ZWxzRGVzYzogW1xyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2Vycm9yJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1swXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICd3YXJuaW5nJyxcclxuICAgICAgY29sb3I6IGNvbG9yc1sxXVxyXG4gICAgfSxcclxuICAgIHtcclxuICAgICAgdGl0bGU6ICdub3RpY2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzJdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ3ZlcmJvc2UnLFxyXG4gICAgICBjb2xvcjogY29sb3JzWzNdXHJcbiAgICB9LFxyXG4gICAge1xyXG4gICAgICB0aXRsZTogJ2JlbmNobWFyaycsXHJcbiAgICAgIGNvbG9yOiBjb2xvcnNbNF1cclxuICAgIH1cclxuICBdLFxyXG4gIC8vIExvZyBsaXN0ZW5lcnNcclxuICBsaXN0ZW5lcnM6IFtdXHJcbn07XHJcblxyXG4vLyBHYXRoZXIgaW5pdCBsb2dnaW5nIG9wdGlvbnNcclxuZm9yIChjb25zdCBba2V5LCBvcHRpb25dIG9mIE9iamVjdC5lbnRyaWVzKGRlZmF1bHRDb25maWcubG9nZ2luZykpIHtcclxuICBsb2dnaW5nW2tleV0gPSBvcHRpb24udmFsdWU7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBMb2dzIHRoZSBwcm92aWRlZCB0ZXh0cyB0byBhIGZpbGUsIGlmIGZpbGUgbG9nZ2luZyBpcyBlbmFibGVkLiBJdCBjcmVhdGVzXHJcbiAqIHRoZSBuZWNlc3NhcnkgZGlyZWN0b3J5IHN0cnVjdHVyZSBpZiBub3QgYWxyZWFkeSBjcmVhdGVkIGFuZCBhcHBlbmRzIHRoZVxyXG4gKiBjb250ZW50LCBpbmNsdWRpbmcgYW4gb3B0aW9uYWwgcHJlZml4LCB0byB0aGUgc3BlY2lmaWVkIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ1tdfSB0ZXh0cyAtIEFuIGFycmF5IG9mIHRleHRzIHRvIGJlIGxvZ2dlZC5cclxuICogQHBhcmFtIHtzdHJpbmd9IHByZWZpeCAtIEFuIG9wdGlvbmFsIHByZWZpeCB0byBiZSBhZGRlZCB0byBlYWNoIGxvZyBlbnRyeS5cclxuICovXHJcbmNvbnN0IGxvZ1RvRmlsZSA9ICh0ZXh0cywgcHJlZml4KSA9PiB7XHJcbiAgaWYgKGxvZ2dpbmcudG9GaWxlKSB7XHJcbiAgICBpZiAoIWxvZ2dpbmcucGF0aENyZWF0ZWQpIHtcclxuICAgICAgLy8gQ3JlYXRlIGlmIGRvZXMgbm90IGV4aXN0XHJcbiAgICAgICFleGlzdHNTeW5jKGxvZ2dpbmcuZGVzdCkgJiYgbWtkaXJTeW5jKGxvZ2dpbmcuZGVzdCk7XHJcblxyXG4gICAgICAvLyBXZSBub3cgYXNzdW1lIHRoZSBwYXRoIGlzIGF2YWlsYWJsZSwgZS5nLiBpdCdzIHRoZSByZXNwb25zaWJpbGl0eVxyXG4gICAgICAvLyBvZiB0aGUgdXNlciB0byBjcmVhdGUgdGhlIHBhdGggd2l0aCB0aGUgY29ycmVjdCBhY2Nlc3MgcmlnaHRzLlxyXG4gICAgICBsb2dnaW5nLnBhdGhDcmVhdGVkID0gdHJ1ZTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBZGQgdGhlIGNvbnRlbnQgdG8gYSBmaWxlXHJcbiAgICBhcHBlbmRGaWxlKFxyXG4gICAgICBgJHtsb2dnaW5nLmRlc3R9JHtsb2dnaW5nLmZpbGV9YCxcclxuICAgICAgW3ByZWZpeF0uY29uY2F0KHRleHRzKS5qb2luKCcgJykgKyAnXFxuJyxcclxuICAgICAgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICBjb25zb2xlLmxvZyhgW2xvZ2dlcl0gVW5hYmxlIHRvIHdyaXRlIHRvIGxvZyBmaWxlOiAke2Vycm9yfWApO1xyXG4gICAgICAgICAgbG9nZ2luZy50b0ZpbGUgPSBmYWxzZTtcclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgYSBtZXNzYWdlLiBBY2NlcHRzIGEgdmFyaWFibGUgYW1vdW50IG9mIGFyZ3VtZW50cy4gQXJndW1lbnRzIGFmdGVyXHJcbiAqIGBsZXZlbGAgd2lsbCBiZSBwYXNzZWQgZGlyZWN0bHkgdG8gY29uc29sZS5sb2csIGFuZC9vciB3aWxsIGJlIGpvaW5lZFxyXG4gKiBhbmQgYXBwZW5kZWQgdG8gdGhlIGxvZyBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gYXJncyAtIEFuIGFycmF5IG9mIGFyZ3VtZW50cyB3aGVyZSB0aGUgZmlyc3QgaXMgdGhlIGxvZyBsZXZlbFxyXG4gKiBhbmQgdGhlIHJlc3QgYXJlIHN0cmluZ3MgdG8gYnVpbGQgYSBtZXNzYWdlIHdpdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbG9nID0gKC4uLmFyZ3MpID0+IHtcclxuICBjb25zdCBbbmV3TGV2ZWwsIC4uLnRleHRzXSA9IGFyZ3M7XHJcblxyXG4gIC8vIEN1cnJlbnQgbG9nZ2luZyBvcHRpb25zXHJcbiAgY29uc3QgeyBsZXZlbCwgbGV2ZWxzRGVzYyB9ID0gbG9nZ2luZztcclxuXHJcbiAgLy8gQ2hlY2sgaWYgbG9nIGxldmVsIGlzIHdpdGhpbiBhIGNvcnJlY3QgcmFuZ2Ugb3IgaXMgYSBiZW5jaG1hcmsgbG9nXHJcbiAgaWYgKFxyXG4gICAgbmV3TGV2ZWwgIT09IDUgJiZcclxuICAgIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpXHJcbiAgKSB7XHJcbiAgICByZXR1cm47XHJcbiAgfVxyXG5cclxuICAvLyBHZXQgcmlkIG9mIHRoZSBHTVQgdGV4dCBpbmZvcm1hdGlvblxyXG4gIGNvbnN0IG5ld0RhdGUgPSBuZXcgRGF0ZSgpLnRvU3RyaW5nKCkuc3BsaXQoJygnKVswXS50cmltKCk7XHJcblxyXG4gIC8vIENyZWF0ZSBhIG1lc3NhZ2UncyBwcmVmaXhcclxuICBjb25zdCBwcmVmaXggPSBgJHtuZXdEYXRlfSBbJHtsZXZlbHNEZXNjW25ld0xldmVsIC0gMV0udGl0bGV9XSAtYDtcclxuXHJcbiAgLy8gQ2FsbCBhdmFpbGFibGUgbG9nIGxpc3RlbmVyc1xyXG4gIGxvZ2dpbmcubGlzdGVuZXJzLmZvckVhY2goKGZuKSA9PiB7XHJcbiAgICBmbihwcmVmaXgsIHRleHRzLmpvaW4oJyAnKSk7XHJcbiAgfSk7XHJcblxyXG4gIC8vIExvZyB0byBjb25zb2xlXHJcbiAgaWYgKGxvZ2dpbmcudG9Db25zb2xlKSB7XHJcbiAgICBjb25zb2xlLmxvZy5hcHBseShcclxuICAgICAgdW5kZWZpbmVkLFxyXG4gICAgICBbcHJlZml4LnRvU3RyaW5nKClbbG9nZ2luZy5sZXZlbHNEZXNjW25ld0xldmVsIC0gMV0uY29sb3JdXS5jb25jYXQodGV4dHMpXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgLy8gTG9nIHRvIGZpbGVcclxuICBsb2dUb0ZpbGUodGV4dHMsIHByZWZpeCk7XHJcbn07XHJcblxyXG4vKipcclxuICogTG9ncyBhbiBlcnJvciBtZXNzYWdlIHdpdGggaXRzIHN0YWNrIHRyYWNlLiBPcHRpb25hbGx5LCBhIGN1c3RvbSBtZXNzYWdlXHJcbiAqIGNhbiBiZSBwcm92aWRlZC5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGxldmVsIC0gVGhlIGxvZyBsZXZlbC5cclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gY3VzdG9tTWVzc2FnZSAtIEFuIG9wdGlvbmFsIGN1c3RvbSBtZXNzYWdlIHRvIGJlIGxvZ2dlZCBhbG9uZ1xyXG4gKiB3aXRoIHRoZSBlcnJvci5cclxuICovXHJcbmV4cG9ydCBjb25zdCBsb2dXaXRoU3RhY2sgPSAobmV3TGV2ZWwsIGVycm9yLCBjdXN0b21NZXNzYWdlKSA9PiB7XHJcbiAgLy8gR2V0IHRoZSBtYWluIG1lc3NhZ2VcclxuICBjb25zdCBtYWluTWVzc2FnZSA9IGN1c3RvbU1lc3NhZ2UgfHwgZXJyb3IubWVzc2FnZTtcclxuXHJcbiAgLy8gQ3VycmVudCBsb2dnaW5nIG9wdGlvbnNcclxuICBjb25zdCB7IGxldmVsLCBsZXZlbHNEZXNjIH0gPSBsb2dnaW5nO1xyXG5cclxuICAvLyBDaGVjayBpZiBsb2cgbGV2ZWwgaXMgd2l0aGluIGEgY29ycmVjdCByYW5nZVxyXG4gIGlmIChuZXdMZXZlbCA9PT0gMCB8fCBuZXdMZXZlbCA+IGxldmVsIHx8IGxldmVsID4gbGV2ZWxzRGVzYy5sZW5ndGgpIHtcclxuICAgIHJldHVybjtcclxuICB9XHJcblxyXG4gIC8vIEdldCByaWQgb2YgdGhlIEdNVCB0ZXh0IGluZm9ybWF0aW9uXHJcbiAgY29uc3QgbmV3RGF0ZSA9IG5ldyBEYXRlKCkudG9TdHJpbmcoKS5zcGxpdCgnKCcpWzBdLnRyaW0oKTtcclxuXHJcbiAgLy8gQ3JlYXRlIGEgbWVzc2FnZSdzIHByZWZpeFxyXG4gIGNvbnN0IHByZWZpeCA9IGAke25ld0RhdGV9IFske2xldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS50aXRsZX1dIC1gO1xyXG5cclxuICAvLyBJZiB0aGUgY3VzdG9tTWVzc2FnZSBleGlzdHMsIHdlIHdhbnQgdG8gZGlzcGxheSB0aGUgd2hvbGUgc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHN0YWNrTWVzc2FnZSA9XHJcbiAgICBlcnJvci5tZXNzYWdlICE9PSBlcnJvci5zdGFja01lc3NhZ2UgfHwgZXJyb3Iuc3RhY2tNZXNzYWdlID09PSB1bmRlZmluZWRcclxuICAgICAgPyBlcnJvci5zdGFja1xyXG4gICAgICA6IGVycm9yLnN0YWNrLnNwbGl0KCdcXG4nKS5zbGljZSgxKS5qb2luKCdcXG4nKTtcclxuXHJcbiAgLy8gQ29tYmluZSBjdXN0b20gbWVzc2FnZSBvciBlcnJvciBtZXNzYWdlIHdpdGggZXJyb3Igc3RhY2sgbWVzc2FnZVxyXG4gIGNvbnN0IHRleHRzID0gW21haW5NZXNzYWdlLCAnXFxuJywgc3RhY2tNZXNzYWdlXTtcclxuXHJcbiAgLy8gTG9nIHRvIGNvbnNvbGVcclxuICBpZiAobG9nZ2luZy50b0NvbnNvbGUpIHtcclxuICAgIGNvbnNvbGUubG9nLmFwcGx5KFxyXG4gICAgICB1bmRlZmluZWQsXHJcbiAgICAgIFtwcmVmaXgudG9TdHJpbmcoKVtsb2dnaW5nLmxldmVsc0Rlc2NbbmV3TGV2ZWwgLSAxXS5jb2xvcl1dLmNvbmNhdChbXHJcbiAgICAgICAgbWFpbk1lc3NhZ2VbY29sb3JzW25ld0xldmVsIC0gMV1dLFxyXG4gICAgICAgICdcXG4nLFxyXG4gICAgICAgIHN0YWNrTWVzc2FnZVxyXG4gICAgICBdKVxyXG4gICAgKTtcclxuICB9XHJcblxyXG4gIC8vIENhbGwgYXZhaWxhYmxlIGxvZyBsaXN0ZW5lcnNcclxuICBsb2dnaW5nLmxpc3RlbmVycy5mb3JFYWNoKChmbikgPT4ge1xyXG4gICAgZm4ocHJlZml4LCB0ZXh0cy5qb2luKCcgJykpO1xyXG4gIH0pO1xyXG5cclxuICAvLyBMb2cgdG8gZmlsZVxyXG4gIGxvZ1RvRmlsZSh0ZXh0cywgcHJlZml4KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBsb2cgbGV2ZWwgdG8gdGhlIHNwZWNpZmllZCB2YWx1ZS4gTG9nIGxldmVscyBhcmUgKDAgPSBubyBsb2dnaW5nLFxyXG4gKiAxID0gZXJyb3IsIDIgPSB3YXJuaW5nLCAzID0gbm90aWNlLCA0ID0gdmVyYm9zZSBvciA1ID0gYmVuY2htYXJrKVxyXG4gKlxyXG4gKiBAcGFyYW0ge251bWJlcn0gbmV3TGV2ZWwgLSBUaGUgbmV3IGxvZyBsZXZlbCB0byBiZSBzZXQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0TG9nTGV2ZWwgPSAobmV3TGV2ZWwpID0+IHtcclxuICBpZiAobmV3TGV2ZWwgPj0gMCAmJiBuZXdMZXZlbCA8PSBsb2dnaW5nLmxldmVsc0Rlc2MubGVuZ3RoKSB7XHJcbiAgICBsb2dnaW5nLmxldmVsID0gbmV3TGV2ZWw7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZXMgZmlsZSBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBkZXN0aW5hdGlvbiBhbmQgbG9nIGZpbGUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBsb2dEZXN0IC0gVGhlIGRlc3RpbmF0aW9uIHBhdGggZm9yIGxvZyBmaWxlcy5cclxuICogQHBhcmFtIHtzdHJpbmd9IGxvZ0ZpbGUgLSBUaGUgbG9nIGZpbGUgbmFtZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVGaWxlTG9nZ2luZyA9IChsb2dEZXN0LCBsb2dGaWxlKSA9PiB7XHJcbiAgLy8gVXBkYXRlIGxvZ2dpbmcgb3B0aW9uc1xyXG4gIGxvZ2dpbmcgPSB7XHJcbiAgICAuLi5sb2dnaW5nLFxyXG4gICAgZGVzdDogbG9nRGVzdCB8fCBsb2dnaW5nLmRlc3QsXHJcbiAgICBmaWxlOiBsb2dGaWxlIHx8IGxvZ2dpbmcuZmlsZSxcclxuICAgIHRvRmlsZTogdHJ1ZVxyXG4gIH07XHJcblxyXG4gIGlmIChsb2dnaW5nLmRlc3QubGVuZ3RoID09PSAwKSB7XHJcbiAgICByZXR1cm4gbG9nKDEsICdbbG9nZ2VyXSBGaWxlIGxvZ2dpbmcgaW5pdGlhbGl6YXRpb246IG5vIHBhdGggc3VwcGxpZWQuJyk7XHJcbiAgfVxyXG5cclxuICBpZiAoIWxvZ2dpbmcuZGVzdC5lbmRzV2l0aCgnLycpKSB7XHJcbiAgICBsb2dnaW5nLmRlc3QgKz0gJy8nO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBsb2dnaW5nIHdpdGggdGhlIHNwZWNpZmllZCBsb2dnaW5nIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBsb2dnaW5nIC0gVGhlIGxvZ2dpbmcgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaW5pdExvZ2dpbmcgPSAobG9nZ2luZykgPT4ge1xyXG4gIC8vIFNldCB0aGUgbG9nIGxldmVsXHJcbiAgc2V0TG9nTGV2ZWwobG9nZ2luZyAmJiBwYXJzZUludChsb2dnaW5nLmxldmVsKSk7XHJcblxyXG4gIC8vIFNldCB0aGUgbG9nIGZpbGUgcGF0aCBhbmQgbmFtZVxyXG4gIGlmIChsb2dnaW5nICYmIGxvZ2dpbmcuZGVzdCkge1xyXG4gICAgZW5hYmxlRmlsZUxvZ2dpbmcoXHJcbiAgICAgIGxvZ2dpbmcuZGVzdCxcclxuICAgICAgbG9nZ2luZy5maWxlIHx8ICdoaWdoY2hhcnRzLWV4cG9ydC1zZXJ2ZXIubG9nJ1xyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIHRvIHRoZSBsb2dnaW5nIHN5c3RlbS5cclxuICpcclxuICogQHBhcmFtIHtmdW5jdGlvbn0gZm4gLSBUaGUgbGlzdGVuZXIgZnVuY3Rpb24gdG8gYmUgYWRkZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbGlzdGVuID0gKGZuKSA9PiB7XHJcbiAgbG9nZ2luZy5saXN0ZW5lcnMucHVzaChmbik7XHJcbn07XHJcblxyXG4vKipcclxuICogVG9nZ2xlcyB0aGUgc3RhbmRhcmQgb3V0cHV0IChjb25zb2xlKSBsb2dnaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWQgLSBJZiB0cnVlLCBlbmFibGVzIGNvbnNvbGUgbG9nZ2luZzsgaWYgZmFsc2UsXHJcbiAqIGRpc2FibGVzIGl0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHRvZ2dsZVNURE91dCA9IChlbmFibGVkKSA9PiB7XHJcbiAgbG9nZ2luZy50b0NvbnNvbGUgPSBlbmFibGVkO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbGlzdGVuLFxyXG4gIHRvZ2dsZVNURE91dFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiB9IGZyb20gJ3BhdGgnO1xyXG5pbXBvcnQgeyBmaWxlVVJMVG9QYXRoIH0gZnJvbSAndXJsJztcclxuXHJcbmltcG9ydCB7IGRlZmF1bHRDb25maWcgfSBmcm9tICcuLi9saWIvc2NoZW1hcy9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuXHJcbmNvbnN0IE1BWF9CQUNLT0ZGX0FUVEVNUFRTID0gNjtcclxuXHJcbmV4cG9ydCBjb25zdCBfX2Rpcm5hbWUgPSBmaWxlVVJMVG9QYXRoKG5ldyBVUkwoJy4uLy4nLCBpbXBvcnQubWV0YS51cmwpKTtcclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgYW5kIHN0YW5kYXJkaXplcyB0ZXh0IGJ5IHJlcGxhY2luZyBtdWx0aXBsZSBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlXHJcbiAqIGNoYXJhY3RlcnMgd2l0aCBhIHNpbmdsZSBzcGFjZSBhbmQgdHJpbW1pbmcgYW55IGxlYWRpbmcgb3IgdHJhaWxpbmdcclxuICogd2hpdGVzcGFjZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgaW5wdXQgdGV4dCB0byBiZSBjbGVhcmVkLlxyXG4gKiBAcGFyYW0ge1JlZ0V4cH0gW3J1bGU9L1xcc1xccysvZ10gLSBUaGUgcmVndWxhciBleHByZXNzaW9uIHJ1bGUgdG8gbWF0Y2hcclxuICogbXVsdGlwbGUgY29uc2VjdXRpdmUgd2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gW3JlcGxhY2VyPScgJ10gLSBUaGUgc3RyaW5nIHVzZWQgdG8gcmVwbGFjZSBtdWx0aXBsZVxyXG4gKiBjb25zZWN1dGl2ZSB3aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIGNsZWFyZWQgYW5kIHN0YW5kYXJkaXplZCB0ZXh0LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyVGV4dCA9ICh0ZXh0LCBydWxlID0gL1xcc1xccysvZywgcmVwbGFjZXIgPSAnICcpID0+XHJcbiAgdGV4dC5yZXBsYWNlQWxsKHJ1bGUsIHJlcGxhY2VyKS50cmltKCk7XHJcblxyXG4vKipcclxuICogSW1wbGVtZW50cyBhbiBleHBvbmVudGlhbCBiYWNrb2ZmIHN0cmF0ZWd5IGZvciByZXRyeWluZyBhIGZ1bmN0aW9uIHVudGlsXHJcbiAqIGEgY2VydGFpbiBudW1iZXIgb2YgYXR0ZW1wdHMgYXJlIHJlYWNoZWQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIC0gVGhlIGZ1bmN0aW9uIHRvIGJlIHJldHJpZWQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSBbYXR0ZW1wdD0wXSAtIFRoZSBjdXJyZW50IGF0dGVtcHQgbnVtYmVyLlxyXG4gKiBAcGFyYW0gey4uLmFueX0gYXJncyAtIEFyZ3VtZW50cyB0byBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCByZXNvbHZlcyB0byB0aGUgcmVzdWx0IG9mIHRoZSBmdW5jdGlvblxyXG4gKiBpZiBzdWNjZXNzZnVsLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gLSBUaHJvd3MgYW4gZXJyb3IgaWYgdGhlIG1heGltdW0gbnVtYmVyIG9mIGF0dGVtcHRzXHJcbiAqIGlzIHJlYWNoZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXhwQmFja29mZiA9IGFzeW5jIChmbiwgYXR0ZW1wdCA9IDAsIC4uLmFyZ3MpID0+IHtcclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIGNhbGwgdGhlIGZ1bmN0aW9uXHJcbiAgICByZXR1cm4gYXdhaXQgZm4oLi4uYXJncyk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIENhbGN1bGF0ZSBkZWxheSBpbiBtc1xyXG4gICAgY29uc3QgZGVsYXlJbk1zID0gMiAqKiBhdHRlbXB0ICogMTAwMDtcclxuXHJcbiAgICAvLyBJZiB0aGUgYXR0ZW1wdCBleGNlZWRzIHRoZSBtYXhpbXVtIGF0dGVtcHRzIG9mIHJlYXBlYXQsIHRocm93IGFuIGVycm9yXHJcbiAgICBpZiAoKythdHRlbXB0ID49IE1BWF9CQUNLT0ZGX0FUVEVNUFRTKSB7XHJcbiAgICAgIHRocm93IGVycm9yO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFdhaXQgZ2l2ZW4gYW1vdW50IG9mIHRpbWVcclxuICAgIGF3YWl0IG5ldyBQcm9taXNlKChyZXNwb25zZSkgPT4gc2V0VGltZW91dChyZXNwb25zZSwgZGVsYXlJbk1zKSk7XHJcbiAgICBsb2coXHJcbiAgICAgIDMsXHJcbiAgICAgIGBbcG9vbF0gV2FpdGVkICR7ZGVsYXlJbk1zfW1zIHVudGlsIG5leHQgY2FsbCBmb3IgdGhlIHJlc291cmNlIGlkOiAke2FyZ3NbMF19LmBcclxuICAgICk7XHJcblxyXG4gICAgLy8gVHJ5IGFnYWluXHJcbiAgICByZXR1cm4gZXhwQmFja29mZihmbiwgYXR0ZW1wdCwgLi4uYXJncyk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZpeGVzIHRoZSBleHBvcnQgdHlwZSBiYXNlZCBvbiBNSU1FIHR5cGVzIGFuZCBmaWxlIGV4dGVuc2lvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIG9yaWdpbmFsIGV4cG9ydCB0eXBlLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gb3V0ZmlsZSAtIFRoZSBmaWxlIHBhdGggb3IgbmFtZS5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gLSBUaGUgY29ycmVjdGVkIGV4cG9ydCB0eXBlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGZpeFR5cGUgPSAodHlwZSwgb3V0ZmlsZSkgPT4ge1xyXG4gIC8vIE1JTUUgdHlwZXNcclxuICBjb25zdCBtaW1lVHlwZXMgPSB7XHJcbiAgICAnaW1hZ2UvcG5nJzogJ3BuZycsXHJcbiAgICAnaW1hZ2UvanBlZyc6ICdqcGVnJyxcclxuICAgICdhcHBsaWNhdGlvbi9wZGYnOiAncGRmJyxcclxuICAgICdpbWFnZS9zdmcreG1sJzogJ3N2ZydcclxuICB9O1xyXG5cclxuICAvLyBGb3JtYXRzXHJcbiAgY29uc3QgZm9ybWF0cyA9IFsncG5nJywgJ2pwZWcnLCAncGRmJywgJ3N2ZyddO1xyXG5cclxuICAvLyBDaGVjayBpZiB0eXBlIGFuZCBvdXRmaWxlJ3MgZXh0ZW5zaW9ucyBhcmUgdGhlIHNhbWVcclxuICBpZiAob3V0ZmlsZSkge1xyXG4gICAgY29uc3Qgb3V0VHlwZSA9IG91dGZpbGUuc3BsaXQoJy4nKS5wb3AoKTtcclxuXHJcbiAgICBpZiAob3V0VHlwZSA9PT0gJ2pwZycpIHtcclxuICAgICAgdHlwZSA9ICdqcGVnJztcclxuICAgIH0gZWxzZSBpZiAoZm9ybWF0cy5pbmNsdWRlcyhvdXRUeXBlKSAmJiB0eXBlICE9PSBvdXRUeXBlKSB7XHJcbiAgICAgIHR5cGUgPSBvdXRUeXBlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGEgY29ycmVjdCB0eXBlXHJcbiAgcmV0dXJuIG1pbWVUeXBlc1t0eXBlXSB8fCBmb3JtYXRzLmZpbmQoKHQpID0+IHQgPT09IHR5cGUpIHx8ICdwbmcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEhhbmRsZXMgYW5kIHZhbGlkYXRlcyByZXNvdXJjZXMgZm9yIGV4cG9ydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R8c3RyaW5nfSByZXNvdXJjZXMgLSBUaGUgcmVzb3VyY2VzIHRvIGJlIGhhbmRsZWQuIENhbiBiZSBlaXRoZXJcclxuICogYSBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTiBvciBhIHBhdGggdG8gYSBKU09OIGZpbGUuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gV2hldGhlciB0byBhbGxvdyBsb2FkaW5nIHJlc291cmNlcyBmcm9tXHJcbiAqIGZpbGVzLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fHVuZGVmaW5lZH0gLSBUaGUgaGFuZGxlZCByZXNvdXJjZXMgb3IgdW5kZWZpbmVkIGlmIG5vIHZhbGlkXHJcbiAqIHJlc291cmNlcyBhcmUgZm91bmQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgaGFuZGxlUmVzb3VyY2VzID0gKHJlc291cmNlcyA9IGZhbHNlLCBhbGxvd0ZpbGVSZXNvdXJjZXMpID0+IHtcclxuICBjb25zdCBhbGxvd2VkUHJvcHMgPSBbJ2pzJywgJ2NzcycsICdmaWxlcyddO1xyXG5cclxuICBsZXQgaGFuZGxlZFJlc291cmNlcyA9IHJlc291cmNlcztcclxuICBsZXQgY29ycmVjdFJlc291cmNlcyA9IGZhbHNlO1xyXG5cclxuICAvLyBUcnkgdG8gbG9hZCByZXNvdXJjZXMgZnJvbSBhIGZpbGVcclxuICBpZiAoYWxsb3dGaWxlUmVzb3VyY2VzICYmIHJlc291cmNlcy5lbmRzV2l0aCgnLmpzb24nKSkge1xyXG4gICAgdHJ5IHtcclxuICAgICAgaGFuZGxlZFJlc291cmNlcyA9IGlzQ29ycmVjdEpTT04ocmVhZEZpbGVTeW5jKHJlc291cmNlcywgJ3V0ZjgnKSk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NsaV0gTm8gcmVzb3VyY2VzIGZvdW5kLmApO1xyXG4gICAgfVxyXG4gIH0gZWxzZSB7XHJcbiAgICAvLyBUcnkgdG8gZ2V0IEpTT05cclxuICAgIGhhbmRsZWRSZXNvdXJjZXMgPSBpc0NvcnJlY3RKU09OKHJlc291cmNlcyk7XHJcblxyXG4gICAgLy8gR2V0IHJpZCBvZiB0aGUgZmlsZXMgc2VjdGlvblxyXG4gICAgaWYgKGhhbmRsZWRSZXNvdXJjZXMgJiYgIWFsbG93RmlsZVJlc291cmNlcykge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlcy5maWxlcztcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEZpbHRlciBmcm9tIHVubmVjZXNzYXJ5IHByb3BlcnRpZXNcclxuICBmb3IgKGNvbnN0IHByb3BOYW1lIGluIGhhbmRsZWRSZXNvdXJjZXMpIHtcclxuICAgIGlmICghYWxsb3dlZFByb3BzLmluY2x1ZGVzKHByb3BOYW1lKSkge1xyXG4gICAgICBkZWxldGUgaGFuZGxlZFJlc291cmNlc1twcm9wTmFtZV07XHJcbiAgICB9IGVsc2UgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICAgIGNvcnJlY3RSZXNvdXJjZXMgPSB0cnVlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2hlY2sgaWYgYXQgbGVhc3Qgb25lIG9mIGFsbG93ZWQgcHJvcGVydGllcyBpcyBwcmVzZW50XHJcbiAgaWYgKCFjb3JyZWN0UmVzb3VyY2VzKSB7XHJcbiAgICByZXR1cm4gbG9nKDMsIGBbY2xpXSBObyByZXNvdXJjZXMgZm91bmQuYCk7XHJcbiAgfVxyXG5cclxuICAvLyBIYW5kbGUgZmlsZXMgc2VjdGlvblxyXG4gIGlmIChoYW5kbGVkUmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzID0gaGFuZGxlZFJlc291cmNlcy5maWxlcy5tYXAoKGl0ZW0pID0+IGl0ZW0udHJpbSgpKTtcclxuICAgIGlmICghaGFuZGxlZFJlc291cmNlcy5maWxlcyB8fCBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzLmxlbmd0aCA8PSAwKSB7XHJcbiAgICAgIGRlbGV0ZSBoYW5kbGVkUmVzb3VyY2VzLmZpbGVzO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIHJlc291cmNlc1xyXG4gIHJldHVybiBoYW5kbGVkUmVzb3VyY2VzO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFZhbGlkYXRlcyBhbmQgcGFyc2VzIEpTT04gZGF0YS4gQ2hlY2tzIGlmIHByb3ZpZGVkIGRhdGEgaXMgb3IgY2FuXHJcbiAqIGJlIGEgY29ycmVjdCBKU09OLiBJZiBhIHByaW1pdGl2ZSBpcyBwcm92aWRlZCwgaXQgaXMgc3RyaW5naWZpZWQgYW5kIHJldHVybmVkLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdHxzdHJpbmd9IGRhdGEgLSBUaGUgSlNPTiBkYXRhIHRvIGJlIHZhbGlkYXRlZCBhbmQgcGFyc2VkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHRvU3RyaW5nIC0gV2hldGhlciB0byByZXR1cm4gYSBzdHJpbmdpZmllZCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgcGFyc2VkIEpTT04uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8c3RyaW5nfGJvb2xlYW59IC0gVGhlIHBhcnNlZCBKU09OIG9iamVjdCwgc3RyaW5naWZpZWQgSlNPTixcclxuICogb3IgZmFsc2UgaWYgdmFsaWRhdGlvbiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBpc0NvcnJlY3RKU09OKGRhdGEsIHRvU3RyaW5nKSB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIEdldCB0aGUgc3RyaW5nIHJlcHJlc2VudGF0aW9uIGlmIG5vdCBhbHJlYWR5IGJlZm9yZSBwYXJzaW5nXHJcbiAgICBjb25zdCBwYXJzZWREYXRhID0gSlNPTi5wYXJzZShcclxuICAgICAgdHlwZW9mIGRhdGEgIT09ICdzdHJpbmcnID8gSlNPTi5zdHJpbmdpZnkoZGF0YSkgOiBkYXRhXHJcbiAgICApO1xyXG5cclxuICAgIC8vIFJldHVybiBhIHN0cmluZ2lmaWVkIHJlcHJlc2VudGF0aW9uIG9mIGEgSlNPTiBpZiByZXF1aXJlZFxyXG4gICAgaWYgKHR5cGVvZiBwYXJzZWREYXRhICE9PSAnc3RyaW5nJyAmJiB0b1N0cmluZykge1xyXG4gICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkocGFyc2VkRGF0YSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmV0dXJuIGEgSlNPTlxyXG4gICAgcmV0dXJuIHBhcnNlZERhdGE7XHJcbiAgfSBjYXRjaCB7XHJcbiAgICByZXR1cm4gZmFsc2U7XHJcbiAgfVxyXG59XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBpdGVtIGlzIGFuIG9iamVjdC5cclxuICpcclxuICogQHBhcmFtIHthbnl9IGl0ZW0gLSBUaGUgaXRlbSB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBpdGVtIGlzIGFuIG9iamVjdCwgZmFsc2Ugb3RoZXJ3aXNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGlzT2JqZWN0ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmICFBcnJheS5pc0FycmF5KGl0ZW0pICYmIGl0ZW0gIT09IG51bGw7XHJcblxyXG4vKipcclxuICogQ2hlY2tzIGlmIHRoZSBnaXZlbiBvYmplY3QgaXMgZW1wdHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBpdGVtIC0gVGhlIG9iamVjdCB0byBiZSBjaGVja2VkLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIHRoZSBvYmplY3QgaXMgZW1wdHksIGZhbHNlIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc09iamVjdEVtcHR5ID0gKGl0ZW0pID0+XHJcbiAgdHlwZW9mIGl0ZW0gPT09ICdvYmplY3QnICYmXHJcbiAgIUFycmF5LmlzQXJyYXkoaXRlbSkgJiZcclxuICBpdGVtICE9PSBudWxsICYmXHJcbiAgT2JqZWN0LmtleXMoaXRlbSkubGVuZ3RoID09PSAwO1xyXG5cclxuLyoqXHJcbiAqIENoZWNrcyBpZiBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMIGlzIGZvdW5kIGluIHRoZSBnaXZlbiBzdHJpbmcuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBpdGVtIC0gVGhlIHN0cmluZyB0byBiZSBjaGVja2VkIGZvciBhIHByaXZhdGUgSVAgcmFuZ2UgVVJMLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUcnVlIGlmIGEgcHJpdmF0ZSBJUCByYW5nZSBVUkwgaXMgZm91bmQsIGZhbHNlXHJcbiAqIG90aGVyd2lzZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBpc1ByaXZhdGVSYW5nZVVybEZvdW5kID0gKGl0ZW0pID0+IHtcclxuICBjb25zdCByZWdleFBhdHRlcm5zID0gW1xyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pP2xvY2FsaG9zdFxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTBcXC5cXGR7MSwzfVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzEyN1xcLlxcZHsxLDN9XFwuXFxkezEsM31cXC5cXGR7MSwzfVxcYi8sXHJcbiAgICAveGxpbms6aHJlZj1cIig/Omh0dHA6XFwvXFwvfGh0dHBzOlxcL1xcLyk/MTcyXFwuKDFbNi05XXwyWzAtOV18M1swLTFdKVxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvLFxyXG4gICAgL3hsaW5rOmhyZWY9XCIoPzpodHRwOlxcL1xcL3xodHRwczpcXC9cXC8pPzE5MlxcLjE2OFxcLlxcZHsxLDN9XFwuXFxkezEsM31cXGIvXHJcbiAgXTtcclxuXHJcbiAgcmV0dXJuIHJlZ2V4UGF0dGVybnMuc29tZSgocGF0dGVybikgPT4gcGF0dGVybi50ZXN0KGl0ZW0pKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGEgZGVlcCBjb3B5IG9mIHRoZSBnaXZlbiBvYmplY3Qgb3IgYXJyYXkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fEFycmF5fSBvYmogLSBUaGUgb2JqZWN0IG9yIGFycmF5IHRvIGJlIGRlZXBseSBjb3BpZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R8QXJyYXl9IC0gVGhlIGRlZXAgY29weSBvZiB0aGUgcHJvdmlkZWQgb2JqZWN0IG9yIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGRlZXBDb3B5ID0gKG9iaikgPT4ge1xyXG4gIGlmIChvYmogPT09IG51bGwgfHwgdHlwZW9mIG9iaiAhPT0gJ29iamVjdCcpIHtcclxuICAgIHJldHVybiBvYmo7XHJcbiAgfVxyXG5cclxuICBjb25zdCBjb3B5ID0gQXJyYXkuaXNBcnJheShvYmopID8gW10gOiB7fTtcclxuXHJcbiAgZm9yIChjb25zdCBrZXkgaW4gb2JqKSB7XHJcbiAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwga2V5KSkge1xyXG4gICAgICBjb3B5W2tleV0gPSBkZWVwQ29weShvYmpba2V5XSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICByZXR1cm4gY29weTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBDb252ZXJ0cyB0aGUgcHJvdmlkZWQgb3B0aW9ucyBvYmplY3QgdG8gYSBKU09OLWZvcm1hdHRlZCBzdHJpbmcgd2l0aCB0aGVcclxuICogb3B0aW9uIHRvIHByZXNlcnZlIGZ1bmN0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgdG8gYmUgY29udmVydGVkIHRvIGEgc3RyaW5nLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IGFsbG93RnVuY3Rpb25zIC0gSWYgc2V0IHRvIHRydWUsIGZ1bmN0aW9ucyBhcmUgcHJlc2VydmVkXHJcbiAqIGluIHRoZSBvdXRwdXQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd9IC0gVGhlIEpTT04tZm9ybWF0dGVkIHN0cmluZyByZXByZXNlbnRpbmcgdGhlIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgb3B0aW9uc1N0cmluZ2lmeSA9IChvcHRpb25zLCBhbGxvd0Z1bmN0aW9ucykgPT4ge1xyXG4gIGNvbnN0IHJlcGxhY2VyQ2FsbGJhY2sgPSAobmFtZSwgdmFsdWUpID0+IHtcclxuICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIHZhbHVlID0gdmFsdWUudHJpbSgpO1xyXG5cclxuICAgICAgLy8gSWYgYWxsb3dGdW5jdGlvbnMgaXMgc2V0IHRvIHRydWUsIHByZXNlcnZlIGZ1bmN0aW9uc1xyXG4gICAgICBpZiAoXHJcbiAgICAgICAgKHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCcpIHx8IHZhbHVlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgnKSkgJiZcclxuICAgICAgICB2YWx1ZS5lbmRzV2l0aCgnfScpXHJcbiAgICAgICkge1xyXG4gICAgICAgIHZhbHVlID0gYWxsb3dGdW5jdGlvbnNcclxuICAgICAgICAgID8gYEVYUF9GVU4keyh2YWx1ZSArICcnKS5yZXBsYWNlQWxsKC9cXG58XFx0fFxcci9nLCAnICcpfUVYUF9GVU5gXHJcbiAgICAgICAgICA6IHVuZGVmaW5lZDtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbidcclxuICAgICAgPyBgRVhQX0ZVTiR7KHZhbHVlICsgJycpLnJlcGxhY2VBbGwoL1xcbnxcXHR8XFxyL2csICcgJyl9RVhQX0ZVTmBcclxuICAgICAgOiB2YWx1ZTtcclxuICB9O1xyXG5cclxuICAvLyBTdHJpbmdpZnkgb3B0aW9ucyBhbmQgaWYgcmVxdWlyZWQsIHJlcGxhY2Ugc3BlY2lhbCBmdW5jdGlvbnMgbWFya3NcclxuICByZXR1cm4gSlNPTi5zdHJpbmdpZnkob3B0aW9ucywgcmVwbGFjZXJDYWxsYmFjaykucmVwbGFjZUFsbChcclxuICAgIC9cIkVYUF9GVU58RVhQX0ZVTlwiL2csXHJcbiAgICAnJ1xyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogUHJpbnRzIHRoZSBIaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXIgbG9nbyBhbmQgdmVyc2lvbiBpbmZvcm1hdGlvbi5cclxuICpcclxuICogQHBhcmFtIHtib29sZWFufSBub0xvZ28gLSBJZiB0cnVlLCBvbmx5IHByaW50cyB2ZXJzaW9uIGluZm9ybWF0aW9uIHdpdGhvdXRcclxuICogdGhlIGxvZ28uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcHJpbnRMb2dvID0gKG5vTG9nbykgPT4ge1xyXG4gIC8vIEdldCBwYWNrYWdlIHZlcnNpb24gZWl0aGVyIGZyb20gZW52IG9yIGZyb20gcGFja2FnZS5qc29uXHJcbiAgY29uc3QgcGFja2FnZVZlcnNpb24gPSBKU09OLnBhcnNlKFxyXG4gICAgcmVhZEZpbGVTeW5jKGpvaW4oX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpXHJcbiAgKS52ZXJzaW9uO1xyXG5cclxuICAvLyBQcmludCB0ZXh0IG9ubHlcclxuICBpZiAobm9Mb2dvKSB7XHJcbiAgICBjb25zb2xlLmxvZyhgU3RhcnRpbmcgSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyIHYke3BhY2thZ2VWZXJzaW9ufS4uLmApO1xyXG4gICAgcmV0dXJuO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJpbnQgdGhlIGxvZ29cclxuICBjb25zb2xlLmxvZyhcclxuICAgIHJlYWRGaWxlU3luYyhfX2Rpcm5hbWUgKyAnL21zZy9zdGFydHVwLm1zZycpLnRvU3RyaW5nKCkuYm9sZC55ZWxsb3csXHJcbiAgICBgdiR7cGFja2FnZVZlcnNpb259XFxuYC5ib2xkXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBQcmludHMgdGhlIHVzYWdlIGluZm9ybWF0aW9uIGZvciBDTEkgYXJndW1lbnRzLiBJZiByZXF1aXJlZCwgaXQgY2FuIGxpc3RcclxuICogcHJvcGVydGllcyByZWN1cnNpdmVseVxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHByaW50VXNhZ2UoKSB7XHJcbiAgY29uc3QgcGFkID0gNDg7XHJcbiAgY29uc3QgcmVhZG1lID0gJ2h0dHBzOi8vZ2l0aHViLmNvbS9oaWdoY2hhcnRzL25vZGUtZXhwb3J0LXNlcnZlciNyZWFkbWUnO1xyXG5cclxuICAvLyBEaXNwbGF5IHJlYWRtZSBpbmZvcm1hdGlvblxyXG4gIGNvbnNvbGUubG9nKFxyXG4gICAgJ1xcblVzYWdlIG9mIENMSSBhcmd1bWVudHM6Jy5ib2xkLFxyXG4gICAgJ1xcbi0tLS0tLScsXHJcbiAgICBgXFxuRm9yIG1vcmUgZGV0YWlsZWQgaW5mb3JtYXRpb24sIHZpc2l0IHRoZSByZWFkbWUgYXQ6ICR7cmVhZG1lLmJvbGQueWVsbG93fS5gXHJcbiAgKTtcclxuXHJcbiAgY29uc3QgY3ljbGVDYXRlZ29yaWVzID0gKG9wdGlvbnMpID0+IHtcclxuICAgIGZvciAoY29uc3QgW25hbWUsIG9wdGlvbl0gb2YgT2JqZWN0LmVudHJpZXMob3B0aW9ucykpIHtcclxuICAgICAgLy8gSWYgY2F0ZWdvcnkgaGFzIG1vcmUgbGV2ZWxzLCBnbyBmdXJ0aGVyXHJcbiAgICAgIGlmICghT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9wdGlvbiwgJ3ZhbHVlJykpIHtcclxuICAgICAgICBjeWNsZUNhdGVnb3JpZXMob3B0aW9uKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICBsZXQgZGVzY05hbWUgPSBgICAtLSR7b3B0aW9uLmNsaU5hbWUgfHwgbmFtZX0gJHtcclxuICAgICAgICAgICgnPCcgKyBvcHRpb24udHlwZSArICc+JykuZ3JlZW5cclxuICAgICAgICB9IGA7XHJcbiAgICAgICAgaWYgKGRlc2NOYW1lLmxlbmd0aCA8IHBhZCkge1xyXG4gICAgICAgICAgZm9yIChsZXQgaSA9IGRlc2NOYW1lLmxlbmd0aDsgaSA8IHBhZDsgaSsrKSB7XHJcbiAgICAgICAgICAgIGRlc2NOYW1lICs9ICcuJztcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIERpc3BsYXkgY29ycmVjdGx5IGFsaWduZWQgbWVzc2FnZXNcclxuICAgICAgICBjb25zb2xlLmxvZyhcclxuICAgICAgICAgIGRlc2NOYW1lLFxyXG4gICAgICAgICAgb3B0aW9uLmRlc2NyaXB0aW9uLFxyXG4gICAgICAgICAgYFtEZWZhdWx0OiAke29wdGlvbi52YWx1ZS50b1N0cmluZygpLmJvbGR9XWAuYmx1ZVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9O1xyXG5cclxuICAvLyBDeWNsZSB0aHJvdWdoIG9wdGlvbnMgb2YgZWFjaCBjYXRlZ29yaWVzIGFuZCBkaXNwbGF5IHRoZSB1c2FnZSBpbmZvXHJcbiAgT2JqZWN0LmtleXMoZGVmYXVsdENvbmZpZykuZm9yRWFjaCgoY2F0ZWdvcnkpID0+IHtcclxuICAgIC8vIE9ubHkgcHVwcGV0ZWVyIGFuZCBoaWdoY2hhcnRzIGNhdGVnb3JpZXMgY2Fubm90IGJlIGNvbmZpZ3VyZWQgdGhyb3VnaCBDTElcclxuICAgIGlmICghWydwdXBwZXRlZXInLCAnaGlnaGNoYXJ0cyddLmluY2x1ZGVzKGNhdGVnb3J5KSkge1xyXG4gICAgICBjb25zb2xlLmxvZyhgXFxuJHtjYXRlZ29yeS50b1VwcGVyQ2FzZSgpfWAucmVkKTtcclxuICAgICAgY3ljbGVDYXRlZ29yaWVzKGRlZmF1bHRDb25maWdbY2F0ZWdvcnldKTtcclxuICAgIH1cclxuICB9KTtcclxuICBjb25zb2xlLmxvZygnXFxuJyk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSb3VuZHMgYSBudW1iZXIgdG8gdGhlIHNwZWNpZmllZCBwcmVjaXNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB2YWx1ZSAtIFRoZSBudW1iZXIgdG8gYmUgcm91bmRlZC5cclxuICogQHBhcmFtIHtudW1iZXJ9IHByZWNpc2lvbiAtIFRoZSBudW1iZXIgb2YgZGVjaW1hbCBwbGFjZXMgdG8gcm91bmQgdG8uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtudW1iZXJ9IC0gVGhlIHJvdW5kZWQgbnVtYmVyLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHJvdW5kTnVtYmVyID0gKHZhbHVlLCBwcmVjaXNpb24gPSAxKSA9PiB7XHJcbiAgY29uc3QgbXVsdGlwbGllciA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24gfHwgMCk7XHJcbiAgcmV0dXJuIE1hdGgucm91bmQoK3ZhbHVlICogbXVsdGlwbGllcikgLyBtdWx0aXBsaWVyO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENvbnZlcnRzIGEgdmFsdWUgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcGFyYW0ge2FueX0gaXRlbSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgdG8gYSBib29sZWFuLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gLSBUaGUgYm9vbGVhbiByZXByZXNlbnRhdGlvbiBvZiB0aGUgaW5wdXQgdmFsdWUuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgdG9Cb29sZWFuID0gKGl0ZW0pID0+XHJcbiAgWydmYWxzZScsICd1bmRlZmluZWQnLCAnbnVsbCcsICdOYU4nLCAnMCcsICcnXS5pbmNsdWRlcyhpdGVtKVxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiAhIWl0ZW07XHJcblxyXG4vKipcclxuICogV3JhcHMgY3VzdG9tIGNvZGUgdG8gZXhlY3V0ZSBpdCBzYWZlbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjdXN0b21Db2RlIC0gVGhlIGN1c3RvbSBjb2RlIHRvIGJlIHdyYXBwZWQuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gYWxsb3dGaWxlUmVzb3VyY2VzIC0gRmxhZyB0byBhbGxvdyBsb2FkaW5nIGNvZGUgZnJvbSBhIGZpbGUuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtzdHJpbmd8Ym9vbGVhbn0gLSBUaGUgd3JhcHBlZCBjdXN0b20gY29kZSBvciBmYWxzZSBpZiB3cmFwcGluZ1xyXG4gKiBmYWlscy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB3cmFwQXJvdW5kID0gKGN1c3RvbUNvZGUsIGFsbG93RmlsZVJlc291cmNlcykgPT4ge1xyXG4gIGlmIChjdXN0b21Db2RlICYmIHR5cGVvZiBjdXN0b21Db2RlID09PSAnc3RyaW5nJykge1xyXG4gICAgY3VzdG9tQ29kZSA9IGN1c3RvbUNvZGUudHJpbSgpO1xyXG5cclxuICAgIGlmIChjdXN0b21Db2RlLmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgICByZXR1cm4gYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICAgPyB3cmFwQXJvdW5kKHJlYWRGaWxlU3luYyhjdXN0b21Db2RlLCAndXRmOCcpKVxyXG4gICAgICAgIDogZmFsc2U7XHJcbiAgICB9IGVsc2UgaWYgKFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uKCknKSB8fFxyXG4gICAgICBjdXN0b21Db2RlLnN0YXJ0c1dpdGgoJ2Z1bmN0aW9uICgpJykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKT0+JykgfHxcclxuICAgICAgY3VzdG9tQ29kZS5zdGFydHNXaXRoKCcoKSA9PicpXHJcbiAgICApIHtcclxuICAgICAgcmV0dXJuIGAoJHtjdXN0b21Db2RlfSkoKWA7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gY3VzdG9tQ29kZS5yZXBsYWNlKC87JC8sICcnKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogVXRpbGl0eSB0byBtZWFzdXJlIGVsYXBzZWQgdGltZSB1c2luZyB0aGUgTm9kZS5qcyBwcm9jZXNzLmhydGltZSgpIG1ldGhvZC5cclxuICpcclxuICogQHJldHVybnMge2Z1bmN0aW9uKCk6IG51bWJlcn0gLSBBIGZ1bmN0aW9uIHRvIGNhbGN1bGF0ZSB0aGUgZWxhcHNlZCB0aW1lXHJcbiAqIGluIG1pbGxpc2Vjb25kcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtZWFzdXJlVGltZSA9ICgpID0+IHtcclxuICBjb25zdCBzdGFydCA9IHByb2Nlc3MuaHJ0aW1lLmJpZ2ludCgpO1xyXG4gIHJldHVybiAoKSA9PiBOdW1iZXIocHJvY2Vzcy5ocnRpbWUuYmlnaW50KCkgLSBzdGFydCkgLyAxMDAwMDAwO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIF9fZGlybmFtZSxcclxuICBjbGVhclRleHQsXHJcbiAgZXhwQmFja29mZixcclxuICBmaXhUeXBlLFxyXG4gIGhhbmRsZVJlc291cmNlcyxcclxuICBpc0NvcnJlY3RKU09OLFxyXG4gIGlzT2JqZWN0LFxyXG4gIGlzT2JqZWN0RW1wdHksXHJcbiAgaXNQcml2YXRlUmFuZ2VVcmxGb3VuZCxcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlLFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kLFxyXG4gIG1lYXN1cmVUaW1lXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgZXhpc3RzU3luYywgcmVhZEZpbGVTeW5jLCBwcm9taXNlcyBhcyBmc1Byb21pc2VzIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHByb21wdHMgZnJvbSAncHJvbXB0cyc7XHJcblxyXG5pbXBvcnQge1xyXG4gIGFic29sdXRlUHJvcHMsXHJcbiAgZGVmYXVsdENvbmZpZyxcclxuICBuZXN0ZWRBcmdzLFxyXG4gIHByb21wdHNDb25maWdcclxufSBmcm9tICcuL3NjaGVtYXMvY29uZmlnLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBkZWVwQ29weSwgaXNPYmplY3QsIHByaW50VXNhZ2UsIHRvQm9vbGVhbiB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxubGV0IGdlbmVyYWxPcHRpb25zID0ge307XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIGFuZCByZXR1cm5zIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0T3B0aW9ucyA9ICgpID0+IGdlbmVyYWxPcHRpb25zO1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIGFuZCBzZXRzIHRoZSBnZW5lcmFsIG9wdGlvbnMgZm9yIHRoZSBzZXJ2ZXIgaW5zdGFjZSwga2VlcGluZ1xyXG4gKiB0aGUgcHJpbmNpcGxlIG9mIHRoZSBvcHRpb25zIGxvYWQgcHJpb3JpdHkuIEl0IGFjY2VwdHMgb3B0aW9uYWwgdXNlck9wdGlvbnNcclxuICogYW5kIGFyZ3MgZnJvbSB0aGUgQ0xJLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gdXNlck9wdGlvbnMgLSBVc2VyLXByb3ZpZGVkIG9wdGlvbnMgZm9yIGN1c3RvbWl6YXRpb24uXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIGZvciBhZGRpdGlvbmFsIGNvbmZpZ3VyYXRpb25cclxuICogKENMSSB1c2FnZSkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IFRoZSB1cGRhdGVkIGdlbmVyYWwgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2V0T3B0aW9ucyA9ICh1c2VyT3B0aW9ucywgYXJncykgPT4ge1xyXG4gIC8vIE9ubHkgZm9yIHRoZSBDTEkgdXNhZ2VcclxuICBpZiAoYXJncz8ubGVuZ3RoKSB7XHJcbiAgICAvLyBHZXQgdGhlIGFkZGl0aW9uYWwgb3B0aW9ucyBmcm9tIHRoZSBjdXN0b20gSlNPTiBmaWxlXHJcbiAgICBnZW5lcmFsT3B0aW9ucyA9IGxvYWRDb25maWdGaWxlKGFyZ3MpO1xyXG4gIH1cclxuXHJcbiAgLy8gVXBkYXRlIHRoZSBkZWZhdWx0IGNvbmZpZyB3aXRoIGEgY29ycmVjdCBvcHRpb24gdmFsdWVzXHJcbiAgdXBkYXRlRGVmYXVsdENvbmZpZyhkZWZhdWx0Q29uZmlnLCBnZW5lcmFsT3B0aW9ucyk7XHJcblxyXG4gIC8vIFNldCB2YWx1ZXMgZm9yIHNlcnZlcidzIG9wdGlvbnMgYW5kIHJldHVybnMgdGhlbVxyXG4gIGdlbmVyYWxPcHRpb25zID0gaW5pdE9wdGlvbnMoZGVmYXVsdENvbmZpZyk7XHJcblxyXG4gIC8vIEFwcGx5IHVzZXIgb3B0aW9ucyBpZiB0aGVyZSBhcmUgYW55XHJcbiAgaWYgKHVzZXJPcHRpb25zKSB7XHJcbiAgICAvLyBNZXJnZSB1c2VyIG9wdGlvbnNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgdXNlck9wdGlvbnMsXHJcbiAgICAgIGFic29sdXRlUHJvcHNcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICAvLyBPbmx5IGZvciB0aGUgQ0xJIHVzYWdlXHJcbiAgaWYgKGFyZ3M/Lmxlbmd0aCkge1xyXG4gICAgLy8gUGFpciBwcm92aWRlZCBhcmd1bWVudHNcclxuICAgIGdlbmVyYWxPcHRpb25zID0gcGFpckFyZ3VtZW50VmFsdWUoZ2VuZXJhbE9wdGlvbnMsIGFyZ3MsIGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgLy8gUmV0dXJuIGZpbmFsIGdlbmVyYWwgb3B0aW9uc1xyXG4gIHJldHVybiBnZW5lcmFsT3B0aW9ucztcclxufTtcclxuXHJcbi8qKlxyXG4gKiBBbGxvd3MgbWFudWFsIGNvbmZpZ3VyYXRpb24gYmFzZWQgb24gc3BlY2lmaWVkIHByb21wdHMgYW5kIHNhdmVzXHJcbiAqIHRoZSBjb25maWd1cmF0aW9uIHRvIGEgZmlsZS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNvbmZpZ0ZpbGVOYW1lIC0gVGhlIG5hbWUgb2YgdGhlIGNvbmZpZ3VyYXRpb24gZmlsZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8Ym9vbGVhbj59IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHRvIHRydWUgb25jZSB0aGUgbWFudWFsXHJcbiAqIGNvbmZpZ3VyYXRpb24gaXMgY29tcGxldGVkIGFuZCBzYXZlZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBtYW51YWxDb25maWcgPSBhc3luYyAoY29uZmlnRmlsZU5hbWUpID0+IHtcclxuICAvLyBQcmVwYXJlIGEgY29uZmlnIG9iamVjdFxyXG4gIGxldCBjb25maWdGaWxlID0ge307XHJcblxyXG4gIC8vIENoZWNrIGlmIHByb3ZpZGVkIGNvbmZpZyBmaWxlIGV4aXN0c1xyXG4gIGlmIChleGlzdHNTeW5jKGNvbmZpZ0ZpbGVOYW1lKSkge1xyXG4gICAgY29uZmlnRmlsZSA9IEpTT04ucGFyc2UocmVhZEZpbGVTeW5jKGNvbmZpZ0ZpbGVOYW1lLCAndXRmOCcpKTtcclxuICB9XHJcblxyXG4gIC8vIFF1ZXN0aW9uIGFib3V0IGEgY29uZmlndXJhdGlvbiBjYXRlZ29yeVxyXG4gIGNvbnN0IG9uU3VibWl0ID0gYXN5bmMgKHAsIGNhdGVnb3JpZXMpID0+IHtcclxuICAgIGxldCBxdWVzdGlvbnNDb3VudGVyID0gMDtcclxuICAgIGxldCBhbGxRdWVzdGlvbnMgPSBbXTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBjb3JyZXNwb25kaW5nIHByb3BlcnR5IGluIHRoZSBtYW51YWxDb25maWcgb2JqZWN0XHJcbiAgICBmb3IgKGNvbnN0IHNlY3Rpb24gb2YgY2F0ZWdvcmllcykge1xyXG4gICAgICAvLyBNYXJrIGVhY2ggb3B0aW9uIHdpdGggYSBzZWN0aW9uXHJcbiAgICAgIHByb21wdHNDb25maWdbc2VjdGlvbl0gPSBwcm9tcHRzQ29uZmlnW3NlY3Rpb25dLm1hcCgob3B0aW9uKSA9PiAoe1xyXG4gICAgICAgIC4uLm9wdGlvbixcclxuICAgICAgICBzZWN0aW9uXHJcbiAgICAgIH0pKTtcclxuXHJcbiAgICAgIC8vIENvbGxlY3QgdGhlIHF1ZXN0aW9uc1xyXG4gICAgICBhbGxRdWVzdGlvbnMgPSBbLi4uYWxsUXVlc3Rpb25zLCAuLi5wcm9tcHRzQ29uZmlnW3NlY3Rpb25dXTtcclxuICAgIH1cclxuXHJcbiAgICBhd2FpdCBwcm9tcHRzKGFsbFF1ZXN0aW9ucywge1xyXG4gICAgICBvblN1Ym1pdDogYXN5bmMgKHByb21wdCwgYW5zd2VyKSA9PiB7XHJcbiAgICAgICAgLy8gR2V0IHRoZSBkZWZhdWx0IG1vZHVsZSBzY3JpcHRzXHJcbiAgICAgICAgaWYgKHByb21wdC5uYW1lID09PSAnbW9kdWxlU2NyaXB0cycpIHtcclxuICAgICAgICAgIGFuc3dlciA9IGFuc3dlci5sZW5ndGhcclxuICAgICAgICAgICAgPyBhbnN3ZXIubWFwKChtb2R1bGUpID0+IHByb21wdC5jaG9pY2VzW21vZHVsZV0pXHJcbiAgICAgICAgICAgIDogcHJvbXB0LmNob2ljZXM7XHJcblxyXG4gICAgICAgICAgY29uZmlnRmlsZVtwcm9tcHQuc2VjdGlvbl1bcHJvbXB0Lm5hbWVdID0gYW5zd2VyO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSA9IHJlY3Vyc2l2ZVByb3BzKFxyXG4gICAgICAgICAgICBPYmplY3QuYXNzaWduKHt9LCBjb25maWdGaWxlW3Byb21wdC5zZWN0aW9uXSB8fCB7fSksXHJcbiAgICAgICAgICAgIHByb21wdC5uYW1lLnNwbGl0KCcuJyksXHJcbiAgICAgICAgICAgIHByb21wdC5jaG9pY2VzID8gcHJvbXB0LmNob2ljZXNbYW5zd2VyXSA6IGFuc3dlclxyXG4gICAgICAgICAgKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIGlmICgrK3F1ZXN0aW9uc0NvdW50ZXIgPT09IGFsbFF1ZXN0aW9ucy5sZW5ndGgpIHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGF3YWl0IGZzUHJvbWlzZXMud3JpdGVGaWxlKFxyXG4gICAgICAgICAgICAgIGNvbmZpZ0ZpbGVOYW1lLFxyXG4gICAgICAgICAgICAgIEpTT04uc3RyaW5naWZ5KGNvbmZpZ0ZpbGUsIG51bGwsIDIpLFxyXG4gICAgICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgbG9nV2l0aFN0YWNrKFxyXG4gICAgICAgICAgICAgIDEsXHJcbiAgICAgICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIEFuIGVycm9yIG9jY3VycmVkIHdoaWxlIGNyZWF0aW5nIHRoZSAke2NvbmZpZ0ZpbGVOYW1lfSBmaWxlLmBcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSk7XHJcblxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfTtcclxuXHJcbiAgLy8gRmluZCB0aGUgY2F0ZWdvcmllc1xyXG4gIGNvbnN0IGNob2ljZXMgPSBPYmplY3Qua2V5cyhwcm9tcHRzQ29uZmlnKS5tYXAoKGNob2ljZSkgPT4gKHtcclxuICAgIHRpdGxlOiBgJHtjaG9pY2V9IG9wdGlvbnNgLFxyXG4gICAgdmFsdWU6IGNob2ljZVxyXG4gIH0pKTtcclxuXHJcbiAgLy8gQ2F0ZWdvcnkgcHJvbXB0XHJcbiAgcmV0dXJuIHByb21wdHMoXHJcbiAgICB7XHJcbiAgICAgIHR5cGU6ICdtdWx0aXNlbGVjdCcsXHJcbiAgICAgIG5hbWU6ICdjYXRlZ29yeScsXHJcbiAgICAgIG1lc3NhZ2U6ICdXaGljaCBjYXRlZ29yeSBkbyB5b3Ugd2FudCB0byBjb25maWd1cmU/JyxcclxuICAgICAgaGludDogJ1NwYWNlOiBTZWxlY3Qgc3BlY2lmaWMsIEE6IFNlbGVjdCBhbGwsIEVudGVyOiBDb25maXJtLicsXHJcbiAgICAgIGluc3RydWN0aW9uczogJycsXHJcbiAgICAgIGNob2ljZXNcclxuICAgIH0sXHJcbiAgICB7IG9uU3VibWl0IH1cclxuICApO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1hcHMgb2xkLXN0cnVjdHVyZWQgKFBoYW50b21KUykgb3B0aW9ucyB0byBhIG5ldyBjb25maWd1cmF0aW9uIGZvcm1hdFxyXG4gKiAoUHVwcGV0ZWVyKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9sZE9wdGlvbnMgLSBPbGQtc3RydWN0dXJlZCBvcHRpb25zIHRvIGJlIG1hcHBlZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gTmV3IG9wdGlvbnMgc3RydWN0dXJlZCBiYXNlZCBvbiB0aGUgZGVmaW5lZCBuZXN0ZWRBcmdzXHJcbiAqIG1hcHBpbmcuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWFwVG9OZXdDb25maWcgPSAob2xkT3B0aW9ucykgPT4ge1xyXG4gIGNvbnN0IG5ld09wdGlvbnMgPSB7fTtcclxuICAvLyBDeWNsZSB0aHJvdWdoIG9sZC1zdHJ1Y3R1cmVkIG9wdGlvbnNcclxuICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhvbGRPcHRpb25zKSkge1xyXG4gICAgY29uc3QgcHJvcGVydGllc0NoYWluID0gbmVzdGVkQXJnc1trZXldID8gbmVzdGVkQXJnc1trZXldLnNwbGl0KCcuJykgOiBbXTtcclxuXHJcbiAgICAvLyBQb3B1bGF0ZSBvYmplY3QgaW4gY29ycmVjdCBwcm9wZXJ0aWVzIGxldmVsc1xyXG4gICAgcHJvcGVydGllc0NoYWluLnJlZHVjZShcclxuICAgICAgKG9iaiwgcHJvcCwgaW5kZXgpID0+XHJcbiAgICAgICAgKG9ialtwcm9wXSA9XHJcbiAgICAgICAgICBwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXggPyB2YWx1ZSA6IG9ialtwcm9wXSB8fCB7fSksXHJcbiAgICAgIG5ld09wdGlvbnNcclxuICAgICk7XHJcbiAgfVxyXG4gIHJldHVybiBuZXdPcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1lcmdlcyB0d28gc2V0cyBvZiBjb25maWd1cmF0aW9uIG9wdGlvbnMsIGNvbnNpZGVyaW5nIGFic29sdXRlIHByb3BlcnRpZXMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gT3JpZ2luYWwgY29uZmlndXJhdGlvbiBvcHRpb25zLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3T3B0aW9ucyAtIE5ldyBjb25maWd1cmF0aW9uIG9wdGlvbnMgdG8gYmUgbWVyZ2VkLlxyXG4gKiBAcGFyYW0ge0FycmF5fSBhYnNvbHV0ZVByb3BzIC0gTGlzdCBvZiBwcm9wZXJ0aWVzIHRoYXQgc2hvdWxkXHJcbiAqIG5vdCBiZSByZWN1cnNpdmVseSBtZXJnZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IE1lcmdlZCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgbWVyZ2VDb25maWdPcHRpb25zID0gKG9wdGlvbnMsIG5ld09wdGlvbnMsIGFic29sdXRlUHJvcHMgPSBbXSkgPT4ge1xyXG4gIGNvbnN0IG1lcmdlZE9wdGlvbnMgPSBkZWVwQ29weShvcHRpb25zKTtcclxuXHJcbiAgZm9yIChjb25zdCBba2V5LCB2YWx1ZV0gb2YgT2JqZWN0LmVudHJpZXMobmV3T3B0aW9ucykpIHtcclxuICAgIG1lcmdlZE9wdGlvbnNba2V5XSA9XHJcbiAgICAgIGlzT2JqZWN0KHZhbHVlKSAmJlxyXG4gICAgICAhYWJzb2x1dGVQcm9wcy5pbmNsdWRlcyhrZXkpICYmXHJcbiAgICAgIG1lcmdlZE9wdGlvbnNba2V5XSAhPT0gdW5kZWZpbmVkXHJcbiAgICAgICAgPyBtZXJnZUNvbmZpZ09wdGlvbnMobWVyZ2VkT3B0aW9uc1trZXldLCB2YWx1ZSwgYWJzb2x1dGVQcm9wcylcclxuICAgICAgICA6IHZhbHVlICE9PSB1bmRlZmluZWRcclxuICAgICAgICAgID8gdmFsdWVcclxuICAgICAgICAgIDogbWVyZ2VkT3B0aW9uc1trZXldO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG1lcmdlZE9wdGlvbnM7XHJcbn07XHJcblxyXG4vKipcclxuICogSW5pdGlhbGl6ZXMgZXhwb3J0IHNldHRpbmdzIGJhc2VkIG9uIHByb3ZpZGVkIGV4cG9ydE9wdGlvbnNcclxuICogYW5kIGdlbmVyYWxPcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZXhwb3J0T3B0aW9ucyAtIE9wdGlvbnMgc3BlY2lmaWMgdG8gdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gZ2VuZXJhbE9wdGlvbnMgLSBHZW5lcmFsIGNvbmZpZ3VyYXRpb24gb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgZXhwb3J0IHNldHRpbmdzLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRFeHBvcnRTZXR0aW5ncyA9IChleHBvcnRPcHRpb25zLCBnZW5lcmFsT3B0aW9ucyA9IHt9KSA9PiB7XHJcbiAgbGV0IG9wdGlvbnMgPSB7fTtcclxuXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuc3ZnKSB7XHJcbiAgICBvcHRpb25zID0gZGVlcENvcHkoZ2VuZXJhbE9wdGlvbnMpO1xyXG4gICAgb3B0aW9ucy5leHBvcnQudHlwZSA9IGV4cG9ydE9wdGlvbnMudHlwZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC50eXBlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQuc2NhbGUgPSBleHBvcnRPcHRpb25zLnNjYWxlIHx8IGV4cG9ydE9wdGlvbnMuZXhwb3J0LnNjYWxlO1xyXG4gICAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICAgIGV4cG9ydE9wdGlvbnMub3V0ZmlsZSB8fCBleHBvcnRPcHRpb25zLmV4cG9ydC5vdXRmaWxlO1xyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGV4cG9ydE9wdGlvbnMuc3ZnXHJcbiAgICB9O1xyXG4gIH0gZWxzZSB7XHJcbiAgICBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKFxyXG4gICAgICBnZW5lcmFsT3B0aW9ucyxcclxuICAgICAgZXhwb3J0T3B0aW9ucyxcclxuICAgICAgLy8gT21pdCBnb2luZyBkb3duIHJlY3Vyc2l2ZWx5IHdpdGggdGhlIGJlbG93c1xyXG4gICAgICBhYnNvbHV0ZVByb3BzXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgb3B0aW9ucy5leHBvcnQub3V0ZmlsZSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3V0ZmlsZSB8fCBgY2hhcnQuJHtvcHRpb25zLmV4cG9ydD8udHlwZSB8fCAncG5nJ31gO1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIExvYWRzIGFkZGl0aW9uYWwgY29uZmlndXJhdGlvbiBmcm9tIGEgc3BlY2lmaWVkIGZpbGUgdXNpbmdcclxuICogdGhlIC0tbG9hZENvbmZpZyBvcHRpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7QXJyYXl9IGFyZ3MgLSBDb21tYW5kLWxpbmUgYXJndW1lbnRzIHRvIGNoZWNrIGZvclxyXG4gKiB0aGUgLS1sb2FkQ29uZmlnIG9wdGlvbi5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gQWRkaXRpb25hbCBjb25maWd1cmF0aW9uIGxvYWRlZCBmcm9tIHRoZSBzcGVjaWZpZWQgZmlsZSxcclxuICogb3IgYW4gZW1wdHkgb2JqZWN0IGlmIG5vdCBmb3VuZCBvciBpbnZhbGlkLlxyXG4gKi9cclxuZnVuY3Rpb24gbG9hZENvbmZpZ0ZpbGUoYXJncykge1xyXG4gIC8vIENoZWNrIGlmIHRoZSAtLWxvYWRDb25maWcgb3B0aW9uIHdhcyB1c2VkXHJcbiAgY29uc3QgY29uZmlnSW5kZXggPSBhcmdzLmZpbmRJbmRleChcclxuICAgIChhcmcpID0+IGFyZy5yZXBsYWNlKC8tL2csICcnKSA9PT0gJ2xvYWRDb25maWcnXHJcbiAgKTtcclxuXHJcbiAgLy8gQ2hlY2sgaWYgdGhlIC0tbG9hZENvbmZpZyBoYXMgYSB2YWx1ZVxyXG4gIGlmIChjb25maWdJbmRleCA+IC0xICYmIGFyZ3NbY29uZmlnSW5kZXggKyAxXSkge1xyXG4gICAgY29uc3QgZmlsZU5hbWUgPSBhcmdzW2NvbmZpZ0luZGV4ICsgMV07XHJcbiAgICB0cnkge1xyXG4gICAgICAvLyBDaGVjayBpZiBhbiBhZGRpdGlvbmFsIGNvbmZpZyBmaWxlIGlzIGEgY29ycmVjdCBKU09OIGZpbGVcclxuICAgICAgaWYgKGZpbGVOYW1lICYmIGZpbGVOYW1lLmVuZHNXaXRoKCcuanNvbicpKSB7XHJcbiAgICAgICAgLy8gTG9hZCBhbiBvcHRpb25hbCBjdXN0b20gSlNPTiBjb25maWcgZmlsZVxyXG4gICAgICAgIHJldHVybiBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhmaWxlTmFtZSkpO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgMixcclxuICAgICAgICBlcnJvcixcclxuICAgICAgICBgW2NvbmZpZ10gVW5hYmxlIHRvIGxvYWQgdGhlIGNvbmZpZ3VyYXRpb24gZnJvbSB0aGUgJHtmaWxlTmFtZX0gZmlsZS5gXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBObyBhZGRpdGlvbmFsIG9wdGlvbnMgdG8gcmV0dXJuXHJcbiAgcmV0dXJuIHt9O1xyXG59XHJcblxyXG4vKipcclxuICogVXBkYXRlcyB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCB3aXRoIHZhbHVlcyBmcm9tIGEgY3VzdG9tIG9iamVjdFxyXG4gKiBhbmQgZW52aXJvbm1lbnQgdmFyaWFibGVzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY29uZmlnT2JqIC0gVGhlIGRlZmF1bHQgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBjdXN0b21PYmogLSBDdXN0b20gY29uZmlndXJhdGlvbiBvYmplY3QgdG8gb3ZlcnJpZGUgZGVmYXVsdHMuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBwcm9wQ2hhaW4gLSBQcm9wZXJ0eSBjaGFpbiBmb3IgdHJhY2tpbmcgbmVzdGVkIHByb3BlcnRpZXNcclxuICogZHVyaW5nIHJlY3Vyc2lvbi5cclxuICovXHJcbmZ1bmN0aW9uIHVwZGF0ZURlZmF1bHRDb25maWcoY29uZmlnT2JqLCBjdXN0b21PYmogPSB7fSwgcHJvcENoYWluID0gJycpIHtcclxuICBPYmplY3Qua2V5cyhjb25maWdPYmopLmZvckVhY2goKGtleSkgPT4ge1xyXG4gICAgY29uc3QgZW50cnkgPSBjb25maWdPYmpba2V5XTtcclxuICAgIGNvbnN0IGN1c3RvbVZhbHVlID0gY3VzdG9tT2JqICYmIGN1c3RvbU9ialtrZXldO1xyXG5cclxuICAgIGlmICh0eXBlb2YgZW50cnkudmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIHVwZGF0ZURlZmF1bHRDb25maWcoZW50cnksIGN1c3RvbVZhbHVlLCBgJHtwcm9wQ2hhaW59LiR7a2V5fWApO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gSWYgYSB2YWx1ZSBmcm9tIGEgY3VzdG9tIEpTT04gZXhpc3RzLCBpdCB0YWtlIHByZWNlZGVuY2VcclxuICAgICAgaWYgKGN1c3RvbVZhbHVlICE9PSB1bmRlZmluZWQpIHtcclxuICAgICAgICBlbnRyeS52YWx1ZSA9IGN1c3RvbVZhbHVlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBhIHZhbHVlIGZyb20gYW4gZW52IHZhcmlhYmxlIGV4aXN0cywgaXQgdGFrZSBwcmVjZWRlbmNlXHJcbiAgICAgIGlmIChlbnRyeS5lbnZMaW5rIGluIGVudnMgJiYgZW52c1tlbnRyeS5lbnZMaW5rXSAhPT0gdW5kZWZpbmVkKSB7XHJcbiAgICAgICAgZW50cnkudmFsdWUgPSBlbnZzW2VudHJ5LmVudkxpbmtdO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyBvcHRpb25zIG9iamVjdCBiYXNlZCBvbiBwcm92aWRlZCBpdGVtcywgc2V0dGluZyB2YWx1ZXMgZnJvbVxyXG4gKiBuZXN0ZWQgcHJvcGVydGllcyByZWN1cnNpdmVseS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGl0ZW1zIC0gQ29uZmlndXJhdGlvbiBpdGVtcyB0byBiZSB1c2VkIGZvciBpbml0aWFsaXppbmdcclxuICogb3B0aW9ucy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gSW5pdGlhbGl6ZWQgb3B0aW9ucyBvYmplY3QuXHJcbiAqL1xyXG5mdW5jdGlvbiBpbml0T3B0aW9ucyhpdGVtcykge1xyXG4gIGxldCBvcHRpb25zID0ge307XHJcbiAgZm9yIChjb25zdCBbbmFtZSwgaXRlbV0gb2YgT2JqZWN0LmVudHJpZXMoaXRlbXMpKSB7XHJcbiAgICBvcHRpb25zW25hbWVdID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKGl0ZW0sICd2YWx1ZScpXHJcbiAgICAgID8gaXRlbS52YWx1ZVxyXG4gICAgICA6IGluaXRPcHRpb25zKGl0ZW0pO1xyXG4gIH1cclxuICByZXR1cm4gb3B0aW9ucztcclxufVxyXG5cclxuLyoqXHJcbiAqIFBhaXJzIGFyZ3VtZW50IHZhbHVlcyB3aXRoIGNvcnJlc3BvbmRpbmcgb3B0aW9ucyBpbiB0aGUgY29uZmlndXJhdGlvbixcclxuICogdXBkYXRpbmcgdGhlIG9wdGlvbnMgb2JqZWN0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gYXJncyAtIENvbW1hbmQtbGluZSBhcmd1bWVudHMgY29udGFpbmluZyB2YWx1ZXMgZm9yIHNwZWNpZmljXHJcbiAqIG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBkZWZhdWx0Q29uZmlnIC0gRGVmYXVsdCBjb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmVmZXJlbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fSBVcGRhdGVkIG9wdGlvbnMgb2JqZWN0LlxyXG4gKi9cclxuZnVuY3Rpb24gcGFpckFyZ3VtZW50VmFsdWUob3B0aW9ucywgYXJncywgZGVmYXVsdENvbmZpZykge1xyXG4gIGxldCBzaG93VXNhZ2UgPSBmYWxzZTtcclxuICBmb3IgKGxldCBpID0gMDsgaSA8IGFyZ3MubGVuZ3RoOyBpKyspIHtcclxuICAgIGNvbnN0IG9wdGlvbiA9IGFyZ3NbaV0ucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gRmluZCB0aGUgcmlnaHQgcGxhY2UgZm9yIHByb3BlcnR5J3MgdmFsdWVcclxuICAgIGNvbnN0IHByb3BlcnRpZXNDaGFpbiA9IG5lc3RlZEFyZ3Nbb3B0aW9uXVxyXG4gICAgICA/IG5lc3RlZEFyZ3Nbb3B0aW9uXS5zcGxpdCgnLicpXHJcbiAgICAgIDogW107XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjb3JyZWN0IHR5cGUgZm9yIENMSSBhcmdzIHdoaWNoIGFyZSBwYXNzZWQgYXMgc3RyaW5nc1xyXG4gICAgbGV0IGFyZ3VtZW50VHlwZTtcclxuICAgIHByb3BlcnRpZXNDaGFpbi5yZWR1Y2UoKG9iaiwgcHJvcCwgaW5kZXgpID0+IHtcclxuICAgICAgaWYgKHByb3BlcnRpZXNDaGFpbi5sZW5ndGggLSAxID09PSBpbmRleCkge1xyXG4gICAgICAgIGFyZ3VtZW50VHlwZSA9IG9ialtwcm9wXS50eXBlO1xyXG4gICAgICB9XHJcbiAgICAgIHJldHVybiBvYmpbcHJvcF07XHJcbiAgICB9LCBkZWZhdWx0Q29uZmlnKTtcclxuXHJcbiAgICBwcm9wZXJ0aWVzQ2hhaW4ucmVkdWNlKChvYmosIHByb3AsIGluZGV4KSA9PiB7XHJcbiAgICAgIGlmIChwcm9wZXJ0aWVzQ2hhaW4ubGVuZ3RoIC0gMSA9PT0gaW5kZXgpIHtcclxuICAgICAgICAvLyBGaW5kcyBhbiBvcHRpb24gYW5kIHNldCBhIGNvcnJlc3BvbmRpbmcgdmFsdWVcclxuICAgICAgICBpZiAodHlwZW9mIG9ialtwcm9wXSAhPT0gJ3VuZGVmaW5lZCcpIHtcclxuICAgICAgICAgIGlmIChhcmdzWysraV0pIHtcclxuICAgICAgICAgICAgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ2Jvb2xlYW4nKSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gdG9Cb29sZWFuKGFyZ3NbaV0pO1xyXG4gICAgICAgICAgICB9IGVsc2UgaWYgKGFyZ3VtZW50VHlwZSA9PT0gJ251bWJlcicpIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSArYXJnc1tpXTtcclxuICAgICAgICAgICAgfSBlbHNlIGlmIChhcmd1bWVudFR5cGUuaW5kZXhPZignXScpID49IDApIHtcclxuICAgICAgICAgICAgICBvYmpbcHJvcF0gPSBhcmdzW2ldLnNwbGl0KCcsJyk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgb2JqW3Byb3BdID0gYXJnc1tpXTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAgIDIsXHJcbiAgICAgICAgICAgICAgYFtjb25maWddIE1pc3NpbmcgdmFsdWUgZm9yIHRoZSAnJHtvcHRpb259JyBhcmd1bWVudC4gVXNpbmcgdGhlIGRlZmF1bHQgdmFsdWUuYFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgICBzaG93VXNhZ2UgPSB0cnVlO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gb2JqW3Byb3BdO1xyXG4gICAgfSwgb3B0aW9ucyk7XHJcbiAgfVxyXG5cclxuICAvLyBEaXNwbGF5IHRoZSB1c2FnZSBmb3IgdGhlIHJlZmVyZW5jZSBpZiBuZWVkZWRcclxuICBpZiAoc2hvd1VzYWdlKSB7XHJcbiAgICBwcmludFVzYWdlKGRlZmF1bHRDb25maWcpO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuIG9wdGlvbnM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBSZWN1cnNpdmVseSB1cGRhdGVzIHByb3BlcnRpZXMgaW4gYW4gb2JqZWN0IGJhc2VkIG9uIG5lc3RlZCBuYW1lcyBhbmQgYXNzaWduc1xyXG4gKiB0aGUgZmluYWwgdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvYmplY3RUb1VwZGF0ZSAtIFRoZSBvYmplY3QgdG8gYmUgdXBkYXRlZC5cclxuICogQHBhcmFtIHtBcnJheX0gbmVzdGVkTmFtZXMgLSBBcnJheSBvZiBuZXN0ZWQgcHJvcGVydHkgbmFtZXMuXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSBmaW5hbCB2YWx1ZSB0byBiZSBhc3NpZ25lZC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVXBkYXRlZCBvYmplY3Qgd2l0aCBhc3NpZ25lZCB2YWx1ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiByZWN1cnNpdmVQcm9wcyhvYmplY3RUb1VwZGF0ZSwgbmVzdGVkTmFtZXMsIHZhbHVlKSB7XHJcbiAgd2hpbGUgKG5lc3RlZE5hbWVzLmxlbmd0aCA+IDEpIHtcclxuICAgIGNvbnN0IHByb3BOYW1lID0gbmVzdGVkTmFtZXMuc2hpZnQoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSBwcm9wZXJ0eSBpbiBvYmplY3QgaWYgaXQgZG9lc24ndCBleGlzdFxyXG4gICAgaWYgKCFPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0VG9VcGRhdGUsIHByb3BOYW1lKSkge1xyXG4gICAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSB7fTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDYWxsIGZ1bmN0aW9uIGFnYWluIGlmIHRoZXJlIHN0aWxsIG5hbWVzIHRvIGdvXHJcbiAgICBvYmplY3RUb1VwZGF0ZVtwcm9wTmFtZV0gPSByZWN1cnNpdmVQcm9wcyhcclxuICAgICAgT2JqZWN0LmFzc2lnbih7fSwgb2JqZWN0VG9VcGRhdGVbcHJvcE5hbWVdKSxcclxuICAgICAgbmVzdGVkTmFtZXMsXHJcbiAgICAgIHZhbHVlXHJcbiAgICApO1xyXG5cclxuICAgIHJldHVybiBvYmplY3RUb1VwZGF0ZTtcclxuICB9XHJcblxyXG4gIC8vIEFzc2lnbiB0aGUgZmluYWwgdmFsdWVcclxuICBvYmplY3RUb1VwZGF0ZVtuZXN0ZWROYW1lc1swXV0gPSB2YWx1ZTtcclxuICByZXR1cm4gb2JqZWN0VG9VcGRhdGU7XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBnZXRPcHRpb25zLFxyXG4gIHNldE9wdGlvbnMsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIG1hcFRvTmV3Q29uZmlnLFxyXG4gIG1lcmdlQ29uZmlnT3B0aW9ucyxcclxuICBpbml0RXhwb3J0U2V0dGluZ3NcclxufTtcclxuIiwiLyoqXHJcbiAqIFRoaXMgbW9kdWxlIGV4cG9ydHMgdHdvIGZ1bmN0aW9uczogZmV0Y2ggKGZvciBHRVQgcmVxdWVzdHMpIGFuZCBwb3N0IChmb3IgUE9TVCByZXF1ZXN0cykuXHJcbiAqL1xyXG5cclxuaW1wb3J0IGh0dHAgZnJvbSAnaHR0cCc7XHJcbmltcG9ydCBodHRwcyBmcm9tICdodHRwcyc7XHJcblxyXG4vKipcclxuICogUmV0dXJucyB0aGUgSFRUUCBvciBIVFRQUyBwcm90b2NvbCBtb2R1bGUgYmFzZWQgb24gdGhlIHByb3ZpZGVkIFVSTC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZGV0ZXJtaW5lIHRoZSBwcm90b2NvbC5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gVGhlIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wgbW9kdWxlIChodHRwIG9yIGh0dHBzKS5cclxuICovXHJcbmNvbnN0IGdldFByb3RvY29sID0gKHVybCkgPT4gKHVybC5zdGFydHNXaXRoKCdodHRwcycpID8gaHR0cHMgOiBodHRwKTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGRhdGEgZnJvbSB0aGUgc3BlY2lmaWVkIFVSTCB1c2luZyBlaXRoZXIgSFRUUCBvciBIVFRQUyBwcm90b2NvbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHVybCAtIFRoZSBVUkwgdG8gZmV0Y2ggZGF0YSBmcm9tLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcmVxdWVzdE9wdGlvbnMgLSBPcHRpb25zIGZvciB0aGUgSFRUUCByZXF1ZXN0IChvcHRpb25hbCkuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPE9iamVjdD59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBIVFRQIHJlc3BvbnNlIG9iamVjdFxyXG4gKiB3aXRoIGFkZGVkICd0ZXh0JyBwcm9wZXJ0eSBvciByZWplY3Rpbmcgd2l0aCBhbiBlcnJvci5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIGZldGNoKHVybCwgcmVxdWVzdE9wdGlvbnMgPSB7fSkge1xyXG4gIHJldHVybiBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XHJcbiAgICBjb25zdCBwcm90b2NvbCA9IGdldFByb3RvY29sKHVybCk7XHJcblxyXG4gICAgcHJvdG9jb2xcclxuICAgICAgLmdldCh1cmwsIHJlcXVlc3RPcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IGRhdGEgPSAnJztcclxuXHJcbiAgICAgICAgLy8gQSBjaHVuayBvZiBkYXRhIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZGF0YScsIChjaHVuaykgPT4ge1xyXG4gICAgICAgICAgZGF0YSArPSBjaHVuaztcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gVGhlIHdob2xlIHJlc3BvbnNlIGhhcyBiZWVuIHJlY2VpdmVkLlxyXG4gICAgICAgIHJlcy5vbignZW5kJywgKCkgPT4ge1xyXG4gICAgICAgICAgaWYgKCFkYXRhKSB7XHJcbiAgICAgICAgICAgIHJlamVjdCgnTm90aGluZyB3YXMgZmV0Y2hlZCBmcm9tIHRoZSBVUkwuJyk7XHJcbiAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgcmVzLnRleHQgPSBkYXRhO1xyXG4gICAgICAgICAgcmVzb2x2ZShyZXMpO1xyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZW5kcyBhIFBPU1QgcmVxdWVzdCB0byB0aGUgc3BlY2lmaWVkIFVSTCB3aXRoIHRoZSBwcm92aWRlZCBKU09OIGJvZHkgdXNpbmdcclxuICogZWl0aGVyIEhUVFAgb3IgSFRUUFMgcHJvdG9jb2wuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSB1cmwgLSBUaGUgVVJMIHRvIHNlbmQgdGhlIFBPU1QgcmVxdWVzdCB0by5cclxuICogQHBhcmFtIHtPYmplY3R9IGJvZHkgLSBUaGUgSlNPTiBib2R5IHRvIGluY2x1ZGUgaW4gdGhlIFBPU1QgcmVxdWVzdFxyXG4gKiAob3B0aW9uYWwsIGRlZmF1bHQgaXMgYW4gZW1wdHkgb2JqZWN0KS5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIEhUVFAgcmVxdWVzdCAob3B0aW9uYWwpLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgSFRUUCByZXNwb25zZSBvYmplY3Qgd2l0aFxyXG4gKiBhZGRlZCAndGV4dCcgcHJvcGVydHkgb3IgcmVqZWN0aW5nIHdpdGggYW4gZXJyb3IuXHJcbiAqL1xyXG5hc3luYyBmdW5jdGlvbiBwb3N0KHVybCwgYm9keSA9IHt9LCByZXF1ZXN0T3B0aW9ucyA9IHt9KSB7XHJcbiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcclxuICAgIGNvbnN0IHByb3RvY29sID0gZ2V0UHJvdG9jb2wodXJsKTtcclxuICAgIGNvbnN0IGRhdGEgPSBKU09OLnN0cmluZ2lmeShib2R5KTtcclxuXHJcbiAgICAvLyBTZXQgZGVmYXVsdCBoZWFkZXJzIGFuZCBtZXJnZSB3aXRoIHJlcXVlc3RPcHRpb25zXHJcbiAgICBjb25zdCBvcHRpb25zID0gT2JqZWN0LmFzc2lnbihcclxuICAgICAge1xyXG4gICAgICAgIG1ldGhvZDogJ1BPU1QnLFxyXG4gICAgICAgIGhlYWRlcnM6IHtcclxuICAgICAgICAgICdDb250ZW50LVR5cGUnOiAnYXBwbGljYXRpb24vanNvbicsXHJcbiAgICAgICAgICAnQ29udGVudC1MZW5ndGgnOiBkYXRhLmxlbmd0aFxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgcmVxdWVzdE9wdGlvbnNcclxuICAgICk7XHJcblxyXG4gICAgY29uc3QgcmVxID0gcHJvdG9jb2xcclxuICAgICAgLnJlcXVlc3QodXJsLCBvcHRpb25zLCAocmVzKSA9PiB7XHJcbiAgICAgICAgbGV0IHJlc3BvbnNlRGF0YSA9ICcnO1xyXG5cclxuICAgICAgICAvLyBBIGNodW5rIG9mIGRhdGEgaGFzIGJlZW4gcmVjZWl2ZWQuXHJcbiAgICAgICAgcmVzLm9uKCdkYXRhJywgKGNodW5rKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZURhdGEgKz0gY2h1bms7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIFRoZSB3aG9sZSByZXNwb25zZSBoYXMgYmVlbiByZWNlaXZlZC5cclxuICAgICAgICByZXMub24oJ2VuZCcsICgpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIHJlcy50ZXh0ID0gcmVzcG9uc2VEYXRhO1xyXG4gICAgICAgICAgICByZXNvbHZlKHJlcyk7XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICByZWplY3QoZXJyb3IpO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH0pO1xyXG4gICAgICB9KVxyXG4gICAgICAub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgICAgcmVqZWN0KGVycm9yKTtcclxuICAgICAgfSk7XHJcblxyXG4gICAgLy8gV3JpdGUgdGhlIHJlcXVlc3QgYm9keSBhbmQgZW5kIHRoZSByZXF1ZXN0LlxyXG4gICAgcmVxLndyaXRlKGRhdGEpO1xyXG4gICAgcmVxLmVuZCgpO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBmZXRjaDtcclxuZXhwb3J0IHsgZmV0Y2gsIHBvc3QgfTtcclxuIiwiY2xhc3MgRXhwb3J0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XHJcbiAgY29uc3RydWN0b3IobWVzc2FnZSkge1xyXG4gICAgc3VwZXIoKTtcclxuICAgIHRoaXMubWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgICB0aGlzLnN0YWNrTWVzc2FnZSA9IG1lc3NhZ2U7XHJcbiAgfVxyXG5cclxuICBzZXRFcnJvcihlcnJvcikge1xyXG4gICAgdGhpcy5lcnJvciA9IGVycm9yO1xyXG4gICAgaWYgKGVycm9yLm5hbWUpIHtcclxuICAgICAgdGhpcy5uYW1lID0gZXJyb3IubmFtZTtcclxuICAgIH1cclxuICAgIGlmIChlcnJvci5zdGF0dXNDb2RlKSB7XHJcbiAgICAgIHRoaXMuc3RhdHVzQ29kZSA9IGVycm9yLnN0YXR1c0NvZGU7XHJcbiAgICB9XHJcbiAgICBpZiAoZXJyb3Iuc3RhY2spIHtcclxuICAgICAgdGhpcy5zdGFja01lc3NhZ2UgPSBlcnJvci5tZXNzYWdlO1xyXG4gICAgICB0aGlzLnN0YWNrID0gZXJyb3Iuc3RhY2s7XHJcbiAgICB9XHJcbiAgICByZXR1cm4gdGhpcztcclxuICB9XHJcbn1cclxuXHJcbmV4cG9ydCBkZWZhdWx0IEV4cG9ydEVycm9yO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbi8vIFRoZSBjYWNoZSBtYW5hZ2VyIG1hbmFnZXMgdGhlIEhpZ2hjaGFydHMgbGlicmFyeSBhbmQgaXRzIGRlcGVuZGVuY2llcy5cclxuLy8gVGhlIGNhY2hlIGl0c2VsZiBpcyBzdG9yZWQgaW4gLmNhY2hlLCBhbmQgaXMgY2hlY2tlZCBieSB0aGUgY29uZmlnIHN5c3RlbVxyXG4vLyBiZWZvcmUgc3RhcnRpbmcgdGhlIHNlcnZpY2VcclxuXHJcbmltcG9ydCB7IGV4aXN0c1N5bmMsIG1rZGlyU3luYywgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgeyBqb2luIH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgeyBIdHRwc1Byb3h5QWdlbnQgfSBmcm9tICdodHRwcy1wcm94eS1hZ2VudCc7XHJcblxyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi9lbnZzLmpzJztcclxuaW1wb3J0IHsgZmV0Y2ggfSBmcm9tICcuL2ZldGNoLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi9sb2dnZXIuanMnO1xyXG5pbXBvcnQgeyBfX2Rpcm5hbWUgfSBmcm9tICcuL3V0aWxzLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5jb25zdCBjYWNoZSA9IHtcclxuICBjZG5VUkw6ICdodHRwczovL2NvZGUuaGlnaGNoYXJ0cy5jb20vJyxcclxuICBhY3RpdmVNYW5pZmVzdDoge30sXHJcbiAgc291cmNlczogJycsXHJcbiAgaGNWZXJzaW9uOiAnJ1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEV4dHJhY3RzIGFuZCBjYWNoZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBmcm9tIHRoZSBzb3VyY2VzIHN0cmluZy5cclxuICpcclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIGV4dHJhY3RlZCBIaWdoY2hhcnRzIHZlcnNpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdFZlcnNpb24gPSAoY2FjaGUpID0+IHtcclxuICByZXR1cm4gY2FjaGUuc291cmNlc1xyXG4gICAgLnN1YnN0cmluZygwLCBjYWNoZS5zb3VyY2VzLmluZGV4T2YoJyovJykpXHJcbiAgICAucmVwbGFjZSgnLyonLCAnJylcclxuICAgIC5yZXBsYWNlKCcqLycsICcnKVxyXG4gICAgLnJlcGxhY2UoL1xcbi9nLCAnJylcclxuICAgIC50cmltKCk7XHJcbn07XHJcblxyXG4vKipcclxuICogRXh0cmFjdHMgdGhlIEhpZ2hjaGFydHMgbW9kdWxlIG5hbWUgYmFzZWQgb24gdGhlIHNjcmlwdFBhdGguXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZXh0cmFjdE1vZHVsZU5hbWUgPSAoc2NyaXB0UGF0aCkgPT4ge1xyXG4gIHJldHVybiBzY3JpcHRQYXRoLnJlcGxhY2UoXHJcbiAgICAvKC4qKVxcL3woLiopbW9kdWxlc1xcL3xzdG9ja1xcLyguKilpbmRpY2F0b3JzXFwvfG1hcHNcXC8oLiopbW9kdWxlc1xcLy9naSxcclxuICAgICcnXHJcbiAgKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTYXZlcyB0aGUgcHJvdmlkZWQgY29uZmlndXJhdGlvbiBhbmQgZmV0Y2hlZCBtb2R1bGVzIHRvIHRoZSBjYWNoZSBtYW5pZmVzdFxyXG4gKiBmaWxlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge29iamVjdH0gY29uZmlnIC0gSGlnaGNoYXJ0cy1yZWxhdGVkIGNvbmZpZ3VyYXRpb24gb2JqZWN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3QgdGhhdCBjb250YWlucyBtYXBwZWQgbmFtZXMgb2ZcclxuICogZmV0Y2hlZCBIaWdoY2hhcnRzIG1vZHVsZXMgdG8gdXNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyB3aGlsZSB3cml0aW5nXHJcbiAqIHRoZSBjYWNoZSBtYW5pZmVzdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzYXZlQ29uZmlnVG9NYW5pZmVzdCA9IGFzeW5jIChjb25maWcsIGZldGNoZWRNb2R1bGVzKSA9PiB7XHJcbiAgY29uc3QgbmV3TWFuaWZlc3QgPSB7XHJcbiAgICB2ZXJzaW9uOiBjb25maWcudmVyc2lvbixcclxuICAgIG1vZHVsZXM6IGZldGNoZWRNb2R1bGVzIHx8IHt9XHJcbiAgfTtcclxuXHJcbiAgLy8gVXBkYXRlIGNhY2hlIG9iamVjdCB3aXRoIHRoZSBjdXJyZW50IG1vZHVsZXNcclxuICBjYWNoZS5hY3RpdmVNYW5pZmVzdCA9IG5ld01hbmlmZXN0O1xyXG5cclxuICBsb2coMywgJ1tjYWNoZV0gV3JpdGluZyBhIG5ldyBtYW5pZmVzdC4nKTtcclxuICB0cnkge1xyXG4gICAgd3JpdGVGaWxlU3luYyhcclxuICAgICAgam9pbihfX2Rpcm5hbWUsIGNvbmZpZy5jYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyksXHJcbiAgICAgIEpTT04uc3RyaW5naWZ5KG5ld01hbmlmZXN0KSxcclxuICAgICAgJ3V0ZjgnXHJcbiAgICApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1tjYWNoZV0gRXJyb3Igd3JpdGluZyB0aGUgY2FjaGUgbWFuaWZlc3QuJykuc2V0RXJyb3IoXHJcbiAgICAgIGVycm9yXHJcbiAgICApO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBGZXRjaGVzIGEgc2luZ2xlIHNjcmlwdCBhbmQgdXBkYXRlcyB0aGUgZmV0Y2hlZE1vZHVsZXMgYWNjb3JkaW5nbHkuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzY3JpcHQgLSBBIHBhdGggdG8gc2NyaXB0IHRvIGdldC5cclxuICogQHBhcmFtIHtPYmplY3R9IHJlcXVlc3RPcHRpb25zIC0gQWRkaXRpb25hbCBvcHRpb25zIGZvciB0aGUgcHJveHkgYWdlbnRcclxuICogdG8gdXNlIGZvciBhIHJlcXVlc3QuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBmZXRjaGVkTW9kdWxlcyAtIEFuIG9iamVjdCB3aGljaCB0cmFja3Mgd2hpY2ggSGlnaGNoYXJ0c1xyXG4gKiBtb2R1bGVzIGhhdmUgYmVlbiBmZXRjaGVkLlxyXG4gKiBAcGFyYW0ge2Jvb2xlYW59IHNob3VsZFRocm93RXJyb3IgLSBBIGZsYWcgdG8gaW5kaWNhdGUgaWYgdGhlIGVycm9yIHNob3VsZCBiZVxyXG4gKiB0aHJvd24uIFRoaXMgc2hvdWxkIGJlIHVzZWQgb25seSBmb3IgdGhlIGNvcmUgc2NyaXB0cy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gQSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdGV4dCByZXByZXNlbnRhdGlvblxyXG4gKiBvZiB0aGUgZmV0Y2hlZCBzY3JpcHQuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSBUaHJvd3MgYW4gRXhwb3J0RXJyb3IgaWYgdGhlcmUgaXMgYSBwcm9ibGVtIHdpdGhcclxuICogZmV0Y2hpbmcgdGhlIHNjcmlwdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaEFuZFByb2Nlc3NTY3JpcHQgPSBhc3luYyAoXHJcbiAgc2NyaXB0LFxyXG4gIHJlcXVlc3RPcHRpb25zLFxyXG4gIGZldGNoZWRNb2R1bGVzLFxyXG4gIHNob3VsZFRocm93RXJyb3IgPSBmYWxzZVxyXG4pID0+IHtcclxuICAvLyBHZXQgcmlkIG9mIHRoZSAuanMgZnJvbSB0aGUgY3VzdG9tIHN0cmluZ3NcclxuICBpZiAoc2NyaXB0LmVuZHNXaXRoKCcuanMnKSkge1xyXG4gICAgc2NyaXB0ID0gc2NyaXB0LnN1YnN0cmluZygwLCBzY3JpcHQubGVuZ3RoIC0gMyk7XHJcbiAgfVxyXG5cclxuICBsb2coNCwgYFtjYWNoZV0gRmV0Y2hpbmcgc2NyaXB0IC0gJHtzY3JpcHR9LmpzYCk7XHJcblxyXG4gIC8vIEZldGNoIHRoZSBzY3JpcHRcclxuICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGZldGNoKGAke3NjcmlwdH0uanNgLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gIC8vIElmIE9LLCByZXR1cm4gaXRzIHRleHQgcmVwcmVzZW50YXRpb25cclxuICBpZiAocmVzcG9uc2Uuc3RhdHVzQ29kZSA9PT0gMjAwICYmIHR5cGVvZiByZXNwb25zZS50ZXh0ID09ICdzdHJpbmcnKSB7XHJcbiAgICBpZiAoZmV0Y2hlZE1vZHVsZXMpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTmFtZSA9IGV4dHJhY3RNb2R1bGVOYW1lKHNjcmlwdCk7XHJcbiAgICAgIGZldGNoZWRNb2R1bGVzW21vZHVsZU5hbWVdID0gMTtcclxuICAgIH1cclxuXHJcbiAgICByZXR1cm4gcmVzcG9uc2UudGV4dDtcclxuICB9XHJcblxyXG4gIGlmIChzaG91bGRUaHJvd0Vycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgIGBDb3VsZCBub3QgZmV0Y2ggdGhlICR7c2NyaXB0fS5qcy4gVGhlIHNjcmlwdCBtaWdodCBub3QgZXhpc3QgaW4gdGhlIHJlcXVlc3RlZCB2ZXJzaW9uIChzdGF0dXMgY29kZTogJHtyZXNwb25zZS5zdGF0dXNDb2RlfSkuYFxyXG4gICAgKS5zZXRFcnJvcihyZXNwb25zZSk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxvZyhcclxuICAgICAgMixcclxuICAgICAgYFtjYWNoZV0gQ291bGQgbm90IGZldGNoIHRoZSAke3NjcmlwdH0uanMuIFRoZSBzY3JpcHQgbWlnaHQgbm90IGV4aXN0IGluIHRoZSByZXF1ZXN0ZWQgdmVyc2lvbi5gXHJcbiAgICApO1xyXG4gIH1cclxuXHJcbiAgcmV0dXJuICcnO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIEZldGNoZXMgSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCBjdXN0b21TY3JpcHRzIGZyb20gdGhlIGdpdmVuIENETnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBjb3JlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgY29yZSBzY3JpcHRzIHRvIGZldGNoLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gbW9kdWxlU2NyaXB0cyAtIEFycmF5IG9mIEhpZ2hjaGFydHMgbW9kdWxlcyB0byBmZXRjaC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGN1c3RvbVNjcmlwdHMgLSBBcnJheSBvZiBjdXN0b20gc2NyaXB0IHBhdGhzIHRvIGZldGNoXHJcbiAqIChmdWxsIFVSTHMpLlxyXG4gKiBAcGFyYW0ge29iamVjdH0gcHJveHlPcHRpb25zIC0gT3B0aW9ucyBmb3IgdGhlIHByb3h5IGFnZW50IHRvIHVzZSBmb3JcclxuICogYSByZXF1ZXN0LlxyXG4gKiBAcGFyYW0ge29iamVjdH0gZmV0Y2hlZE1vZHVsZXMgLSBBbiBvYmplY3Qgd2hpY2ggdHJhY2tzIHdoaWNoIEhpZ2hjaGFydHNcclxuICogbW9kdWxlcyBoYXZlIGJlZW4gZmV0Y2hlZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8c3RyaW5nPn0gVGhlIGZldGNoZWQgc2NyaXB0cyBjb250ZW50IGpvaW5lZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmZXRjaFNjcmlwdHMgPSBhc3luYyAoXHJcbiAgY29yZVNjcmlwdHMsXHJcbiAgbW9kdWxlU2NyaXB0cyxcclxuICBjdXN0b21TY3JpcHRzLFxyXG4gIHByb3h5T3B0aW9ucyxcclxuICBmZXRjaGVkTW9kdWxlc1xyXG4pID0+IHtcclxuICAvLyBDb25maWd1cmUgcHJveHkgaWYgZXhpc3RzXHJcbiAgbGV0IHByb3h5QWdlbnQ7XHJcbiAgY29uc3QgcHJveHlIb3N0ID0gcHJveHlPcHRpb25zLmhvc3Q7XHJcbiAgY29uc3QgcHJveHlQb3J0ID0gcHJveHlPcHRpb25zLnBvcnQ7XHJcblxyXG4gIC8vIFRyeSB0byBjcmVhdGUgYSBQcm94eSBBZ2VudFxyXG4gIGlmIChwcm94eUhvc3QgJiYgcHJveHlQb3J0KSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBwcm94eUFnZW50ID0gbmV3IEh0dHBzUHJveHlBZ2VudCh7XHJcbiAgICAgICAgaG9zdDogcHJveHlIb3N0LFxyXG4gICAgICAgIHBvcnQ6IHByb3h5UG9ydFxyXG4gICAgICB9KTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignW2NhY2hlXSBDb3VsZCBub3QgY3JlYXRlIGEgUHJveHkgQWdlbnQuJykuc2V0RXJyb3IoXHJcbiAgICAgICAgZXJyb3JcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIGV4aXN0cywgYWRkIHByb3h5IGFnZW50IHRvIHJlcXVlc3Qgb3B0aW9uc1xyXG4gIGNvbnN0IHJlcXVlc3RPcHRpb25zID0gcHJveHlBZ2VudFxyXG4gICAgPyB7XHJcbiAgICAgICAgYWdlbnQ6IHByb3h5QWdlbnQsXHJcbiAgICAgICAgdGltZW91dDogZW52cy5TRVJWRVJfUFJPWFlfVElNRU9VVFxyXG4gICAgICB9XHJcbiAgICA6IHt9O1xyXG5cclxuICBjb25zdCBhbGxGZXRjaFByb21pc2VzID0gW1xyXG4gICAgLi4uY29yZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzLCB0cnVlKVxyXG4gICAgKSxcclxuICAgIC4uLm1vZHVsZVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMsIGZldGNoZWRNb2R1bGVzKVxyXG4gICAgKSxcclxuICAgIC4uLmN1c3RvbVNjcmlwdHMubWFwKChzY3JpcHQpID0+XHJcbiAgICAgIGZldGNoQW5kUHJvY2Vzc1NjcmlwdChgJHtzY3JpcHR9YCwgcmVxdWVzdE9wdGlvbnMpXHJcbiAgICApXHJcbiAgXTtcclxuXHJcbiAgY29uc3QgZmV0Y2hlZFNjcmlwdHMgPSBhd2FpdCBQcm9taXNlLmFsbChhbGxGZXRjaFByb21pc2VzKTtcclxuICByZXR1cm4gZmV0Y2hlZFNjcmlwdHMuam9pbignO1xcbicpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIGxvY2FsIGNhY2hlIHdpdGggSGlnaGNoYXJ0cyBzY3JpcHRzIGFuZCB0aGVpciB2ZXJzaW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBPYmplY3QgY29udGFpbmluZyBhbGwgb3B0aW9ucy5cclxuICogQHBhcmFtIHtzdHJpbmd9IHNvdXJjZVBhdGggLSBUaGUgcGF0aCB0byB0aGUgc291cmNlIGZpbGUgaW4gdGhlIGNhY2hlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIG9iamVjdCByZXByZXNlbnRpbmdcclxuICogdGhlIGZldGNoZWQgbW9kdWxlcy5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiB0aGUgbG9jYWwgSGlnaGNoYXJ0cyBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVDYWNoZSA9IGFzeW5jIChcclxuICBoaWdoY2hhcnRzT3B0aW9ucyxcclxuICBwcm94eU9wdGlvbnMsXHJcbiAgc291cmNlUGF0aFxyXG4pID0+IHtcclxuICBjb25zdCB2ZXJzaW9uID0gaGlnaGNoYXJ0c09wdGlvbnMudmVyc2lvbjtcclxuICBjb25zdCBoY1ZlcnNpb24gPSB2ZXJzaW9uID09PSAnbGF0ZXN0JyB8fCAhdmVyc2lvbiA/ICcnIDogYCR7dmVyc2lvbn0vYDtcclxuICBjb25zdCBjZG5VUkwgPSBoaWdoY2hhcnRzT3B0aW9ucy5jZG5VUkwgfHwgY2FjaGUuY2RuVVJMO1xyXG5cclxuICBsb2coXHJcbiAgICAzLFxyXG4gICAgYFtjYWNoZV0gVXBkYXRpbmcgY2FjaGUgdmVyc2lvbiB0byBIaWdoY2hhcnRzOiAke2hjVmVyc2lvbiB8fCAnbGF0ZXN0J30uYFxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZldGNoZWRNb2R1bGVzID0ge307XHJcbiAgdHJ5IHtcclxuICAgIGNhY2hlLnNvdXJjZXMgPSBhd2FpdCBmZXRjaFNjcmlwdHMoXHJcbiAgICAgIFtcclxuICAgICAgICAuLi5oaWdoY2hhcnRzT3B0aW9ucy5jb3JlU2NyaXB0cy5tYXAoKGMpID0+IGAke2NkblVSTH0ke2hjVmVyc2lvbn0ke2N9YClcclxuICAgICAgXSxcclxuICAgICAgW1xyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLm1vZHVsZVNjcmlwdHMubWFwKChtKSA9PlxyXG4gICAgICAgICAgbSA9PT0gJ21hcCdcclxuICAgICAgICAgICAgPyBgJHtjZG5VUkx9bWFwcy8ke2hjVmVyc2lvbn1tb2R1bGVzLyR7bX1gXHJcbiAgICAgICAgICAgIDogYCR7Y2RuVVJMfSR7aGNWZXJzaW9ufW1vZHVsZXMvJHttfWBcclxuICAgICAgICApLFxyXG4gICAgICAgIC4uLmhpZ2hjaGFydHNPcHRpb25zLmluZGljYXRvclNjcmlwdHMubWFwKFxyXG4gICAgICAgICAgKGkpID0+IGAke2NkblVSTH1zdG9jay8ke2hjVmVyc2lvbn1pbmRpY2F0b3JzLyR7aX1gXHJcbiAgICAgICAgKVxyXG4gICAgICBdLFxyXG4gICAgICBoaWdoY2hhcnRzT3B0aW9ucy5jdXN0b21TY3JpcHRzLFxyXG4gICAgICBwcm94eU9wdGlvbnMsXHJcbiAgICAgIGZldGNoZWRNb2R1bGVzXHJcbiAgICApO1xyXG5cclxuICAgIGNhY2hlLmhjVmVyc2lvbiA9IGV4dHJhY3RWZXJzaW9uKGNhY2hlKTtcclxuXHJcbiAgICAvLyBTYXZlIHRoZSBmZXRjaGVkIG1vZHVsZXMgaW50byBjYWNoZXMnIHNvdXJjZSBKU09OXHJcbiAgICB3cml0ZUZpbGVTeW5jKHNvdXJjZVBhdGgsIGNhY2hlLnNvdXJjZXMpO1xyXG4gICAgcmV0dXJuIGZldGNoZWRNb2R1bGVzO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2FjaGVdIFVuYWJsZSB0byB1cGRhdGUgdGhlIGxvY2FsIEhpZ2hjaGFydHMgY2FjaGUuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFVwZGF0ZXMgdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBpbiB0aGUgYXBwbGllZCBjb25maWd1cmF0aW9uIGFuZCBjaGVja3NcclxuICogdGhlIGNhY2hlIGZvciB0aGUgbmV3IHZlcnNpb24uXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBuZXdWZXJzaW9uIC0gVGhlIG5ldyBIaWdoY2hhcnRzIHZlcnNpb24gdG8gYmUgYXBwbGllZC5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8KG9iamVjdHxib29sZWFuKT59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIHVwZGF0ZWRcclxuICogY29uZmlndXJhdGlvbiB3aXRoIHRoZSBuZXcgdmVyc2lvbiwgb3IgZmFsc2UgaWYgbm8gYXBwbGllZCBjb25maWd1cmF0aW9uXHJcbiAqIGV4aXN0cy5cclxuICovXHJcbmV4cG9ydCBjb25zdCB1cGRhdGVWZXJzaW9uID0gYXN5bmMgKG5ld1ZlcnNpb24pID0+IHtcclxuICBjb25zdCBvcHRpb25zID0gZ2V0T3B0aW9ucygpO1xyXG4gIGlmIChvcHRpb25zPy5oaWdoY2hhcnRzKSB7XHJcbiAgICBvcHRpb25zLmhpZ2hjaGFydHMudmVyc2lvbiA9IG5ld1ZlcnNpb247XHJcbiAgfVxyXG4gIGF3YWl0IGNoZWNrQW5kVXBkYXRlQ2FjaGUob3B0aW9ucyk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2hlY2tzIHRoZSBjYWNoZSBmb3IgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMsIHVwZGF0ZXMgdGhlIGNhY2hlIGlmIG5lZWRlZCxcclxuICogYW5kIGxvYWRzIHRoZSBzb3VyY2VzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIE9iamVjdCBjb250YWluaW5nIGFsbCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgY2FjaGUgaXMgY2hlY2tlZFxyXG4gKiBhbmQgdXBkYXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiB0aGVyZSBpcyBhbiBpc3N1ZSB1cGRhdGluZ1xyXG4gKiBvciByZWFkaW5nIHRoZSBjYWNoZS5cclxuICovXHJcbmV4cG9ydCBjb25zdCBjaGVja0FuZFVwZGF0ZUNhY2hlID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGhpZ2hjaGFydHMsIHNlcnZlciB9ID0gb3B0aW9ucztcclxuICBjb25zdCBjYWNoZVBhdGggPSBqb2luKF9fZGlybmFtZSwgaGlnaGNoYXJ0cy5jYWNoZVBhdGgpO1xyXG5cclxuICBsZXQgZmV0Y2hlZE1vZHVsZXM7XHJcbiAgLy8gUHJlcGFyZSBwYXRocyB0byBtYW5pZmVzdCBhbmQgc291cmNlcyBmcm9tIHRoZSAuY2FjaGUgZm9sZGVyXHJcbiAgY29uc3QgbWFuaWZlc3RQYXRoID0gam9pbihjYWNoZVBhdGgsICdtYW5pZmVzdC5qc29uJyk7XHJcbiAgY29uc3Qgc291cmNlUGF0aCA9IGpvaW4oY2FjaGVQYXRoLCAnc291cmNlcy5qcycpO1xyXG5cclxuICAvLyBDcmVhdGUgdGhlIGNhY2hlIGRlc3RpbmF0aW9uIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeVxyXG4gICFleGlzdHNTeW5jKGNhY2hlUGF0aCkgJiYgbWtkaXJTeW5jKGNhY2hlUGF0aCk7XHJcblxyXG4gIC8vIEZldGNoIGFsbCB0aGUgc2NyaXB0cyBlaXRoZXIgaWYgbWFuaWZlc3QuanNvbiBkb2VzIG5vdCBleGlzdFxyXG4gIC8vIG9yIGlmIHRoZSBmb3JjZUZldGNoIG9wdGlvbiBpcyBlbmFibGVkXHJcbiAgaWYgKCFleGlzdHNTeW5jKG1hbmlmZXN0UGF0aCkgfHwgaGlnaGNoYXJ0cy5mb3JjZUZldGNoKSB7XHJcbiAgICBsb2coMywgJ1tjYWNoZV0gRmV0Y2hpbmcgYW5kIGNhY2hpbmcgSGlnaGNoYXJ0cyBkZXBlbmRlbmNpZXMuJyk7XHJcbiAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgfSBlbHNlIHtcclxuICAgIGxldCByZXF1ZXN0VXBkYXRlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gUmVhZCB0aGUgbWFuaWZlc3QgSlNPTlxyXG4gICAgY29uc3QgbWFuaWZlc3QgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhtYW5pZmVzdFBhdGgpKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiB0aGUgbW9kdWxlcyBpcyBhbiBhcnJheSwgaWYgc28sIHdlIHJld3JpdGUgaXQgdG8gYSBtYXAgdG8gbWFrZVxyXG4gICAgLy8gaXQgZWFzaWVyIHRvIHJlc29sdmUgbW9kdWxlcy5cclxuICAgIGlmIChtYW5pZmVzdC5tb2R1bGVzICYmIEFycmF5LmlzQXJyYXkobWFuaWZlc3QubW9kdWxlcykpIHtcclxuICAgICAgY29uc3QgbW9kdWxlTWFwID0ge307XHJcbiAgICAgIG1hbmlmZXN0Lm1vZHVsZXMuZm9yRWFjaCgobSkgPT4gKG1vZHVsZU1hcFttXSA9IDEpKTtcclxuICAgICAgbWFuaWZlc3QubW9kdWxlcyA9IG1vZHVsZU1hcDtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IGNvcmVTY3JpcHRzLCBtb2R1bGVTY3JpcHRzLCBpbmRpY2F0b3JTY3JpcHRzIH0gPSBoaWdoY2hhcnRzO1xyXG4gICAgY29uc3QgbnVtYmVyT2ZNb2R1bGVzID1cclxuICAgICAgY29yZVNjcmlwdHMubGVuZ3RoICsgbW9kdWxlU2NyaXB0cy5sZW5ndGggKyBpbmRpY2F0b3JTY3JpcHRzLmxlbmd0aDtcclxuXHJcbiAgICAvLyBDb21wYXJlIHRoZSBsb2FkZWQgaGlnaGNoYXJ0cyBjb25maWcgd2l0aCB0aGUgY29udGVudHMgaW4gY2FjaGUuXHJcbiAgICAvLyBJZiB0aGVyZSBhcmUgY2hhbmdlcywgZmV0Y2ggcmVxdWVzdGVkIG1vZHVsZXMgYW5kIHByb2R1Y3RzLFxyXG4gICAgLy8gYW5kIGJha2UgdGhlbSBpbnRvIGEgZ2lhbnQgYmxvYi4gU2F2ZSB0aGUgYmxvYi5cclxuICAgIGlmIChtYW5pZmVzdC52ZXJzaW9uICE9PSBoaWdoY2hhcnRzLnZlcnNpb24pIHtcclxuICAgICAgbG9nKFxyXG4gICAgICAgIDIsXHJcbiAgICAgICAgJ1tjYWNoZV0gQSBIaWdoY2hhcnRzIHZlcnNpb24gbWlzbWF0Y2ggaW4gdGhlIGNhY2hlLCBuZWVkIHRvIHJlLWZldGNoLidcclxuICAgICAgKTtcclxuICAgICAgcmVxdWVzdFVwZGF0ZSA9IHRydWU7XHJcbiAgICB9IGVsc2UgaWYgKE9iamVjdC5rZXlzKG1hbmlmZXN0Lm1vZHVsZXMgfHwge30pLmxlbmd0aCAhPT0gbnVtYmVyT2ZNb2R1bGVzKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICAyLFxyXG4gICAgICAgICdbY2FjaGVdIFRoZSBjYWNoZSBhbmQgdGhlIHJlcXVlc3RlZCBtb2R1bGVzIGRvIG5vdCBtYXRjaCwgbmVlZCB0byByZS1mZXRjaC4nXHJcbiAgICAgICk7XHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSB0cnVlO1xyXG4gICAgfSBlbHNlIHtcclxuICAgICAgLy8gQ2hlY2sgZWFjaCBtb2R1bGUsIGlmIGFueXRoaW5nIGlzIG1pc3NpbmcgcmVmZXRjaCBldmVyeXRoaW5nXHJcbiAgICAgIHJlcXVlc3RVcGRhdGUgPSAobW9kdWxlU2NyaXB0cyB8fCBbXSkuc29tZSgobW9kdWxlTmFtZSkgPT4ge1xyXG4gICAgICAgIGlmICghbWFuaWZlc3QubW9kdWxlc1ttb2R1bGVOYW1lXSkge1xyXG4gICAgICAgICAgbG9nKFxyXG4gICAgICAgICAgICAyLFxyXG4gICAgICAgICAgICBgW2NhY2hlXSBUaGUgJHttb2R1bGVOYW1lfSBpcyBtaXNzaW5nIGluIHRoZSBjYWNoZSwgbmVlZCB0byByZS1mZXRjaC5gXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgICAgcmV0dXJuIHRydWU7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBpZiAocmVxdWVzdFVwZGF0ZSkge1xyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IGF3YWl0IHVwZGF0ZUNhY2hlKGhpZ2hjaGFydHMsIHNlcnZlci5wcm94eSwgc291cmNlUGF0aCk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICBsb2coMywgJ1tjYWNoZV0gRGVwZW5kZW5jeSBjYWNoZSBpcyB1cCB0byBkYXRlLCBwcm9jZWVkaW5nLicpO1xyXG5cclxuICAgICAgLy8gTG9hZCB0aGUgc291cmNlc1xyXG4gICAgICBjYWNoZS5zb3VyY2VzID0gcmVhZEZpbGVTeW5jKHNvdXJjZVBhdGgsICd1dGY4Jyk7XHJcblxyXG4gICAgICAvLyBHZXQgY3VycmVudCBtb2R1bGVzIG1hcFxyXG4gICAgICBmZXRjaGVkTW9kdWxlcyA9IG1hbmlmZXN0Lm1vZHVsZXM7XHJcblxyXG4gICAgICBjYWNoZS5oY1ZlcnNpb24gPSBleHRyYWN0VmVyc2lvbihjYWNoZSk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBGaW5hbGx5LCBzYXZlIHRoZSBuZXcgbWFuaWZlc3QsIHdoaWNoIGlzIGJhc2ljYWxseSBvdXIgY3VycmVudCBjb25maWdcclxuICAvLyBpbiBhIHNsaWdodGx5IGRpZmZlcmVudCBmb3JtYXRcclxuICBhd2FpdCBzYXZlQ29uZmlnVG9NYW5pZmVzdChoaWdoY2hhcnRzLCBmZXRjaGVkTW9kdWxlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgY29uc3QgZ2V0Q2FjaGVQYXRoID0gKCkgPT5cclxuICBqb2luKF9fZGlybmFtZSwgZ2V0T3B0aW9ucygpLmhpZ2hjaGFydHMuY2FjaGVQYXRoKTtcclxuXHJcbmV4cG9ydCBjb25zdCBnZXRDYWNoZSA9ICgpID0+IGNhY2hlO1xyXG5cclxuZXhwb3J0IGNvbnN0IGhpZ2hjaGFydHMgPSAoKSA9PiBjYWNoZS5zb3VyY2VzO1xyXG5cclxuZXhwb3J0IGNvbnN0IHZlcnNpb24gPSAoKSA9PiBjYWNoZS5oY1ZlcnNpb247XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgY2hlY2tBbmRVcGRhdGVDYWNoZSxcclxuICBnZXRDYWNoZVBhdGgsXHJcbiAgdXBkYXRlVmVyc2lvbixcclxuICBnZXRDYWNoZSxcclxuICBoaWdoY2hhcnRzLFxyXG4gIHZlcnNpb25cclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKiBlc2xpbnQtZGlzYWJsZSBuby11bmRlZiAqL1xyXG5cclxuLyoqXHJcbiAqIFNldHRpbmcgdGhlIGFuaW1PYmplY3QuIENhbGxlZCB3aGVuIGluaXRpbmcgdGhlIHBhZ2UuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBIaWdoY2hhcnRzKCkge1xyXG4gIEhpZ2hjaGFydHMuYW5pbU9iamVjdCA9IGZ1bmN0aW9uICgpIHtcclxuICAgIHJldHVybiB7IGR1cmF0aW9uOiAwIH07XHJcbiAgfTtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgdGhlIGFjdHVhbCBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtvYmplY3R9IGNoYXJ0T3B0aW9ucyAtIFRoZSBvcHRpb25zIGZvciB0aGUgSGlnaGNoYXJ0cyBjaGFydC5cclxuICogQHBhcmFtIHtvYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMuXHJcbiAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzcGxheUVycm9ycyAtIEEgZmxhZyBpbmRpY2F0aW5nIHdoZXRoZXIgdG8gZGlzcGxheSBlcnJvcnMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gdHJpZ2dlckV4cG9ydChjaGFydE9wdGlvbnMsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpIHtcclxuICAvLyBEaXNwbGF5IGVycm9ycyBmbGFnIHRha2VuIGZyb20gY2hhcnQgb3B0aW9ucyBuYWQgZGVidWdnZXIgbW9kdWxlXHJcbiAgd2luZG93Ll9kaXNwbGF5RXJyb3JzID0gZGlzcGxheUVycm9ycztcclxuXHJcbiAgLy8gR2V0IHJlcXVpcmVkIGZ1bmN0aW9uc1xyXG4gIGNvbnN0IHsgZ2V0T3B0aW9ucywgbWVyZ2UsIHNldE9wdGlvbnMsIHdyYXAgfSA9IEhpZ2hjaGFydHM7XHJcblxyXG4gIC8vIENyZWF0ZSBhIHNlcGFyYXRlIG9iamVjdCBmb3IgYSBwb3RlbnRpYWwgc2V0T3B0aW9ucyB1c2FnZXMgaW4gb3JkZXIgdG9cclxuICAvLyBwcmV2ZW50IGZyb20gcG9sbHV0aW5nIG90aGVyIGV4cG9ydHMgdGhhdCBjYW4gaGFwcGVuIG9uIHRoZSBzYW1lIHBhZ2VcclxuICBIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmogPSBtZXJnZShmYWxzZSwge30sIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIFRyaWdnZXIgY3VzdG9tIGNvZGVcclxuICBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSB7XHJcbiAgICBuZXcgRnVuY3Rpb24ob3B0aW9ucy5jdXN0b21Mb2dpYy5jdXN0b21Db2RlKSgpO1xyXG4gIH1cclxuXHJcbiAgLy8gQnkgZGVmYXVsdCBhbmltYXRpb24gaXMgZGlzYWJsZWRcclxuICBjb25zdCBjaGFydCA9IHtcclxuICAgIGFuaW1hdGlvbjogZmFsc2VcclxuICB9O1xyXG5cclxuICAvLyBXaGVuIHN0cmFpZ2h0IGluamVjdCwgdGhlIHNpemUgaXMgc2V0IHRocm91Z2ggQ1NTIG9ubHlcclxuICBpZiAob3B0aW9ucy5leHBvcnQuc3RySW5qKSB7XHJcbiAgICBjaGFydC5oZWlnaHQgPSBjaGFydE9wdGlvbnMuY2hhcnQuaGVpZ2h0O1xyXG4gICAgY2hhcnQud2lkdGggPSBjaGFydE9wdGlvbnMuY2hhcnQud2lkdGg7XHJcbiAgfVxyXG5cclxuICAvLyBOT1RFOiBJcyB0aGlzIHVzZWQgZm9yIGFueXRoaW5nIHVzZWZ1bD9cclxuICB3aW5kb3cuaXNSZW5kZXJDb21wbGV0ZSA9IGZhbHNlO1xyXG4gIHdyYXAoSGlnaGNoYXJ0cy5DaGFydC5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIHVzZXJPcHRpb25zLCBjYikge1xyXG4gICAgLy8gT3ZlcnJpZGUgdXNlck9wdGlvbnMgd2l0aCBpbWFnZSBmcmllbmRseSBvcHRpb25zXHJcbiAgICB1c2VyT3B0aW9ucyA9IG1lcmdlKHVzZXJPcHRpb25zLCB7XHJcbiAgICAgIGV4cG9ydGluZzoge1xyXG4gICAgICAgIGVuYWJsZWQ6IGZhbHNlXHJcbiAgICAgIH0sXHJcbiAgICAgIHBsb3RPcHRpb25zOiB7XHJcbiAgICAgICAgc2VyaWVzOiB7XHJcbiAgICAgICAgICBsYWJlbDoge1xyXG4gICAgICAgICAgICBlbmFibGVkOiBmYWxzZVxyXG4gICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgLyogRXhwZWN0cyB0b29sdGlwIGluIHVzZXJPcHRpb25zIHdoZW4gZm9yRXhwb3J0IGlzIHRydWUuXHJcbiAgICAgICAgaHR0cHM6Ly9naXRodWIuY29tL2hpZ2hjaGFydHMvaGlnaGNoYXJ0cy9ibG9iLzNhZDQzMGEzNTNiODA1NmI5ZTc2NGFhNGU1Y2Q2ODI4YWE0NzlkYjIvanMvcGFydHMvQ2hhcnQuanMjTDI0MVxyXG4gICAgICAgICovXHJcbiAgICAgIHRvb2x0aXA6IHt9XHJcbiAgICB9KTtcclxuXHJcbiAgICAodXNlck9wdGlvbnMuc2VyaWVzIHx8IFtdKS5mb3JFYWNoKGZ1bmN0aW9uIChzZXJpZXMpIHtcclxuICAgICAgc2VyaWVzLmFuaW1hdGlvbiA9IGZhbHNlO1xyXG4gICAgfSk7XHJcblxyXG4gICAgLy8gQWRkIGZsYWcgdG8ga25vdyBpZiBjaGFydCByZW5kZXIgaGFzIGJlZW4gY2FsbGVkLlxyXG4gICAgaWYgKCF3aW5kb3cub25IaWdoY2hhcnRzUmVuZGVyKSB7XHJcbiAgICAgIHdpbmRvdy5vbkhpZ2hjaGFydHNSZW5kZXIgPSBIaWdoY2hhcnRzLmFkZEV2ZW50KHRoaXMsICdyZW5kZXInLCAoKSA9PiB7XHJcbiAgICAgICAgd2luZG93LmlzUmVuZGVyQ29tcGxldGUgPSB0cnVlO1xyXG4gICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFt1c2VyT3B0aW9ucywgY2JdKTtcclxuICB9KTtcclxuXHJcbiAgd3JhcChIaWdoY2hhcnRzLlNlcmllcy5wcm90b3R5cGUsICdpbml0JywgZnVuY3Rpb24gKHByb2NlZWQsIGNoYXJ0LCBvcHRpb25zKSB7XHJcbiAgICBwcm9jZWVkLmFwcGx5KHRoaXMsIFtjaGFydCwgb3B0aW9uc10pO1xyXG4gIH0pO1xyXG5cclxuICAvLyBHZXQgdGhlIHVzZXIgb3B0aW9uc1xyXG4gIGNvbnN0IHVzZXJPcHRpb25zID0gb3B0aW9ucy5leHBvcnQuc3RySW5qXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5leHBvcnQuc3RySW5qfWApKClcclxuICAgIDogY2hhcnRPcHRpb25zO1xyXG5cclxuICAvLyBNZXJnZSB0aGUgZ2xvYmFsT3B0aW9ucywgdGhlbWVPcHRpb25zLCBvcHRpb25zIGZyb20gdGhlIHdyYXBwZWRcclxuICAvLyBzZXRPcHRpb25zIGZ1bmN0aW9uIGFuZCB1c2VyIG9wdGlvbnMgdG8gY3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxyXG4gIGNvbnN0IGZpbmFsT3B0aW9ucyA9IG1lcmdlKFxyXG4gICAgZmFsc2UsXHJcbiAgICBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0LnRoZW1lT3B0aW9ucyksXHJcbiAgICB1c2VyT3B0aW9ucyxcclxuICAgIC8vIFBsYWNlZCBpdCBoZXJlIGluc3RlYWQgaW4gdGhlIGluaXQgYmVjYXVzZSBvZiB0aGUgc2l6ZSBpc3N1ZXNcclxuICAgIHsgY2hhcnQgfVxyXG4gICk7XHJcblxyXG4gIGNvbnN0IGZpbmFsQ2FsbGJhY2sgPSBvcHRpb25zLmN1c3RvbUxvZ2ljLmNhbGxiYWNrXHJcbiAgICA/IG5ldyBGdW5jdGlvbihgcmV0dXJuICR7b3B0aW9ucy5jdXN0b21Mb2dpYy5jYWxsYmFja31gKSgpXHJcbiAgICA6IHVuZGVmaW5lZDtcclxuXHJcbiAgLy8gU2V0IHRoZSBnbG9iYWwgb3B0aW9ucyBpZiBleGlzdFxyXG4gIGNvbnN0IGdsb2JhbE9wdGlvbnMgPSBKU09OLnBhcnNlKG9wdGlvbnMuZXhwb3J0Lmdsb2JhbE9wdGlvbnMpO1xyXG4gIGlmIChnbG9iYWxPcHRpb25zKSB7XHJcbiAgICBzZXRPcHRpb25zKGdsb2JhbE9wdGlvbnMpO1xyXG4gIH1cclxuXHJcbiAgSGlnaGNoYXJ0c1tvcHRpb25zLmV4cG9ydC5jb25zdHIgfHwgJ2NoYXJ0J10oXHJcbiAgICAnY29udGFpbmVyJyxcclxuICAgIGZpbmFsT3B0aW9ucyxcclxuICAgIGZpbmFsQ2FsbGJhY2tcclxuICApO1xyXG5cclxuICAvLyBHZXQgdGhlIGN1cnJlbnQgZ2xvYmFsIG9wdGlvbnNcclxuICBjb25zdCBkZWZhdWx0T3B0aW9ucyA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gQ2xlYXIgaXQganVzdCBpbiBjYXNlIChlLmcuIHRoZSBzZXRPcHRpb25zIHdhcyB1c2VkIGluIHRoZSBjdXN0b21Db2RlKVxyXG4gIGZvciAoY29uc3QgcHJvcCBpbiBkZWZhdWx0T3B0aW9ucykge1xyXG4gICAgaWYgKHR5cGVvZiBkZWZhdWx0T3B0aW9uc1twcm9wXSAhPT0gJ2Z1bmN0aW9uJykge1xyXG4gICAgICBkZWxldGUgZGVmYXVsdE9wdGlvbnNbcHJvcF07XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBTZXQgdGhlIGRlZmF1bHQgb3B0aW9ucyBiYWNrXHJcbiAgc2V0T3B0aW9ucyhIaWdoY2hhcnRzLnNldE9wdGlvbnNPYmopO1xyXG5cclxuICAvLyBFbXB0eSB0aGUgY3VzdG9tIGdsb2JhbCBvcHRpb25zIG9iamVjdFxyXG4gIEhpZ2hjaGFydHMuc2V0T3B0aW9uc09iaiA9IHt9O1xyXG59XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5pbXBvcnQgcGF0aCBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCBwdXBwZXRlZXIgZnJvbSAncHVwcGV0ZWVyJztcclxuXHJcbmltcG9ydCB7IGdldENhY2hlUGF0aCB9IGZyb20gJy4vY2FjaGUuanMnO1xyXG5pbXBvcnQgeyBnZXRPcHRpb25zIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBzZXR1cEhpZ2hjaGFydHMgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gR2V0IHRoZSB0ZW1wbGF0ZSBmb3IgdGhlIHBhZ2VcclxuY29uc3QgdGVtcGxhdGUgPSByZWFkRmlsZVN5bmMoX19kaXJuYW1lICsgJy90ZW1wbGF0ZXMvdGVtcGxhdGUuaHRtbCcsICd1dGY4Jyk7XHJcblxyXG5sZXQgYnJvd3NlcjtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgdGhlIGV4aXN0aW5nIFB1cHBldGVlciBicm93c2VyIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxvYmplY3Q+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBQdXBwZXRlZXIgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBubyB2YWxpZCBicm93c2VyIGhhcyBiZWVuXHJcbiAqIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0KCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKCdbYnJvd3Nlcl0gTm8gdmFsaWQgYnJvd3NlciBoYXMgYmVlbiBjcmVhdGVkLicpO1xyXG4gIH1cclxuICByZXR1cm4gYnJvd3NlcjtcclxufVxyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSB3aXRoIHRoZSBzcGVjaWZpZWQgYXJndW1lbnRzLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0FycmF5fSBwdXBwZXRlZXJBcmdzIC0gQWRkaXRpb25hbCBhcmd1bWVudHMgZm9yIFB1cHBldGVlciBsYXVuY2guXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPG9iamVjdD59IEEgUHJvbWlzZSByZXNvbHZpbmcgdG8gdGhlIFB1cHBldGVlciBicm93c2VyXHJcbiAqIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIG1heCByZXRyaWVzIHRvIG9wZW4gYSBicm93c2VyXHJcbiAqIGluc3RhbmNlIGFyZSByZWFjaGVkLCBvciBpZiBubyBicm93c2VyIGluc3RhbmNlIGlzIGZvdW5kIGFmdGVyIHJldHJpZXMuXHJcbiAqL1xyXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY3JlYXRlKHB1cHBldGVlckFyZ3MpIHtcclxuICAvLyBHZXQgZGVidWcgYW5kIG90aGVyIG9wdGlvbnNcclxuICBjb25zdCB7IGRlYnVnLCBvdGhlciB9ID0gZ2V0T3B0aW9ucygpO1xyXG5cclxuICAvLyBHZXQgdGhlIGRlYnVnIG9wdGlvbnNcclxuICBjb25zdCB7IGVuYWJsZTogZW5hYmxlZERlYnVnLCAuLi5kZWJ1Z09wdGlvbnMgfSA9IGRlYnVnO1xyXG5cclxuICBjb25zdCBsYXVuY2hPcHRpb25zID0ge1xyXG4gICAgaGVhZGxlc3M6IG90aGVyLmJyb3dzZXJTaGVsbE1vZGUgPyAnc2hlbGwnIDogdHJ1ZSxcclxuICAgIHVzZXJEYXRhRGlyOiAnLi90bXAvJyxcclxuICAgIGFyZ3M6IHB1cHBldGVlckFyZ3MsXHJcbiAgICBoYW5kbGVTSUdJTlQ6IGZhbHNlLFxyXG4gICAgaGFuZGxlU0lHVEVSTTogZmFsc2UsXHJcbiAgICBoYW5kbGVTSUdIVVA6IGZhbHNlLFxyXG4gICAgd2FpdEZvckluaXRpYWxQYWdlOiBmYWxzZSxcclxuICAgIGRlZmF1bHRWaWV3cG9ydDogbnVsbCxcclxuICAgIC4uLihlbmFibGVkRGVidWcgJiYgZGVidWdPcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIENyZWF0ZSBhIGJyb3dzZXJcclxuICBpZiAoIWJyb3dzZXIpIHtcclxuICAgIGxldCB0cnlDb3VudCA9IDA7XHJcblxyXG4gICAgY29uc3Qgb3BlbiA9IGFzeW5jICgpID0+IHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFticm93c2VyXSBBdHRlbXB0aW5nIHRvIGdldCBhIGJyb3dzZXIgaW5zdGFuY2UgKHRyeSAkeysrdHJ5Q291bnR9KS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgICBicm93c2VyID0gYXdhaXQgcHVwcGV0ZWVyLmxhdW5jaChsYXVuY2hPcHRpb25zKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgICAgICAxLFxyXG4gICAgICAgICAgZXJyb3IsXHJcbiAgICAgICAgICAnW2Jyb3dzZXJdIEZhaWxlZCB0byBsYXVuY2ggYSBicm93c2VyIGluc3RhbmNlLidcclxuICAgICAgICApO1xyXG5cclxuICAgICAgICAvLyBSZXRyeSB0byBsYXVuY2ggYnJvd3NlciB1bnRpbCByZWFjaGluZyBtYXggYXR0ZW1wdHNcclxuICAgICAgICBpZiAodHJ5Q291bnQgPCAyNSkge1xyXG4gICAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gUmV0cnkgdG8gb3BlbiBhIGJyb3dzZXIgKCR7dHJ5Q291bnR9IG91dCBvZiAyNSkuYCk7XHJcbiAgICAgICAgICBhd2FpdCBuZXcgUHJvbWlzZSgocmVzcG9uc2UpID0+IHNldFRpbWVvdXQocmVzcG9uc2UsIDQwMDApKTtcclxuICAgICAgICAgIGF3YWl0IG9wZW4oKTtcclxuICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgfVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIHRyeSB7XHJcbiAgICAgIGF3YWl0IG9wZW4oKTtcclxuXHJcbiAgICAgIC8vIFNoZWxsIG1vZGUgaW5mb3JtXHJcbiAgICAgIGlmIChsYXVuY2hPcHRpb25zLmhlYWRsZXNzID09PSAnc2hlbGwnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBzaGVsbCBtb2RlLmApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBEZWJ1ZyBtb2RlIGluZm9ybVxyXG4gICAgICBpZiAoZW5hYmxlZERlYnVnKSB7XHJcbiAgICAgICAgbG9nKDMsIGBbYnJvd3Nlcl0gTGF1bmNoZWQgYnJvd3NlciBpbiBkZWJ1ZyBtb2RlLmApO1xyXG4gICAgICB9XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgJ1ticm93c2VyXSBNYXhpbXVtIHJldHJpZXMgdG8gb3BlbiBhIGJyb3dzZXIgaW5zdGFuY2UgcmVhY2hlZC4nXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICghYnJvd3Nlcikge1xyXG4gICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1ticm93c2VyXSBDYW5ub3QgZmluZCBhIGJyb3dzZXIgdG8gb3Blbi4nKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIFJldHVybiBhIGJyb3dzZXIgcHJvbWlzZVxyXG4gIHJldHVybiBicm93c2VyO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xvc2VzIHRoZSBQdXBwZXRlZXIgYnJvd3NlciBpbnN0YW5jZSBpZiBpdCBpcyBjb25uZWN0ZWQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPGJvb2xlYW4+fSBBIFByb21pc2UgcmVzb2x2aW5nIHRvIHRydWUgYWZ0ZXIgdGhlIGJyb3dzZXJcclxuICogaXMgY2xvc2VkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsb3NlKCkge1xyXG4gIC8vIENsb3NlIHRoZSBicm93c2VyIHdoZW4gY29ubm5lY3RlZFxyXG4gIGlmIChicm93c2VyPy5jb25uZWN0ZWQpIHtcclxuICAgIGF3YWl0IGJyb3dzZXIuY2xvc2UoKTtcclxuICB9XHJcbiAgbG9nKDQsICdbYnJvd3Nlcl0gQ2xvc2VkIHRoZSBicm93c2VyLicpO1xyXG59XHJcblxyXG4vKipcclxuICogQ3JlYXRlcyBhIG5ldyBQdXBwZXRlZXIgUGFnZSB3aXRoaW4gYW4gZXhpc3RpbmcgYnJvd3NlciBpbnN0YW5jZS5cclxuICpcclxuICogSWYgdGhlIGJyb3dzZXIgaW5zdGFuY2UgaXMgbm90IGF2YWlsYWJsZSwgcmV0dXJucyBmYWxzZS5cclxuICpcclxuICogVGhlIGZ1bmN0aW9uIGNyZWF0ZXMgYSBuZXcgcGFnZSwgZGlzYWJsZXMgY2FjaGluZywgc2V0cyBjb250ZW50IHVzaW5nXHJcbiAqIHNldFBhZ2VDb250ZW50KCksIGFuZCByZXR1cm5zIHRoZSBjcmVhdGVkIFB1cHBldGVlciBQYWdlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7KGJvb2xlYW58b2JqZWN0KX0gUmV0dXJucyBmYWxzZSBpZiB0aGUgYnJvd3NlciBpbnN0YW5jZSBpcyBub3RcclxuICogYXZhaWxhYmxlLCBvciBhIFB1cHBldGVlciBQYWdlIG9iamVjdCByZXByZXNlbnRpbmcgdGhlIG5ld2x5IGNyZWF0ZWQgcGFnZS5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBuZXdQYWdlKCkge1xyXG4gIGlmICghYnJvd3Nlcikge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gQ3JlYXRlIGEgcGFnZVxyXG4gIGNvbnN0IHBhZ2UgPSBhd2FpdCBicm93c2VyLm5ld1BhZ2UoKTtcclxuXHJcbiAgLy8gRGlzYWJsZSBjYWNoZVxyXG4gIGF3YWl0IHBhZ2Uuc2V0Q2FjaGVFbmFibGVkKGZhbHNlKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb250ZW50XHJcbiAgYXdhaXQgc2V0UGFnZUNvbnRlbnQocGFnZSk7XHJcblxyXG4gIC8vIFNldCBwYWdlIGV2ZW50c1xyXG4gIHNldFBhZ2VFdmVudHMocGFnZSk7XHJcblxyXG4gIHJldHVybiBwYWdlO1xyXG59XHJcblxyXG4vKipcclxuICogQ2xlYXJzIHRoZSBjb250ZW50IG9mIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZCBtb2RlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtib29sZWFufSBoYXJkUmVzZXQgLSBBIGZsYWcgaW5kaWNhdGluZyB0aGUgdHlwZSBvZiBjbGVhcmluZ1xyXG4gKiB0byBiZSBwZXJmb3JtZWQuIElmIHRydWUsIG5hdmlnYXRlcyB0byAnYWJvdXQ6YmxhbmsnIGFuZCByZXNldHMgY29udGVudFxyXG4gKiBhbmQgc2NyaXB0cy4gSWYgZmFsc2UsIGNsZWFycyB0aGUgYm9keSBjb250ZW50IGJ5IHNldHRpbmcgYSBwcmVkZWZpbmVkIEhUTUxcclxuICogc3RydWN0dXJlLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFcnJvcn0gTG9ncyB0aHJvd24gZXJyb3IgaWYgY2xlYXJpbmcgdGhlIHBhZ2UgY29udGVudCBmYWlscy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBjbGVhclBhZ2UocGFnZSwgaGFyZFJlc2V0ID0gZmFsc2UpIHtcclxuICB0cnkge1xyXG4gICAgaWYgKCFwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgaWYgKGhhcmRSZXNldCkge1xyXG4gICAgICAgIC8vIE5hdmlnYXRlIHRvIGFib3V0OmJsYW5rXHJcbiAgICAgICAgYXdhaXQgcGFnZS5nb3RvKCdhYm91dDpibGFuaycsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gICAgICAgIC8vIFNldCB0aGUgY29udGVudCBhbmQgYW5kIHNjcmlwdHMgYWdhaW5cclxuICAgICAgICBhd2FpdCBzZXRQYWdlQ29udGVudChwYWdlKTtcclxuICAgICAgfSBlbHNlIHtcclxuICAgICAgICAvLyBDbGVhciBib2R5IGNvbnRlbnRcclxuICAgICAgICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuaW5uZXJIVE1MID1cclxuICAgICAgICAgICAgJzxkaXYgaWQ9XCJjaGFydC1jb250YWluZXJcIj48ZGl2IGlkPVwiY29udGFpbmVyXCI+PC9kaXY+PC9kaXY+JztcclxuICAgICAgICB9KTtcclxuICAgICAgfVxyXG4gICAgfVxyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBsb2dXaXRoU3RhY2soXHJcbiAgICAgIDIsXHJcbiAgICAgIGVycm9yLFxyXG4gICAgICAnW2Jyb3dzZXJdIENvdWxkIG5vdCBjbGVhciB0aGUgY29udGVudCBvZiB0aGUgcGFnZS4nXHJcbiAgICApO1xyXG4gIH1cclxufVxyXG5cclxuLyoqXHJcbiAqIEFkZHMgY3VzdG9tIEpTIGFuZCBDU1MgcmVzb3VyY2VzIHRvIGEgUHVwcGV0ZWVyIFBhZ2UgYmFzZWQgb24gdGhlIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgdG8gd2hpY2ggcmVzb3VyY2VzIHdpbGwgYmVcclxuICogYWRkZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEFycmF5PE9iamVjdD4+fSAtIFByb21pc2UgcmVzb2x2aW5nIHRvIGFuIGFycmF5IG9mIGluamVjdGVkXHJcbiAqIHJlc291cmNlcy5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBhZGRQYWdlUmVzb3VyY2VzKHBhZ2UsIG9wdGlvbnMpIHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXlcclxuICBjb25zdCBpbmplY3RlZFJlc291cmNlcyA9IFtdO1xyXG5cclxuICAvLyBVc2UgcmVzb3VyY2VzXHJcbiAgY29uc3QgcmVzb3VyY2VzID0gb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXM7XHJcbiAgaWYgKHJlc291cmNlcykge1xyXG4gICAgY29uc3QgaW5qZWN0ZWRKcyA9IFtdO1xyXG5cclxuICAgIC8vIExvYWQgY3VzdG9tIEpTIGNvZGVcclxuICAgIGlmIChyZXNvdXJjZXMuanMpIHtcclxuICAgICAgaW5qZWN0ZWRKcy5wdXNoKHtcclxuICAgICAgICBjb250ZW50OiByZXNvdXJjZXMuanNcclxuICAgICAgfSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gTG9hZCBzY3JpcHRzIGZyb20gYWxsIGN1c3RvbSBmaWxlc1xyXG4gICAgaWYgKHJlc291cmNlcy5maWxlcykge1xyXG4gICAgICBmb3IgKGNvbnN0IGZpbGUgb2YgcmVzb3VyY2VzLmZpbGVzKSB7XHJcbiAgICAgICAgY29uc3QgaXNMb2NhbCA9ICFmaWxlLnN0YXJ0c1dpdGgoJ2h0dHAnKSA/IHRydWUgOiBmYWxzZTtcclxuXHJcbiAgICAgICAgLy8gQWRkIGVhY2ggY3VzdG9tIHNjcmlwdCBmcm9tIHJlc291cmNlcycgZmlsZXNcclxuICAgICAgICBpbmplY3RlZEpzLnB1c2goXHJcbiAgICAgICAgICBpc0xvY2FsXHJcbiAgICAgICAgICAgID8ge1xyXG4gICAgICAgICAgICAgICAgY29udGVudDogcmVhZEZpbGVTeW5jKGZpbGUsICd1dGY4JylcclxuICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIDoge1xyXG4gICAgICAgICAgICAgICAgdXJsOiBmaWxlXHJcbiAgICAgICAgICAgICAgfVxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBmb3IgKGNvbnN0IGpzUmVzb3VyY2Ugb2YgaW5qZWN0ZWRKcykge1xyXG4gICAgICB0cnkge1xyXG4gICAgICAgIGluamVjdGVkUmVzb3VyY2VzLnB1c2goYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoanNSZXNvdXJjZSkpO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjaygyLCBlcnJvciwgYFtleHBvcnRdIFRoZSBKUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICB9XHJcbiAgICB9XHJcbiAgICBpbmplY3RlZEpzLmxlbmd0aCA9IDA7XHJcblxyXG4gICAgLy8gTG9hZCBDU1NcclxuICAgIGNvbnN0IGluamVjdGVkQ3NzID0gW107XHJcbiAgICBpZiAocmVzb3VyY2VzLmNzcykge1xyXG4gICAgICBsZXQgY3NzSW1wb3J0cyA9IHJlc291cmNlcy5jc3MubWF0Y2goL0BpbXBvcnRcXHMqKFteO10qKTsvZyk7XHJcbiAgICAgIGlmIChjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgLy8gSGFuZGxlIGNzcyBzZWN0aW9uXHJcbiAgICAgICAgZm9yIChsZXQgY3NzSW1wb3J0UGF0aCBvZiBjc3NJbXBvcnRzKSB7XHJcbiAgICAgICAgICBpZiAoY3NzSW1wb3J0UGF0aCkge1xyXG4gICAgICAgICAgICBjc3NJbXBvcnRQYXRoID0gY3NzSW1wb3J0UGF0aFxyXG4gICAgICAgICAgICAgIC5yZXBsYWNlKCd1cmwoJywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoJ0BpbXBvcnQnLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgJycpXHJcbiAgICAgICAgICAgICAgLnJlcGxhY2UoLzsvLCAnJylcclxuICAgICAgICAgICAgICAucmVwbGFjZSgvXFwpL2csICcnKVxyXG4gICAgICAgICAgICAgIC50cmltKCk7XHJcblxyXG4gICAgICAgICAgICAvLyBBZGQgZWFjaCBjdXN0b20gY3NzIGZyb20gcmVzb3VyY2VzXHJcbiAgICAgICAgICAgIGlmIChjc3NJbXBvcnRQYXRoLnN0YXJ0c1dpdGgoJ2h0dHAnKSkge1xyXG4gICAgICAgICAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgICAgICAgICAgdXJsOiBjc3NJbXBvcnRQYXRoXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSBpZiAob3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0ZpbGVSZXNvdXJjZXMpIHtcclxuICAgICAgICAgICAgICBpbmplY3RlZENzcy5wdXNoKHtcclxuICAgICAgICAgICAgICAgIHBhdGg6IHBhdGguam9pbihfX2Rpcm5hbWUsIGNzc0ltcG9ydFBhdGgpXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIFRoZSByZXN0IG9mIHRoZSBDU1Mgc2VjdGlvbiB3aWxsIGJlIGNvbnRlbnQgYnkgbm93XHJcbiAgICAgIGluamVjdGVkQ3NzLnB1c2goe1xyXG4gICAgICAgIGNvbnRlbnQ6IHJlc291cmNlcy5jc3MucmVwbGFjZSgvQGltcG9ydFxccyooW147XSopOy9nLCAnJykgfHwgJyAnXHJcbiAgICAgIH0pO1xyXG5cclxuICAgICAgZm9yIChjb25zdCBjc3NSZXNvdXJjZSBvZiBpbmplY3RlZENzcykge1xyXG4gICAgICAgIHRyeSB7XHJcbiAgICAgICAgICBpbmplY3RlZFJlc291cmNlcy5wdXNoKGF3YWl0IHBhZ2UuYWRkU3R5bGVUYWcoY3NzUmVzb3VyY2UpKTtcclxuICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2V4cG9ydF0gVGhlIENTUyByZXNvdXJjZSBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgICBpbmplY3RlZENzcy5sZW5ndGggPSAwO1xyXG4gICAgfVxyXG4gIH1cclxuICByZXR1cm4gaW5qZWN0ZWRSZXNvdXJjZXM7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBDbGVhcnMgb3V0IGFsbCBzdGF0ZSBzZXQgb24gdGhlIHBhZ2Ugd2l0aCBhZGRTY3JpcHRUYWcvYWRkU3R5bGVUYWcuIFJlbW92ZXNcclxuICogaW5qZWN0ZWQgcmVzb3VyY2VzIGFuZCByZXNldHMgQ1NTIGFuZCBzY3JpcHQgdGFncyBvbiB0aGUgcGFnZS4gQWRkaXRpb25hbGx5LFxyXG4gKiBpdCBkZXN0cm95cyBwcmV2aW91c2x5IGV4aXN0aW5nIGNoYXJ0cy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IGZyb20gd2hpY2ggcmVzb3VyY2VzIHdpbGxcclxuICogYmUgY2xlYXJlZC5cclxuICogQHBhcmFtIHtBcnJheTxPYmplY3Q+fSBpbmplY3RlZFJlc291cmNlcyAtIEFycmF5IG9mIGluamVjdGVkIHJlc291cmNlc1xyXG4gKiB0byBiZSBjbGVhcmVkLlxyXG4gKi9cclxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcykge1xyXG4gIGZvciAoY29uc3QgcmVzb3VyY2Ugb2YgaW5qZWN0ZWRSZXNvdXJjZXMpIHtcclxuICAgIGF3YWl0IHJlc291cmNlLmRpc3Bvc2UoKTtcclxuICB9XHJcblxyXG4gIC8vIERlc3Ryb3kgb2xkIGNoYXJ0cyBhZnRlciBleHBvcnQgaXMgZG9uZSBhbmQgcmVzZXQgYWxsIENTUyBhbmQgc2NyaXB0IHRhZ3NcclxuICBhd2FpdCBwYWdlLmV2YWx1YXRlKCgpID0+IHtcclxuICAgIC8vIFdlIGFyZSBub3QgZ3VhcmFudGVlZCB0aGF0IEhpZ2hjaGFydHMgaXMgbG9hZGVkLCBlLGcsIHdoZW4gZG9pbmcgU1ZHXHJcbiAgICAvLyBleHBvcnRzXHJcbiAgICBpZiAodHlwZW9mIEhpZ2hjaGFydHMgIT09ICd1bmRlZmluZWQnKSB7XHJcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICBjb25zdCBvbGRDaGFydHMgPSBIaWdoY2hhcnRzLmNoYXJ0cztcclxuXHJcbiAgICAgIC8vIENoZWNrIGluIGFueSBhbHJlYWR5IGV4aXN0aW5nIGNoYXJ0c1xyXG4gICAgICBpZiAoQXJyYXkuaXNBcnJheShvbGRDaGFydHMpICYmIG9sZENoYXJ0cy5sZW5ndGgpIHtcclxuICAgICAgICAvLyBEZXN0cm95IG9sZCBjaGFydHNcclxuICAgICAgICBmb3IgKGNvbnN0IG9sZENoYXJ0IG9mIG9sZENoYXJ0cykge1xyXG4gICAgICAgICAgb2xkQ2hhcnQgJiYgb2xkQ2hhcnQuZGVzdHJveSgpO1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBIaWdoY2hhcnRzLmNoYXJ0cy5zaGlmdCgpO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgY29uc3QgWy4uLnNjcmlwdHNUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnc2NyaXB0Jyk7XHJcbiAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgIGNvbnN0IFssIC4uLnN0eWxlc1RvUmVtb3ZlXSA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdzdHlsZScpO1xyXG4gICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICBjb25zdCBbLi4ubGlua3NUb1JlbW92ZV0gPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnbGluaycpO1xyXG5cclxuICAgIC8vIFJlbW92ZSB0YWdzXHJcbiAgICBmb3IgKGNvbnN0IGVsZW1lbnQgb2YgW1xyXG4gICAgICAuLi5zY3JpcHRzVG9SZW1vdmUsXHJcbiAgICAgIC4uLnN0eWxlc1RvUmVtb3ZlLFxyXG4gICAgICAuLi5saW5rc1RvUmVtb3ZlXHJcbiAgICBdKSB7XHJcbiAgICAgIGVsZW1lbnQucmVtb3ZlKCk7XHJcbiAgICB9XHJcbiAgfSk7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTZXRzIHRoZSBjb250ZW50IGZvciBhIFB1cHBldGVlciBQYWdlIHVzaW5nIGEgcHJlZGVmaW5lZCB0ZW1wbGF0ZVxyXG4gKiBhbmQgYWRkaXRpb25hbCBzY3JpcHRzLiBBbHNvLCBzZXRzIHRoZSBwYWdlZXJyb3IgaW4gb3JkZXIgdG8gY2F0Y2hcclxuICogYW5kIGRpc3BsYXkgZXJyb3JzIGZyb20gdGhlIHdpbmRvdyBjb250ZXh0LlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFRoZSBQdXBwZXRlZXIgUGFnZSBvYmplY3QgZm9yIHdoaWNoIHRoZSBjb250ZW50XHJcbiAqIGlzIGJlaW5nIHNldC5cclxuICovXHJcbmFzeW5jIGZ1bmN0aW9uIHNldFBhZ2VDb250ZW50KHBhZ2UpIHtcclxuICBhd2FpdCBwYWdlLnNldENvbnRlbnQodGVtcGxhdGUsIHsgd2FpdFVudGlsOiAnZG9tY29udGVudGxvYWRlZCcgfSk7XHJcblxyXG4gIC8vIEFkZCBhbGwgcmVnaXN0ZXJlZCBIaWdjaGFydHMgc2NyaXB0cywgcXVpdGUgZGVtYW5kaW5nXHJcbiAgYXdhaXQgcGFnZS5hZGRTY3JpcHRUYWcoeyBwYXRoOiBgJHtnZXRDYWNoZVBhdGgoKX0vc291cmNlcy5qc2AgfSk7XHJcblxyXG4gIC8vIFNldCB0aGUgaW5pdGlhbCBhbmltT2JqZWN0XHJcbiAgYXdhaXQgcGFnZS5ldmFsdWF0ZShzZXR1cEhpZ2hjaGFydHMpO1xyXG59XHJcblxyXG4vKipcclxuICogU2V0IGV2ZW50cyBmb3IgYSBQdXBwZXRlZXIgUGFnZS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBUaGUgUHVwcGV0ZWVyIFBhZ2Ugb2JqZWN0IHRvIHNldCBldmVudHMgdG8uXHJcbiAqL1xyXG5mdW5jdGlvbiBzZXRQYWdlRXZlbnRzKHBhZ2UpIHtcclxuICAvLyBHZXQgZGVidWcgb3B0aW9uc1xyXG4gIGNvbnN0IHsgZGVidWcgfSA9IGdldE9wdGlvbnMoKTtcclxuXHJcbiAgLy8gU2V0IHRoZSBjb25zb2xlIGxpc3RlbmVyLCBpZiBuZWVkZWRcclxuICBpZiAoZGVidWcuZW5hYmxlICYmIGRlYnVnLmxpc3RlblRvQ29uc29sZSkge1xyXG4gICAgcGFnZS5vbignY29uc29sZScsIChtZXNzYWdlKSA9PiB7XHJcbiAgICAgIGNvbnNvbGUubG9nKGBbZGVidWddICR7bWVzc2FnZS50ZXh0KCl9YCk7XHJcbiAgICB9KTtcclxuICB9XHJcblxyXG4gIC8vIFNldCB0aGUgcGFnZWVycm9yIGxpc3RlbmVyXHJcbiAgcGFnZS5vbigncGFnZWVycm9yJywgYXN5bmMgKGVycm9yKSA9PiB7XHJcbiAgICAvLyBUT0RPOiBDb25zaWRlciBhZGRpbmcgYSBzd2l0Y2ggaGVyZSB0aGF0IHR1cm5zIG9uIGxvZygwKSBsb2dnaW5nXHJcbiAgICAvLyBvbiBwYWdlIGVycm9ycy5cclxuICAgIGF3YWl0IHBhZ2UuJGV2YWwoXHJcbiAgICAgICcjY29udGFpbmVyJyxcclxuICAgICAgKGVsZW1lbnQsIGVycm9yTWVzc2FnZSkgPT4ge1xyXG4gICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby11bmRlZlxyXG4gICAgICAgIGlmICh3aW5kb3cuX2Rpc3BsYXlFcnJvcnMpIHtcclxuICAgICAgICAgIGVsZW1lbnQuaW5uZXJIVE1MID0gZXJyb3JNZXNzYWdlO1xyXG4gICAgICAgIH1cclxuICAgICAgfSxcclxuICAgICAgYDxoMT5DaGFydCBpbnB1dCBkYXRhIGVycm9yOiA8L2gxPiR7ZXJyb3IudG9TdHJpbmcoKX1gXHJcbiAgICApO1xyXG4gIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgZ2V0LFxyXG4gIGNyZWF0ZSxcclxuICBjbG9zZSxcclxuICBuZXdQYWdlLFxyXG4gIGNsZWFyUGFnZSxcclxuICBhZGRQYWdlUmVzb3VyY2VzLFxyXG4gIGNsZWFyUGFnZVJlc291cmNlc1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGFkZFBhZ2VSZXNvdXJjZXMsIGNsZWFyUGFnZVJlc291cmNlcyB9IGZyb20gJy4vYnJvd3Nlci5qcyc7XHJcbmltcG9ydCB7IGdldENhY2hlIH0gZnJvbSAnLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IHRyaWdnZXJFeHBvcnQgfSBmcm9tICcuL2hpZ2hjaGFydHMuanMnO1xyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG5pbXBvcnQgc3ZnVGVtcGxhdGUgZnJvbSAnLi8uLi90ZW1wbGF0ZXMvc3ZnX2V4cG9ydC9zdmdfZXhwb3J0LmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHRoZSBjbGlwcGluZyByZWdpb24gY29vcmRpbmF0ZXMgb2YgdGhlIHNwZWNpZmllZCBwYWdlIGVsZW1lbnQgd2l0aFxyXG4gKiB0aGUgaWQgJ2NoYXJ0LWNvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byBhbiBvYmplY3QgY29udGFpbmluZ1xyXG4gKiB4LCB5LCB3aWR0aCwgYW5kIGhlaWdodCBwcm9wZXJ0aWVzLlxyXG4gKi9cclxuY29uc3QgZ2V0Q2xpcFJlZ2lvbiA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjaGFydC1jb250YWluZXInLCAoZWxlbWVudCkgPT4ge1xyXG4gICAgY29uc3QgeyB4LCB5LCB3aWR0aCwgaGVpZ2h0IH0gPSBlbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG4gICAgcmV0dXJuIHtcclxuICAgICAgeCxcclxuICAgICAgeSxcclxuICAgICAgd2lkdGgsXHJcbiAgICAgIGhlaWdodDogTWF0aC50cnVuYyhoZWlnaHQgPiAxID8gaGVpZ2h0IDogNTAwKVxyXG4gICAgfTtcclxuICB9KTtcclxuXHJcbi8qKlxyXG4gKiBDcmVhdGVzIGFuIGltYWdlIHVzaW5nIFB1cHBldGVlcidzIHBhZ2Ugc2NyZWVuc2hvdCBmdW5jdGlvbmFsaXR5IHdpdGhcclxuICogc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gdHlwZSAtIEltYWdlIHR5cGUuXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBlbmNvZGluZyAtIEltYWdlIGVuY29kaW5nLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2xpcCAtIENsaXBwaW5nIHJlZ2lvbiBjb29yZGluYXRlcy5cclxuICogQHBhcmFtIHtudW1iZXJ9IHJhc3Rlcml6YXRpb25UaW1lb3V0IC0gVGltZW91dCBmb3IgcmFzdGVyaXphdGlvblxyXG4gKiBpbiBtaWxsaXNlY29uZHMuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPEJ1ZmZlcj59IFByb21pc2UgcmVzb2x2aW5nIHRvIHRoZSBpbWFnZSBidWZmZXIgb3IgcmVqZWN0aW5nXHJcbiAqIHdpdGggYW4gRXhwb3J0RXJyb3IgZm9yIHRpbWVvdXQuXHJcbiAqL1xyXG5jb25zdCBjcmVhdGVJbWFnZSA9IChwYWdlLCB0eXBlLCBlbmNvZGluZywgY2xpcCwgcmFzdGVyaXphdGlvblRpbWVvdXQpID0+XHJcbiAgUHJvbWlzZS5yYWNlKFtcclxuICAgIHBhZ2Uuc2NyZWVuc2hvdCh7XHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGVuY29kaW5nLFxyXG4gICAgICBjbGlwLFxyXG4gICAgICBjYXB0dXJlQmV5b25kVmlld3BvcnQ6IHRydWUsXHJcbiAgICAgIGZ1bGxQYWdlOiBmYWxzZSxcclxuICAgICAgb3B0aW1pemVGb3JTcGVlZDogdHJ1ZSxcclxuICAgICAgLi4uKHR5cGUgIT09ICdwbmcnID8geyBxdWFsaXR5OiA4MCB9IDoge30pLFxyXG5cclxuICAgICAgLy8gIzQ0NywgIzQ2MyAtIGFsd2F5cyByZW5kZXIgb24gYSB0cmFuc3BhcmVudCBwYWdlIGlmIHRoZSBleHBlY3RlZCB0eXBlXHJcbiAgICAgIC8vIGZvcm1hdCBpcyBQTkdcclxuICAgICAgb21pdEJhY2tncm91bmQ6IHR5cGUgPT0gJ3BuZydcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYSBQREYgdXNpbmcgUHVwcGV0ZWVyJ3MgcGFnZSBwZGYgZnVuY3Rpb25hbGl0eSB3aXRoIHNwZWNpZmllZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFBERiBoZWlnaHQuXHJcbiAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFBERiB3aWR0aC5cclxuICogQHBhcmFtIHtzdHJpbmd9IGVuY29kaW5nIC0gUERGIGVuY29kaW5nLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxCdWZmZXI+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgUERGIGJ1ZmZlci5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVBERiA9IGFzeW5jIChcclxuICBwYWdlLFxyXG4gIGhlaWdodCxcclxuICB3aWR0aCxcclxuICBlbmNvZGluZyxcclxuICByYXN0ZXJpemF0aW9uVGltZW91dFxyXG4pID0+IHtcclxuICBhd2FpdCBwYWdlLmVtdWxhdGVNZWRpYVR5cGUoJ3NjcmVlbicpO1xyXG4gIHJldHVybiBQcm9taXNlLnJhY2UoW1xyXG4gICAgcGFnZS5wZGYoe1xyXG4gICAgICAvLyBUaGlzIHdpbGwgcmVtb3ZlIGFuIGV4dHJhIGVtcHR5IHBhZ2UgaW4gUERGIGV4cG9ydHNcclxuICAgICAgaGVpZ2h0OiBoZWlnaHQgKyAxLFxyXG4gICAgICB3aWR0aCxcclxuICAgICAgZW5jb2RpbmdcclxuICAgIH0pLFxyXG4gICAgbmV3IFByb21pc2UoKF9yZXNvbHZlLCByZWplY3QpID0+XHJcbiAgICAgIHNldFRpbWVvdXQoXHJcbiAgICAgICAgKCkgPT4gcmVqZWN0KG5ldyBFeHBvcnRFcnJvcignUmFzdGVyaXphdGlvbiB0aW1lb3V0JykpLFxyXG4gICAgICAgIHJhc3Rlcml6YXRpb25UaW1lb3V0IHx8IDE1MDBcclxuICAgICAgKVxyXG4gICAgKVxyXG4gIF0pO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIENyZWF0ZXMgYW4gU1ZHIHN0cmluZyBieSBldmFsdWF0aW5nIHRoZSBvdXRlckhUTUwgb2YgdGhlIGZpcnN0ICdzdmcnIGVsZW1lbnRcclxuICogaW5zaWRlIGFuIGVsZW1lbnQgd2l0aCB0aGUgaWQgJ2NvbnRhaW5lcicuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBwYWdlIC0gUHVwcGV0ZWVyIHBhZ2Ugb2JqZWN0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxzdHJpbmc+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgU1ZHIHN0cmluZy5cclxuICovXHJcbmNvbnN0IGNyZWF0ZVNWRyA9IChwYWdlKSA9PlxyXG4gIHBhZ2UuJGV2YWwoJyNjb250YWluZXIgc3ZnOmZpcnN0LW9mLXR5cGUnLCAoZWxlbWVudCkgPT4gZWxlbWVudC5vdXRlckhUTUwpO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIHNwZWNpZmllZCBjaGFydCBhbmQgb3B0aW9ucyBhcyBjb25maWd1cmF0aW9uIGludG8gdGhlIHRyaWdnZXJFeHBvcnRcclxuICogZnVuY3Rpb24gd2l0aGluIHRoZSB3aW5kb3cgY29udGV4dCB1c2luZyBwYWdlLmV2YWx1YXRlLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gcGFnZSAtIFB1cHBldGVlciBwYWdlIG9iamVjdC5cclxuICogQHBhcmFtIHthbnl9IGNoYXJ0IC0gVGhlIGNoYXJ0IG9iamVjdCB0byBiZSBjb25maWd1cmVkLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGNoYXJ0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gUHJvbWlzZSByZXNvbHZpbmcgYWZ0ZXIgdGhlIGNvbmZpZ3VyYXRpb24gaXMgc2V0LlxyXG4gKi9cclxuY29uc3Qgc2V0QXNDb25maWcgPSBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMsIGRpc3BsYXlFcnJvcnMpID0+XHJcbiAgcGFnZS5ldmFsdWF0ZSh0cmlnZ2VyRXhwb3J0LCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcblxyXG4vKipcclxuICogRXhwb3J0cyB0byBhIGNoYXJ0IGZyb20gYSBwYWdlIHVzaW5nIFB1cHBldGVlci5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHBhZ2UgLSBQdXBwZXRlZXIgcGFnZSBvYmplY3QuXHJcbiAqIEBwYXJhbSB7YW55fSBjaGFydCAtIFRoZSBjaGFydCBvYmplY3Qgb3IgU1ZHIGNvbmZpZ3VyYXRpb24gdG8gYmUgZXhwb3J0ZWQuXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gRXhwb3J0IG9wdGlvbnMgYW5kIGNvbmZpZ3VyYXRpb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHN0cmluZyB8IEJ1ZmZlciB8IEV4cG9ydEVycm9yPn0gUHJvbWlzZSByZXNvbHZpbmcgdG9cclxuICogdGhlIGV4cG9ydGVkIGRhdGEgb3IgcmVqZWN0aW5nIHdpdGggYW4gRXhwb3J0RXJyb3IuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBhc3luYyAocGFnZSwgY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICAvLyBJbmplY3RlZCByZXNvdXJjZXMgYXJyYXkgKGFkZGl0aW9uYWwgSlMgYW5kIENTUylcclxuICBsZXQgaW5qZWN0ZWRSZXNvdXJjZXMgPSBbXTtcclxuXHJcbiAgdHJ5IHtcclxuICAgIGxvZyg0LCAnW2V4cG9ydF0gRGV0ZXJtaW5pbmcgZXhwb3J0IHBhdGguJyk7XHJcblxyXG4gICAgY29uc3QgZXhwb3J0T3B0aW9ucyA9IG9wdGlvbnMuZXhwb3J0O1xyXG5cclxuICAgIC8vIERlY2lkZSB3aGV0aGVyIGRpc3BsYXkgZXJyb3Igb3IgZGViYnVnZXIgd3JhcHBlciBhcm91bmQgaXRcclxuICAgIGNvbnN0IGRpc3BsYXlFcnJvcnMgPVxyXG4gICAgICBleHBvcnRPcHRpb25zPy5vcHRpb25zPy5jaGFydD8uZGlzcGxheUVycm9ycyAmJlxyXG4gICAgICBnZXRDYWNoZSgpLmFjdGl2ZU1hbmlmZXN0Lm1vZHVsZXMuZGVidWdnZXI7XHJcblxyXG4gICAgbGV0IGlzU1ZHO1xyXG4gICAgaWYgKFxyXG4gICAgICBjaGFydC5pbmRleE9mICYmXHJcbiAgICAgIChjaGFydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fCBjaGFydC5pbmRleE9mKCc8P3htbCcpID49IDApXHJcbiAgICApIHtcclxuICAgICAgLy8gU1ZHIGlucHV0IGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgU1ZHLicpO1xyXG5cclxuICAgICAgLy8gSWYgaW5wdXQgaXMgYWxzbyBTVkcsIGp1c3QgcmV0dXJuIGl0XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zLnR5cGUgPT09ICdzdmcnKSB7XHJcbiAgICAgICAgcmV0dXJuIGNoYXJ0O1xyXG4gICAgICB9XHJcblxyXG4gICAgICBpc1NWRyA9IHRydWU7XHJcbiAgICAgIGF3YWl0IHBhZ2Uuc2V0Q29udGVudChzdmdUZW1wbGF0ZShjaGFydCksIHtcclxuICAgICAgICB3YWl0VW50aWw6ICdkb21jb250ZW50bG9hZGVkJ1xyXG4gICAgICB9KTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIC8vIEpTT04gY29uZmlnIGhhbmRsaW5nXHJcbiAgICAgIGxvZyg0LCAnW2V4cG9ydF0gVHJlYXRpbmcgYXMgY29uZmlnLicpO1xyXG5cclxuICAgICAgLy8gTmVlZCB0byBwZXJmb3JtIHN0cmFpZ2h0IGluamVjdFxyXG4gICAgICBpZiAoZXhwb3J0T3B0aW9ucy5zdHJJbmopIHtcclxuICAgICAgICAvLyBJbmplY3Rpb24gYmFzZWQgY29uZmlndXJhdGlvbiBleHBvcnRcclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhcclxuICAgICAgICAgIHBhZ2UsXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIGNoYXJ0OiB7XHJcbiAgICAgICAgICAgICAgaGVpZ2h0OiBleHBvcnRPcHRpb25zLmhlaWdodCxcclxuICAgICAgICAgICAgICB3aWR0aDogZXhwb3J0T3B0aW9ucy53aWR0aFxyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9LFxyXG4gICAgICAgICAgb3B0aW9ucyxcclxuICAgICAgICAgIGRpc3BsYXlFcnJvcnNcclxuICAgICAgICApO1xyXG4gICAgICB9IGVsc2Uge1xyXG4gICAgICAgIC8vIEJhc2ljIGNvbmZpZ3VyYXRpb24gZXhwb3J0XHJcbiAgICAgICAgY2hhcnQuY2hhcnQuaGVpZ2h0ID0gZXhwb3J0T3B0aW9ucy5oZWlnaHQ7XHJcbiAgICAgICAgY2hhcnQuY2hhcnQud2lkdGggPSBleHBvcnRPcHRpb25zLndpZHRoO1xyXG5cclxuICAgICAgICBhd2FpdCBzZXRBc0NvbmZpZyhwYWdlLCBjaGFydCwgb3B0aW9ucywgZGlzcGxheUVycm9ycyk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICAvLyBLZWVwcyB0cmFjayBvZiBhbGwgcmVzb3VyY2VzIGFkZGVkIG9uIHRoZSBwYWdlIHdpdGggYWRkWFhYVGFnLiBldGNcclxuICAgIC8vIEl0J3MgVklUQUwgdGhhdCBhbGwgYWRkZWQgcmVzb3VyY2VzIGVuZHMgdXAgaGVyZSBzbyB3ZSBjYW4gY2xlYXIgdGhpbmdzXHJcbiAgICAvLyBvdXQgd2hlbiBkb2luZyBhIG5ldyBleHBvcnQgaW4gdGhlIHNhbWUgcGFnZSFcclxuICAgIGluamVjdGVkUmVzb3VyY2VzID0gYXdhaXQgYWRkUGFnZVJlc291cmNlcyhwYWdlLCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIHJlYWwgY2hhcnQgc2l6ZSBhbmQgc2V0IHRoZSB6b29tIGFjY29yZGluZ2x5XHJcbiAgICBjb25zdCBzaXplID0gaXNTVkdcclxuICAgICAgPyBhd2FpdCBwYWdlLmV2YWx1YXRlKChzY2FsZSkgPT4ge1xyXG4gICAgICAgICAgY29uc3Qgc3ZnRWxlbWVudCA9IGRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoXHJcbiAgICAgICAgICAgICcjY2hhcnQtY29udGFpbmVyIHN2ZzpmaXJzdC1vZi10eXBlJ1xyXG4gICAgICAgICAgKTtcclxuXHJcbiAgICAgICAgICAvLyBHZXQgdGhlIHZhbHVlcyBjb3JyZWN0bHkgc2NhbGVkXHJcbiAgICAgICAgICBjb25zdCBjaGFydEhlaWdodCA9IHN2Z0VsZW1lbnQuaGVpZ2h0LmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuICAgICAgICAgIGNvbnN0IGNoYXJ0V2lkdGggPSBzdmdFbGVtZW50LndpZHRoLmJhc2VWYWwudmFsdWUgKiBzY2FsZTtcclxuXHJcbiAgICAgICAgICAvLyBJbiBjYXNlIG9mIFNWRyB0aGUgem9vbSBtdXN0IGJlIHNldCBkaXJlY3RseSBmb3IgYm9keVxyXG4gICAgICAgICAgLy8gU2V0IHRoZSB6b29tIGFzIHNjYWxlXHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuem9vbSA9IHNjYWxlO1xyXG5cclxuICAgICAgICAgIC8vIFNldCB0aGUgbWFyZ2luIHRvIDBweFxyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLm1hcmdpbiA9ICcwcHgnO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0sIHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSkpXHJcbiAgICAgIDogYXdhaXQgcGFnZS5ldmFsdWF0ZSgoKSA9PiB7XHJcbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbm8tdW5kZWZcclxuICAgICAgICAgIGNvbnN0IHsgY2hhcnRIZWlnaHQsIGNoYXJ0V2lkdGggfSA9IHdpbmRvdy5IaWdoY2hhcnRzLmNoYXJ0c1swXTtcclxuXHJcbiAgICAgICAgICAvLyBObyBuZWVkIGZvciBzdWNoIHNjYWxlIG1hbmlwdWxhdGlvbiBpbiBjYXNlIG9mIG90aGVyIHR5cGVzIG9mIGV4cG9ydHNcclxuICAgICAgICAgIC8vIFJlc2V0IHRoZSB6b29tIGZvciBvdGhlciBleHBvcnRzIHRoYW4gdG8gU1ZHc1xyXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5vLXVuZGVmXHJcbiAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLnpvb20gPSAxO1xyXG5cclxuICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGNoYXJ0SGVpZ2h0LFxyXG4gICAgICAgICAgICBjaGFydFdpZHRoXHJcbiAgICAgICAgICB9O1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgIC8vIFNldCBmaW5hbCBoZWlnaHQgYW5kIHdpZHRoIGZvciB2aWV3cG9ydFxyXG4gICAgY29uc3Qgdmlld3BvcnRIZWlnaHQgPSBNYXRoLmNlaWwoc2l6ZS5jaGFydEhlaWdodCB8fCBleHBvcnRPcHRpb25zLmhlaWdodCk7XHJcbiAgICBjb25zdCB2aWV3cG9ydFdpZHRoID0gTWF0aC5jZWlsKHNpemUuY2hhcnRXaWR0aCB8fCBleHBvcnRPcHRpb25zLndpZHRoKTtcclxuXHJcbiAgICAvLyBHZXQgdGhlIGNsaXAgcmVnaW9uIGZvciB0aGUgcGFnZVxyXG4gICAgY29uc3QgeyB4LCB5IH0gPSBhd2FpdCBnZXRDbGlwUmVnaW9uKHBhZ2UpO1xyXG5cclxuICAgIC8vIFNldCB0aGUgZmluYWwgdmlld3BvcnQgbm93IHRoYXQgd2UgaGF2ZSB0aGUgcmVhbCBoZWlnaHRcclxuICAgIGF3YWl0IHBhZ2Uuc2V0Vmlld3BvcnQoe1xyXG4gICAgICBoZWlnaHQ6IHZpZXdwb3J0SGVpZ2h0LFxyXG4gICAgICB3aWR0aDogdmlld3BvcnRXaWR0aCxcclxuICAgICAgZGV2aWNlU2NhbGVGYWN0b3I6IGlzU1ZHID8gMSA6IHBhcnNlRmxvYXQoZXhwb3J0T3B0aW9ucy5zY2FsZSlcclxuICAgIH0pO1xyXG5cclxuICAgIGxldCBkYXRhO1xyXG4gICAgLy8gUmFzdGVyaXphdGlvbiBwcm9jZXNzXHJcbiAgICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgICAvLyBTVkdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZVNWRyhwYWdlKTtcclxuICAgIH0gZWxzZSBpZiAoWydwbmcnLCAnanBlZyddLmluY2x1ZGVzKGV4cG9ydE9wdGlvbnMudHlwZSkpIHtcclxuICAgICAgLy8gUE5HIG9yIEpQRUdcclxuICAgICAgZGF0YSA9IGF3YWl0IGNyZWF0ZUltYWdlKFxyXG4gICAgICAgIHBhZ2UsXHJcbiAgICAgICAgZXhwb3J0T3B0aW9ucy50eXBlLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIHtcclxuICAgICAgICAgIHdpZHRoOiB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICAgaGVpZ2h0OiB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICAgIHgsXHJcbiAgICAgICAgICB5XHJcbiAgICAgICAgfSxcclxuICAgICAgICBleHBvcnRPcHRpb25zLnJhc3Rlcml6YXRpb25UaW1lb3V0XHJcbiAgICAgICk7XHJcbiAgICB9IGVsc2UgaWYgKGV4cG9ydE9wdGlvbnMudHlwZSA9PT0gJ3BkZicpIHtcclxuICAgICAgLy8gUERGXHJcbiAgICAgIGRhdGEgPSBhd2FpdCBjcmVhdGVQREYoXHJcbiAgICAgICAgcGFnZSxcclxuICAgICAgICB2aWV3cG9ydEhlaWdodCxcclxuICAgICAgICB2aWV3cG9ydFdpZHRoLFxyXG4gICAgICAgICdiYXNlNjQnLFxyXG4gICAgICAgIGV4cG9ydE9wdGlvbnMucmFzdGVyaXphdGlvblRpbWVvdXRcclxuICAgICAgKTtcclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2V4cG9ydF0gVW5zdXBwb3J0ZWQgb3V0cHV0IGZvcm1hdCAke2V4cG9ydE9wdGlvbnMudHlwZX0uYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIENsZWFyIHByZXZpb3VzbHkgaW5qZWN0ZWQgSlMgYW5kIENTUyByZXNvdXJjZXNcclxuICAgIGF3YWl0IGNsZWFyUGFnZVJlc291cmNlcyhwYWdlLCBpbmplY3RlZFJlc291cmNlcyk7XHJcbiAgICByZXR1cm4gZGF0YTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgYXdhaXQgY2xlYXJQYWdlUmVzb3VyY2VzKHBhZ2UsIGluamVjdGVkUmVzb3VyY2VzKTtcclxuICAgIHJldHVybiBlcnJvcjtcclxuICB9XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IGNzc1RlbXBsYXRlIGZyb20gJy4vY3NzLmpzJztcclxuXHJcbmV4cG9ydCBkZWZhdWx0IChjaGFydCkgPT4gYFxyXG48IURPQ1RZUEUgaHRtbD5cclxuPGh0bWwgbGFuZz0nZW4tVVMnPlxyXG4gIDxoZWFkPlxyXG4gICAgPG1ldGEgaHR0cC1lcXVpdj1cIkNvbnRlbnQtVHlwZVwiIGNvbnRlbnQ9XCJ0ZXh0L2h0bWw7IGNoYXJzZXQ9dXRmLThcIj5cclxuICAgIDx0aXRsZT5IaWdoY2hhcnRzIEV4cG9ydDwvdGl0bGU+XHJcbiAgPC9oZWFkPlxyXG4gIDxzdHlsZT5cclxuICAgICR7Y3NzVGVtcGxhdGUoKX1cclxuICA8L3N0eWxlPlxyXG4gIDxib2R5PlxyXG4gICAgPGRpdiBpZD1cImNoYXJ0LWNvbnRhaW5lclwiPlxyXG4gICAgICAke2NoYXJ0fVxyXG4gICAgPC9kaXY+XHJcbiAgPC9ib2R5PlxyXG48L2h0bWw+XHJcblxyXG5gO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IFBvb2wgfSBmcm9tICd0YXJuJztcclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHtcclxuICBjcmVhdGUgYXMgY3JlYXRlQnJvd3NlcixcclxuICBjbG9zZSBhcyBjbG9zZUJyb3dzZXIsXHJcbiAgbmV3UGFnZSxcclxuICBjbGVhclBhZ2VcclxufSBmcm9tICcuL2Jyb3dzZXIuanMnO1xyXG5pbXBvcnQgcHVwcGV0ZWVyRXhwb3J0IGZyb20gJy4vZXhwb3J0LmpzJztcclxuaW1wb3J0IHsgbG9nLCBsb2dXaXRoU3RhY2sgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcbmltcG9ydCB7IG1lYXN1cmVUaW1lIH0gZnJvbSAnLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgRXhwb3J0RXJyb3IgZnJvbSAnLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gVGhlIHBvb2wgaW5zdGFuY2VcclxubGV0IHBvb2wgPSBmYWxzZTtcclxuXHJcbi8vIFBvb2wgc3RhdGlzdGljc1xyXG5leHBvcnQgY29uc3Qgc3RhdHMgPSB7XHJcbiAgcGVyZm9ybWVkRXhwb3J0czogMCxcclxuICBleHBvcnRBdHRlbXB0czogMCxcclxuICBleHBvcnRGcm9tU3ZnQXR0ZW1wdHM6IDAsXHJcbiAgdGltZVNwZW50OiAwLFxyXG4gIGRyb3BwZWRFeHBvcnRzOiAwLFxyXG4gIHNwZW50QXZlcmFnZTogMFxyXG59O1xyXG5cclxubGV0IHBvb2xDb25maWcgPSB7fTtcclxuXHJcbmNvbnN0IGZhY3RvcnkgPSB7XHJcbiAgLyoqXHJcbiAgICogQ3JlYXRlcyBhIG5ldyB3b3JrZXIgcGFnZSBmb3IgdGhlIGV4cG9ydCBwb29sLlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge09iamVjdH0gLSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd29ya2VyIElELCBhIHJlZmVyZW5jZSB0byB0aGVcclxuICAgKiBicm93c2VyIHBhZ2UsIGFuZCBpbml0aWFsIHdvcmsgY291bnQuXHJcbiAgICpcclxuICAgKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gLSBJZiB0aGVyZSdzIGFuIGVycm9yIGR1cmluZyB0aGUgY3JlYXRpb24gb2YgdGhlIG5ld1xyXG4gICAqIHBhZ2UuXHJcbiAgICovXHJcbiAgY3JlYXRlOiBhc3luYyAoKSA9PiB7XHJcbiAgICBsZXQgcGFnZSA9IGZhbHNlO1xyXG5cclxuICAgIGNvbnN0IGlkID0gdXVpZCgpO1xyXG4gICAgY29uc3Qgc3RhcnREYXRlID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XHJcblxyXG4gICAgdHJ5IHtcclxuICAgICAgcGFnZSA9IGF3YWl0IG5ld1BhZ2UoKTtcclxuXHJcbiAgICAgIGlmICghcGFnZSB8fCBwYWdlLmlzQ2xvc2VkKCkpIHtcclxuICAgICAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoJ1RoZSBwYWdlIGlzIGludmFsaWQgb3IgY2xvc2VkLicpO1xyXG4gICAgICB9XHJcblxyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFN1Y2Nlc3NmdWxseSBjcmVhdGVkIGEgd29ya2VyICR7aWR9IC0gdG9vayAke1xyXG4gICAgICAgICAgbmV3IERhdGUoKS5nZXRUaW1lKCkgLSBzdGFydERhdGVcclxuICAgICAgICB9IG1zLmBcclxuICAgICAgKTtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAnRXJyb3IgZW5jb3VudGVyZWQgd2hlbiBjcmVhdGluZyBhIG5ldyBwYWdlLidcclxuICAgICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHtcclxuICAgICAgaWQsXHJcbiAgICAgIHBhZ2UsXHJcbiAgICAgIC8vIFRyeSB0byBkaXN0cmlidXRlIHRoZSBpbml0aWFsIHdvcmsgY291bnRcclxuICAgICAgd29ya0NvdW50OiBNYXRoLnJvdW5kKE1hdGgucmFuZG9tKCkgKiAocG9vbENvbmZpZy53b3JrTGltaXQgLyAyKSlcclxuICAgIH07XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogVmFsaWRhdGVzIGEgd29ya2VyIHBhZ2UgaW4gdGhlIGV4cG9ydCBwb29sLCBjaGVja2luZyBpZiBpdCBoYXMgZXhjZWVkZWRcclxuICAgKiB0aGUgd29yayBsaW1pdC5cclxuICAgKlxyXG4gICAqIEBwYXJhbSB7T2JqZWN0fSB3b3JrZXJIYW5kbGUgLSBUaGUgaGFuZGxlIHRvIHRoZSB3b3JrZXIsIGNvbnRhaW5pbmcgdGhlXHJcbiAgICogd29ya2VyJ3MgSUQsIGEgcmVmZXJlbmNlIHRvIHRoZSBicm93c2VyIHBhZ2UsIGFuZCB3b3JrIGNvdW50LlxyXG4gICAqXHJcbiAgICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyB0cnVlIGlmIHRoZSB3b3JrZXIgaXMgdmFsaWQgYW5kIHdpdGhpblxyXG4gICAqIHRoZSB3b3JrIGxpbWl0OyBvdGhlcndpc2UsIHJldHVybnMgZmFsc2UuXHJcbiAgICovXHJcbiAgdmFsaWRhdGU6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGlmIChcclxuICAgICAgcG9vbENvbmZpZy53b3JrTGltaXQgJiZcclxuICAgICAgKyt3b3JrZXJIYW5kbGUud29ya0NvdW50ID4gcG9vbENvbmZpZy53b3JrTGltaXRcclxuICAgICkge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMyxcclxuICAgICAgICBgW3Bvb2xdIFdvcmtlciBmYWlsZWQgdmFsaWRhdGlvbjogZXhjZWVkZWQgd29yayBsaW1pdCAobGltaXQgaXMgJHtwb29sQ29uZmlnLndvcmtMaW1pdH0pLmBcclxuICAgICAgKTtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRydWU7XHJcbiAgfSxcclxuXHJcbiAgLyoqXHJcbiAgICogRGVzdHJveXMgYSB3b3JrZXIgZW50cnkgaW4gdGhlIGV4cG9ydCBwb29sLCBjbG9zaW5nIGl0cyBhc3NvY2lhdGVkIHBhZ2UuXHJcbiAgICpcclxuICAgKiBAcGFyYW0ge09iamVjdH0gd29ya2VySGFuZGxlIC0gVGhlIGhhbmRsZSB0byB0aGUgd29ya2VyLCBjb250YWluaW5nXHJcbiAgICogdGhlIHdvcmtlcidzIElEIGFuZCBhIHJlZmVyZW5jZSB0byB0aGUgYnJvd3NlciBwYWdlLlxyXG4gICAqL1xyXG4gIGRlc3Ryb3k6IGFzeW5jICh3b3JrZXJIYW5kbGUpID0+IHtcclxuICAgIGxvZygzLCBgW3Bvb2xdIERlc3Ryb3lpbmcgcG9vbCBlbnRyeSAke3dvcmtlckhhbmRsZS5pZH0uYCk7XHJcblxyXG4gICAgaWYgKHdvcmtlckhhbmRsZS5wYWdlKSB7XHJcbiAgICAgIC8vIFdlIGRvbid0IHJlYWxseSBuZWVkIHRvIHdhaXQgYXJvdW5kIGZvciB0aGlzXHJcbiAgICAgIGF3YWl0IHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICB9XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEluaXRpYWxpemVzIHRoZSBleHBvcnQgcG9vbCB3aXRoIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLCBjcmVhdGluZ1xyXG4gKiBhIGJyb3dzZXIgaW5zdGFuY2UgYW5kIHNldHRpbmcgdXAgd29ya2VyIHJlc291cmNlcy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IGNvbmZpZyAtIENvbmZpZ3VyYXRpb24gb3B0aW9ucyBmb3IgdGhlIGV4cG9ydCBwb29sIGFsb25nXHJcbiAqIHdpdGggY3VzdG9tIHB1cHBldGVlciBhcmd1bWVudHMgZm9yIHRoZSBwdXBwZXRlZXIubGF1bmNoIGZ1bmN0aW9uLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGluaXRQb29sID0gYXN5bmMgKGNvbmZpZykgPT4ge1xyXG4gIC8vIEZvciB0aGUgbW9kdWxlIHNjb3BlIHVzYWdlXHJcbiAgcG9vbENvbmZpZyA9IGNvbmZpZyAmJiBjb25maWcucG9vbCA/IHsgLi4uY29uZmlnLnBvb2wgfSA6IHt9O1xyXG5cclxuICAvLyBDcmVhdGUgYSBicm93c2VyIGluc3RhbmNlIHdpdGggdGhlIHB1cHBldGVlciBhcmd1bWVudHNcclxuICBhd2FpdCBjcmVhdGVCcm93c2VyKGNvbmZpZy5wdXBwZXRlZXJBcmdzKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcG9vbF0gSW5pdGlhbGl6aW5nIHBvb2wgd2l0aCB3b3JrZXJzOiBtaW4gJHtwb29sQ29uZmlnLm1pbldvcmtlcnN9LCBtYXggJHtwb29sQ29uZmlnLm1heFdvcmtlcnN9LmBcclxuICApO1xyXG5cclxuICBpZiAocG9vbCkge1xyXG4gICAgcmV0dXJuIGxvZyhcclxuICAgICAgNCxcclxuICAgICAgJ1twb29sXSBBbHJlYWR5IGluaXRpYWxpemVkLCBwbGVhc2Uga2lsbCBpdCBiZWZvcmUgY3JlYXRpbmcgYSBuZXcgb25lLidcclxuICAgICk7XHJcbiAgfVxyXG5cclxuICBpZiAocGFyc2VJbnQocG9vbENvbmZpZy5taW5Xb3JrZXJzKSA+IHBhcnNlSW50KHBvb2xDb25maWcubWF4V29ya2VycykpIHtcclxuICAgIHBvb2xDb25maWcubWluV29ya2VycyA9IHBvb2xDb25maWcubWF4V29ya2VycztcclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBDcmVhdGUgYSBwb29sIGFsb25nIHdpdGggYSBtaW5pbWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIHBvb2wgPSBuZXcgUG9vbCh7XHJcbiAgICAgIC8vIEdldCB0aGUgY3JlYXRlL3ZhbGlkYXRlL2Rlc3Ryb3kvbG9nIGZ1bmN0aW9uc1xyXG4gICAgICAuLi5mYWN0b3J5LFxyXG4gICAgICBtaW46IHBhcnNlSW50KHBvb2xDb25maWcubWluV29ya2VycyksXHJcbiAgICAgIG1heDogcGFyc2VJbnQocG9vbENvbmZpZy5tYXhXb3JrZXJzKSxcclxuICAgICAgYWNxdWlyZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuYWNxdWlyZVRpbWVvdXQsXHJcbiAgICAgIGNyZWF0ZVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuY3JlYXRlVGltZW91dCxcclxuICAgICAgZGVzdHJveVRpbWVvdXRNaWxsaXM6IHBvb2xDb25maWcuZGVzdHJveVRpbWVvdXQsXHJcbiAgICAgIGlkbGVUaW1lb3V0TWlsbGlzOiBwb29sQ29uZmlnLmlkbGVUaW1lb3V0LFxyXG4gICAgICBjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzOiBwb29sQ29uZmlnLmNyZWF0ZVJldHJ5SW50ZXJ2YWwsXHJcbiAgICAgIHJlYXBJbnRlcnZhbE1pbGxpczogcG9vbENvbmZpZy5yZWFwZXJJbnRlcnZhbCxcclxuICAgICAgcHJvcGFnYXRlQ3JlYXRlRXJyb3I6IGZhbHNlXHJcbiAgICB9KTtcclxuXHJcbiAgICAvLyBTZXQgZXZlbnRzXHJcbiAgICBwb29sLm9uKCdyZWxlYXNlJywgYXN5bmMgKHJlc291cmNlKSA9PiB7XHJcbiAgICAgIC8vIENsZWFyIHBhZ2VcclxuICAgICAgYXdhaXQgY2xlYXJQYWdlKHJlc291cmNlLnBhZ2UsIGZhbHNlKTtcclxuICAgICAgbG9nKDQsIGBbcG9vbF0gUmVsZWFzaW5nIGEgd29ya2VyIHdpdGggSUQgJHtyZXNvdXJjZS5pZH0uYCk7XHJcbiAgICB9KTtcclxuXHJcbiAgICBwb29sLm9uKCdkZXN0cm95U3VjY2VzcycsIChldmVudElkLCByZXNvdXJjZSkgPT4ge1xyXG4gICAgICBsb2coNCwgYFtwb29sXSBEZXN0cm95ZWQgYSB3b3JrZXIgd2l0aCBJRCAke3Jlc291cmNlLmlkfS5gKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGNvbnN0IGluaXRpYWxSZXNvdXJjZXMgPSBbXTtcclxuICAgIC8vIENyZWF0ZSBhbiBpbml0aWFsIG51bWJlciBvZiByZXNvdXJjZXNcclxuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgcG9vbENvbmZpZy5taW5Xb3JrZXJzOyBpKyspIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZSA9IGF3YWl0IHBvb2wuYWNxdWlyZSgpLnByb21pc2U7XHJcbiAgICAgICAgaW5pdGlhbFJlc291cmNlcy5wdXNoKHJlc291cmNlKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsICdbcG9vbF0gQ291bGQgbm90IGNyZWF0ZSBhbiBpbml0aWFsIHJlc291cmNlLicpO1xyXG4gICAgICB9XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVsZWFzZSB0aGUgaW5pdGlhbCBudW1iZXIgb2YgcmVzb3VyY2VzIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIGluaXRpYWxSZXNvdXJjZXMuZm9yRWFjaCgocmVzb3VyY2UpID0+IHtcclxuICAgICAgcG9vbC5yZWxlYXNlKHJlc291cmNlKTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyhcclxuICAgICAgMyxcclxuICAgICAgYFtwb29sXSBUaGUgcG9vbCBpcyByZWFkeSR7aW5pdGlhbFJlc291cmNlcy5sZW5ndGggPyBgIHdpdGggJHtpbml0aWFsUmVzb3VyY2VzLmxlbmd0aH0gaW5pdGlhbCByZXNvdXJjZXMgd2FpdGluZy5gIDogJy4nfWBcclxuICAgICk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgJ1twb29sXSBDb3VsZCBub3QgY3JlYXRlIHRoZSBwb29sIG9mIHdvcmtlcnMuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIEtpbGxzIGFsbCB3b3JrZXJzIGluIHRoZSBwb29sLCBkZXN0cm95cyB0aGUgcG9vbCwgYW5kIGNsb3NlcyB0aGUgYnJvd3NlclxyXG4gKiBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IEEgcHJvbWlzZSB0aGF0IHJlc29sdmVzIGFmdGVyIHRoZSB3b3JrZXJzIGFyZVxyXG4gKiBraWxsZWQsIHRoZSBwb29sIGlzIGRlc3Ryb3llZCwgYW5kIHRoZSBicm93c2VyIGlzIGNsb3NlZC5cclxuICovXHJcbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBraWxsUG9vbCgpIHtcclxuICBsb2coMywgJ1twb29sXSBLaWxsaW5nIHBvb2wgd2l0aCBhbGwgd29ya2VycyBhbmQgY2xvc2luZyBicm93c2VyLicpO1xyXG5cclxuICAvLyBJZiBzdGlsbCBhbGl2ZSwgZGVzdHJveSB0aGUgcG9vbCBvZiBwYWdlcyBiZWZvcmUgY2xvc2luZyBhIGJyb3dzZXJcclxuICBpZiAocG9vbCkge1xyXG4gICAgLy8gRnJlZSB1cCBub3QgcmVsZWFzZWQgd29ya2Vyc1xyXG4gICAgZm9yIChjb25zdCB3b3JrZXIgb2YgcG9vbC51c2VkKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXIucmVzb3VyY2UpO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIERlc3Ryb3kgdGhlIHBvb2wgaWYgaXQgaXMgc3RpbGwgYXZhaWxhYmxlXHJcbiAgICBpZiAoIXBvb2wuZGVzdHJveWVkKSB7XHJcbiAgICAgIGF3YWl0IHBvb2wuZGVzdHJveSgpO1xyXG4gICAgICBsb2coNCwgJ1ticm93c2VyXSBEZXN0cm95ZWQgdGhlIHBvb2wgb2YgcmVzb3VyY2VzLicpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gQ2xvc2UgdGhlIGJyb3dzZXIgaW5zdGFuY2VcclxuICBhd2FpdCBjbG9zZUJyb3dzZXIoKTtcclxufVxyXG5cclxuLyoqXHJcbiAqIFByb2Nlc3NlcyB0aGUgZXhwb3J0IHdvcmsgdXNpbmcgYSB3b3JrZXIgZnJvbSB0aGUgcG9vbC4gQWNxdWlyZXMgYSB3b3JrZXJcclxuICogaGFuZGxlIGZyb20gdGhlIHBvb2wsIHBlcmZvcm1zIHRoZSBleHBvcnQgdXNpbmcgcHVwcGV0ZWVyLCBhbmQgcmVsZWFzZXNcclxuICogdGhlIHdvcmtlciBoYW5kbGUgYmFjayB0byB0aGUgcG9vbC5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IGNoYXJ0IC0gVGhlIGNoYXJ0IGRhdGEgb3IgY29uZmlndXJhdGlvbiB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucyBhbmQgY29uZmlndXJhdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8T2JqZWN0Pn0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgd2l0aCB0aGUgZXhwb3J0IHJlc3VsdGFuZFxyXG4gKiBvcHRpb25zLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gSWYgYW4gZXJyb3Igb2NjdXJzIGR1cmluZyB0aGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgcG9zdFdvcmsgPSBhc3luYyAoY2hhcnQsIG9wdGlvbnMpID0+IHtcclxuICBsZXQgd29ya2VySGFuZGxlO1xyXG5cclxuICB0cnkge1xyXG4gICAgbG9nKDQsICdbcG9vbF0gV29yayByZWNlaXZlZCwgc3RhcnRpbmcgdG8gcHJvY2Vzcy4nKTtcclxuXHJcbiAgICArK3N0YXRzLmV4cG9ydEF0dGVtcHRzO1xyXG4gICAgaWYgKHBvb2xDb25maWcuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGdldFBvb2xJbmZvKCk7XHJcbiAgICB9XHJcblxyXG4gICAgaWYgKCFwb29sKSB7XHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcignV29yayByZWNlaXZlZCwgYnV0IHBvb2wgaGFzIG5vdCBiZWVuIHN0YXJ0ZWQuJyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWNxdWlyZSB0aGUgd29ya2VyIGFsb25nIHdpdGggdGhlIGlkIG9mIHJlc291cmNlIGFuZCB3b3JrIGNvdW50XHJcbiAgICBjb25zdCBhY3F1aXJlQ291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1twb29sXSBBY3F1aXJpbmcgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG4gICAgICB3b3JrZXJIYW5kbGUgPSBhd2FpdCBwb29sLmFjcXVpcmUoKS5wcm9taXNlO1xyXG5cclxuICAgICAgLy8gQ2hlY2sgdGhlIHBhZ2UgYWNxdWlyZSB0aW1lXHJcbiAgICAgIGlmIChvcHRpb25zLnNlcnZlci5iZW5jaG1hcmtpbmcpIHtcclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICA1LFxyXG4gICAgICAgICAgb3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgICAgPyBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7b3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWR9IC1gXHJcbiAgICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICAgIGBBY3F1aXJlZCBhIHdvcmtlciBoYW5kbGU6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgIChvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZFxyXG4gICAgICAgICAgPyBgRm9yIHJlcXVlc3Qgd2l0aCBJRCAke29wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkfSAtIGBcclxuICAgICAgICAgIDogJycpICtcclxuICAgICAgICAgIGBFcnJvciBlbmNvdW50ZXJlZCB3aGVuIGFjcXVpcmluZyBhbiBhdmFpbGFibGUgZW50cnk6ICR7YWNxdWlyZUNvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgfVxyXG4gICAgbG9nKDQsICdbcG9vbF0gQWNxdWlyZWQgYSB3b3JrZXIgaGFuZGxlLicpO1xyXG5cclxuICAgIGlmICghd29ya2VySGFuZGxlLnBhZ2UpIHtcclxuICAgICAgdGhyb3cgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICdSZXNvbHZlZCB3b3JrZXIgcGFnZSBpcyBpbnZhbGlkOiB0aGUgcG9vbCBzZXR1cCBpcyB3b25reS4nXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgc3RhcnQgdGltZVxyXG4gICAgbGV0IHdvcmtTdGFydCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xyXG5cclxuICAgIGxvZyg0LCBgW3Bvb2xdIFN0YXJ0aW5nIHdvcmsgb24gcG9vbCBlbnRyeSB3aXRoIElEICR7d29ya2VySGFuZGxlLmlkfS5gKTtcclxuXHJcbiAgICAvLyBQZXJmb3JtIGFuIGV4cG9ydCBvbiBhIHB1cHBldGVlciBsZXZlbFxyXG4gICAgY29uc3QgZXhwb3J0Q291bnRlciA9IG1lYXN1cmVUaW1lKCk7XHJcbiAgICBjb25zdCByZXN1bHQgPSBhd2FpdCBwdXBwZXRlZXJFeHBvcnQod29ya2VySGFuZGxlLnBhZ2UsIGNoYXJ0LCBvcHRpb25zKTtcclxuXHJcbiAgICAvLyBDaGVjayBpZiBpdCdzIGFuIGVycm9yXHJcbiAgICBpZiAocmVzdWx0IGluc3RhbmNlb2YgRXJyb3IpIHtcclxuICAgICAgLy8gVE9ETzogSWYgdGhlIGV4cG9ydCBmYWlsZWQgYmVjYXVzZSBwdXBwZXRlZXIgdGltZWQgb3V0LCB3ZSBuZWVkIHRvIGZvcmNlIGtpbGwgdGhlIHdvcmtlciBzbyB3ZSBnZXQgYSBuZXcgcGFnZS4gVGhhdCBuZWVkcyB0byBiZSBoYW5kbGVkIGJldHRlciB0aGFuIHRoaXMgaGFjay5cclxuICAgICAgaWYgKHJlc3VsdC5tZXNzYWdlID09PSAnUmFzdGVyaXphdGlvbiB0aW1lb3V0Jykge1xyXG4gICAgICAgIHdvcmtlckhhbmRsZS5wYWdlLmNsb3NlKCk7XHJcbiAgICAgICAgd29ya2VySGFuZGxlLnBhZ2UgPSBhd2FpdCBuZXdQYWdlKCk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICAob3B0aW9ucy5wYXlsb2FkPy5yZXF1ZXN0SWRcclxuICAgICAgICAgID8gYEZvciByZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLSBgXHJcbiAgICAgICAgICA6ICcnKSArIGBFcnJvciBlbmNvdW50ZXJlZCBkdXJpbmcgZXhwb3J0OiAke2V4cG9ydENvdW50ZXIoKX1tcy5gXHJcbiAgICAgICkuc2V0RXJyb3IocmVzdWx0KTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBDaGVjayB0aGUgUHVwcGV0ZWVyIGV4cG9ydCB0aW1lXHJcbiAgICBpZiAob3B0aW9ucy5zZXJ2ZXIuYmVuY2htYXJraW5nKSB7XHJcbiAgICAgIGxvZyhcclxuICAgICAgICA1LFxyXG4gICAgICAgIG9wdGlvbnMucGF5bG9hZD8ucmVxdWVzdElkXHJcbiAgICAgICAgICA/IGBbYmVuY2htYXJrXSBSZXF1ZXN0IHdpdGggSUQgJHtvcHRpb25zLnBheWxvYWQ/LnJlcXVlc3RJZH0gLWBcclxuICAgICAgICAgIDogJ1tiZW5jaG1hcmtdJyxcclxuICAgICAgICBgRXhwb3J0ZWQgYSBjaGFydCBzdWNlc3NmdWxseTogJHtleHBvcnRDb3VudGVyKCl9bXMuYFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFJlbGVhc2UgdGhlIHJlc291cmNlIGJhY2sgdG8gdGhlIHBvb2xcclxuICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG5cclxuICAgIC8vIFVzZWQgZm9yIHN0YXRpc3RpY3MgaW4gYXZlcmFnZVRpbWUgYW5kIHByb2Nlc3NlZFdvcmtDb3VudCwgd2hpY2hcclxuICAgIC8vIGluIHR1cm4gaXMgdXNlZCBieSB0aGUgL2hlYWx0aCByb3V0ZS5cclxuICAgIGNvbnN0IHdvcmtFbmQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcclxuICAgIGNvbnN0IGV4cG9ydFRpbWUgPSB3b3JrRW5kIC0gd29ya1N0YXJ0O1xyXG4gICAgc3RhdHMudGltZVNwZW50ICs9IGV4cG9ydFRpbWU7XHJcbiAgICBzdGF0cy5zcGVudEF2ZXJhZ2UgPSBzdGF0cy50aW1lU3BlbnQgLyArK3N0YXRzLnBlcmZvcm1lZEV4cG9ydHM7XHJcblxyXG4gICAgbG9nKDQsIGBbcG9vbF0gV29yayBjb21wbGV0ZWQgaW4gJHtleHBvcnRUaW1lfSBtcy5gKTtcclxuXHJcbiAgICAvLyBPdGhlcndpc2UgcmV0dXJuIHRoZSByZXN1bHRcclxuICAgIHJldHVybiB7XHJcbiAgICAgIHJlc3VsdCxcclxuICAgICAgb3B0aW9uc1xyXG4gICAgfTtcclxuICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgKytzdGF0cy5kcm9wcGVkRXhwb3J0cztcclxuXHJcbiAgICBpZiAod29ya2VySGFuZGxlKSB7XHJcbiAgICAgIHBvb2wucmVsZWFzZSh3b3JrZXJIYW5kbGUpO1xyXG4gICAgfVxyXG5cclxuICAgIHRocm93IG5ldyBFeHBvcnRFcnJvcihgW3Bvb2xdIEluIHBvb2wucG9zdFdvcms6ICR7ZXJyb3IubWVzc2FnZX1gKS5zZXRFcnJvcihcclxuICAgICAgZXJyb3JcclxuICAgICk7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFJldHJpZXZlcyB0aGUgY3VycmVudCBwb29sIGluc3RhbmNlLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7T2JqZWN0fG51bGx9IFRoZSBjdXJyZW50IHBvb2wgaW5zdGFuY2UgaWYgaW5pdGlhbGl6ZWQsIG9yIG51bGxcclxuICogaWYgdGhlIHBvb2wgaGFzIG5vdCBiZWVuIGNyZWF0ZWQuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0UG9vbCA9ICgpID0+IHBvb2w7XHJcblxyXG4vKipcclxuICogUmV0cmlldmVzIHBvb2wgaW5mb3JtYXRpb24gaW4gSlNPTiBmb3JtYXQsIGluY2x1ZGluZyBtaW5pbXVtIGFuZCBtYXhpbXVtXHJcbiAqIHdvcmtlcnMsIGF2YWlsYWJsZSB3b3JrZXJzLCB3b3JrZXJzIGluIHVzZSwgYW5kIHBlbmRpbmcgYWNxdWlyZSByZXF1ZXN0cy5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gUG9vbCBpbmZvcm1hdGlvbiBpbiBKU09OIGZvcm1hdC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXRQb29sSW5mb0pTT04gPSAoKSA9PiAoe1xyXG4gIG1pbjogcG9vbC5taW4sXHJcbiAgbWF4OiBwb29sLm1heCxcclxuICBhbGw6IHBvb2wubnVtRnJlZSgpICsgcG9vbC5udW1Vc2VkKCksXHJcbiAgYXZhaWxhYmxlOiBwb29sLm51bUZyZWUoKSxcclxuICB1c2VkOiBwb29sLm51bVVzZWQoKSxcclxuICBwZW5kaW5nOiBwb29sLm51bVBlbmRpbmdBY3F1aXJlcygpXHJcbn0pO1xyXG5cclxuLyoqXHJcbiAqIExvZ3MgaW5mb3JtYXRpb24gYWJvdXQgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIHBvb2wsIGluY2x1ZGluZyB0aGUgbWluaW11bVxyXG4gKiBhbmQgbWF4aW11bSB3b3JrZXJzLCBhdmFpbGFibGUgd29ya2Vycywgd29ya2VycyBpbiB1c2UsIGFuZCBwZW5kaW5nIGFjcXVpcmVcclxuICogcmVxdWVzdHMuXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24gZ2V0UG9vbEluZm8oKSB7XHJcbiAgY29uc3QgeyBtaW4sIG1heCwgYWxsLCBhdmFpbGFibGUsIHVzZWQsIHBlbmRpbmcgfSA9IGdldFBvb2xJbmZvSlNPTigpO1xyXG5cclxuICBsb2coNSwgYFtwb29sXSBUaGUgbWluaW11bSBudW1iZXIgb2YgcmVzb3VyY2VzIGFsbG93ZWQgYnkgcG9vbDogJHttaW59LmApO1xyXG4gIGxvZyg1LCBgW3Bvb2xdIFRoZSBtYXhpbXVtIG51bWJlciBvZiByZXNvdXJjZXMgYWxsb3dlZCBieSBwb29sOiAke21heH0uYCk7XHJcbiAgbG9nKDUsIGBbcG9vbF0gVGhlIG51bWJlciBvZiBhbGwgY3JlYXRlZCByZXNvdXJjZXM6ICR7YWxsfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGF2YWlsYWJsZSByZXNvdXJjZXM6ICR7YXZhaWxhYmxlfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIGFjcXVpcmVkIHJlc291cmNlczogJHt1c2VkfS5gKTtcclxuICBsb2coNSwgYFtwb29sXSBUaGUgbnVtYmVyIG9mIHJlc291cmNlcyB3YWl0aW5nIHRvIGJlIGFjcXVpcmVkOiAke3BlbmRpbmd9LmApO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgaW5pdFBvb2wsXHJcbiAga2lsbFBvb2wsXHJcbiAgcG9zdFdvcmssXHJcbiAgZ2V0UG9vbCxcclxuICBnZXRQb29sSW5mbyxcclxuICBnZXRQb29sSW5mb0pTT04sXHJcbiAgZ2V0U3RhdHM6ICgpID0+IHN0YXRzXHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgcmVhZEZpbGVTeW5jLCB3cml0ZUZpbGVTeW5jIH0gZnJvbSAnZnMnO1xyXG5cclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgaW5pdEV4cG9ydFNldHRpbmdzIH0gZnJvbSAnLi9jb25maWcuanMnO1xyXG5pbXBvcnQgeyBsb2csIGxvZ1dpdGhTdGFjayB9IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsga2lsbFBvb2wsIHBvc3RXb3JrLCBzdGF0cyB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7XHJcbiAgZml4VHlwZSxcclxuICBoYW5kbGVSZXNvdXJjZXMsXHJcbiAgaXNDb3JyZWN0SlNPTixcclxuICBvcHRpb25zU3RyaW5naWZ5LFxyXG4gIHJvdW5kTnVtYmVyLFxyXG4gIHRvQm9vbGVhbixcclxuICB3cmFwQXJvdW5kXHJcbn0gZnJvbSAnLi91dGlscy5qcyc7XHJcbmltcG9ydCB7IHNhbml0aXplIH0gZnJvbSAnLi9zYW5pdGl6ZS5qcyc7XHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuL2Vycm9ycy9FeHBvcnRFcnJvci5qcyc7XHJcblxyXG5sZXQgYWxsb3dDb2RlRXhlY3V0aW9uID0gZmFsc2U7XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIGV4cG9ydCBwcm9jZXNzLiBUaGUgYHNldHRpbmdzYCBjb250YWlucyBmaW5hbCBvcHRpb25zIGdhdGhlcmVkXHJcbiAqIGZyb20gYWxsIHBvc3NpYmxlIHNvdXJjZXMgKGNvbmZpZywgZW52LCBjbGksIGpzb24pLiBUaGUgYGVuZENhbGxiYWNrYCBpc1xyXG4gKiBjYWxsZWQgd2hlbiB0aGUgZXhwb3J0IGlzIGNvbXBsZXRlZCwgd2l0aCBhbiBlcnJvciBvYmplY3QgYXMgdGhlIGZpcnN0XHJcbiAqIGFyZ3VtZW50IGFuZCB0aGUgc2Vjb25kIGNvbnRhaW5pbmcgdGhlIGJhc2U2NCByZXNwcmVzZW50YXRpb24gb2YgYSBjaGFydC5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNldHRpbmdzIC0gVGhlIHNldHRpbmdzIG9iamVjdCBjb250YWluaW5nIGV4cG9ydFxyXG4gKiBjb25maWd1cmF0aW9uLlxyXG4gKiBAcGFyYW0ge2Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHVwb25cclxuICogZmluYWxpemluZyB3b3JrIG9yIHVwb24gZXJyb3Igb2NjdXJhbmNlIG9mIHRoZSBleHBvcnRpbmcgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge3ZvaWR9IFRoaXMgZnVuY3Rpb24gZG9lcyBub3QgcmV0dXJuIGEgdmFsdWUgZGlyZWN0bHk7IGluc3RlYWQsXHJcbiAqIGl0IGNvbW11bmljYXRlcyByZXN1bHRzIHZpYSB0aGUgZW5kQ2FsbGJhY2suXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRFeHBvcnQgPSBhc3luYyAoc2V0dGluZ3MsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgLy8gU3RhcnRpbmcgZXhwb3J0aW5nIHByb2Nlc3MgbWVzc2FnZVxyXG4gIGxvZyg0LCAnW2NoYXJ0XSBTdGFydGluZyB0aGUgZXhwb3J0aW5nIHByb2Nlc3MuJyk7XHJcblxyXG4gIC8vIEluaXRpYWxpemUgb3B0aW9uc1xyXG4gIGNvbnN0IG9wdGlvbnMgPSBpbml0RXhwb3J0U2V0dGluZ3Moc2V0dGluZ3MsIGdldE9wdGlvbnMoKSk7XHJcblxyXG4gIC8vIEdldCB0aGUgZXhwb3J0IG9wdGlvbnNcclxuICBjb25zdCBleHBvcnRPcHRpb25zID0gb3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gIC8vIElmIFNWRyBpcyBhbiBpbnB1dCAoYXJndW1lbnQgY2FuIGJlIHNlbnQgb25seSBieSB0aGUgcmVxdWVzdClcclxuICBpZiAob3B0aW9ucy5wYXlsb2FkPy5zdmcgJiYgb3B0aW9ucy5wYXlsb2FkLnN2ZyAhPT0gJycpIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGEgU1ZHIGlucHV0LicpO1xyXG5cclxuICAgICAgY29uc3QgcmVzdWx0ID0gZXhwb3J0QXNTdHJpbmcoXHJcbiAgICAgICAgc2FuaXRpemUob3B0aW9ucy5wYXlsb2FkLnN2ZyksIC8vICMyMDlcclxuICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgIGVuZENhbGxiYWNrXHJcbiAgICAgICk7XHJcblxyXG4gICAgICArK3N0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cztcclxuICAgICAgcmV0dXJuIHJlc3VsdDtcclxuICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoJ1tjaGFydF0gRXJyb3IgbG9hZGluZyBTVkcgaW5wdXQuJykuc2V0RXJyb3IoZXJyb3IpXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgfVxyXG5cclxuICAvLyBFeHBvcnQgdXNpbmcgb3B0aW9ucyBmcm9tIHRoZSBmaWxlXHJcbiAgaWYgKGV4cG9ydE9wdGlvbnMuaW5maWxlICYmIGV4cG9ydE9wdGlvbnMuaW5maWxlLmxlbmd0aCkge1xyXG4gICAgLy8gVHJ5IHRvIHJlYWQgdGhlIGZpbGUgdG8gZ2V0IHRoZSBzdHJpbmcgcmVwcmVzZW50YXRpb25cclxuICAgIHRyeSB7XHJcbiAgICAgIGxvZyg0LCAnW2NoYXJ0XSBBdHRlbXB0aW5nIHRvIGV4cG9ydCBmcm9tIGFuIGlucHV0IGZpbGUuJyk7XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Lmluc3RyID0gcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnMuaW5maWxlLCAndXRmOCcpO1xyXG4gICAgICByZXR1cm4gZXhwb3J0QXNTdHJpbmcob3B0aW9ucy5leHBvcnQuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgaW5wdXQgZmlsZS4nKS5zZXRFcnJvcihlcnJvcilcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEV4cG9ydCB3aXRoIG9wdGlvbnMgZnJvbSB0aGUgcmF3IHJlcHJlc2VudGF0aW9uXHJcbiAgaWYgKFxyXG4gICAgKGV4cG9ydE9wdGlvbnMuaW5zdHIgJiYgZXhwb3J0T3B0aW9ucy5pbnN0ciAhPT0gJycpIHx8XHJcbiAgICAoZXhwb3J0T3B0aW9ucy5vcHRpb25zICYmIGV4cG9ydE9wdGlvbnMub3B0aW9ucyAhPT0gJycpXHJcbiAgKSB7XHJcbiAgICB0cnkge1xyXG4gICAgICBsb2coNCwgJ1tjaGFydF0gQXR0ZW1wdGluZyB0byBleHBvcnQgZnJvbSBhIHJhdyBpbnB1dC4nKTtcclxuXHJcbiAgICAgIC8vIFBlcmZvcm0gYSBkaXJlY3QgaW5qZWN0IHdoZW4gZm9yY2VkXHJcbiAgICAgIGlmICh0b0Jvb2xlYW4ob3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICAgIHJldHVybiBkb1N0cmFpZ2h0SW5qZWN0KG9wdGlvbnMsIGVuZENhbGxiYWNrKTtcclxuICAgICAgfVxyXG5cclxuICAgICAgLy8gRWl0aGVyIHRyeSB0byBwYXJzZSB0byBKU09OIGZpcnN0IG9yIGRvIHRoZSBkaXJlY3QgZXhwb3J0XHJcbiAgICAgIHJldHVybiB0eXBlb2YgZXhwb3J0T3B0aW9ucy5pbnN0ciA9PT0gJ3N0cmluZydcclxuICAgICAgICA/IGV4cG9ydEFzU3RyaW5nKGV4cG9ydE9wdGlvbnMuaW5zdHIudHJpbSgpLCBvcHRpb25zLCBlbmRDYWxsYmFjaylcclxuICAgICAgICA6IGRvRXhwb3J0KFxyXG4gICAgICAgICAgICBvcHRpb25zLFxyXG4gICAgICAgICAgICBleHBvcnRPcHRpb25zLmluc3RyIHx8IGV4cG9ydE9wdGlvbnMub3B0aW9ucyxcclxuICAgICAgICAgICAgZW5kQ2FsbGJhY2tcclxuICAgICAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKCdbY2hhcnRdIEVycm9yIGxvYWRpbmcgcmF3IGlucHV0LicpLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gTm8gaW5wdXQgc3BlY2lmaWVkLCBwYXNzIGFuIGVycm9yIG1lc3NhZ2UgdG8gdGhlIGNhbGxiYWNrXHJcbiAgcmV0dXJuIGVuZENhbGxiYWNrKFxyXG4gICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICBgW2NoYXJ0XSBObyB2YWxpZCBpbnB1dCBzcGVjaWZpZWQuIENoZWNrIGlmIGF0IGxlYXN0IG9uZSBvZiB0aGUgZm9sbG93aW5nIHBhcmFtZXRlcnMgaXMgY29ycmVjdGx5IHNldDogJ2luZmlsZScsICdpbnN0cicsICdvcHRpb25zJywgb3IgJ3N2ZycuYFxyXG4gICAgKVxyXG4gICk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGEgYmF0Y2ggZXhwb3J0IHByb2Nlc3MgZm9yIG11bHRpcGxlIGNoYXJ0cyBiYXNlZCBvbiB0aGUgaW5mb3JtYXRpb25cclxuICogaW4gdGhlIGJhdGNoIG9wdGlvbi4gVGhlIGJhdGNoIGlzIGEgc3RyaW5nIGluIHRoZSBmb2xsb3dpbmcgZm9ybWF0OlxyXG4gKiBcImluZmlsZTEuanNvbj1vdXRmaWxlMS5wbmc7aW5maWxlMi5qc29uPW91dGZpbGUyLnBuZzsuLi5cIlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFRoZSBvcHRpb25zIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gZm9yXHJcbiAqIGEgYmF0Y2ggZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgYmF0Y2ggZXhwb3J0XHJcbiAqIHByb2Nlc3MgaXMgY29tcGxldGVkLlxyXG4gKlxyXG4gKiBAdGhyb3dzIHtFeHBvcnRFcnJvcn0gVGhyb3dzIGFuIEV4cG9ydEVycm9yIGlmIGFuIGVycm9yIG9jY3VycyBkdXJpbmdcclxuICogYW55IG9mIHRoZSBiYXRjaCBleHBvcnQgcHJvY2Vzcy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBiYXRjaEV4cG9ydCA9IGFzeW5jIChvcHRpb25zKSA9PiB7XHJcbiAgY29uc3QgYmF0Y2hGdW5jdGlvbnMgPSBbXTtcclxuXHJcbiAgLy8gU3BsaXQgYW5kIHBhaXIgdGhlIC0tYmF0Y2ggYXJndW1lbnRzXHJcbiAgZm9yIChsZXQgcGFpciBvZiBvcHRpb25zLmV4cG9ydC5iYXRjaC5zcGxpdCgnOycpKSB7XHJcbiAgICBwYWlyID0gcGFpci5zcGxpdCgnPScpO1xyXG4gICAgaWYgKHBhaXIubGVuZ3RoID09PSAyKSB7XHJcbiAgICAgIGJhdGNoRnVuY3Rpb25zLnB1c2goXHJcbiAgICAgICAgc3RhcnRFeHBvcnQoXHJcbiAgICAgICAgICB7XHJcbiAgICAgICAgICAgIC4uLm9wdGlvbnMsXHJcbiAgICAgICAgICAgIGV4cG9ydDoge1xyXG4gICAgICAgICAgICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgICAgICAgICAgIGluZmlsZTogcGFpclswXSxcclxuICAgICAgICAgICAgICBvdXRmaWxlOiBwYWlyWzFdXHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgIH0sXHJcbiAgICAgICAgICAoZXJyb3IsIGluZm8pID0+IHtcclxuICAgICAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3JcclxuICAgICAgICAgICAgaWYgKGVycm9yKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIFNhdmUgdGhlIGJhc2U2NCBmcm9tIGEgYnVmZmVyIHRvIGEgY29ycmVjdCBpbWFnZSBmaWxlXHJcbiAgICAgICAgICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgICAgICAgICAgaW5mby5vcHRpb25zLmV4cG9ydC5vdXRmaWxlLFxyXG4gICAgICAgICAgICAgIGluZm8ub3B0aW9ucy5leHBvcnQudHlwZSAhPT0gJ3N2ZydcclxuICAgICAgICAgICAgICAgID8gQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKVxyXG4gICAgICAgICAgICAgICAgOiBpbmZvLnJlc3VsdFxyXG4gICAgICAgICAgICApO1xyXG4gICAgICAgICAgfVxyXG4gICAgICAgIClcclxuICAgICAgKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIHRyeSB7XHJcbiAgICAvLyBBd2FpdCBhbGwgZXhwb3J0cyBhcmUgZG9uZVxyXG4gICAgYXdhaXQgUHJvbWlzZS5hbGwoYmF0Y2hGdW5jdGlvbnMpO1xyXG5cclxuICAgIC8vIEtpbGwgcG9vbCBhbmQgY2xvc2UgYnJvd3NlciBhZnRlciBmaW5pc2hpbmcgYmF0Y2ggZXhwb3J0XHJcbiAgICBhd2FpdCBraWxsUG9vbCgpO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbY2hhcnRdIEVycm9yIGVuY291bnRlcmVkIGR1cmluZyBiYXRjaCBleHBvcnQuJ1xyXG4gICAgKS5zZXRFcnJvcihlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFN0YXJ0cyBhIHNpbmdsZSBleHBvcnQgcHJvY2VzcyBiYXNlZCBvbiB0aGUgc3BlY2lmaWVkIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogYSBzaW5nbGUgZXhwb3J0LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTx2b2lkPn0gQSBQcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgc2luZ2xlIGV4cG9ydFxyXG4gKiBwcm9jZXNzIGlzIGNvbXBsZXRlZC5cclxuICpcclxuICogQHRocm93cyB7RXhwb3J0RXJyb3J9IFRocm93cyBhbiBFeHBvcnRFcnJvciBpZiBhbiBlcnJvciBvY2N1cnMgZHVyaW5nXHJcbiAqIHRoZSBzaW5nbGUgZXhwb3J0IHByb2Nlc3MuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2luZ2xlRXhwb3J0ID0gYXN5bmMgKG9wdGlvbnMpID0+IHtcclxuICAvLyBVc2UgaW5zdHIgb3IgaXRzIGFsaWFzLCBvcHRpb25zXHJcbiAgb3B0aW9ucy5leHBvcnQuaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAvLyBQZXJmb3JtIGFuIGV4cG9ydFxyXG4gIGF3YWl0IHN0YXJ0RXhwb3J0KG9wdGlvbnMsIGFzeW5jIChlcnJvciwgaW5mbykgPT4ge1xyXG4gICAgLy8gRXhpdCBwcm9jZXNzIHdoZW4gZXJyb3JcclxuICAgIGlmIChlcnJvcikge1xyXG4gICAgICB0aHJvdyBlcnJvcjtcclxuICAgIH1cclxuXHJcbiAgICBjb25zdCB7IG91dGZpbGUsIHR5cGUgfSA9IGluZm8ub3B0aW9ucy5leHBvcnQ7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgYmFzZTY0IGZyb20gYSBidWZmZXIgdG8gYSBjb3JyZWN0IGltYWdlIGZpbGVcclxuICAgIHdyaXRlRmlsZVN5bmMoXHJcbiAgICAgIG91dGZpbGUgfHwgYGNoYXJ0LiR7dHlwZX1gLFxyXG4gICAgICB0eXBlICE9PSAnc3ZnJyA/IEJ1ZmZlci5mcm9tKGluZm8ucmVzdWx0LCAnYmFzZTY0JykgOiBpbmZvLnJlc3VsdFxyXG4gICAgKTtcclxuXHJcbiAgICAvLyBLaWxsIHBvb2wgYW5kIGNsb3NlIGJyb3dzZXIgYWZ0ZXIgZmluaXNoaW5nIHNpbmdsZSBleHBvcnRcclxuICAgIGF3YWl0IGtpbGxQb29sKCk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogRGV0ZXJtaW5lcyB0aGUgc2l6ZSBhbmQgc2NhbGUgZm9yIGNoYXJ0IGV4cG9ydCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucy5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgb3B0aW9ucyBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIGZvclxyXG4gKiBjaGFydCBleHBvcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSBjYWxjdWxhdGVkIGhlaWdodCwgd2lkdGgsXHJcbiAqIGFuZCBzY2FsZSBmb3IgdGhlIGNoYXJ0IGV4cG9ydC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBmaW5kQ2hhcnRTaXplID0gKG9wdGlvbnMpID0+IHtcclxuICBjb25zdCB7IGNoYXJ0LCBleHBvcnRpbmcgfSA9XHJcbiAgICBvcHRpb25zLmV4cG9ydD8ub3B0aW9ucyB8fCBpc0NvcnJlY3RKU09OKG9wdGlvbnMuZXhwb3J0Py5pbnN0cik7XHJcblxyXG4gIC8vIFNlZSBpZiBnbG9iYWxPcHRpb25zIGhvbGRzIGNoYXJ0IG9yIGV4cG9ydGluZyBzaXplXHJcbiAgY29uc3QgZ2xvYmFsT3B0aW9ucyA9IGlzQ29ycmVjdEpTT04ob3B0aW9ucy5leHBvcnQ/Lmdsb2JhbE9wdGlvbnMpO1xyXG5cclxuICAvLyBTZWN1cmUgc2NhbGUgdmFsdWVcclxuICBsZXQgc2NhbGUgPVxyXG4gICAgb3B0aW9ucy5leHBvcnQ/LnNjYWxlIHx8XHJcbiAgICBleHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNjYWxlIHx8XHJcbiAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFNjYWxlIHx8XHJcbiAgICAxO1xyXG5cclxuICAvLyB0aGUgc2NhbGUgY2Fubm90IGJlIGxvd2VyIHRoYW4gMC4xIGFuZCBjYW5ub3QgYmUgaGlnaGVyIHRoYW4gNS4wXHJcbiAgc2NhbGUgPSBNYXRoLm1heCgwLjEsIE1hdGgubWluKHNjYWxlLCA1LjApKTtcclxuXHJcbiAgLy8gd2Ugd2FudCB0byByb3VuZCB0aGUgbnVtYmVycyBsaWtlIDAuMjMyMzQgLT4gMC4yM1xyXG4gIHNjYWxlID0gcm91bmROdW1iZXIoc2NhbGUsIDIpO1xyXG5cclxuICAvLyBGaW5kIGNoYXJ0IHNpemUgYW5kIHNjYWxlXHJcbiAgY29uc3Qgc2l6ZSA9IHtcclxuICAgIGhlaWdodDpcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmhlaWdodCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZUhlaWdodCB8fFxyXG4gICAgICBjaGFydD8uaGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmV4cG9ydGluZz8uc291cmNlSGVpZ2h0IHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py5oZWlnaHQgfHxcclxuICAgICAgb3B0aW9ucy5leHBvcnQ/LmRlZmF1bHRIZWlnaHQgfHxcclxuICAgICAgNDAwLFxyXG4gICAgd2lkdGg6XHJcbiAgICAgIG9wdGlvbnMuZXhwb3J0Py53aWR0aCB8fFxyXG4gICAgICBleHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBnbG9iYWxPcHRpb25zPy5leHBvcnRpbmc/LnNvdXJjZVdpZHRoIHx8XHJcbiAgICAgIGdsb2JhbE9wdGlvbnM/LmNoYXJ0Py53aWR0aCB8fFxyXG4gICAgICBvcHRpb25zLmV4cG9ydD8uZGVmYXVsdFdpZHRoIHx8XHJcbiAgICAgIDYwMCxcclxuICAgIHNjYWxlXHJcbiAgfTtcclxuXHJcbiAgLy8gR2V0IHJpZCBvZiBwb3RlbnRpYWwgcHggYW5kICVcclxuICBmb3IgKGxldCBbcGFyYW0sIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhzaXplKSkge1xyXG4gICAgc2l6ZVtwYXJhbV0gPVxyXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gK3ZhbHVlLnJlcGxhY2UoL3B4fCUvZ2ksICcnKSA6IHZhbHVlO1xyXG4gIH1cclxuICByZXR1cm4gc2l6ZTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBGdW5jdGlvbiBmb3IgZmluYWxpemluZyBvcHRpb25zIGJlZm9yZSBleHBvcnQuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gVGhlIG9wdGlvbnMgb2JqZWN0IGNvbnRhaW5pbmcgY29uZmlndXJhdGlvbiBmb3JcclxuICogdGhlIGV4cG9ydCBwcm9jZXNzLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gY2hhcnRKc29uIC0gVGhlIEpTT04gcmVwcmVzZW50YXRpb24gb2YgdGhlIGNoYXJ0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBlbmRDYWxsYmFjayAtIFRoZSBjYWxsYmFjayBmdW5jdGlvbiB0byBiZSBjYWxsZWQgdXBvblxyXG4gKiBjb21wbGV0aW9uIG9yIGVycm9yLlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gc3ZnIC0gVGhlIFNWRyByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2hhcnQuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtQcm9taXNlPHZvaWQ+fSBBIFByb21pc2UgdGhhdCByZXNvbHZlcyBvbmNlIHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gKiBpcyBjb21wbGV0ZWQuXHJcbiAqL1xyXG5jb25zdCBkb0V4cG9ydCA9IGFzeW5jIChvcHRpb25zLCBjaGFydEpzb24sIGVuZENhbGxiYWNrLCBzdmcpID0+IHtcclxuICBsZXQgeyBleHBvcnQ6IGV4cG9ydE9wdGlvbnMsIGN1c3RvbUxvZ2ljOiBjdXN0b21Mb2dpY09wdGlvbnMgfSA9IG9wdGlvbnM7XHJcblxyXG4gIGNvbnN0IGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCA9XHJcbiAgICB0eXBlb2YgY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvbiA9PT0gJ2Jvb2xlYW4nXHJcbiAgICAgID8gY3VzdG9tTG9naWNPcHRpb25zLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICAgICA6IGFsbG93Q29kZUV4ZWN1dGlvbjtcclxuXHJcbiAgaWYgKCFjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucyA9IG9wdGlvbnMuY3VzdG9tTG9naWMgPSB7fTtcclxuICB9IGVsc2UgaWYgKGFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCkge1xyXG4gICAgaWYgKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9PT0gJ3N0cmluZycpIHtcclxuICAgICAgLy8gUHJvY2VzcyByZXNvdXJjZXNcclxuICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMgPSBoYW5kbGVSZXNvdXJjZXMoXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMsXHJcbiAgICAgICAgdG9Cb29sZWFuKG9wdGlvbnMuY3VzdG9tTG9naWMuYWxsb3dGaWxlUmVzb3VyY2VzKVxyXG4gICAgICApO1xyXG4gICAgfSBlbHNlIGlmICghb3B0aW9ucy5jdXN0b21Mb2dpYy5yZXNvdXJjZXMpIHtcclxuICAgICAgdHJ5IHtcclxuICAgICAgICBjb25zdCByZXNvdXJjZXMgPSByZWFkRmlsZVN5bmMoJ3Jlc291cmNlcy5qc29uJywgJ3V0ZjgnKTtcclxuICAgICAgICBvcHRpb25zLmN1c3RvbUxvZ2ljLnJlc291cmNlcyA9IGhhbmRsZVJlc291cmNlcyhcclxuICAgICAgICAgIHJlc291cmNlcyxcclxuICAgICAgICAgIHRvQm9vbGVhbihvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93RmlsZVJlc291cmNlcylcclxuICAgICAgICApO1xyXG4gICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgIGxvZ1dpdGhTdGFjayhcclxuICAgICAgICAgIDIsXHJcbiAgICAgICAgICBlcnJvcixcclxuICAgICAgICAgIGBbY2hhcnRdIFVuYWJsZSB0byBsb2FkIHRoZSBkZWZhdWx0IHJlc291cmNlcy5qc29uIGZpbGUuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIElmIHRoZSBhbGxvd0NvZGVFeGVjdXRpb24gZmxhZyBpc24ndCBzZXQsIHdlIHNob3VsZCByZWZ1c2UgdGhlIHVzYWdlXHJcbiAgLy8gb2YgY2FsbGJhY2ssIHJlc291cmNlcywgYW5kIGN1c3RvbSBjb2RlLiBBZGRpdGlvbmFsbHksIHRoZSB3b3JrZXIgd2lsbFxyXG4gIC8vIHJlZnVzZSB0byBydW4gYXJiaXRyYXJ5IEphdmFTY3JpcHQuIFByaW9yaXRpemVkIHNob3VsZCBiZSB0aGUgc2NvcGVkXHJcbiAgLy8gb3B0aW9uLCB0aGVuIHdlIHNob3VsZCB0YWtlIGEgbG9vayBhdCB0aGUgb3ZlcmFsbCBwb29sIG9wdGlvbi5cclxuICBpZiAoIWFsbG93Q29kZUV4ZWN1dGlvblNjb3BlZCAmJiBjdXN0b21Mb2dpY09wdGlvbnMpIHtcclxuICAgIGlmIChcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrIHx8XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5yZXNvdXJjZXMgfHxcclxuICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGVcclxuICAgICkge1xyXG4gICAgICAvLyBTZW5kIGJhY2sgYSBmcmllbmRseSBtZXNzYWdlIHNheWluZyB0aGF0IHRoZSBleHBvcnRlciBkb2VzIG5vdCBzdXBwb3J0XHJcbiAgICAgIC8vIHRoZXNlIHNldHRpbmdzLlxyXG4gICAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgICAgbmV3IEV4cG9ydEVycm9yKFxyXG4gICAgICAgICAgYFtjaGFydF0gVGhlICdjYWxsYmFjaycsICdyZXNvdXJjZXMnIGFuZCAnY3VzdG9tQ29kZScgb3B0aW9ucyBoYXZlIGJlZW4gZGlzYWJsZWQgZm9yIHRoaXMgc2VydmVyLmBcclxuICAgICAgICApXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gUmVzZXQgYWxsIGFkZGl0aW9uYWwgY3VzdG9tIGNvZGVcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLnJlc291cmNlcyA9IGZhbHNlO1xyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmN1c3RvbUNvZGUgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIC8vIENsZWFuIHByb3BlcnRpZXMgdG8ga2VlcCBpdCBsZWFuIGFuZCBtZWFuXHJcbiAgaWYgKGNoYXJ0SnNvbikge1xyXG4gICAgY2hhcnRKc29uLmNoYXJ0ID0gY2hhcnRKc29uLmNoYXJ0IHx8IHt9O1xyXG4gICAgY2hhcnRKc29uLmV4cG9ydGluZyA9IGNoYXJ0SnNvbi5leHBvcnRpbmcgfHwge307XHJcbiAgICBjaGFydEpzb24uZXhwb3J0aW5nLmVuYWJsZWQgPSBmYWxzZTtcclxuICB9XHJcblxyXG4gIGV4cG9ydE9wdGlvbnMuY29uc3RyID0gZXhwb3J0T3B0aW9ucy5jb25zdHIgfHwgJ2NoYXJ0JztcclxuICBleHBvcnRPcHRpb25zLnR5cGUgPSBmaXhUeXBlKGV4cG9ydE9wdGlvbnMudHlwZSwgZXhwb3J0T3B0aW9ucy5vdXRmaWxlKTtcclxuICBpZiAoZXhwb3J0T3B0aW9ucy50eXBlID09PSAnc3ZnJykge1xyXG4gICAgZXhwb3J0T3B0aW9ucy53aWR0aCA9IGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gUHJlcGFyZSBnbG9iYWwgYW5kIHRoZW1lIG9wdGlvbnNcclxuICBbJ2dsb2JhbE9wdGlvbnMnLCAndGhlbWVPcHRpb25zJ10uZm9yRWFjaCgob3B0aW9uc05hbWUpID0+IHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGlmIChleHBvcnRPcHRpb25zICYmIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdKSB7XHJcbiAgICAgICAgaWYgKFxyXG4gICAgICAgICAgdHlwZW9mIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID09PSAnc3RyaW5nJyAmJlxyXG4gICAgICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0uZW5kc1dpdGgoJy5qc29uJylcclxuICAgICAgICApIHtcclxuICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdID0gaXNDb3JyZWN0SlNPTihcclxuICAgICAgICAgICAgcmVhZEZpbGVTeW5jKGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLCAndXRmOCcpLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICBleHBvcnRPcHRpb25zW29wdGlvbnNOYW1lXSA9IGlzQ29ycmVjdEpTT04oXHJcbiAgICAgICAgICAgIGV4cG9ydE9wdGlvbnNbb3B0aW9uc05hbWVdLFxyXG4gICAgICAgICAgICB0cnVlXHJcbiAgICAgICAgICApO1xyXG4gICAgICAgIH1cclxuICAgICAgfVxyXG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgZXhwb3J0T3B0aW9uc1tvcHRpb25zTmFtZV0gPSB7fTtcclxuICAgICAgbG9nV2l0aFN0YWNrKDIsIGVycm9yLCBgW2NoYXJ0XSBUaGUgJyR7b3B0aW9uc05hbWV9JyBjYW5ub3QgYmUgbG9hZGVkLmApO1xyXG4gICAgfVxyXG4gIH0pO1xyXG5cclxuICAvLyBQcmVwYXJlIHRoZSBjdXN0b21Db2RlXHJcbiAgaWYgKGN1c3RvbUxvZ2ljT3B0aW9ucy5hbGxvd0NvZGVFeGVjdXRpb24pIHtcclxuICAgIHRyeSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jdXN0b21Db2RlID0gd3JhcEFyb3VuZChcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY3VzdG9tQ29kZSxcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzXHJcbiAgICAgICk7XHJcbiAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY3VzdG9tQ29kZScgY2Fubm90IGJlIGxvYWRlZC5gKTtcclxuICAgIH1cclxuICB9XHJcblxyXG4gIC8vIEdldCB0aGUgY2FsbGJhY2tcclxuICBpZiAoXHJcbiAgICBjdXN0b21Mb2dpY09wdGlvbnMgJiZcclxuICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayAmJlxyXG4gICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrPy5pbmRleE9mKCd7JykgPCAwXHJcbiAgKSB7XHJcbiAgICAvLyBUaGUgYWxsb3dGaWxlUmVzb3VyY2VzIGlzIGFsd2F5cyBzZXQgdG8gZmFsc2UgZm9yIEhUVFAgcmVxdWVzdHMgdG8gYXZvaWRcclxuICAgIC8vIGluamVjdGluZyBhcmJpdHJhcnkgZmlsZXMgZnJvbSB0aGUgZnNcclxuICAgIGlmIChjdXN0b21Mb2dpY09wdGlvbnMuYWxsb3dGaWxlUmVzb3VyY2VzKSB7XHJcbiAgICAgIHRyeSB7XHJcbiAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrID0gcmVhZEZpbGVTeW5jKFxyXG4gICAgICAgICAgY3VzdG9tTG9naWNPcHRpb25zLmNhbGxiYWNrLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICBjdXN0b21Mb2dpY09wdGlvbnMuY2FsbGJhY2sgPSBmYWxzZTtcclxuICAgICAgICBsb2dXaXRoU3RhY2soMiwgZXJyb3IsIGBbY2hhcnRdIFRoZSAnY2FsbGJhY2snIGNhbm5vdCBiZSBsb2FkZWQuYCk7XHJcbiAgICAgIH1cclxuICAgIH0gZWxzZSB7XHJcbiAgICAgIGN1c3RvbUxvZ2ljT3B0aW9ucy5jYWxsYmFjayA9IGZhbHNlO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgLy8gU2l6ZSBzZWFyY2hcclxuICBvcHRpb25zLmV4cG9ydCA9IHtcclxuICAgIC4uLm9wdGlvbnMuZXhwb3J0LFxyXG4gICAgLi4uZmluZENoYXJ0U2l6ZShvcHRpb25zKVxyXG4gIH07XHJcblxyXG4gIC8vIFBvc3QgdGhlIHdvcmsgdG8gdGhlIHBvb2xcclxuICB0cnkge1xyXG4gICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgcG9zdFdvcmsoXHJcbiAgICAgIGV4cG9ydE9wdGlvbnMuc3RySW5qIHx8IGNoYXJ0SnNvbiB8fCBzdmcsXHJcbiAgICAgIG9wdGlvbnNcclxuICAgICk7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soZmFsc2UsIHJlc3VsdCk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIHJldHVybiBlbmRDYWxsYmFjayhlcnJvcik7XHJcbiAgfVxyXG59O1xyXG5cclxuLyoqXHJcbiAqIFBlcmZvcm1zIGEgZGlyZWN0IGluamVjdCBvZiBvcHRpb25zIGJlZm9yZSBleHBvcnQuIFRoZSBmdW5jdGlvbiBhdHRlbXB0c1xyXG4gKiB0byBzdHJpbmdpZnkgdGhlIHByb3ZpZGVkIG9wdGlvbnMgYW5kIHJlbW92ZXMgdW5uZWNlc3NhcnkgY2hhcmFjdGVycyxcclxuICogZW5zdXJpbmcgYSBjbGVhbiBhbmQgZm9ybWF0dGVkIGlucHV0LiBUaGUgcmVzdWx0aW5nIHN0cmluZyBpcyBzYXZlZCBhc1xyXG4gKiBhIFwic3RyaWdodCBpbmplY3RcIiBzdHJpbmcgaW4gdGhlIGV4cG9ydCBvcHRpb25zLiBJdCB0aGVuIGludm9rZXMgdGhlXHJcbiAqIGRvRXhwb3J0IGZ1bmN0aW9uIHdpdGggdGhlIHVwZGF0ZWQgb3B0aW9ucy5cclxuICpcclxuICogSU1QT1JUQU5UOiBEYW5nZXJvdXMgYW5kIG11c3QgYmUgdXNlZCBkZWxpYmVyYXRlbHkgYnkgc29tZW9uZSB3aG8gc2V0cyB1cFxyXG4gKiBhIHNlcnZlciAoc2VlIHRoZSAgLS1hbGxvd0NvZGVFeGVjdXRpb24gb3B0aW9uKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBUaGUgZXhwb3J0IG9wdGlvbnMgY29udGFpbmluZyB0aGUgaW5wdXRcclxuICogdG8gYmUgaW5qZWN0ZWQuXHJcbiAqIEBwYXJhbSB7ZnVuY3Rpb259IGVuZENhbGxiYWNrIC0gVGhlIGNhbGxiYWNrIGZ1bmN0aW9uIHRvIGJlIGludm9rZWRcclxuICogYXQgdGhlIGVuZCBvZiB0aGUgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2V9IEEgUHJvbWlzZSB0aGF0IHJlc29sdmVzIHdpdGggdGhlIHJlc3VsdCBvZiB0aGUgZXhwb3J0XHJcbiAqIG9wZXJhdGlvbiBvciByZWplY3RzIHdpdGggYW4gZXJyb3IgaWYgYW55IGlzc3VlcyBvY2N1ciBkdXJpbmcgdGhlIHByb2Nlc3MuXHJcbiAqL1xyXG5jb25zdCBkb1N0cmFpZ2h0SW5qZWN0ID0gKG9wdGlvbnMsIGVuZENhbGxiYWNrKSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIGxldCBzdHJJbmo7XHJcbiAgICBsZXQgaW5zdHIgPSBvcHRpb25zLmV4cG9ydC5pbnN0ciB8fCBvcHRpb25zLmV4cG9ydC5vcHRpb25zO1xyXG5cclxuICAgIGlmICh0eXBlb2YgaW5zdHIgIT09ICdzdHJpbmcnKSB7XHJcbiAgICAgIC8vIFRyeSB0byBzdHJpbmdpZnkgb3B0aW9uc1xyXG4gICAgICBzdHJJbmogPSBpbnN0ciA9IG9wdGlvbnNTdHJpbmdpZnkoXHJcbiAgICAgICAgaW5zdHIsXHJcbiAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2dpYz8uYWxsb3dDb2RlRXhlY3V0aW9uXHJcbiAgICAgICk7XHJcbiAgICB9XHJcbiAgICBzdHJJbmogPSBpbnN0ci5yZXBsYWNlQWxsKC9cXHR8XFxufFxcci9nLCAnJykudHJpbSgpO1xyXG5cclxuICAgIC8vIEdldCByaWQgb2YgdGhlIDtcclxuICAgIGlmIChzdHJJbmpbc3RySW5qLmxlbmd0aCAtIDFdID09PSAnOycpIHtcclxuICAgICAgc3RySW5qID0gc3RySW5qLnN1YnN0cmluZygwLCBzdHJJbmoubGVuZ3RoIC0gMSk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2F2ZSBhcyBzdHJpZ2h0IGluamVjdCBzdHJpbmdcclxuICAgIG9wdGlvbnMuZXhwb3J0LnN0ckluaiA9IHN0ckluajtcclxuICAgIHJldHVybiBkb0V4cG9ydChvcHRpb25zLCBmYWxzZSwgZW5kQ2FsbGJhY2spO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICByZXR1cm4gZW5kQ2FsbGJhY2soXHJcbiAgICAgIG5ldyBFeHBvcnRFcnJvcihcclxuICAgICAgICBgW2NoYXJ0XSBNYWxmb3JtZWQgaW5wdXQgZGV0ZWN0ZWQgZm9yICR7b3B0aW9ucy5leHBvcnQ/LnJlcXVlc3RJZCB8fCAnPyd9LiBQbGVhc2UgbWFrZSBzdXJlIHRoYXQgeW91ciBKU09OL0phdmFTY3JpcHQgb3B0aW9ucyBhcmUgc2VudCB1c2luZyB0aGUgXCJvcHRpb25zXCIgYXR0cmlidXRlLCBhbmQgdGhhdCBpZiB5b3UncmUgdXNpbmcgU1ZHLCBpdCBpcyB1bmVzY2FwZWQuYFxyXG4gICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgKTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogRXhwb3J0cyBhIHN0cmluZyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3B0aW9ucyBhbmQgaW52b2tlcyBhbiBlbmQgY2FsbGJhY2suXHJcbiAqXHJcbiAqIEBwYXJhbSB7c3RyaW5nfSBzdHJpbmdUb0V4cG9ydCAtIFRoZSBzdHJpbmcgY29udGVudCB0byBiZSBleHBvcnRlZC5cclxuICogQHBhcmFtIHtPYmplY3R9IG9wdGlvbnMgLSBFeHBvcnQgb3B0aW9ucywgaW5jbHVkaW5nIGN1c3RvbUxvZ2ljIHdpdGhcclxuICogYWxsb3dDb2RlRXhlY3V0aW9uIGZsYWcuXHJcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGVuZENhbGxiYWNrIC0gQ2FsbGJhY2sgZnVuY3Rpb24gdG8gYmUgaW52b2tlZCBhdCB0aGUgZW5kXHJcbiAqIG9mIHRoZSBleHBvcnQgcHJvY2Vzcy5cclxuICpcclxuICogQHJldHVybnMge2FueX0gUmVzdWx0IG9mIHRoZSBleHBvcnQgcHJvY2VzcyBvciBhbiBlcnJvciBpZiBlbmNvdW50ZXJlZC5cclxuICovXHJcbmNvbnN0IGV4cG9ydEFzU3RyaW5nID0gKHN0cmluZ1RvRXhwb3J0LCBvcHRpb25zLCBlbmRDYWxsYmFjaykgPT4ge1xyXG4gIGNvbnN0IHsgYWxsb3dDb2RlRXhlY3V0aW9uIH0gPSBvcHRpb25zLmN1c3RvbUxvZ2ljO1xyXG5cclxuICAvLyBDaGVjayBpZiBpdCBpcyBTVkdcclxuICBpZiAoXHJcbiAgICBzdHJpbmdUb0V4cG9ydC5pbmRleE9mKCc8c3ZnJykgPj0gMCB8fFxyXG4gICAgc3RyaW5nVG9FeHBvcnQuaW5kZXhPZignPD94bWwnKSA+PSAwXHJcbiAgKSB7XHJcbiAgICBsb2coNCwgJ1tjaGFydF0gUGFyc2luZyBpbnB1dCBhcyBTVkcuJyk7XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgZmFsc2UsIGVuZENhbGxiYWNrLCBzdHJpbmdUb0V4cG9ydCk7XHJcbiAgfVxyXG5cclxuICB0cnkge1xyXG4gICAgLy8gVHJ5IHRvIHBhcnNlIHRvIEpTT04gYW5kIGNhbGwgdGhlIGRvRXhwb3J0IGZ1bmN0aW9uXHJcbiAgICBjb25zdCBjaGFydEpTT04gPSBKU09OLnBhcnNlKHN0cmluZ1RvRXhwb3J0LnJlcGxhY2VBbGwoL1xcdHxcXG58XFxyL2csICcgJykpO1xyXG5cclxuICAgIC8vIElmIGEgY29ycmVjdCBKU09OLCBkbyB0aGUgZXhwb3J0XHJcbiAgICByZXR1cm4gZG9FeHBvcnQob3B0aW9ucywgY2hhcnRKU09OLCBlbmRDYWxsYmFjayk7XHJcbiAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgIC8vIE5vdCBhIHZhbGlkIEpTT05cclxuICAgIGlmICh0b0Jvb2xlYW4oYWxsb3dDb2RlRXhlY3V0aW9uKSkge1xyXG4gICAgICByZXR1cm4gZG9TdHJhaWdodEluamVjdChvcHRpb25zLCBlbmRDYWxsYmFjayk7XHJcbiAgICB9IGVsc2Uge1xyXG4gICAgICAvLyBEbyBub3QgYWxsb3cgc3RyYWlnaHQgaW5qZWN0aW9uIHdpdGhvdXQgdGhlIGFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnXHJcbiAgICAgIHJldHVybiBlbmRDYWxsYmFjayhcclxuICAgICAgICBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICAgICAnW2NoYXJ0XSBPbmx5IEpTT04gY29uZmlndXJhdGlvbnMgYW5kIFNWRyBhcmUgYWxsb3dlZCBmb3IgdGhpcyBzZXJ2ZXIuIElmIHRoaXMgaXMgeW91ciBzZXJ2ZXIsIEphdmFTY3JpcHQgY3VzdG9tIGNvZGUgY2FuIGJlIGVuYWJsZWQgYnkgc3RhcnRpbmcgdGhlIHNlcnZlciB3aXRoIHRoZSAtLWFsbG93Q29kZUV4ZWN1dGlvbiBmbGFnLidcclxuICAgICAgICApLnNldEVycm9yKGVycm9yKVxyXG4gICAgICApO1xyXG4gICAgfVxyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBSZXRyaWV2ZXMgYW5kIHJldHVybnMgdGhlIGN1cnJlbnQgc3RhdHVzIG9mIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24uXHJcbiAqXHJcbiAqIEByZXR1cm5zIHthbnl9IFRoZSB2YWx1ZSBvZiBhbGxvd0NvZGVFeGVjdXRpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uID0gKCkgPT4gYWxsb3dDb2RlRXhlY3V0aW9uO1xyXG5cclxuLyoqXHJcbiAqIFNldHMgdGhlIGNvZGUgZXhlY3V0aW9uIHBlcm1pc3Npb24gYmFzZWQgb24gdGhlIHByb3ZpZGVkIGJvb2xlYW4gdmFsdWUuXHJcbiAqXHJcbiAqIEBwYXJhbSB7YW55fSB2YWx1ZSAtIFRoZSB2YWx1ZSB0byBiZSBjb252ZXJ0ZWQgYW5kIGFzc2lnbmVkXHJcbiAqIHRvIGFsbG93Q29kZUV4ZWN1dGlvbi5cclxuICovXHJcbmV4cG9ydCBjb25zdCBzZXRBbGxvd0NvZGVFeGVjdXRpb24gPSAodmFsdWUpID0+IHtcclxuICBhbGxvd0NvZGVFeGVjdXRpb24gPSB0b0Jvb2xlYW4odmFsdWUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIGJhdGNoRXhwb3J0LFxyXG4gIHNpbmdsZUV4cG9ydCxcclxuICBnZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uLFxyXG4gIHN0YXJ0RXhwb3J0LFxyXG4gIGZpbmRDaGFydFNpemVcclxufTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG4vKipcclxuICogQG92ZXJ2aWV3IFVzZWQgdG8gc2FuaXRpemUgdGhlIHN0cmluZ3MgY29taW5nIGZyb20gdGhlIGV4cG9ydGluZyBtb2R1bGVcclxuICogdG8gcHJldmVudCBYU1MgYXR0YWNrcyAod2l0aCB0aGUgRE9NUHVyaWZ5IGxpYnJhcnkpLlxyXG4gKiovXHJcblxyXG5pbXBvcnQgeyBKU0RPTSB9IGZyb20gJ2pzZG9tJztcclxuaW1wb3J0IERPTVB1cmlmeSBmcm9tICdkb21wdXJpZnknO1xyXG5cclxuLyoqXHJcbiAqIFNhbml0aXplcyBhIGdpdmVuIEhUTUwgc3RyaW5nIGJ5IHJlbW92aW5nIDxzY3JpcHQ+IHRhZ3MuXHJcbiAqIFRoaXMgZnVuY3Rpb24gdXNlcyBhIHJlZ3VsYXIgZXhwcmVzc2lvbiB0byBmaW5kIGFuZCByZW1vdmUgYWxsXHJcbiAqIG9jY3VycmVuY2VzIG9mIDxzY3JpcHQ+Li4uPC9zY3JpcHQ+IHRhZ3MgYW5kIGFueSBjb250ZW50IHdpdGhpbiB0aGVtLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gaW5wdXQgVGhlIEhUTUwgc3RyaW5nIHRvIGJlIHNhbml0aXplZC5cclxuICogQHJldHVybnMge3N0cmluZ30gVGhlIHNhbml0aXplZCBIVE1MIHN0cmluZy5cclxuICovXHJcbmV4cG9ydCBmdW5jdGlvbiBzYW5pdGl6ZShpbnB1dCkge1xyXG4gIGNvbnN0IHdpbmRvdyA9IG5ldyBKU0RPTSgnJykud2luZG93O1xyXG4gIGNvbnN0IHB1cmlmeSA9IERPTVB1cmlmeSh3aW5kb3cpO1xyXG4gIHJldHVybiBwdXJpZnkuc2FuaXRpemUoaW5wdXQsIHsgQUREX1RBR1M6IFsnZm9yZWlnbk9iamVjdCddIH0pO1xyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBzYW5pdGl6ZTtcclxuIiwiLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcclxuXHJcbkhpZ2hjaGFydHMgRXhwb3J0IFNlcnZlclxyXG5cclxuQ29weXJpZ2h0IChjKSAyMDE2LTIwMjQsIEhpZ2hzb2Z0XHJcblxyXG5MaWNlbmNlZCB1bmRlciB0aGUgTUlUIGxpY2VuY2UuXHJcblxyXG5BZGRpdGlvbmFsbHkgYSB2YWxpZCBIaWdoY2hhcnRzIGxpY2Vuc2UgaXMgcmVxdWlyZWQgZm9yIHVzZS5cclxuXHJcblNlZSBMSUNFTlNFIGZpbGUgaW4gcm9vdCBmb3IgZGV0YWlscy5cclxuXHJcbioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXHJcblxyXG5pbXBvcnQgeyBsb2cgfSBmcm9tICcuL2xvZ2dlci5qcyc7XHJcblxyXG4vLyBBcnJheSB0aGF0IGNvbnRhaW5zIGlkcyBvZiBhbGwgb25nb2luZyBpbnRlcnZhbHNcclxuY29uc3QgaW50ZXJ2YWxJZHMgPSBbXTtcclxuXHJcbi8qKlxyXG4gKiBBZGRzIGlkIG9mIGEgc2V0SW50ZXJ2YWwgdG8gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKlxyXG4gKiBAcGFyYW0ge05vZGVKUy5UaW1lb3V0fSBpZCAtIElkIG9mIGFuIGludGVydmFsLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGFkZEludGVydmFsID0gKGlkKSA9PiB7XHJcbiAgaW50ZXJ2YWxJZHMucHVzaChpZCk7XHJcbn07XHJcblxyXG4vKipcclxuICogQ2xlYXJzIGFsbCBvZiBvbmdvaW5nIGludGVydmFscyBieSBpZHMgZ2F0aGVyZWQgaW4gdGhlIGludGVydmFsSWRzIGFycmF5LlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsZWFyQWxsSW50ZXJ2YWxzID0gKCkgPT4ge1xyXG4gIGxvZyg0LCBgW3NlcnZlcl0gQ2xlYXJpbmcgYWxsIHJlZ2lzdGVyZWQgaW50ZXJ2YWxzLmApO1xyXG4gIGZvciAoY29uc3QgaWQgb2YgaW50ZXJ2YWxJZHMpIHtcclxuICAgIGNsZWFySW50ZXJ2YWwoaWQpO1xyXG4gIH1cclxufTtcclxuXHJcbmV4cG9ydCBkZWZhdWx0IHtcclxuICBhZGRJbnRlcnZhbCxcclxuICBjbGVhckFsbEludGVydmFsc1xyXG59O1xyXG4iLCJpbXBvcnQgeyBlbnZzIH0gZnJvbSAnLi4vZW52cy5qcyc7XHJcbmltcG9ydCB7IGxvZ1dpdGhTdGFjayB9IGZyb20gJy4uL2xvZ2dlci5qcyc7XHJcblxyXG4vKipcclxuICogTWlkZGxld2FyZSBmb3IgbG9nZ2luZyBlcnJvcnMgd2l0aCBzdGFjayB0cmFjZSBhbmQgaGFuZGxpbmcgZXJyb3IgcmVzcG9uc2UuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXJyb3J9IGVycm9yIC0gVGhlIGVycm9yIG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcSAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlcyAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtGdW5jdGlvbn0gbmV4dCAtIFRoZSBuZXh0IG1pZGRsZXdhcmUgZnVuY3Rpb24uXHJcbiAqL1xyXG5jb25zdCBsb2dFcnJvck1pZGRsZXdhcmUgPSAoZXJyb3IsIHJlcSwgcmVzLCBuZXh0KSA9PiB7XHJcbiAgLy8gRGlzcGxheSB0aGUgZXJyb3Igd2l0aCBzdGFjayBpbiBhIGNvcnJlY3QgZm9ybWF0XHJcbiAgbG9nV2l0aFN0YWNrKDEsIGVycm9yKTtcclxuXHJcbiAgLy8gRGVsZXRlIHRoZSBzdGFjayBmb3IgdGhlIGVudmlyb25tZW50IG90aGVyIHRoYW4gdGhlIGRldmVsb3BtZW50XHJcbiAgaWYgKGVudnMuT1RIRVJfTk9ERV9FTlYgIT09ICdkZXZlbG9wbWVudCcpIHtcclxuICAgIGRlbGV0ZSBlcnJvci5zdGFjaztcclxuICB9XHJcblxyXG4gIC8vIENhbGwgdGhlIHJldHVybkVycm9yTWlkZGxld2FyZVxyXG4gIG5leHQoZXJyb3IpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIE1pZGRsZXdhcmUgZm9yIHJldHVybmluZyBlcnJvciByZXNwb25zZS5cclxuICpcclxuICogQHBhcmFtIHtFcnJvcn0gZXJyb3IgLSBUaGUgZXJyb3Igb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxIC0gVGhlIEV4cHJlc3MgcmVxdWVzdCBvYmplY3QuXHJcbiAqIEBwYXJhbSB7RXhwcmVzcy5SZXNwb25zZX0gcmVzIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICovXHJcbmNvbnN0IHJldHVybkVycm9yTWlkZGxld2FyZSA9IChlcnJvciwgcmVxLCByZXMsIG5leHQpID0+IHtcclxuICAvLyBHYXRoZXIgYWxsIHJlcXVpZWQgaW5mb3JtYXRpb24gZm9yIHRoZSByZXNwb25zZVxyXG4gIGNvbnN0IHsgc3RhdHVzQ29kZTogc3RDb2RlLCBzdGF0dXMsIG1lc3NhZ2UsIHN0YWNrIH0gPSBlcnJvcjtcclxuICBjb25zdCBzdGF0dXNDb2RlID0gc3RDb2RlIHx8IHN0YXR1cyB8fCA1MDA7XHJcblxyXG4gIC8vIFNldCBhbmQgcmV0dXJuIHJlc3BvbnNlXHJcbiAgcmVzLnN0YXR1cyhzdGF0dXNDb2RlKS5qc29uKHsgc3RhdHVzQ29kZSwgbWVzc2FnZSwgc3RhY2sgfSk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLy8gQWRkIGxvZyBlcnJvciBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsb2dFcnJvck1pZGRsZXdhcmUpO1xyXG5cclxuICAvLyBBZGQgc2V0IHN0YXR1cyBhbmQgcmV0dXJuIGVycm9yIG1pZGRsZXdhcmVcclxuICBhcHAudXNlKHJldHVybkVycm9yTWlkZGxld2FyZSk7XHJcbn07XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHJhdGVMaW1pdCBmcm9tICdleHByZXNzLXJhdGUtbGltaXQnO1xyXG5cclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuXHJcbi8qKlxyXG4gKiBNaWRkbGV3YXJlIGZvciBlbmFibGluZyByYXRlIGxpbWl0aW5nIG9uIHRoZSBzcGVjaWZpZWQgRXhwcmVzcyBhcHAuXHJcbiAqXHJcbiAqIEBwYXJhbSB7RXhwcmVzc30gYXBwIC0gVGhlIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9wdGlvbnMgZm9yIHJhdGUgbGltaXRpbmcuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwLCBsaW1pdENvbmZpZykgPT4ge1xyXG4gIGNvbnN0IG1zZyA9XHJcbiAgICAnVG9vIG1hbnkgcmVxdWVzdHMsIHlvdSBoYXZlIGJlZW4gcmF0ZSBsaW1pdGVkLiBQbGVhc2UgdHJ5IGFnYWluIGxhdGVyLic7XHJcblxyXG4gIC8vIE9wdGlvbnMgZm9yIHRoZSByYXRlIGxpbWl0ZXJcclxuICBjb25zdCByYXRlT3B0aW9ucyA9IHtcclxuICAgIG1heDogbGltaXRDb25maWcubWF4UmVxdWVzdHMgfHwgMzAsXHJcbiAgICB3aW5kb3c6IGxpbWl0Q29uZmlnLndpbmRvdyB8fCAxLFxyXG4gICAgZGVsYXk6IGxpbWl0Q29uZmlnLmRlbGF5IHx8IDAsXHJcbiAgICB0cnVzdFByb3h5OiBsaW1pdENvbmZpZy50cnVzdFByb3h5IHx8IGZhbHNlLFxyXG4gICAgc2tpcEtleTogbGltaXRDb25maWcuc2tpcEtleSB8fCBmYWxzZSxcclxuICAgIHNraXBUb2tlbjogbGltaXRDb25maWcuc2tpcFRva2VuIHx8IGZhbHNlXHJcbiAgfTtcclxuXHJcbiAgLy8gU2V0IGlmIGJlaGluZCBhIHByb3h5XHJcbiAgaWYgKHJhdGVPcHRpb25zLnRydXN0UHJveHkpIHtcclxuICAgIGFwcC5lbmFibGUoJ3RydXN0IHByb3h5Jyk7XHJcbiAgfVxyXG5cclxuICAvLyBDcmVhdGUgYSBsaW1pdGVyXHJcbiAgY29uc3QgbGltaXRlciA9IHJhdGVMaW1pdCh7XHJcbiAgICB3aW5kb3dNczogcmF0ZU9wdGlvbnMud2luZG93ICogNjAgKiAxMDAwLFxyXG4gICAgLy8gTGltaXQgZWFjaCBJUCB0byAxMDAgcmVxdWVzdHMgcGVyIHdpbmRvd01zXHJcbiAgICBtYXg6IHJhdGVPcHRpb25zLm1heCxcclxuICAgIC8vIERpc2FibGUgZGVsYXlpbmcsIGZ1bGwgc3BlZWQgdW50aWwgdGhlIG1heCBsaW1pdCBpcyByZWFjaGVkXHJcbiAgICBkZWxheU1zOiByYXRlT3B0aW9ucy5kZWxheSxcclxuICAgIGhhbmRsZXI6IChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICByZXNwb25zZS5mb3JtYXQoe1xyXG4gICAgICAgIGpzb246ICgpID0+IHtcclxuICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cyg0MjkpLnNlbmQoeyBtZXNzYWdlOiBtc2cgfSk7XHJcbiAgICAgICAgfSxcclxuICAgICAgICBkZWZhdWx0OiAoKSA9PiB7XHJcbiAgICAgICAgICByZXNwb25zZS5zdGF0dXMoNDI5KS5zZW5kKG1zZyk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9KTtcclxuICAgIH0sXHJcbiAgICBza2lwOiAocmVxdWVzdCkgPT4ge1xyXG4gICAgICAvLyBBbGxvdyBieXBhc3NpbmcgdGhlIGxpbWl0ZXIgaWYgYSB2YWxpZCBrZXkvdG9rZW4gaGFzIGJlZW4gc2VudFxyXG4gICAgICBpZiAoXHJcbiAgICAgICAgcmF0ZU9wdGlvbnMuc2tpcEtleSAhPT0gZmFsc2UgJiZcclxuICAgICAgICByYXRlT3B0aW9ucy5za2lwVG9rZW4gIT09IGZhbHNlICYmXHJcbiAgICAgICAgcmVxdWVzdC5xdWVyeS5rZXkgPT09IHJhdGVPcHRpb25zLnNraXBLZXkgJiZcclxuICAgICAgICByZXF1ZXN0LnF1ZXJ5LmFjY2Vzc190b2tlbiA9PT0gcmF0ZU9wdGlvbnMuc2tpcFRva2VuXHJcbiAgICAgICkge1xyXG4gICAgICAgIGxvZyg0LCAnW3JhdGUgbGltaXRpbmddIFNraXBwaW5nIHJhdGUgbGltaXRlci4nKTtcclxuICAgICAgICByZXR1cm4gdHJ1ZTtcclxuICAgICAgfVxyXG4gICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICB9XHJcbiAgfSk7XHJcblxyXG4gIC8vIFVzZSBhIGxpbWl0ZXIgYXMgYSBtaWRkbGV3YXJlXHJcbiAgYXBwLnVzZShsaW1pdGVyKTtcclxuXHJcbiAgbG9nKFxyXG4gICAgMyxcclxuICAgIGBbcmF0ZSBsaW1pdGluZ10gRW5hYmxlZCByYXRlIGxpbWl0aW5nIHdpdGggJHtyYXRlT3B0aW9ucy5tYXh9IHJlcXVlc3RzIHBlciAke3JhdGVPcHRpb25zLndpbmRvd30gbWludXRlIGZvciBlYWNoIElQLCB0cnVzdGluZyBwcm94eTogJHtyYXRlT3B0aW9ucy50cnVzdFByb3h5fS5gXHJcbiAgKTtcclxufTtcclxuIiwiaW1wb3J0IEV4cG9ydEVycm9yIGZyb20gJy4vRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXhwb3J0RXJyb3Ige1xyXG4gIGNvbnN0cnVjdG9yKG1lc3NhZ2UsIHN0YXR1cykge1xyXG4gICAgc3VwZXIobWVzc2FnZSk7XHJcbiAgICB0aGlzLnN0YXR1cyA9IHRoaXMuc3RhdHVzQ29kZSA9IHN0YXR1cztcclxuICB9XHJcblxyXG4gIHNldFN0YXR1cyhzdGF0dXMpIHtcclxuICAgIHRoaXMuc3RhdHVzID0gc3RhdHVzO1xyXG4gICAgcmV0dXJuIHRoaXM7XHJcbiAgfVxyXG59XHJcblxyXG5leHBvcnQgZGVmYXVsdCBIdHRwRXJyb3I7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdXBkYXRlVmVyc2lvbiwgdmVyc2lvbiB9IGZyb20gJy4uLy4uL2NhY2hlLmpzJztcclxuaW1wb3J0IHsgZW52cyB9IGZyb20gJy4uLy4uL2VudnMuanMnO1xyXG5cclxuaW1wb3J0IEh0dHBFcnJvciBmcm9tICcuLi8uLi9lcnJvcnMvSHR0cEVycm9yLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBQT1NUIC9jaGFuZ2VfaGNfdmVyc2lvbi86bmV3VmVyc2lvbiByb3V0ZSB0aGF0IGNhbiBiZSB1dGlsaXplZCB0byBtb2RpZnlcclxuICogdGhlIEhpZ2hjaGFydHMgdmVyc2lvbiBvbiB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBUT0RPOiBBZGQgYXV0aCB0b2tlbiBhbmQgY29ubmVjdCB0byBBUElcclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IChhcHApID0+XHJcbiAgIWFwcFxyXG4gICAgPyBmYWxzZVxyXG4gICAgOiBhcHAucG9zdChcclxuICAgICAgICAnL3ZlcnNpb24vY2hhbmdlLzpuZXdWZXJzaW9uJyxcclxuICAgICAgICBhc3luYyAocmVxdWVzdCwgcmVzcG9uc2UsIG5leHQpID0+IHtcclxuICAgICAgICAgIHRyeSB7XHJcbiAgICAgICAgICAgIGNvbnN0IGFkbWluVG9rZW4gPSBlbnZzLkhJR0hDSEFSVFNfQURNSU5fVE9LRU47XHJcblxyXG4gICAgICAgICAgICAvLyBDaGVjayB0aGUgZXhpc3RlbmNlIG9mIHRoZSB0b2tlblxyXG4gICAgICAgICAgICBpZiAoIWFkbWluVG9rZW4gfHwgIWFkbWluVG9rZW4ubGVuZ3RoKSB7XHJcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgICAgICAgICdUaGUgc2VydmVyIGlzIG5vdCBjb25maWd1cmVkIHRvIHBlcmZvcm0gcnVuLXRpbWUgdmVyc2lvbiBjaGFuZ2VzOiBISUdIQ0hBUlRTX0FETUlOX1RPS0VOIGlzIG5vdCBzZXQuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENoZWNrIGlmIHRoZSBoYy1hdXRoIGhlYWRlciBjb250YWluIGEgY29ycmVjdCB0b2tlblxyXG4gICAgICAgICAgICBjb25zdCB0b2tlbiA9IHJlcXVlc3QuZ2V0KCdoYy1hdXRoJyk7XHJcbiAgICAgICAgICAgIGlmICghdG9rZW4gfHwgdG9rZW4gIT09IGFkbWluVG9rZW4pIHtcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgICAgICAgICAgJ0ludmFsaWQgb3IgbWlzc2luZyB0b2tlbjogU2V0IHRoZSB0b2tlbiBpbiB0aGUgaGMtYXV0aCBoZWFkZXIuJyxcclxuICAgICAgICAgICAgICAgIDQwMVxyXG4gICAgICAgICAgICAgICk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIENvbXBhcmUgdmVyc2lvbnNcclxuICAgICAgICAgICAgY29uc3QgbmV3VmVyc2lvbiA9IHJlcXVlc3QucGFyYW1zLm5ld1ZlcnNpb247XHJcbiAgICAgICAgICAgIGlmIChuZXdWZXJzaW9uKSB7XHJcbiAgICAgICAgICAgICAgdHJ5IHtcclxuICAgICAgICAgICAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBpbXBvcnQvbm8tbmFtZWQtYXMtZGVmYXVsdC1tZW1iZXJcclxuICAgICAgICAgICAgICAgIGF3YWl0IHVwZGF0ZVZlcnNpb24obmV3VmVyc2lvbik7XHJcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgICAgICAgICAgIGBWZXJzaW9uIGNoYW5nZTogJHtlcnJvci5tZXNzYWdlfWAsXHJcbiAgICAgICAgICAgICAgICAgIGVycm9yLnN0YXR1c0NvZGVcclxuICAgICAgICAgICAgICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgLy8gU3VjY2Vzc1xyXG4gICAgICAgICAgICAgIHJlc3BvbnNlLnN0YXR1cygyMDApLnNlbmQoe1xyXG4gICAgICAgICAgICAgICAgc3RhdHVzQ29kZTogMjAwLFxyXG4gICAgICAgICAgICAgICAgdmVyc2lvbjogdmVyc2lvbigpLFxyXG4gICAgICAgICAgICAgICAgbWVzc2FnZTogYFN1Y2Nlc3NmdWxseSB1cGRhdGVkIEhpZ2hjaGFydHMgdG8gdmVyc2lvbjogJHtuZXdWZXJzaW9ufS5gXHJcbiAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgLy8gTm8gdmVyc2lvbiBzcGVjaWZpZWRcclxuICAgICAgICAgICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKCdObyBuZXcgdmVyc2lvbiBzdXBwbGllZC4nLCA0MDApO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICB9IGNhdGNoIChlcnJvcikge1xyXG4gICAgICAgICAgICBuZXh0KGVycm9yKTtcclxuICAgICAgICAgIH1cclxuICAgICAgICB9XHJcbiAgICAgICk7XHJcbiIsIi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXHJcblxyXG5IaWdoY2hhcnRzIEV4cG9ydCBTZXJ2ZXJcclxuXHJcbkNvcHlyaWdodCAoYykgMjAxNi0yMDI0LCBIaWdoc29mdFxyXG5cclxuTGljZW5jZWQgdW5kZXIgdGhlIE1JVCBsaWNlbmNlLlxyXG5cclxuQWRkaXRpb25hbGx5IGEgdmFsaWQgSGlnaGNoYXJ0cyBsaWNlbnNlIGlzIHJlcXVpcmVkIGZvciB1c2UuXHJcblxyXG5TZWUgTElDRU5TRSBmaWxlIGluIHJvb3QgZm9yIGRldGFpbHMuXHJcblxyXG4qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xyXG5cclxuaW1wb3J0IHsgdjQgYXMgdXVpZCB9IGZyb20gJ3V1aWQnO1xyXG5cclxuaW1wb3J0IHsgZ2V0QWxsb3dDb2RlRXhlY3V0aW9uLCBzdGFydEV4cG9ydCB9IGZyb20gJy4uLy4uL2NoYXJ0LmpzJztcclxuaW1wb3J0IHsgZ2V0T3B0aW9ucywgbWVyZ2VDb25maWdPcHRpb25zIH0gZnJvbSAnLi4vLi4vY29uZmlnLmpzJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHtcclxuICBmaXhUeXBlLFxyXG4gIGlzQ29ycmVjdEpTT04sXHJcbiAgaXNPYmplY3RFbXB0eSxcclxuICBpc1ByaXZhdGVSYW5nZVVybEZvdW5kLFxyXG4gIG9wdGlvbnNTdHJpbmdpZnksXHJcbiAgbWVhc3VyZVRpbWVcclxufSBmcm9tICcuLi8uLi91dGlscy5qcyc7XHJcblxyXG5pbXBvcnQgSHR0cEVycm9yIGZyb20gJy4uLy4uL2Vycm9ycy9IdHRwRXJyb3IuanMnO1xyXG5cclxuLy8gUmV2ZXJzZWQgTUlNRSB0eXBlc1xyXG5jb25zdCByZXZlcnNlZE1pbWUgPSB7XHJcbiAgcG5nOiAnaW1hZ2UvcG5nJyxcclxuICBqcGVnOiAnaW1hZ2UvanBlZycsXHJcbiAgZ2lmOiAnaW1hZ2UvZ2lmJyxcclxuICBwZGY6ICdhcHBsaWNhdGlvbi9wZGYnLFxyXG4gIHN2ZzogJ2ltYWdlL3N2Zyt4bWwnXHJcbn07XHJcblxyXG4vLyBUaGUgcmVxdWVzdHMgY291bnRlclxyXG5sZXQgcmVxdWVzdHNDb3VudGVyID0gMDtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBiZWZvcmUgYSByZXF1ZXN0XHJcbmNvbnN0IGJlZm9yZVJlcXVlc3QgPSBbXTtcclxuXHJcbi8vIFRoZSBhcnJheSBvZiBjYWxsYmFja3MgdG8gY2FsbCBhZnRlciBhIHJlcXVlc3RcclxuY29uc3QgYWZ0ZXJSZXF1ZXN0ID0gW107XHJcblxyXG4vKipcclxuICogSW52b2tlcyBhbiBhcnJheSBvZiBjYWxsYmFjayBmdW5jdGlvbnMgd2l0aCBzcGVjaWZpZWQgcGFyYW1ldGVycywgYWxsb3dpbmdcclxuICogY3VzdG9taXphdGlvbiBvZiByZXF1ZXN0IGhhbmRsaW5nLlxyXG4gKlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9uW119IGNhbGxiYWNrcyAtIEFuIGFycmF5IG9mIGNhbGxiYWNrIGZ1bmN0aW9uc1xyXG4gKiB0byBiZSBleGVjdXRlZC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlcXVlc3R9IHJlcXVlc3QgLSBUaGUgRXhwcmVzcyByZXF1ZXN0IG9iamVjdC5cclxuICogQHBhcmFtIHtFeHByZXNzLlJlc3BvbnNlfSByZXNwb25zZSAtIFRoZSBFeHByZXNzIHJlc3BvbnNlIG9iamVjdC5cclxuICogQHBhcmFtIHtPYmplY3R9IGRhdGEgLSBBbiBvYmplY3QgY29udGFpbmluZyBwYXJhbWV0ZXJzIGxpa2UgaWQsIHVuaXF1ZUlkLFxyXG4gKiB0eXBlLCBhbmQgYm9keS5cclxuICpcclxuICogQHJldHVybnMge2Jvb2xlYW59IC0gUmV0dXJucyBhIGJvb2xlYW4gaW5kaWNhdGluZyB0aGUgb3ZlcmFsbCByZXN1bHRcclxuICogb2YgdGhlIGNhbGxiYWNrIGludm9jYXRpb25zLlxyXG4gKi9cclxuY29uc3QgZG9DYWxsYmFja3MgPSAoY2FsbGJhY2tzLCByZXF1ZXN0LCByZXNwb25zZSwgZGF0YSkgPT4ge1xyXG4gIGxldCByZXN1bHQgPSB0cnVlO1xyXG4gIGNvbnN0IHsgaWQsIHVuaXF1ZUlkLCB0eXBlLCBib2R5IH0gPSBkYXRhO1xyXG5cclxuICBjYWxsYmFja3Muc29tZSgoY2FsbGJhY2spID0+IHtcclxuICAgIGlmIChjYWxsYmFjaykge1xyXG4gICAgICBsZXQgY2FsbFJlc3BvbnNlID0gY2FsbGJhY2socmVxdWVzdCwgcmVzcG9uc2UsIGlkLCB1bmlxdWVJZCwgdHlwZSwgYm9keSk7XHJcblxyXG4gICAgICBpZiAoY2FsbFJlc3BvbnNlICE9PSB1bmRlZmluZWQgJiYgY2FsbFJlc3BvbnNlICE9PSB0cnVlKSB7XHJcbiAgICAgICAgcmVzdWx0ID0gY2FsbFJlc3BvbnNlO1xyXG4gICAgICB9XHJcblxyXG4gICAgICByZXR1cm4gdHJ1ZTtcclxuICAgIH1cclxuICB9KTtcclxuXHJcbiAgcmV0dXJuIHJlc3VsdDtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBIYW5kbGVzIHRoZSBleHBvcnQgcmVxdWVzdHMgZnJvbSB0aGUgY2xpZW50LlxyXG4gKlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVxdWVzdH0gcmVxdWVzdCAtIFRoZSBFeHByZXNzIHJlcXVlc3Qgb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0V4cHJlc3MuUmVzcG9uc2V9IHJlc3BvbnNlIC0gVGhlIEV4cHJlc3MgcmVzcG9uc2Ugb2JqZWN0LlxyXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBuZXh0IC0gVGhlIG5leHQgbWlkZGxld2FyZSBmdW5jdGlvbi5cclxuICpcclxuICogQHJldHVybnMge1Byb21pc2U8dm9pZD59IC0gQSBwcm9taXNlIHRoYXQgcmVzb2x2ZXMgb25jZSB0aGUgZXhwb3J0IHByb2Nlc3NcclxuICogaXMgY29tcGxldGUuXHJcbiAqL1xyXG5jb25zdCBleHBvcnRIYW5kbGVyID0gYXN5bmMgKHJlcXVlc3QsIHJlc3BvbnNlLCBuZXh0KSA9PiB7XHJcbiAgdHJ5IHtcclxuICAgIC8vIFN0YXJ0IGNvdW50aW5nIHRpbWVcclxuICAgIGNvbnN0IHN0b3BDb3VudGVyID0gbWVhc3VyZVRpbWUoKTtcclxuXHJcbiAgICAvLyBDcmVhdGUgYSB1bmlxdWUgSUQgZm9yIGEgcmVxdWVzdFxyXG4gICAgY29uc3QgdW5pcXVlSWQgPSB1dWlkKCkucmVwbGFjZSgvLS9nLCAnJyk7XHJcblxyXG4gICAgLy8gR2V0IHRoZSBjdXJyZW50IHNlcnZlcidzIGdlbmVyYWwgb3B0aW9uc1xyXG4gICAgY29uc3QgZGVmYXVsdE9wdGlvbnMgPSBnZXRPcHRpb25zKCk7XHJcblxyXG4gICAgY29uc3QgYm9keSA9IHJlcXVlc3QuYm9keTtcclxuICAgIGNvbnN0IGlkID0gKytyZXF1ZXN0c0NvdW50ZXI7XHJcblxyXG4gICAgbGV0IHR5cGUgPSBmaXhUeXBlKGJvZHkudHlwZSk7XHJcblxyXG4gICAgLy8gVGhyb3cgJ0JhZCBSZXF1ZXN0JyBpZiB0aGVyZSdzIG5vIGJvZHlcclxuICAgIGlmICghYm9keSB8fCBpc09iamVjdEVtcHR5KGJvZHkpKSB7XHJcbiAgICAgIHRocm93IG5ldyBIdHRwRXJyb3IoXHJcbiAgICAgICAgJ1RoZSByZXF1ZXN0IGJvZHkgaXMgcmVxdWlyZWQuIFBsZWFzZSBlbnN1cmUgdGhhdCB5b3VyIENvbnRlbnQtVHlwZSBoZWFkZXIgaXMgY29ycmVjdCAoYWNjZXB0ZWQgdHlwZXMgYXJlIGFwcGxpY2F0aW9uL2pzb24gYW5kIG11bHRpcGFydC9mb3JtLWRhdGEpLicsXHJcbiAgICAgICAgNDAwXHJcbiAgICAgICk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gQWxsIG9mIHRoZSBiZWxvdyBjYW4gYmUgdXNlZFxyXG4gICAgbGV0IGluc3RyID0gaXNDb3JyZWN0SlNPTihib2R5LmluZmlsZSB8fCBib2R5Lm9wdGlvbnMgfHwgYm9keS5kYXRhKTtcclxuXHJcbiAgICAvLyBUaHJvdyAnQmFkIFJlcXVlc3QnIGlmIHRoZXJlJ3Mgbm8gSlNPTiBvciBTVkcgdG8gZXhwb3J0XHJcbiAgICBpZiAoIWluc3RyICYmICFib2R5LnN2Zykge1xyXG4gICAgICBsb2coXHJcbiAgICAgICAgMixcclxuICAgICAgICBgVGhlIHJlcXVlc3Qgd2l0aCBJRCAke3VuaXF1ZUlkfSBmcm9tICR7XHJcbiAgICAgICAgICByZXF1ZXN0LmhlYWRlcnNbJ3gtZm9yd2FyZGVkLWZvciddIHx8IHJlcXVlc3QuY29ubmVjdGlvbi5yZW1vdGVBZGRyZXNzXHJcbiAgICAgICAgfSB3YXMgaW5jb3JyZWN0LiBQYXlsb2FkIHJlY2VpdmVkOiAke0pTT04uc3RyaW5naWZ5KGJvZHkpfS5gXHJcbiAgICAgICk7XHJcblxyXG4gICAgICB0aHJvdyBuZXcgSHR0cEVycm9yKFxyXG4gICAgICAgIFwiTm8gY29ycmVjdCBjaGFydCBkYXRhIGZvdW5kLiBFbnN1cmUgdGhhdCB5b3UgYXJlIHVzaW5nIGVpdGhlciBhcHBsaWNhdGlvbi9qc29uIG9yIG11bHRpcGFydC9mb3JtLWRhdGEgaGVhZGVycy4gSWYgc2VuZGluZyBKU09OLCBtYWtlIHN1cmUgdGhlIGNoYXJ0IGRhdGEgaXMgaW4gdGhlICdpbmZpbGUnLCAnb3B0aW9ucycsIG9yICdkYXRhJyBhdHRyaWJ1dGUuIElmIHNlbmRpbmcgU1ZHLCBlbnN1cmUgaXQgaXMgaW4gdGhlICdzdmcnIGF0dHJpYnV0ZS5cIixcclxuICAgICAgICA0MDBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY2FsbFJlc3BvbnNlID0gZmFsc2U7XHJcblxyXG4gICAgLy8gQ2FsbCB0aGUgYmVmb3JlIHJlcXVlc3QgZnVuY3Rpb25zXHJcbiAgICBjYWxsUmVzcG9uc2UgPSBkb0NhbGxiYWNrcyhiZWZvcmVSZXF1ZXN0LCByZXF1ZXN0LCByZXNwb25zZSwge1xyXG4gICAgICBpZCxcclxuICAgICAgdW5pcXVlSWQsXHJcbiAgICAgIHR5cGUsXHJcbiAgICAgIGJvZHlcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIEJsb2NrIHRoZSByZXF1ZXN0IGlmIG9uZSBvZiBhIGNhbGxiYWNrcyBmYWlsZWRcclxuICAgIGlmIChjYWxsUmVzcG9uc2UgIT09IHRydWUpIHtcclxuICAgICAgcmV0dXJuIHJlc3BvbnNlLnNlbmQoY2FsbFJlc3BvbnNlKTtcclxuICAgIH1cclxuXHJcbiAgICBsZXQgY29ubmVjdGlvbkFib3J0ZWQgPSBmYWxzZTtcclxuXHJcbiAgICAvLyBJbiBjYXNlIHRoZSBjb25uZWN0aW9uIGlzIGNsb3NlZCwgZm9yY2UgdG8gYWJvcnQgZnVydGhlciBhY3Rpb25zXHJcbiAgICByZXF1ZXN0LnNvY2tldC5vbignY2xvc2UnLCAoKSA9PiB7XHJcbiAgICAgIGNvbm5lY3Rpb25BYm9ydGVkID0gdHJ1ZTtcclxuICAgIH0pO1xyXG5cclxuICAgIGxvZyg0LCBgW2V4cG9ydF0gR290IGFuIGluY29taW5nIEhUVFAgcmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9LmApO1xyXG5cclxuICAgIGJvZHkuY29uc3RyID0gKHR5cGVvZiBib2R5LmNvbnN0ciA9PT0gJ3N0cmluZycgJiYgYm9keS5jb25zdHIpIHx8ICdjaGFydCc7XHJcblxyXG4gICAgLy8gR2F0aGVyIGFuZCBvcmdhbml6ZSBvcHRpb25zIGZyb20gdGhlIHBheWxvYWRcclxuICAgIGNvbnN0IHJlcXVlc3RPcHRpb25zID0ge1xyXG4gICAgICBleHBvcnQ6IHtcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICB0eXBlLFxyXG4gICAgICAgIGNvbnN0cjogYm9keS5jb25zdHJbMF0udG9Mb3dlckNhc2UoKSArIGJvZHkuY29uc3RyLnN1YnN0cigxKSxcclxuICAgICAgICBoZWlnaHQ6IGJvZHkuaGVpZ2h0LFxyXG4gICAgICAgIHdpZHRoOiBib2R5LndpZHRoLFxyXG4gICAgICAgIHNjYWxlOiBib2R5LnNjYWxlIHx8IGRlZmF1bHRPcHRpb25zLmV4cG9ydC5zY2FsZSxcclxuICAgICAgICBnbG9iYWxPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkuZ2xvYmFsT3B0aW9ucywgdHJ1ZSksXHJcbiAgICAgICAgdGhlbWVPcHRpb25zOiBpc0NvcnJlY3RKU09OKGJvZHkudGhlbWVPcHRpb25zLCB0cnVlKVxyXG4gICAgICB9LFxyXG4gICAgICBjdXN0b21Mb2dpYzoge1xyXG4gICAgICAgIGFsbG93Q29kZUV4ZWN1dGlvbjogZ2V0QWxsb3dDb2RlRXhlY3V0aW9uKCksXHJcbiAgICAgICAgYWxsb3dGaWxlUmVzb3VyY2VzOiBmYWxzZSxcclxuICAgICAgICByZXNvdXJjZXM6IGlzQ29ycmVjdEpTT04oYm9keS5yZXNvdXJjZXMsIHRydWUpLFxyXG4gICAgICAgIGNhbGxiYWNrOiBib2R5LmNhbGxiYWNrLFxyXG4gICAgICAgIGN1c3RvbUNvZGU6IGJvZHkuY3VzdG9tQ29kZVxyXG4gICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIGlmIChpbnN0cikge1xyXG4gICAgICAvLyBTdHJpbmdpZnkgSlNPTiB3aXRoIG9wdGlvbnNcclxuICAgICAgcmVxdWVzdE9wdGlvbnMuZXhwb3J0Lmluc3RyID0gb3B0aW9uc1N0cmluZ2lmeShcclxuICAgICAgICBpbnN0cixcclxuICAgICAgICByZXF1ZXN0T3B0aW9ucy5jdXN0b21Mb2dpYy5hbGxvd0NvZGVFeGVjdXRpb25cclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBNZXJnZSB0aGUgcmVxdWVzdCBvcHRpb25zIGludG8gZGVmYXVsdCBvbmVzXHJcbiAgICBjb25zdCBvcHRpb25zID0gbWVyZ2VDb25maWdPcHRpb25zKGRlZmF1bHRPcHRpb25zLCByZXF1ZXN0T3B0aW9ucyk7XHJcblxyXG4gICAgLy8gU2F2ZSB0aGUgSlNPTiBpZiBleGlzdHNcclxuICAgIG9wdGlvbnMuZXhwb3J0Lm9wdGlvbnMgPSBpbnN0cjtcclxuXHJcbiAgICAvLyBMYXN0bHksIGFkZCB0aGUgc2VydmVyIHNwZWNpZmljIGFyZ3VtZW50cyBpbnRvIG9wdGlvbnMgYXMgcGF5bG9hZFxyXG4gICAgb3B0aW9ucy5wYXlsb2FkID0ge1xyXG4gICAgICBzdmc6IGJvZHkuc3ZnIHx8IGZhbHNlLFxyXG4gICAgICBiNjQ6IGJvZHkuYjY0IHx8IGZhbHNlLFxyXG4gICAgICBub0Rvd25sb2FkOiBib2R5Lm5vRG93bmxvYWQgfHwgZmFsc2UsXHJcbiAgICAgIHJlcXVlc3RJZDogdW5pcXVlSWRcclxuICAgIH07XHJcblxyXG4gICAgLy8gVGVzdCB4bGluazpocmVmIGVsZW1lbnRzIGZyb20gcGF5bG9hZCdzIFNWR1xyXG4gICAgaWYgKGJvZHkuc3ZnICYmIGlzUHJpdmF0ZVJhbmdlVXJsRm91bmQob3B0aW9ucy5wYXlsb2FkLnN2ZykpIHtcclxuICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAnU1ZHIHBvdGVudGlhbGx5IGNvbnRhaW4gYXQgbGVhc3Qgb25lIGZvcmJpZGRlbiBVUkwgaW4geGxpbms6aHJlZiBlbGVtZW50LiBQbGVhc2UgcmV2aWV3IHRoZSBTVkcgY29udGVudCBhbmQgZW5zdXJlIHRoYXQgYWxsIHJlZmVyZW5jZWQgVVJMcyBjb21wbHkgd2l0aCBzZWN1cml0eSBwb2xpY2llcy4nLFxyXG4gICAgICAgIDQwMFxyXG4gICAgICApO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIFN0YXJ0IHRoZSBleHBvcnQgcHJvY2Vzc1xyXG4gICAgYXdhaXQgc3RhcnRFeHBvcnQob3B0aW9ucywgKGVycm9yLCBpbmZvKSA9PiB7XHJcbiAgICAgIC8vIFJlbW92ZSB0aGUgY2xvc2UgZXZlbnQgZnJvbSB0aGUgc29ja2V0XHJcbiAgICAgIHJlcXVlc3Quc29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygnY2xvc2UnKTtcclxuXHJcbiAgICAgIC8vIEFmdGVyIHRoZSB3aG9sZSBleHBvcnRpbmcgcHJvY2Vzc1xyXG4gICAgICBpZiAoZGVmYXVsdE9wdGlvbnMuc2VydmVyLmJlbmNobWFya2luZykge1xyXG4gICAgICAgIGxvZyhcclxuICAgICAgICAgIDUsXHJcbiAgICAgICAgICBgW2JlbmNobWFya10gUmVxdWVzdCB3aXRoIElEICR7dW5pcXVlSWR9IC0gQWZ0ZXIgdGhlIHdob2xlIGV4cG9ydGluZyBwcm9jZXNzOiAke3N0b3BDb3VudGVyKCl9bXMuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIElmIHRoZSBjb25uZWN0aW9uIHdhcyBjbG9zZWQsIGRvIG5vdGhpbmdcclxuICAgICAgaWYgKGNvbm5lY3Rpb25BYm9ydGVkKSB7XHJcbiAgICAgICAgcmV0dXJuIGxvZyhcclxuICAgICAgICAgIDMsXHJcbiAgICAgICAgICBgW2V4cG9ydF0gVGhlIGNsaWVudCBjbG9zZWQgdGhlIGNvbm5lY3Rpb24gYmVmb3JlIHRoZSBjaGFydCBmaW5pc2hlZCBwcm9jZXNzaW5nLmBcclxuICAgICAgICApO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBlcnJvciwgbG9nIGl0IGFuZCBzZW5kIGl0IHRvIHRoZSBlcnJvciBtaWRkbGV3YXJlXHJcbiAgICAgIGlmIChlcnJvcikge1xyXG4gICAgICAgIHRocm93IGVycm9yO1xyXG4gICAgICB9XHJcblxyXG4gICAgICAvLyBJZiBkYXRhIGlzIG1pc3NpbmcsIGxvZyB0aGUgbWVzc2FnZSBhbmQgc2VuZCBpdCB0byB0aGUgZXJyb3IgbWlkZGxld2FyZVxyXG4gICAgICBpZiAoIWluZm8gfHwgIWluZm8ucmVzdWx0KSB7XHJcbiAgICAgICAgdGhyb3cgbmV3IEh0dHBFcnJvcihcclxuICAgICAgICAgIGBVbmV4cGVjdGVkIHJldHVybiBmcm9tIGNoYXJ0IGdlbmVyYXRpb24uIFBsZWFzZSBjaGVjayB5b3VyIHJlcXVlc3QgZGF0YS4gRm9yIHRoZSByZXF1ZXN0IHdpdGggSUQgJHt1bmlxdWVJZH0sIHRoZSByZXN1bHQgaXMgJHtpbmZvLnJlc3VsdH0uYCxcclxuICAgICAgICAgIDQwMFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIC8vIEdldCB0aGUgdHlwZSBmcm9tIG9wdGlvbnNcclxuICAgICAgdHlwZSA9IGluZm8ub3B0aW9ucy5leHBvcnQudHlwZTtcclxuXHJcbiAgICAgIC8vIFRoZSBhZnRlciByZXF1ZXN0IGNhbGxiYWNrc1xyXG4gICAgICBkb0NhbGxiYWNrcyhhZnRlclJlcXVlc3QsIHJlcXVlc3QsIHJlc3BvbnNlLCB7IGlkLCBib2R5OiBpbmZvLnJlc3VsdCB9KTtcclxuXHJcbiAgICAgIGlmIChpbmZvLnJlc3VsdCkge1xyXG4gICAgICAgIC8vIElmIG9ubHkgYmFzZTY0IGlzIHJlcXVpcmVkLCByZXR1cm4gaXRcclxuICAgICAgICBpZiAoYm9keS5iNjQpIHtcclxuICAgICAgICAgIC8vIFNWRyBFeGNlcHRpb24gZm9yIHRoZSBIaWdoY2hhcnRzIDExLjMuMCB2ZXJzaW9uXHJcbiAgICAgICAgICBpZiAodHlwZSA9PT0gJ3BkZicgfHwgdHlwZSA9PSAnc3ZnJykge1xyXG4gICAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChcclxuICAgICAgICAgICAgICBCdWZmZXIuZnJvbShpbmZvLnJlc3VsdCwgJ3V0ZjgnKS50b1N0cmluZygnYmFzZTY0JylcclxuICAgICAgICAgICAgKTtcclxuICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICByZXR1cm4gcmVzcG9uc2Uuc2VuZChpbmZvLnJlc3VsdCk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBTZXQgY29ycmVjdCBjb250ZW50IHR5cGVcclxuICAgICAgICByZXNwb25zZS5oZWFkZXIoJ0NvbnRlbnQtVHlwZScsIHJldmVyc2VkTWltZVt0eXBlXSB8fCAnaW1hZ2UvcG5nJyk7XHJcblxyXG4gICAgICAgIC8vIERlY2lkZSB3aGV0aGVyIHRvIGRvd25sb2FkIG9yIG5vdCBjaGFydCBmaWxlXHJcbiAgICAgICAgaWYgKCFib2R5Lm5vRG93bmxvYWQpIHtcclxuICAgICAgICAgIHJlc3BvbnNlLmF0dGFjaG1lbnQoXHJcbiAgICAgICAgICAgIGAke3JlcXVlc3QucGFyYW1zLmZpbGVuYW1lIHx8IHJlcXVlc3QuYm9keS5maWxlbmFtZSB8fCAnY2hhcnQnfS4ke1xyXG4gICAgICAgICAgICAgIHR5cGUgfHwgJ3BuZydcclxuICAgICAgICAgICAgfWBcclxuICAgICAgICAgICk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBJZiBTVkcsIHJldHVybiBwbGFpbiBjb250ZW50XHJcbiAgICAgICAgcmV0dXJuIHR5cGUgPT09ICdzdmcnXHJcbiAgICAgICAgICA/IHJlc3BvbnNlLnNlbmQoaW5mby5yZXN1bHQpXHJcbiAgICAgICAgICA6IHJlc3BvbnNlLnNlbmQoQnVmZmVyLmZyb20oaW5mby5yZXN1bHQsICdiYXNlNjQnKSk7XHJcbiAgICAgIH1cclxuICAgIH0pO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICBuZXh0KGVycm9yKTtcclxuICB9XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PiB7XHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgYXQgdGhlIHJvb3QgZW5kcG9pbnQuXHJcbiAgICovXHJcbiAgYXBwLnBvc3QoJy8nLCBleHBvcnRIYW5kbGVyKTtcclxuXHJcbiAgLyoqXHJcbiAgICogQWRkcyB0aGUgUE9TVCAvOmZpbGVuYW1lIGEgcm91dGUgZm9yIGhhbmRsaW5nIFBPU1QgcmVxdWVzdHMgd2l0aFxyXG4gICAqIGEgc3BlY2lmaWVkIGZpbGVuYW1lIHBhcmFtZXRlci5cclxuICAgKi9cclxuICBhcHAucG9zdCgnLzpmaWxlbmFtZScsIGV4cG9ydEhhbmRsZXIpO1xyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHJlYWRGaWxlU3luYyB9IGZyb20gJ2ZzJztcclxuaW1wb3J0IHsgam9pbiBhcyBwYXRoZXIgfSBmcm9tICdwYXRoJztcclxuaW1wb3J0IHsgbG9nIH0gZnJvbSAnLi4vLi4vbG9nZ2VyLmpzJztcclxuXHJcbmltcG9ydCB7IHZlcnNpb24gfSBmcm9tICcuLi8uLi9jYWNoZS5qcyc7XHJcbmltcG9ydCB7IGFkZEludGVydmFsIH0gZnJvbSAnLi4vLi4vaW50ZXJ2YWxzLmpzJztcclxuaW1wb3J0IHBvb2wgZnJvbSAnLi4vLi4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbmNvbnN0IHBrZ0ZpbGUgPSBKU09OLnBhcnNlKHJlYWRGaWxlU3luYyhwYXRoZXIoX19kaXJuYW1lLCAncGFja2FnZS5qc29uJykpKTtcclxuXHJcbmNvbnN0IHNlcnZlclN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XHJcblxyXG5jb25zdCBzdWNjZXNzUmF0ZXMgPSBbXTtcclxuY29uc3QgcmVjb3JkSW50ZXJ2YWwgPSA2MCAqIDEwMDA7IC8vIHJlY29yZCBldmVyeSBtaW51dGVcclxuY29uc3Qgd2luZG93U2l6ZSA9IDMwOyAvLyAzMCBtaW51dGVzXHJcblxyXG4vKipcclxuICogQ2FsY3VsYXRlcyBtb3ZpbmcgYXZlcmFnZSBpbmRpY2F0b3IgYmFzZWQgb24gdGhlIGRhdGEgZnJvbSB0aGUgc3VjY2Vzc1JhdGVzXHJcbiAqIGFycmF5LlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7bnVtYmVyfSAtIEEgbW92aW5nIGF2ZXJhZ2UgZm9yIHN1Y2Nlc3MgcmF0aW8gb2YgdGhlIHNlcnZlciBleHBvcnRzLlxyXG4gKi9cclxuZnVuY3Rpb24gY2FsY3VsYXRlTW92aW5nQXZlcmFnZSgpIHtcclxuICBjb25zdCBzdW0gPSBzdWNjZXNzUmF0ZXMucmVkdWNlKChhLCBiKSA9PiBhICsgYiwgMCk7XHJcbiAgcmV0dXJuIHN1bSAvIHN1Y2Nlc3NSYXRlcy5sZW5ndGg7XHJcbn1cclxuXHJcbi8qKlxyXG4gKiBTdGFydHMgdGhlIGludGVydmFsIHJlc3BvbnNpYmxlIGZvciBjYWxjdWxhdGluZyBjdXJyZW50IHN1Y2Nlc3MgcmF0ZSByYXRpb1xyXG4gKiBhbmQgZ2F0aGVyc1xyXG4gKlxyXG4gKiBAcmV0dXJucyB7Tm9kZUpTLlRpbWVvdXR9IGlkIC0gSWQgb2YgYW4gaW50ZXJ2YWwuXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc3RhcnRTdWNjZXNzUmF0ZSA9ICgpID0+XHJcbiAgc2V0SW50ZXJ2YWwoKCkgPT4ge1xyXG4gICAgY29uc3Qgc3RhdHMgPSBwb29sLmdldFN0YXRzKCk7XHJcbiAgICBjb25zdCBzdWNjZXNzUmF0aW8gPVxyXG4gICAgICBzdGF0cy5leHBvcnRBdHRlbXB0cyA9PT0gMFxyXG4gICAgICAgID8gMVxyXG4gICAgICAgIDogKHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMgLyBzdGF0cy5leHBvcnRBdHRlbXB0cykgKiAxMDA7XHJcblxyXG4gICAgc3VjY2Vzc1JhdGVzLnB1c2goc3VjY2Vzc1JhdGlvKTtcclxuICAgIGlmIChzdWNjZXNzUmF0ZXMubGVuZ3RoID4gd2luZG93U2l6ZSkge1xyXG4gICAgICBzdWNjZXNzUmF0ZXMuc2hpZnQoKTtcclxuICAgIH1cclxuICB9LCByZWNvcmRJbnRlcnZhbCk7XHJcblxyXG4vKipcclxuICogQWRkcyB0aGUgL2hlYWx0aCBhbmQgL3N1Y2Nlc3MtbW92aW5nLWF2ZXJhZ2Ugcm91dGVzXHJcbiAqIHdoaWNoIG91dHB1dCBiYXNpYyBzdGF0cyBmb3IgdGhlIHNlcnZlci5cclxuICovXHJcbmV4cG9ydCBkZWZhdWx0IGZ1bmN0aW9uIGFkZEhlYWx0aFJvdXRlcyhhcHApIHtcclxuICBpZiAoIWFwcCkge1xyXG4gICAgcmV0dXJuIGZhbHNlO1xyXG4gIH1cclxuXHJcbiAgLy8gU3RhcnQgcHJvY2Vzc2luZyBzdWNjZXNzIHJhdGUgcmF0aW8gaW50ZXJ2YWwgYW5kIHNhdmUgaXRzIGlkIHRvIHRoZSBhcnJheVxyXG4gIC8vIGZvciB0aGUgZ3JhY2VmdWwgY2xlYXJpbmcgb24gc2h1dGRvd24gd2l0aCBpbmplY3RlZCBhZGRJbnRlcnZhbCBmdW50aW9uXHJcbiAgYWRkSW50ZXJ2YWwoc3RhcnRTdWNjZXNzUmF0ZSgpKTtcclxuXHJcbiAgYXBwLmdldCgnL2hlYWx0aCcsIChfLCByZXMpID0+IHtcclxuICAgIGNvbnN0IHN0YXRzID0gcG9vbC5nZXRTdGF0cygpO1xyXG4gICAgY29uc3QgcGVyaW9kID0gc3VjY2Vzc1JhdGVzLmxlbmd0aDtcclxuICAgIGNvbnN0IG1vdmluZ0F2ZXJhZ2UgPSBjYWxjdWxhdGVNb3ZpbmdBdmVyYWdlKCk7XHJcblxyXG4gICAgbG9nKDQsICdbaGVhbHRoLmpzXSBHRVQgL2hlYWx0aCBbMjAwXSAtIHJldHVybmluZyBzZXJ2ZXIgaGVhbHRoLicpO1xyXG5cclxuICAgIHJlcy5zZW5kKHtcclxuICAgICAgc3RhdHVzOiAnT0snLFxyXG4gICAgICBib290VGltZTogc2VydmVyU3RhcnRUaW1lLFxyXG4gICAgICB1cHRpbWU6XHJcbiAgICAgICAgTWF0aC5mbG9vcihcclxuICAgICAgICAgIChuZXcgRGF0ZSgpLmdldFRpbWUoKSAtIHNlcnZlclN0YXJ0VGltZS5nZXRUaW1lKCkpIC8gMTAwMCAvIDYwXHJcbiAgICAgICAgKSArICcgbWludXRlcycsXHJcbiAgICAgIHZlcnNpb246IHBrZ0ZpbGUudmVyc2lvbixcclxuICAgICAgaGlnaGNoYXJ0c1ZlcnNpb246IHZlcnNpb24oKSxcclxuICAgICAgYXZlcmFnZVByb2Nlc3NpbmdUaW1lOiBzdGF0cy5zcGVudEF2ZXJhZ2UsXHJcbiAgICAgIHBlcmZvcm1lZEV4cG9ydHM6IHN0YXRzLnBlcmZvcm1lZEV4cG9ydHMsXHJcbiAgICAgIGZhaWxlZEV4cG9ydHM6IHN0YXRzLmRyb3BwZWRFeHBvcnRzLFxyXG4gICAgICBleHBvcnRBdHRlbXB0czogc3RhdHMuZXhwb3J0QXR0ZW1wdHMsXHJcbiAgICAgIHN1Y2Vzc1JhdGlvOiAoc3RhdHMucGVyZm9ybWVkRXhwb3J0cyAvIHN0YXRzLmV4cG9ydEF0dGVtcHRzKSAqIDEwMCxcclxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGltcG9ydC9uby1uYW1lZC1hcy1kZWZhdWx0LW1lbWJlclxyXG4gICAgICBwb29sOiBwb29sLmdldFBvb2xJbmZvSlNPTigpLFxyXG5cclxuICAgICAgLy8gTW92aW5nIGF2ZXJhZ2VcclxuICAgICAgcGVyaW9kLFxyXG4gICAgICBtb3ZpbmdBdmVyYWdlLFxyXG4gICAgICBtZXNzYWdlOiBgTGFzdCAke3BlcmlvZH0gbWludXRlcyBoYWQgYSBzdWNjZXNzIHJhdGUgb2YgJHttb3ZpbmdBdmVyYWdlLnRvRml4ZWQoMil9JS5gLFxyXG5cclxuICAgICAgLy8gU1ZHL0pTT04gYXR0ZW1wdHNcclxuICAgICAgc3ZnRXhwb3J0QXR0ZW1wdHM6IHN0YXRzLmV4cG9ydEZyb21TdmdBdHRlbXB0cyxcclxuICAgICAganNvbkV4cG9ydEF0dGVtcHRzOiBzdGF0cy5wZXJmb3JtZWRFeHBvcnRzIC0gc3RhdHMuZXhwb3J0RnJvbVN2Z0F0dGVtcHRzXHJcbiAgICB9KTtcclxuICB9KTtcclxufVxyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IHByb21pc2VzIGFzIGZzUHJvbWlzZXMgfSBmcm9tICdmcyc7XHJcbmltcG9ydCB7IHBvc2l4IH0gZnJvbSAncGF0aCc7XHJcblxyXG5pbXBvcnQgY29ycyBmcm9tICdjb3JzJztcclxuaW1wb3J0IGV4cHJlc3MgZnJvbSAnZXhwcmVzcyc7XHJcbmltcG9ydCBodHRwIGZyb20gJ2h0dHAnO1xyXG5pbXBvcnQgaHR0cHMgZnJvbSAnaHR0cHMnO1xyXG5pbXBvcnQgbXVsdGVyIGZyb20gJ211bHRlcic7XHJcblxyXG5pbXBvcnQgZXJyb3JIYW5kbGVyIGZyb20gJy4vZXJyb3IuanMnO1xyXG5pbXBvcnQgcmF0ZUxpbWl0IGZyb20gJy4vcmF0ZV9saW1pdC5qcyc7XHJcbmltcG9ydCB7IGxvZywgbG9nV2l0aFN0YWNrIH0gZnJvbSAnLi4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgX19kaXJuYW1lIH0gZnJvbSAnLi4vdXRpbHMuanMnO1xyXG5cclxuaW1wb3J0IHZTd2l0Y2hSb3V0ZSBmcm9tICcuL3JvdXRlcy9jaGFuZ2VfaGNfdmVyc2lvbi5qcyc7XHJcbmltcG9ydCBleHBvcnRSb3V0ZXMgZnJvbSAnLi9yb3V0ZXMvZXhwb3J0LmpzJztcclxuaW1wb3J0IGhlYWx0aFJvdXRlIGZyb20gJy4vcm91dGVzL2hlYWx0aC5qcyc7XHJcbmltcG9ydCB1aVJvdXRlIGZyb20gJy4vcm91dGVzL3VpLmpzJztcclxuXHJcbmltcG9ydCBFeHBvcnRFcnJvciBmcm9tICcuLi9lcnJvcnMvRXhwb3J0RXJyb3IuanMnO1xyXG5cclxuLy8gQXJyYXkgb2YgYW4gYWN0aXZlIHNlcnZlcnNcclxuY29uc3QgYWN0aXZlU2VydmVycyA9IG5ldyBNYXAoKTtcclxuXHJcbi8vIENyZWF0ZSBleHByZXNzIGFwcFxyXG5jb25zdCBhcHAgPSBleHByZXNzKCk7XHJcblxyXG4vLyBEaXNhYmxlIHRoZSBYLVBvd2VyZWQtQnkgaGVhZGVyXHJcbmFwcC5kaXNhYmxlKCd4LXBvd2VyZWQtYnknKTtcclxuXHJcbi8vIEVuYWJsZSBDT1JTIHN1cHBvcnRcclxuYXBwLnVzZShjb3JzKCkpO1xyXG5cclxuLy8gRW5hYmxlIHBhcnNpbmcgb2YgZm9ybSBkYXRhIChmaWxlcykgd2l0aCBNdWx0ZXIgcGFja2FnZVxyXG5jb25zdCBzdG9yYWdlID0gbXVsdGVyLm1lbW9yeVN0b3JhZ2UoKTtcclxuY29uc3QgdXBsb2FkID0gbXVsdGVyKHtcclxuICBzdG9yYWdlLFxyXG4gIGxpbWl0czoge1xyXG4gICAgZmllbGRTaXplOiA1MCAqIDEwMjQgKiAxMDI0XHJcbiAgfVxyXG59KTtcclxuXHJcbi8vIEVuYWJsZSBib2R5IHBhcnNlclxyXG5hcHAudXNlKGV4cHJlc3MuanNvbih7IGxpbWl0OiA1MCAqIDEwMjQgKiAxMDI0IH0pKTtcclxuYXBwLnVzZShleHByZXNzLnVybGVuY29kZWQoeyBleHRlbmRlZDogdHJ1ZSwgbGltaXQ6IDUwICogMTAyNCAqIDEwMjQgfSkpO1xyXG5cclxuLy8gVXNlIG9ubHkgbm9uLWZpbGUgbXVsdGlwYXJ0IGZvcm0gZmllbGRzXHJcbmFwcC51c2UodXBsb2FkLm5vbmUoKSk7XHJcblxyXG4vKipcclxuICogQXR0YWNoIGVycm9yIGhhbmRsZXJzIHRvIHRoZSBzZXJ2ZXIuXHJcbiAqXHJcbiAqIEBwYXJhbSB7aHR0cC5TZXJ2ZXJ9IHNlcnZlciAtIFRoZSBIVFRQL0hUVFBTIHNlcnZlciBpbnN0YW5jZS5cclxuICovXHJcbmNvbnN0IGF0dGFjaFNlcnZlckVycm9ySGFuZGxlcnMgPSAoc2VydmVyKSA9PiB7XHJcbiAgc2VydmVyLm9uKCdjbGllbnRFcnJvcicsIChlcnJvcikgPT4ge1xyXG4gICAgbG9nV2l0aFN0YWNrKDEsIGVycm9yLCBgW3NlcnZlcl0gQ2xpZW50IGVycm9yOiAke2Vycm9yLm1lc3NhZ2V9YCk7XHJcbiAgfSk7XHJcblxyXG4gIHNlcnZlci5vbignZXJyb3InLCAoZXJyb3IpID0+IHtcclxuICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNlcnZlciBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gIH0pO1xyXG5cclxuICBzZXJ2ZXIub24oJ2Nvbm5lY3Rpb24nLCAoc29ja2V0KSA9PiB7XHJcbiAgICBzb2NrZXQub24oJ2Vycm9yJywgKGVycm9yKSA9PiB7XHJcbiAgICAgIGxvZ1dpdGhTdGFjaygxLCBlcnJvciwgYFtzZXJ2ZXJdIFNvY2tldCBlcnJvcjogJHtlcnJvci5tZXNzYWdlfWApO1xyXG4gICAgfSk7XHJcbiAgfSk7XHJcbn07XHJcblxyXG4vKipcclxuICogU3RhcnRzIGFuIEhUVFAgc2VydmVyIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBjb25maWd1cmF0aW9uLiBUaGUgYHNlcnZlckNvbmZpZ2BcclxuICogb2JqZWN0IGNvbnRhaW5zIGFsbCBzZXJ2ZXIgcmVsYXRlZCBwcm9wZXJ0aWVzIChzZWUgdGhlIGBzZXJ2ZXJgIHNlY3Rpb25cclxuICogaW4gdGhlIGBsaWIvc2NoZW1hcy9jb25maWcuanNgIGZpbGUgZm9yIGEgcmVmZXJlbmNlKS5cclxuICpcclxuICogQHBhcmFtIHtPYmplY3R9IHNlcnZlckNvbmZpZyAtIFRoZSBzZXJ2ZXIgY29uZmlndXJhdGlvbiBvYmplY3QuXHJcbiAqXHJcbiAqIEB0aHJvd3Mge0V4cG9ydEVycm9yfSAtIFRocm93cyBhbiBlcnJvciBpZiB0aGUgc2VydmVyIGNhbm5vdCBiZSBjb25maWd1cmVkXHJcbiAqIGFuZCBzdGFydGVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHN0YXJ0U2VydmVyID0gYXN5bmMgKHNlcnZlckNvbmZpZykgPT4ge1xyXG4gIHRyeSB7XHJcbiAgICAvLyBTdG9wIGlmIG5vdCBlbmFibGVkXHJcbiAgICBpZiAoIXNlcnZlckNvbmZpZy5lbmFibGUpIHtcclxuICAgICAgcmV0dXJuIGZhbHNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIExpc3RlbiBIVFRQIHNlcnZlclxyXG4gICAgaWYgKCFzZXJ2ZXJDb25maWcuc3NsLmZvcmNlKSB7XHJcbiAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQKVxyXG4gICAgICBjb25zdCBodHRwU2VydmVyID0gaHR0cC5jcmVhdGVTZXJ2ZXIoYXBwKTtcclxuXHJcbiAgICAgIC8vIEF0dGFjaCBlcnJvciBoYW5kbGVycyBhbmQgbGlzdGVuIHRvIHRoZSBzZXJ2ZXJcclxuICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIC8vIExpc3RlblxyXG4gICAgICBodHRwU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcucG9ydCwgc2VydmVyQ29uZmlnLmhvc3QpO1xyXG5cclxuICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFAgc2VydmVyXHJcbiAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5wb3J0LCBodHRwU2VydmVyKTtcclxuXHJcbiAgICAgIGxvZyhcclxuICAgICAgICAzLFxyXG4gICAgICAgIGBbc2VydmVyXSBTdGFydGVkIEhUVFAgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnBvcnR9LmBcclxuICAgICAgKTtcclxuICAgIH1cclxuXHJcbiAgICAvLyBMaXN0ZW4gSFRUUFMgc2VydmVyXHJcbiAgICBpZiAoc2VydmVyQ29uZmlnLnNzbC5lbmFibGUpIHtcclxuICAgICAgLy8gU2V0IHVwIGFuIFNTTCBzZXJ2ZXIgYWxzb1xyXG4gICAgICBsZXQga2V5LCBjZXJ0O1xyXG5cclxuICAgICAgdHJ5IHtcclxuICAgICAgICAvLyBHZXQgdGhlIFNTTCBrZXlcclxuICAgICAgICBrZXkgPSBhd2FpdCBmc1Byb21pc2VzLnJlYWRGaWxlKFxyXG4gICAgICAgICAgcG9zaXguam9pbihzZXJ2ZXJDb25maWcuc3NsLmNlcnRQYXRoLCAnc2VydmVyLmtleScpLFxyXG4gICAgICAgICAgJ3V0ZjgnXHJcbiAgICAgICAgKTtcclxuXHJcbiAgICAgICAgLy8gR2V0IHRoZSBTU0wgY2VydGlmaWNhdGVcclxuICAgICAgICBjZXJ0ID0gYXdhaXQgZnNQcm9taXNlcy5yZWFkRmlsZShcclxuICAgICAgICAgIHBvc2l4LmpvaW4oc2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aCwgJ3NlcnZlci5jcnQnKSxcclxuICAgICAgICAgICd1dGY4J1xyXG4gICAgICAgICk7XHJcbiAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICAgICAgbG9nKFxyXG4gICAgICAgICAgMixcclxuICAgICAgICAgIGBbc2VydmVyXSBVbmFibGUgdG8gbG9hZCBrZXkvY2VydGlmaWNhdGUgZnJvbSB0aGUgJyR7c2VydmVyQ29uZmlnLnNzbC5jZXJ0UGF0aH0nIHBhdGguIENvdWxkIG5vdCBydW4gc2VjdXJlZCBsYXllciBzZXJ2ZXIuYFxyXG4gICAgICAgICk7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIGlmIChrZXkgJiYgY2VydCkge1xyXG4gICAgICAgIC8vIE1haW4gc2VydmVyIGluc3RhbmNlIChIVFRQUylcclxuICAgICAgICBjb25zdCBodHRwc1NlcnZlciA9IGh0dHBzLmNyZWF0ZVNlcnZlcih7IGtleSwgY2VydCB9LCBhcHApO1xyXG5cclxuICAgICAgICAvLyBBdHRhY2ggZXJyb3IgaGFuZGxlcnMgYW5kIGxpc3RlbiB0byB0aGUgc2VydmVyXHJcbiAgICAgICAgYXR0YWNoU2VydmVyRXJyb3JIYW5kbGVycyhodHRwc1NlcnZlcik7XHJcblxyXG4gICAgICAgIC8vIExpc3RlblxyXG4gICAgICAgIGh0dHBzU2VydmVyLmxpc3RlbihzZXJ2ZXJDb25maWcuc3NsLnBvcnQsIHNlcnZlckNvbmZpZy5ob3N0KTtcclxuXHJcbiAgICAgICAgLy8gU2F2ZSB0aGUgcmVmZXJlbmNlIHRvIEhUVFBTIHNlcnZlclxyXG4gICAgICAgIGFjdGl2ZVNlcnZlcnMuc2V0KHNlcnZlckNvbmZpZy5zc2wucG9ydCwgaHR0cHNTZXJ2ZXIpO1xyXG5cclxuICAgICAgICBsb2coXHJcbiAgICAgICAgICAzLFxyXG4gICAgICAgICAgYFtzZXJ2ZXJdIFN0YXJ0ZWQgSFRUUFMgc2VydmVyIG9uICR7c2VydmVyQ29uZmlnLmhvc3R9OiR7c2VydmVyQ29uZmlnLnNzbC5wb3J0fS5gXHJcbiAgICAgICAgKTtcclxuICAgICAgfVxyXG4gICAgfVxyXG5cclxuICAgIC8vIEVuYWJsZSB0aGUgcmF0ZSBsaW1pdGVyIGlmIGNvbmZpZyBzYXlzIHNvXHJcbiAgICBpZiAoXHJcbiAgICAgIHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcgJiZcclxuICAgICAgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZy5lbmFibGUgJiZcclxuICAgICAgIVswLCBOYU5dLmluY2x1ZGVzKHNlcnZlckNvbmZpZy5yYXRlTGltaXRpbmcubWF4UmVxdWVzdHMpXHJcbiAgICApIHtcclxuICAgICAgcmF0ZUxpbWl0KGFwcCwgc2VydmVyQ29uZmlnLnJhdGVMaW1pdGluZyk7XHJcbiAgICB9XHJcblxyXG4gICAgLy8gU2V0IHVwIHN0YXRpYyBmb2xkZXIncyByb3V0ZVxyXG4gICAgYXBwLnVzZShleHByZXNzLnN0YXRpYyhwb3NpeC5qb2luKF9fZGlybmFtZSwgJ3B1YmxpYycpKSk7XHJcblxyXG4gICAgLy8gU2V0IHVwIHJvdXRlc1xyXG4gICAgaGVhbHRoUm91dGUoYXBwKTtcclxuICAgIGV4cG9ydFJvdXRlcyhhcHApO1xyXG4gICAgdWlSb3V0ZShhcHApO1xyXG4gICAgdlN3aXRjaFJvdXRlKGFwcCk7XHJcblxyXG4gICAgLy8gU2V0IHVwIGNlbnRyYWxpemVkIGVycm9yIGhhbmRsZXJcclxuICAgIGVycm9ySGFuZGxlcihhcHApO1xyXG4gIH0gY2F0Y2ggKGVycm9yKSB7XHJcbiAgICB0aHJvdyBuZXcgRXhwb3J0RXJyb3IoXHJcbiAgICAgICdbc2VydmVyXSBDb3VsZCBub3QgY29uZmlndXJlIGFuZCBzdGFydCB0aGUgc2VydmVyLidcclxuICAgICkuc2V0RXJyb3IoZXJyb3IpO1xyXG4gIH1cclxufTtcclxuXHJcbi8qKlxyXG4gKiBDbG9zZXMgYWxsIHNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGNsb3NlU2VydmVycyA9ICgpID0+IHtcclxuICBsb2coNCwgYFtzZXJ2ZXJdIENsb3NpbmcgYWxsIHNlcnZlcnMuYCk7XHJcbiAgZm9yIChjb25zdCBbcG9ydCwgc2VydmVyXSBvZiBhY3RpdmVTZXJ2ZXJzKSB7XHJcbiAgICBzZXJ2ZXIuY2xvc2UoKCkgPT4ge1xyXG4gICAgICBhY3RpdmVTZXJ2ZXJzLmRlbGV0ZShwb3J0KTtcclxuICAgICAgbG9nKDQsIGBbc2VydmVyXSBDbG9zZWQgc2VydmVyIG9uIHBvcnQ6ICR7cG9ydH0uYCk7XHJcbiAgICB9KTtcclxuICB9XHJcbn07XHJcblxyXG4vKipcclxuICogR2V0IGFsbCBzZXJ2ZXJzIGFzc29jaWF0ZWQgd2l0aCBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge0FycmF5fSAtIFNlcnZlcnMgYXNzb2NpYXRlZCB3aXRoIEV4cHJlc3MgYXBwIGluc3RhbmNlLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IGdldFNlcnZlcnMgPSAoKSA9PiBhY3RpdmVTZXJ2ZXJzO1xyXG5cclxuLyoqXHJcbiAqIEVuYWJsZSByYXRlIGxpbWl0aW5nIGZvciB0aGUgc2VydmVyLlxyXG4gKlxyXG4gKiBAcGFyYW0ge09iamVjdH0gbGltaXRDb25maWcgLSBDb25maWd1cmF0aW9uIG9iamVjdCBmb3IgcmF0ZSBsaW1pdGluZy5cclxuICovXHJcbmV4cG9ydCBjb25zdCBlbmFibGVSYXRlTGltaXRpbmcgPSAobGltaXRDb25maWcpID0+IHJhdGVMaW1pdChhcHAsIGxpbWl0Q29uZmlnKTtcclxuXHJcbi8qKlxyXG4gKiBHZXQgdGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqXHJcbiAqIEByZXR1cm5zIHtPYmplY3R9IC0gVGhlIEV4cHJlc3MgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0RXhwcmVzcyA9ICgpID0+IGV4cHJlc3M7XHJcblxyXG4vKipcclxuICogR2V0IHRoZSBFeHByZXNzIGFwcCBpbnN0YW5jZS5cclxuICpcclxuICogQHJldHVybnMge09iamVjdH0gLSBUaGUgRXhwcmVzcyBhcHAgaW5zdGFuY2UuXHJcbiAqL1xyXG5leHBvcnQgY29uc3QgZ2V0QXBwID0gKCkgPT4gYXBwO1xyXG5cclxuLyoqXHJcbiAqIEFwcGx5IG1pZGRsZXdhcmUocykgdG8gYSBzcGVjaWZpYyBwYXRoLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSBwYXRoIHRvIHdoaWNoIHRoZSBtaWRkbGV3YXJlKHMpIHNob3VsZCBiZSBhcHBsaWVkLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHVzZSA9IChwYXRoLCAuLi5taWRkbGV3YXJlcykgPT4ge1xyXG4gIGFwcC51c2UocGF0aCwgLi4ubWlkZGxld2FyZXMpO1xyXG59O1xyXG5cclxuLyoqXHJcbiAqIFNldCB1cCBhIHJvdXRlIHdpdGggR0VUIG1ldGhvZCBhbmQgYXBwbHkgbWlkZGxld2FyZShzKS5cclxuICpcclxuICogQHBhcmFtIHtzdHJpbmd9IHBhdGggLSBUaGUgcm91dGUgcGF0aC5cclxuICogQHBhcmFtIHsuLi5GdW5jdGlvbn0gbWlkZGxld2FyZXMgLSBUaGUgbWlkZGxld2FyZSBmdW5jdGlvbnMgdG8gYmUgYXBwbGllZC5cclxuICovXHJcbmV4cG9ydCBjb25zdCBnZXQgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAuZ2V0KHBhdGgsIC4uLm1pZGRsZXdhcmVzKTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBTZXQgdXAgYSByb3V0ZSB3aXRoIFBPU1QgbWV0aG9kIGFuZCBhcHBseSBtaWRkbGV3YXJlKHMpLlxyXG4gKlxyXG4gKiBAcGFyYW0ge3N0cmluZ30gcGF0aCAtIFRoZSByb3V0ZSBwYXRoLlxyXG4gKiBAcGFyYW0gey4uLkZ1bmN0aW9ufSBtaWRkbGV3YXJlcyAtIFRoZSBtaWRkbGV3YXJlIGZ1bmN0aW9ucyB0byBiZSBhcHBsaWVkLlxyXG4gKi9cclxuZXhwb3J0IGNvbnN0IHBvc3QgPSAocGF0aCwgLi4ubWlkZGxld2FyZXMpID0+IHtcclxuICBhcHAucG9zdChwYXRoLCAuLi5taWRkbGV3YXJlcyk7XHJcbn07XHJcblxyXG5leHBvcnQgZGVmYXVsdCB7XHJcbiAgc3RhcnRTZXJ2ZXIsXHJcbiAgY2xvc2VTZXJ2ZXJzLFxyXG4gIGdldFNlcnZlcnMsXHJcbiAgZW5hYmxlUmF0ZUxpbWl0aW5nLFxyXG4gIGdldEV4cHJlc3MsXHJcbiAgZ2V0QXBwLFxyXG4gIHVzZSxcclxuICBnZXQsXHJcbiAgcG9zdFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGpvaW4gfSBmcm9tICdwYXRoJztcclxuXHJcbmltcG9ydCB7IF9fZGlybmFtZSB9IGZyb20gJy4uLy4uL3V0aWxzLmpzJztcclxuXHJcbi8qKlxyXG4gKiBBZGRzIHRoZSBHRVQgLyByb3V0ZSBmb3IgYSBVSSB3aGVuIGVuYWJsZWQgb24gdGhlIGV4cG9ydCBzZXJ2ZXIuXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCAoYXBwKSA9PlxyXG4gICFhcHBcclxuICAgID8gZmFsc2VcclxuICAgIDogYXBwLmdldCgnLycsIChyZXF1ZXN0LCByZXNwb25zZSkgPT4ge1xyXG4gICAgICAgIHJlc3BvbnNlLnNlbmRGaWxlKGpvaW4oX19kaXJuYW1lLCAncHVibGljJywgJ2luZGV4Lmh0bWwnKSk7XHJcbiAgICAgIH0pO1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCB7IGNsZWFyQWxsSW50ZXJ2YWxzIH0gZnJvbSAnLi9pbnRlcnZhbHMuanMnO1xyXG5pbXBvcnQgeyBraWxsUG9vbCB9IGZyb20gJy4vcG9vbC5qcyc7XHJcbmltcG9ydCB7IGNsb3NlU2VydmVycyB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcblxyXG4vKipcclxuICogQ2xlYW4gdXAgZnVuY3Rpb24gdG8gdHJpZ2dlciBiZWZvcmUgZW5kaW5nIHByb2Nlc3MgZm9yIHRoZSBncmFjZWZ1bCBzaHV0ZG93bi5cclxuICpcclxuICogQHBhcmFtIHtudW1iZXJ9IGV4aXRDb2RlIC0gQW4gZXhpdCBjb2RlIGZvciB0aGUgcHJvY2Vzcy5leGl0KCkgZnVuY3Rpb24uXHJcbiAqL1xyXG5leHBvcnQgY29uc3Qgc2h1dGRvd25DbGVhblVwID0gYXN5bmMgKGV4aXRDb2RlKSA9PiB7XHJcbiAgLy8gQXdhaXQgZnJlZWluZyBhbGwgcmVzb3VyY2VzXHJcbiAgYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFtcclxuICAgIC8vIENsZWFyIGFsbCBvbmdvaW5nIGludGVydmFsc1xyXG4gICAgY2xlYXJBbGxJbnRlcnZhbHMoKSxcclxuXHJcbiAgICAvLyBHZXQgYXZhaWxhYmxlIHNlcnZlciBpbnN0YW5jZXMgKEhUVFAvSFRUUFMpIGFuZCBjbG9zZSB0aGVtXHJcbiAgICBjbG9zZVNlcnZlcnMoKSxcclxuXHJcbiAgICAvLyBDbG9zZSBwb29sIGFsb25nIHdpdGggaXRzIHdvcmtlcnMgYW5kIHRoZSBicm93c2VyIGluc3RhbmNlLCBpZiBleGlzdHNcclxuICAgIGtpbGxQb29sKClcclxuICBdKTtcclxuXHJcbiAgLy8gRXhpdCBwcm9jZXNzIHdpdGggYSBjb3JyZWN0IGNvZGVcclxuICBwcm9jZXNzLmV4aXQoZXhpdENvZGUpO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIHNodXRkb3duQ2xlYW5VcFxyXG59O1xyXG4iLCIvKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKlxyXG5cclxuSGlnaGNoYXJ0cyBFeHBvcnQgU2VydmVyXHJcblxyXG5Db3B5cmlnaHQgKGMpIDIwMTYtMjAyNCwgSGlnaHNvZnRcclxuXHJcbkxpY2VuY2VkIHVuZGVyIHRoZSBNSVQgbGljZW5jZS5cclxuXHJcbkFkZGl0aW9uYWxseSBhIHZhbGlkIEhpZ2hjaGFydHMgbGljZW5zZSBpcyByZXF1aXJlZCBmb3IgdXNlLlxyXG5cclxuU2VlIExJQ0VOU0UgZmlsZSBpbiByb290IGZvciBkZXRhaWxzLlxyXG5cclxuKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cclxuXHJcbmltcG9ydCAnY29sb3JzJztcclxuXHJcbmltcG9ydCB7IGNoZWNrQW5kVXBkYXRlQ2FjaGUgfSBmcm9tICcuL2NhY2hlLmpzJztcclxuaW1wb3J0IHtcclxuICBiYXRjaEV4cG9ydCxcclxuICBzZXRBbGxvd0NvZGVFeGVjdXRpb24sXHJcbiAgc2luZ2xlRXhwb3J0LFxyXG4gIHN0YXJ0RXhwb3J0XHJcbn0gZnJvbSAnLi9jaGFydC5qcyc7XHJcbmltcG9ydCB7IG1hcFRvTmV3Q29uZmlnLCBtYW51YWxDb25maWcsIHNldE9wdGlvbnMgfSBmcm9tICcuL2NvbmZpZy5qcyc7XHJcbmltcG9ydCB7XHJcbiAgaW5pdExvZ2dpbmcsXHJcbiAgbG9nLFxyXG4gIGxvZ1dpdGhTdGFjayxcclxuICBzZXRMb2dMZXZlbCxcclxuICBlbmFibGVGaWxlTG9nZ2luZ1xyXG59IGZyb20gJy4vbG9nZ2VyLmpzJztcclxuaW1wb3J0IHsgaW5pdFBvb2wsIGtpbGxQb29sIH0gZnJvbSAnLi9wb29sLmpzJztcclxuaW1wb3J0IHsgc2h1dGRvd25DbGVhblVwIH0gZnJvbSAnLi9yZXNvdXJjZV9yZWxlYXNlLmpzJztcclxuaW1wb3J0IHNlcnZlciwgeyBzdGFydFNlcnZlciB9IGZyb20gJy4vc2VydmVyL3NlcnZlci5qcyc7XHJcbmltcG9ydCB7IHByaW50TG9nbywgcHJpbnRVc2FnZSB9IGZyb20gJy4vdXRpbHMuanMnO1xyXG5cclxuLyoqXHJcbiAqIEF0dGFjaGVzIGV4aXQgbGlzdGVuZXJzIHRvIHRoZSBwcm9jZXNzLCBlbnN1cmluZyBwcm9wZXIgY2xlYW51cCBvZiByZXNvdXJjZXNcclxuICogYW5kIHRlcm1pbmF0aW9uIG9uIGV4aXQgc2lnbmFscy4gSGFuZGxlcyAnZXhpdCcsICdTSUdJTlQnLCAnU0lHVEVSTScsIGFuZFxyXG4gKiAndW5jYXVnaHRFeGNlcHRpb24nIGV2ZW50cy5cclxuICovXHJcbmNvbnN0IGF0dGFjaFByb2Nlc3NFeGl0TGlzdGVuZXJzID0gKCkgPT4ge1xyXG4gIGxvZygzLCAnW3Byb2Nlc3NdIEF0dGFjaGluZyBleGl0IGxpc3RlbmVycyB0byB0aGUgcHJvY2Vzcy4nKTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdleGl0J1xyXG4gIHByb2Nlc3Mub24oJ2V4aXQnLCAoY29kZSkgPT4ge1xyXG4gICAgbG9nKDQsIGBQcm9jZXNzIGV4aXRlZCB3aXRoIGNvZGUgJHtjb2RlfS5gKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdJTlQnXHJcbiAgcHJvY2Vzcy5vbignU0lHSU5UJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ1NJR1RFUk0nXHJcbiAgcHJvY2Vzcy5vbignU0lHVEVSTScsIGFzeW5jIChuYW1lLCBjb2RlKSA9PiB7XHJcbiAgICBsb2coNCwgYFRoZSAke25hbWV9IGV2ZW50IHdpdGggY29kZTogJHtjb2RlfS5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgwKTtcclxuICB9KTtcclxuXHJcbiAgLy8gSGFuZGxlciBmb3IgdGhlICdTSUdIVVAnXHJcbiAgcHJvY2Vzcy5vbignU0lHSFVQJywgYXN5bmMgKG5hbWUsIGNvZGUpID0+IHtcclxuICAgIGxvZyg0LCBgVGhlICR7bmFtZX0gZXZlbnQgd2l0aCBjb2RlOiAke2NvZGV9LmApO1xyXG4gICAgYXdhaXQgc2h1dGRvd25DbGVhblVwKDApO1xyXG4gIH0pO1xyXG5cclxuICAvLyBIYW5kbGVyIGZvciB0aGUgJ3VuY2F1Z2h0RXhjZXB0aW9uJ1xyXG4gIHByb2Nlc3Mub24oJ3VuY2F1Z2h0RXhjZXB0aW9uJywgYXN5bmMgKGVycm9yLCBuYW1lKSA9PiB7XHJcbiAgICBsb2dXaXRoU3RhY2soMSwgZXJyb3IsIGBUaGUgJHtuYW1lfSBlcnJvci5gKTtcclxuICAgIGF3YWl0IHNodXRkb3duQ2xlYW5VcCgxKTtcclxuICB9KTtcclxufTtcclxuXHJcbi8qKlxyXG4gKiBJbml0aWFsaXplcyB0aGUgZXhwb3J0IHByb2Nlc3MuIFRhc2tzIHN1Y2ggYXMgY29uZmlndXJpbmcgbG9nZ2luZywgY2hlY2tpbmdcclxuICogY2FjaGUgYW5kIHNvdXJjZXMsIGFuZCBpbml0aWFsaXppbmcgdGhlIHBvb2wgb2YgcmVzb3VyY2VzIGhhcHBlbiBkdXJpbmdcclxuICogdGhpcyBzdGFnZS4gRnVuY3Rpb24gdGhhdCBpcyByZXF1aXJlZCB0byBiZSBjYWxsZWQgYmVmb3JlIHRyeWluZyB0byBleHBvcnQgY2hhcnRzIG9yIHNldHRpbmcgYSBzZXJ2ZXIuIFRoZSBgb3B0aW9uc2AgaXMgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgYWxsIG9wdGlvbnMuXHJcbiAqXHJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQWxsIGV4cG9ydCBvcHRpb25zLlxyXG4gKlxyXG4gKiBAcmV0dXJucyB7UHJvbWlzZTxPYmplY3Q+fSBQcm9taXNlIHJlc29sdmluZyB0byB0aGUgdXBkYXRlZCBleHBvcnQgb3B0aW9ucy5cclxuICovXHJcbmNvbnN0IGluaXRFeHBvcnQgPSBhc3luYyAob3B0aW9ucykgPT4ge1xyXG4gIC8vIFNldCB0aGUgYWxsb3dDb2RlRXhlY3V0aW9uIHBlciBleHBvcnQgbW9kdWxlIHNjb3BlXHJcbiAgc2V0QWxsb3dDb2RlRXhlY3V0aW9uKFxyXG4gICAgb3B0aW9ucy5jdXN0b21Mb2dpYyAmJiBvcHRpb25zLmN1c3RvbUxvZ2ljLmFsbG93Q29kZUV4ZWN1dGlvblxyXG4gICk7XHJcblxyXG4gIC8vIEluaXQgdGhlIGxvZ2dpbmdcclxuICBpbml0TG9nZ2luZyhvcHRpb25zLmxvZ2dpbmcpO1xyXG5cclxuICAvLyBBdHRhY2ggcHJvY2VzcycgZXhpdCBsaXN0ZW5lcnNcclxuICBpZiAob3B0aW9ucy5vdGhlci5saXN0ZW5Ub1Byb2Nlc3NFeGl0cykge1xyXG4gICAgYXR0YWNoUHJvY2Vzc0V4aXRMaXN0ZW5lcnMoKTtcclxuICB9XHJcblxyXG4gIC8vIENoZWNrIGlmIGNhY2hlIG5lZWRzIHRvIGJlIHVwZGF0ZWRcclxuICBhd2FpdCBjaGVja0FuZFVwZGF0ZUNhY2hlKG9wdGlvbnMpO1xyXG5cclxuICAvLyBJbml0IHRoZSBwb29sXHJcbiAgYXdhaXQgaW5pdFBvb2woe1xyXG4gICAgcG9vbDogb3B0aW9ucy5wb29sIHx8IHtcclxuICAgICAgbWluV29ya2VyczogMSxcclxuICAgICAgbWF4V29ya2VyczogMVxyXG4gICAgfSxcclxuICAgIHB1cHBldGVlckFyZ3M6IG9wdGlvbnMucHVwcGV0ZWVyLmFyZ3MgfHwgW11cclxuICB9KTtcclxuXHJcbiAgLy8gUmV0dXJuIHVwZGF0ZWQgb3B0aW9uc1xyXG4gIHJldHVybiBvcHRpb25zO1xyXG59O1xyXG5cclxuZXhwb3J0IGRlZmF1bHQge1xyXG4gIC8vIFNlcnZlclxyXG4gIHNlcnZlcixcclxuICBzdGFydFNlcnZlcixcclxuXHJcbiAgLy8gRXhwb3J0aW5nXHJcbiAgaW5pdEV4cG9ydCxcclxuICBzaW5nbGVFeHBvcnQsXHJcbiAgYmF0Y2hFeHBvcnQsXHJcbiAgc3RhcnRFeHBvcnQsXHJcblxyXG4gIC8vIFBvb2xcclxuICBpbml0UG9vbCxcclxuICBraWxsUG9vbCxcclxuXHJcbiAgLy8gT3RoZXJcclxuICBzZXRPcHRpb25zLFxyXG4gIHNodXRkb3duQ2xlYW5VcCxcclxuXHJcbiAgLy8gTG9nc1xyXG4gIGxvZyxcclxuICBsb2dXaXRoU3RhY2ssXHJcbiAgc2V0TG9nTGV2ZWwsXHJcbiAgZW5hYmxlRmlsZUxvZ2dpbmcsXHJcblxyXG4gIC8vIFV0aWxzXHJcbiAgbWFwVG9OZXdDb25maWcsXHJcbiAgbWFudWFsQ29uZmlnLFxyXG4gIHByaW50TG9nbyxcclxuICBwcmludFVzYWdlXHJcbn07XHJcbiJdLCJuYW1lcyI6WyJzY3JpcHRzTmFtZXMiLCJjb3JlIiwibW9kdWxlcyIsImluZGljYXRvcnMiLCJkZWZhdWx0Q29uZmlnIiwicHVwcGV0ZWVyIiwiYXJncyIsInZhbHVlIiwidHlwZSIsImRlc2NyaXB0aW9uIiwiaGlnaGNoYXJ0cyIsInZlcnNpb24iLCJlbnZMaW5rIiwiY2RuVVJMIiwiY29yZVNjcmlwdHMiLCJtb2R1bGVTY3JpcHRzIiwiaW5kaWNhdG9yU2NyaXB0cyIsImN1c3RvbVNjcmlwdHMiLCJmb3JjZUZldGNoIiwiY2FjaGVQYXRoIiwiZXhwb3J0IiwiaW5maWxlIiwiaW5zdHIiLCJvcHRpb25zIiwib3V0ZmlsZSIsImNvbnN0ciIsImRlZmF1bHRIZWlnaHQiLCJkZWZhdWx0V2lkdGgiLCJkZWZhdWx0U2NhbGUiLCJoZWlnaHQiLCJ3aWR0aCIsInNjYWxlIiwiZ2xvYmFsT3B0aW9ucyIsInRoZW1lT3B0aW9ucyIsImJhdGNoIiwicmFzdGVyaXphdGlvblRpbWVvdXQiLCJjdXN0b21Mb2dpYyIsImFsbG93Q29kZUV4ZWN1dGlvbiIsImFsbG93RmlsZVJlc291cmNlcyIsImN1c3RvbUNvZGUiLCJjYWxsYmFjayIsInJlc291cmNlcyIsImxvYWRDb25maWciLCJsZWdhY3lOYW1lIiwiY3JlYXRlQ29uZmlnIiwic2VydmVyIiwiZW5hYmxlIiwiY2xpTmFtZSIsImhvc3QiLCJwb3J0IiwiYmVuY2htYXJraW5nIiwicHJveHkiLCJ0aW1lb3V0IiwicmF0ZUxpbWl0aW5nIiwibWF4UmVxdWVzdHMiLCJ3aW5kb3ciLCJkZWxheSIsInRydXN0UHJveHkiLCJza2lwS2V5Iiwic2tpcFRva2VuIiwic3NsIiwiZm9yY2UiLCJjZXJ0UGF0aCIsInBvb2wiLCJtaW5Xb3JrZXJzIiwibWF4V29ya2VycyIsIndvcmtMaW1pdCIsImFjcXVpcmVUaW1lb3V0IiwiY3JlYXRlVGltZW91dCIsImRlc3Ryb3lUaW1lb3V0IiwiaWRsZVRpbWVvdXQiLCJjcmVhdGVSZXRyeUludGVydmFsIiwicmVhcGVySW50ZXJ2YWwiLCJsb2dnaW5nIiwibGV2ZWwiLCJmaWxlIiwiZGVzdCIsInVpIiwicm91dGUiLCJvdGhlciIsIm5vZGVFbnYiLCJsaXN0ZW5Ub1Byb2Nlc3NFeGl0cyIsIm5vTG9nbyIsImhhcmRSZXNldFBhZ2UiLCJicm93c2VyU2hlbGxNb2RlIiwiZGVidWciLCJoZWFkbGVzcyIsImRldnRvb2xzIiwibGlzdGVuVG9Db25zb2xlIiwiZHVtcGlvIiwic2xvd01vIiwiZGVidWdnaW5nUG9ydCIsInByb21wdHNDb25maWciLCJuYW1lIiwibWVzc2FnZSIsImluaXRpYWwiLCJqb2luIiwic2VwYXJhdG9yIiwiaW5zdHJ1Y3Rpb25zIiwiY2hvaWNlcyIsImhpbnQiLCJtaW4iLCJtYXgiLCJyb3VuZCIsImFic29sdXRlUHJvcHMiLCJuZXN0ZWRBcmdzIiwiY3JlYXRlTmVzdGVkQXJncyIsIm9iaiIsInByb3BDaGFpbiIsIk9iamVjdCIsImtleXMiLCJmb3JFYWNoIiwiayIsImluY2x1ZGVzIiwiZW50cnkiLCJzdWJzdHJpbmciLCJ1bmRlZmluZWQiLCJkb3RlbnYiLCJjb25maWciLCJ2IiwiZmlsdGVyQXJyYXkiLCJ6Iiwic3RyaW5nIiwidHJhbnNmb3JtIiwic3BsaXQiLCJtYXAiLCJ0cmltIiwiZmlsdGVyIiwibGVuZ3RoIiwiZW51bSIsInZhbHVlcyIsInJlZmluZSIsImlzTmFOIiwicGFyc2VGbG9hdCIsImVudnMiLCJvYmplY3QiLCJISUdIQ0hBUlRTX1ZFUlNJT04iLCJ0ZXN0IiwiSElHSENIQVJUU19DRE5fVVJMIiwic3RhcnRzV2l0aCIsIkhJR0hDSEFSVFNfQ09SRV9TQ1JJUFRTIiwiSElHSENIQVJUU19NT0RVTEVfU0NSSVBUUyIsIkhJR0hDSEFSVFNfSU5ESUNBVE9SX1NDUklQVFMiLCJISUdIQ0hBUlRTX0ZPUkNFX0ZFVENIIiwiSElHSENIQVJUU19DQUNIRV9QQVRIIiwiSElHSENIQVJUU19BRE1JTl9UT0tFTiIsIkVYUE9SVF9UWVBFIiwiRVhQT1JUX0NPTlNUUiIsIkVYUE9SVF9ERUZBVUxUX0hFSUdIVCIsIkVYUE9SVF9ERUZBVUxUX1dJRFRIIiwiRVhQT1JUX0RFRkFVTFRfU0NBTEUiLCJFWFBPUlRfUkFTVEVSSVpBVElPTl9USU1FT1VUIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0NPREVfRVhFQ1VUSU9OIiwiQ1VTVE9NX0xPR0lDX0FMTE9XX0ZJTEVfUkVTT1VSQ0VTIiwiU0VSVkVSX0VOQUJMRSIsIlNFUlZFUl9IT1NUIiwiU0VSVkVSX1BPUlQiLCJTRVJWRVJfQkVOQ0hNQVJLSU5HIiwiU0VSVkVSX1BST1hZX0hPU1QiLCJTRVJWRVJfUFJPWFlfUE9SVCIsIlNFUlZFUl9QUk9YWV9USU1FT1VUIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfRU5BQkxFIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfTUFYX1JFUVVFU1RTIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfV0lORE9XIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfREVMQVkiLCJTRVJWRVJfUkFURV9MSU1JVElOR19UUlVTVF9QUk9YWSIsIlNFUlZFUl9SQVRFX0xJTUlUSU5HX1NLSVBfS0VZIiwiU0VSVkVSX1JBVEVfTElNSVRJTkdfU0tJUF9UT0tFTiIsIlNFUlZFUl9TU0xfRU5BQkxFIiwiU0VSVkVSX1NTTF9GT1JDRSIsIlNFUlZFUl9TU0xfUE9SVCIsIlNFUlZFUl9TU0xfQ0VSVF9QQVRIIiwiUE9PTF9NSU5fV09SS0VSUyIsIlBPT0xfTUFYX1dPUktFUlMiLCJQT09MX1dPUktfTElNSVQiLCJQT09MX0FDUVVJUkVfVElNRU9VVCIsIlBPT0xfQ1JFQVRFX1RJTUVPVVQiLCJQT09MX0RFU1RST1lfVElNRU9VVCIsIlBPT0xfSURMRV9USU1FT1VUIiwiUE9PTF9DUkVBVEVfUkVUUllfSU5URVJWQUwiLCJQT09MX1JFQVBFUl9JTlRFUlZBTCIsIlBPT0xfQkVOQ0hNQVJLSU5HIiwiTE9HR0lOR19MRVZFTCIsIkxPR0dJTkdfRklMRSIsIkxPR0dJTkdfREVTVCIsIlVJX0VOQUJMRSIsIlVJX1JPVVRFIiwiT1RIRVJfTk9ERV9FTlYiLCJPVEhFUl9MSVNURU5fVE9fUFJPQ0VTU19FWElUUyIsIk9USEVSX05PX0xPR08iLCJPVEhFUl9IQVJEX1JFU0VUX1BBR0UiLCJPVEhFUl9CUk9XU0VSX1NIRUxMX01PREUiLCJERUJVR19FTkFCTEUiLCJERUJVR19IRUFETEVTUyIsIkRFQlVHX0RFVlRPT0xTIiwiREVCVUdfTElTVEVOX1RPX0NPTlNPTEUiLCJERUJVR19EVU1QSU8iLCJERUJVR19TTE9XX01PIiwiREVCVUdfREVCVUdHSU5HX1BPUlQiLCJwYXJ0aWFsIiwicGFyc2UiLCJwcm9jZXNzIiwiZW52IiwiY29sb3JzIiwidG9Db25zb2xlIiwidG9GaWxlIiwicGF0aENyZWF0ZWQiLCJsZXZlbHNEZXNjIiwidGl0bGUiLCJjb2xvciIsImxpc3RlbmVycyIsImtleSIsIm9wdGlvbiIsImVudHJpZXMiLCJsb2dUb0ZpbGUiLCJ0ZXh0cyIsInByZWZpeCIsImV4aXN0c1N5bmMiLCJta2RpclN5bmMiLCJhcHBlbmRGaWxlIiwiY29uY2F0IiwiZXJyb3IiLCJjb25zb2xlIiwibG9nIiwibmV3TGV2ZWwiLCJEYXRlIiwidG9TdHJpbmciLCJmbiIsImFwcGx5IiwibG9nV2l0aFN0YWNrIiwiY3VzdG9tTWVzc2FnZSIsIm1haW5NZXNzYWdlIiwic3RhY2tNZXNzYWdlIiwic3RhY2siLCJzbGljZSIsInNldExvZ0xldmVsIiwiZW5hYmxlRmlsZUxvZ2dpbmciLCJsb2dEZXN0IiwibG9nRmlsZSIsImVuZHNXaXRoIiwiX19kaXJuYW1lIiwiZmlsZVVSTFRvUGF0aCIsIlVSTCIsImRvY3VtZW50IiwicmVxdWlyZSIsInBhdGhUb0ZpbGVVUkwiLCJfX2ZpbGVuYW1lIiwiaHJlZiIsIl9kb2N1bWVudEN1cnJlbnRTY3JpcHQiLCJzcmMiLCJiYXNlVVJJIiwiZml4VHlwZSIsImZvcm1hdHMiLCJvdXRUeXBlIiwicG9wIiwiZmluZCIsInQiLCJoYW5kbGVSZXNvdXJjZXMiLCJhbGxvd2VkUHJvcHMiLCJoYW5kbGVkUmVzb3VyY2VzIiwiY29ycmVjdFJlc291cmNlcyIsImlzQ29ycmVjdEpTT04iLCJyZWFkRmlsZVN5bmMiLCJmaWxlcyIsInByb3BOYW1lIiwiaXRlbSIsImRhdGEiLCJwYXJzZWREYXRhIiwiSlNPTiIsInN0cmluZ2lmeSIsImRlZXBDb3B5IiwiY29weSIsIkFycmF5IiwiaXNBcnJheSIsInByb3RvdHlwZSIsImhhc093blByb3BlcnR5IiwiY2FsbCIsIm9wdGlvbnNTdHJpbmdpZnkiLCJhbGxvd0Z1bmN0aW9ucyIsInJlcGxhY2VBbGwiLCJwcmludFVzYWdlIiwiYm9sZCIsInllbGxvdyIsImN5Y2xlQ2F0ZWdvcmllcyIsImRlc2NOYW1lIiwiZ3JlZW4iLCJpIiwiYmx1ZSIsImNhdGVnb3J5IiwidG9VcHBlckNhc2UiLCJyZWQiLCJ0b0Jvb2xlYW4iLCJ3cmFwQXJvdW5kIiwicmVwbGFjZSIsIm1lYXN1cmVUaW1lIiwic3RhcnQiLCJocnRpbWUiLCJiaWdpbnQiLCJOdW1iZXIiLCJnZW5lcmFsT3B0aW9ucyIsImdldE9wdGlvbnMiLCJtZXJnZUNvbmZpZ09wdGlvbnMiLCJuZXdPcHRpb25zIiwibWVyZ2VkT3B0aW9ucyIsInVwZGF0ZURlZmF1bHRDb25maWciLCJjb25maWdPYmoiLCJjdXN0b21PYmoiLCJjdXN0b21WYWx1ZSIsImluaXRPcHRpb25zIiwiaXRlbXMiLCJyZWN1cnNpdmVQcm9wcyIsIm9iamVjdFRvVXBkYXRlIiwibmVzdGVkTmFtZXMiLCJzaGlmdCIsImFzc2lnbiIsImFzeW5jIiwiZmV0Y2giLCJ1cmwiLCJyZXF1ZXN0T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwicmVqZWN0IiwicHJvdG9jb2wiLCJodHRwcyIsImh0dHAiLCJnZXRQcm90b2NvbCIsImdldCIsInJlcyIsIm9uIiwiY2h1bmsiLCJ0ZXh0IiwiRXhwb3J0RXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwic3VwZXIiLCJ0aGlzIiwic2V0RXJyb3IiLCJzdGF0dXNDb2RlIiwiY2FjaGUiLCJhY3RpdmVNYW5pZmVzdCIsInNvdXJjZXMiLCJoY1ZlcnNpb24iLCJleHRyYWN0VmVyc2lvbiIsImluZGV4T2YiLCJmZXRjaEFuZFByb2Nlc3NTY3JpcHQiLCJzY3JpcHQiLCJmZXRjaGVkTW9kdWxlcyIsInNob3VsZFRocm93RXJyb3IiLCJyZXNwb25zZSIsInVwZGF0ZUNhY2hlIiwiaGlnaGNoYXJ0c09wdGlvbnMiLCJwcm94eU9wdGlvbnMiLCJzb3VyY2VQYXRoIiwicHJveHlBZ2VudCIsInByb3h5SG9zdCIsInByb3h5UG9ydCIsIkh0dHBzUHJveHlBZ2VudCIsImFnZW50IiwiYWxsRmV0Y2hQcm9taXNlcyIsImFsbCIsImZldGNoU2NyaXB0cyIsImMiLCJtIiwid3JpdGVGaWxlU3luYyIsImNoZWNrQW5kVXBkYXRlQ2FjaGUiLCJtYW5pZmVzdFBhdGgiLCJyZXF1ZXN0VXBkYXRlIiwibWFuaWZlc3QiLCJtb2R1bGVNYXAiLCJudW1iZXJPZk1vZHVsZXMiLCJzb21lIiwibW9kdWxlTmFtZSIsIm5ld01hbmlmZXN0Iiwic2F2ZUNvbmZpZ1RvTWFuaWZlc3QiLCJnZXRDYWNoZVBhdGgiLCJzZXR1cEhpZ2hjaGFydHMiLCJIaWdoY2hhcnRzIiwiYW5pbU9iamVjdCIsImR1cmF0aW9uIiwidHJpZ2dlckV4cG9ydCIsImNoYXJ0T3B0aW9ucyIsImRpc3BsYXlFcnJvcnMiLCJfZGlzcGxheUVycm9ycyIsIm1lcmdlIiwic2V0T3B0aW9ucyIsIndyYXAiLCJzZXRPcHRpb25zT2JqIiwiRnVuY3Rpb24iLCJjaGFydCIsImFuaW1hdGlvbiIsInN0ckluaiIsImlzUmVuZGVyQ29tcGxldGUiLCJDaGFydCIsInByb2NlZWQiLCJ1c2VyT3B0aW9ucyIsImNiIiwiZXhwb3J0aW5nIiwiZW5hYmxlZCIsInBsb3RPcHRpb25zIiwic2VyaWVzIiwibGFiZWwiLCJ0b29sdGlwIiwib25IaWdoY2hhcnRzUmVuZGVyIiwiYWRkRXZlbnQiLCJTZXJpZXMiLCJmaW5hbE9wdGlvbnMiLCJmaW5hbENhbGxiYWNrIiwiZGVmYXVsdE9wdGlvbnMiLCJwcm9wIiwidGVtcGxhdGUiLCJicm93c2VyIiwibmV3UGFnZSIsInBhZ2UiLCJzZXRDYWNoZUVuYWJsZWQiLCJzZXRQYWdlQ29udGVudCIsIiRldmFsIiwiZWxlbWVudCIsImVycm9yTWVzc2FnZSIsImlubmVySFRNTCIsInNldFBhZ2VFdmVudHMiLCJjbGVhclBhZ2VSZXNvdXJjZXMiLCJpbmplY3RlZFJlc291cmNlcyIsInJlc291cmNlIiwiZGlzcG9zZSIsImV2YWx1YXRlIiwib2xkQ2hhcnRzIiwiY2hhcnRzIiwib2xkQ2hhcnQiLCJkZXN0cm95Iiwic2NyaXB0c1RvUmVtb3ZlIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJzdHlsZXNUb1JlbW92ZSIsImxpbmtzVG9SZW1vdmUiLCJyZW1vdmUiLCJzZXRDb250ZW50Iiwid2FpdFVudGlsIiwiYWRkU2NyaXB0VGFnIiwicGF0aCIsInNldEFzQ29uZmlnIiwicHVwcGV0ZWVyRXhwb3J0IiwiZXhwb3J0T3B0aW9ucyIsImRlYnVnZ2VyIiwiaXNTVkciLCJzdmdUZW1wbGF0ZSIsImluamVjdGVkSnMiLCJqcyIsInB1c2giLCJjb250ZW50IiwiaXNMb2NhbCIsImpzUmVzb3VyY2UiLCJpbmplY3RlZENzcyIsImNzcyIsImNzc0ltcG9ydHMiLCJtYXRjaCIsImNzc0ltcG9ydFBhdGgiLCJjc3NSZXNvdXJjZSIsImFkZFN0eWxlVGFnIiwiYWRkUGFnZVJlc291cmNlcyIsInNpemUiLCJzdmdFbGVtZW50IiwicXVlcnlTZWxlY3RvciIsImNoYXJ0SGVpZ2h0IiwiYmFzZVZhbCIsImNoYXJ0V2lkdGgiLCJib2R5Iiwic3R5bGUiLCJ6b29tIiwibWFyZ2luIiwidmlld3BvcnRIZWlnaHQiLCJNYXRoIiwiY2VpbCIsInZpZXdwb3J0V2lkdGgiLCJ4IiwieSIsImdldEJvdW5kaW5nQ2xpZW50UmVjdCIsInRydW5jIiwiZ2V0Q2xpcFJlZ2lvbiIsInNldFZpZXdwb3J0IiwiZGV2aWNlU2NhbGVGYWN0b3IiLCJvdXRlckhUTUwiLCJjcmVhdGVTVkciLCJlbmNvZGluZyIsImNsaXAiLCJyYWNlIiwic2NyZWVuc2hvdCIsImNhcHR1cmVCZXlvbmRWaWV3cG9ydCIsImZ1bGxQYWdlIiwib3B0aW1pemVGb3JTcGVlZCIsInF1YWxpdHkiLCJvbWl0QmFja2dyb3VuZCIsIl9yZXNvbHZlIiwic2V0VGltZW91dCIsImNyZWF0ZUltYWdlIiwiZW11bGF0ZU1lZGlhVHlwZSIsInBkZiIsImNyZWF0ZVBERiIsInN0YXRzIiwicGVyZm9ybWVkRXhwb3J0cyIsImV4cG9ydEF0dGVtcHRzIiwiZXhwb3J0RnJvbVN2Z0F0dGVtcHRzIiwidGltZVNwZW50IiwiZHJvcHBlZEV4cG9ydHMiLCJzcGVudEF2ZXJhZ2UiLCJwb29sQ29uZmlnIiwiZmFjdG9yeSIsImNyZWF0ZSIsImlkIiwidXVpZCIsInN0YXJ0RGF0ZSIsImdldFRpbWUiLCJpc0Nsb3NlZCIsIndvcmtDb3VudCIsInJhbmRvbSIsInZhbGlkYXRlIiwid29ya2VySGFuZGxlIiwiY2xvc2UiLCJpbml0UG9vbCIsInB1cHBldGVlckFyZ3MiLCJlbmFibGVkRGVidWciLCJkZWJ1Z09wdGlvbnMiLCJsYXVuY2hPcHRpb25zIiwidXNlckRhdGFEaXIiLCJoYW5kbGVTSUdJTlQiLCJoYW5kbGVTSUdURVJNIiwiaGFuZGxlU0lHSFVQIiwid2FpdEZvckluaXRpYWxQYWdlIiwiZGVmYXVsdFZpZXdwb3J0IiwidHJ5Q291bnQiLCJvcGVuIiwibGF1bmNoIiwiY3JlYXRlQnJvd3NlciIsInBhcnNlSW50IiwiUG9vbCIsImFjcXVpcmVUaW1lb3V0TWlsbGlzIiwiY3JlYXRlVGltZW91dE1pbGxpcyIsImRlc3Ryb3lUaW1lb3V0TWlsbGlzIiwiaWRsZVRpbWVvdXRNaWxsaXMiLCJjcmVhdGVSZXRyeUludGVydmFsTWlsbGlzIiwicmVhcEludGVydmFsTWlsbGlzIiwicHJvcGFnYXRlQ3JlYXRlRXJyb3IiLCJoYXJkUmVzZXQiLCJnb3RvIiwiY2xlYXJQYWdlIiwiZXZlbnRJZCIsImluaXRpYWxSZXNvdXJjZXMiLCJhY3F1aXJlIiwicHJvbWlzZSIsInJlbGVhc2UiLCJraWxsUG9vbCIsIndvcmtlciIsInVzZWQiLCJkZXN0cm95ZWQiLCJjb25uZWN0ZWQiLCJjbG9zZUJyb3dzZXIiLCJwb3N0V29yayIsImdldFBvb2xJbmZvIiwiYWNxdWlyZUNvdW50ZXIiLCJwYXlsb2FkIiwicmVxdWVzdElkIiwid29ya1N0YXJ0IiwiZXhwb3J0Q291bnRlciIsInJlc3VsdCIsImV4cG9ydFRpbWUiLCJnZXRQb29sSW5mb0pTT04iLCJudW1GcmVlIiwibnVtVXNlZCIsImF2YWlsYWJsZSIsInBlbmRpbmciLCJudW1QZW5kaW5nQWNxdWlyZXMiLCJwb29sJDEiLCJzdGFydEV4cG9ydCIsInNldHRpbmdzIiwiZW5kQ2FsbGJhY2siLCJzdmciLCJpbml0RXhwb3J0U2V0dGluZ3MiLCJleHBvcnRBc1N0cmluZyIsImlucHV0IiwiSlNET00iLCJET01QdXJpZnkiLCJzYW5pdGl6ZSIsIkFERF9UQUdTIiwiZG9TdHJhaWdodEluamVjdCIsImRvRXhwb3J0IiwiZmluZENoYXJ0U2l6ZSIsInByZWNpc2lvbiIsIm11bHRpcGxpZXIiLCJwb3ciLCJyb3VuZE51bWJlciIsInNvdXJjZUhlaWdodCIsInNvdXJjZVdpZHRoIiwicGFyYW0iLCJjaGFydEpzb24iLCJjdXN0b21Mb2dpY09wdGlvbnMiLCJhbGxvd0NvZGVFeGVjdXRpb25TY29wZWQiLCJvcHRpb25zTmFtZSIsInN0cmluZ1RvRXhwb3J0IiwiY2hhcnRKU09OIiwiaW50ZXJ2YWxJZHMiLCJjbGVhckFsbEludGVydmFscyIsImNsZWFySW50ZXJ2YWwiLCJsb2dFcnJvck1pZGRsZXdhcmUiLCJyZXEiLCJuZXh0IiwicmV0dXJuRXJyb3JNaWRkbGV3YXJlIiwic3RDb2RlIiwic3RhdHVzIiwianNvbiIsInJhdGVMaW1pdCIsImFwcCIsImxpbWl0Q29uZmlnIiwibXNnIiwicmF0ZU9wdGlvbnMiLCJsaW1pdGVyIiwid2luZG93TXMiLCJkZWxheU1zIiwiaGFuZGxlciIsInJlcXVlc3QiLCJmb3JtYXQiLCJzZW5kIiwiZGVmYXVsdCIsInNraXAiLCJxdWVyeSIsImFjY2Vzc190b2tlbiIsInVzZSIsIkh0dHBFcnJvciIsInNldFN0YXR1cyIsInZTd2l0Y2hSb3V0ZSIsInBvc3QiLCJhZG1pblRva2VuIiwidG9rZW4iLCJuZXdWZXJzaW9uIiwicGFyYW1zIiwidXBkYXRlVmVyc2lvbiIsInJldmVyc2VkTWltZSIsInBuZyIsImpwZWciLCJnaWYiLCJyZXF1ZXN0c0NvdW50ZXIiLCJiZWZvcmVSZXF1ZXN0IiwiYWZ0ZXJSZXF1ZXN0IiwiZG9DYWxsYmFja3MiLCJjYWxsYmFja3MiLCJ1bmlxdWVJZCIsImNhbGxSZXNwb25zZSIsImV4cG9ydEhhbmRsZXIiLCJzdG9wQ291bnRlciIsImhlYWRlcnMiLCJjb25uZWN0aW9uIiwicmVtb3RlQWRkcmVzcyIsImNvbm5lY3Rpb25BYm9ydGVkIiwic29ja2V0IiwidG9Mb3dlckNhc2UiLCJzdWJzdHIiLCJiNjQiLCJub0Rvd25sb2FkIiwicGF0dGVybiIsImlzUHJpdmF0ZVJhbmdlVXJsRm91bmQiLCJpbmZvIiwicmVtb3ZlQWxsTGlzdGVuZXJzIiwiQnVmZmVyIiwiZnJvbSIsImhlYWRlciIsImF0dGFjaG1lbnQiLCJmaWxlbmFtZSIsInBrZ0ZpbGUiLCJwYXRoZXIiLCJzZXJ2ZXJTdGFydFRpbWUiLCJzdWNjZXNzUmF0ZXMiLCJhZGRIZWFsdGhSb3V0ZXMiLCJzZXRJbnRlcnZhbCIsInN1Y2Nlc3NSYXRpbyIsIl8iLCJwZXJpb2QiLCJtb3ZpbmdBdmVyYWdlIiwicmVkdWNlIiwiYSIsImIiLCJib290VGltZSIsInVwdGltZSIsImZsb29yIiwiaGlnaGNoYXJ0c1ZlcnNpb24iLCJhdmVyYWdlUHJvY2Vzc2luZ1RpbWUiLCJmYWlsZWRFeHBvcnRzIiwic3VjZXNzUmF0aW8iLCJ0b0ZpeGVkIiwic3ZnRXhwb3J0QXR0ZW1wdHMiLCJqc29uRXhwb3J0QXR0ZW1wdHMiLCJhY3RpdmVTZXJ2ZXJzIiwiTWFwIiwiZXhwcmVzcyIsImRpc2FibGUiLCJjb3JzIiwic3RvcmFnZSIsIm11bHRlciIsIm1lbW9yeVN0b3JhZ2UiLCJ1cGxvYWQiLCJsaW1pdHMiLCJmaWVsZFNpemUiLCJsaW1pdCIsInVybGVuY29kZWQiLCJleHRlbmRlZCIsIm5vbmUiLCJhdHRhY2hTZXJ2ZXJFcnJvckhhbmRsZXJzIiwic3RhcnRTZXJ2ZXIiLCJzZXJ2ZXJDb25maWciLCJodHRwU2VydmVyIiwiY3JlYXRlU2VydmVyIiwibGlzdGVuIiwic2V0IiwiY2VydCIsImZzUHJvbWlzZXMiLCJyZWFkRmlsZSIsInBvc2l4IiwiaHR0cHNTZXJ2ZXIiLCJOYU4iLCJzdGF0aWMiLCJoZWFsdGhSb3V0ZSIsImV4cG9ydFJvdXRlcyIsInNlbmRGaWxlIiwidWlSb3V0ZSIsImVycm9ySGFuZGxlciIsImNsb3NlU2VydmVycyIsImRlbGV0ZSIsImdldFNlcnZlcnMiLCJlbmFibGVSYXRlTGltaXRpbmciLCJnZXRFeHByZXNzIiwiZ2V0QXBwIiwibWlkZGxld2FyZXMiLCJzaHV0ZG93bkNsZWFuVXAiLCJleGl0Q29kZSIsImFsbFNldHRsZWQiLCJleGl0IiwiaW5kZXgiLCJpbml0RXhwb3J0IiwiaW5pdExvZ2dpbmciLCJjb2RlIiwic2luZ2xlRXhwb3J0IiwiYmF0Y2hFeHBvcnQiLCJiYXRjaEZ1bmN0aW9ucyIsInBhaXIiLCJjb25maWdJbmRleCIsImZpbmRJbmRleCIsImFyZyIsImZpbGVOYW1lIiwibG9hZENvbmZpZ0ZpbGUiLCJzaG93VXNhZ2UiLCJwcm9wZXJ0aWVzQ2hhaW4iLCJhcmd1bWVudFR5cGUiLCJwYWlyQXJndW1lbnRWYWx1ZSIsIm1hcFRvTmV3Q29uZmlnIiwib2xkT3B0aW9ucyIsIm1hbnVhbENvbmZpZyIsImNvbmZpZ0ZpbGVOYW1lIiwiY29uZmlnRmlsZSIsImNob2ljZSIsInByb21wdHMiLCJvblN1Ym1pdCIsInAiLCJjYXRlZ29yaWVzIiwicXVlc3Rpb25zQ291bnRlciIsImFsbFF1ZXN0aW9ucyIsInNlY3Rpb24iLCJwcm9tcHQiLCJhbnN3ZXIiLCJtb2R1bGUiLCJwcm9taXNlcyIsIndyaXRlRmlsZSIsInByaW50TG9nbyIsInBhY2thZ2VWZXJzaW9uIl0sIm1hcHBpbmdzIjoiK2NBZU8sTUFBTUEsRUFBZSxDQUMxQkMsS0FBTSxDQUFDLGFBQWMsa0JBQW1CLGlCQUN4Q0MsUUFBUyxDQUNQLFFBQ0EsTUFDQSxRQUNBLFlBQ0EsY0FDQSx1QkFDQSxnQkFFQSxlQUNBLFFBQ0EsT0FDQSxhQUNBLG1CQUNBLGVBQ0EsY0FDQSxVQUNBLFVBQ0EsY0FDQSxXQUNBLFVBQ0EsWUFDQSxjQUNBLFlBQ0Esc0JBQ0EsU0FDQSxTQUNBLFdBQ0EsYUFDQSxZQUNBLGVBQ0EseUJBQ0EsU0FDQSxlQUNBLFlBQ0Esa0JB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 diff --git a/dist/index.esm.js b/dist/index.esm.js index c0557975..0c91fcd2 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 r,readFileSync as o,promises as i,writeFileSync as s}from"fs";import n,{join as a,posix as l}from"path";import{HttpsProxyAgent as c}from"https-proxy-agent";import p from"prompts";import h from"dotenv";import{z as u}from"zod";import{fileURLToPath as d}from"url";import g from"http";import m from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import y from"puppeteer";import{JSDOM as b}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import x from"express-rate-limit";const R={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","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","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"],indicators:["indicators-all"]},L={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:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],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 logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},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."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},O={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:L.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:L.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:L.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:L.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:L.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:L.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${L.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${L.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:L.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:L.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:L.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:L.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:L.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:L.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:L.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:L.server.host.value},{type:"number",name:"port",message:"Server port",initial:L.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:L.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:L.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:L.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:L.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:L.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:L.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:L.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:L.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:L.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:L.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:L.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:L.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:L.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:L.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:L.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:L.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:L.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:L.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:L.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:L.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:L.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:L.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:L.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:L.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:L.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:L.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:L.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:L.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:L.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:L.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:L.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:L.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:L.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:L.other.hardResetPage.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:L.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:L.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:L.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:L.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:L.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:L.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:L.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?I(o,`${t}.${r}`):(k[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(k[o.legacyName]=`${t}.${r}`.substring(1)))}}))};I(L),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)),A=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),N=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)),D=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(R.core),HIGHCHARTS_MODULE_SCRIPTS:C(R.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(R.indicators),HIGHCHARTS_FORCE_FETCH:A(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:N(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:N(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:A(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:A(),SERVER_ENABLE:A(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:A(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:A(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:A(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:A(),SERVER_SSL_FORCE:A(),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:A(),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(),UI_ENABLE:A(),UI_ROUTE:P(),OTHER_NODE_ENV:N(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:A(),OTHER_NO_LOGO:A(),OTHER_HARD_RESET_PAGE:A(),DEBUG_ENABLE:A(),DEBUG_HEADLESS:A(),DEBUG_DEVTOOLS:A(),DEBUG_LISTEN_TO_CONSOLE:A(),DEBUG_DUMPIO:A(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),U=["red","yellow","blue","gray","green"];let G={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:[]};for(const[e,t]of Object.entries(L.logging))G[e]=t.value;const j=(o,i)=>{G.toFile&&(G.pathCreated||(!e(G.dest)&&t(G.dest),G.pathCreated=!0),r(`${G.dest}${G.file}`,[i].concat(o).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),G.toFile=!1)})))},M=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=G;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;G.listeners.forEach((e=>{e(s,r.join(" "))})),G.toConsole&&console.log.apply(void 0,[s.toString()[G.levelsDesc[t-1].color]].concat(r)),j(r,s)},F=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=G;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];G.toConsole&&console.log.apply(void 0,[n.toString()[G.levelsDesc[e-1].color]].concat([o[U[e-1]],"\n",a])),G.listeners.forEach((e=>{e(n,l.join(" "))})),j(l,n)},W=e=>{e>=0&&e<=G.levelsDesc.length&&(G.level=e)},V=(e,t)=>{if(G={...G,dest:e||G.dest,file:t||G.file,toFile:!0},0===G.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");G.dest.endsWith("/")||(G.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(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"},X=(e=!1,t)=>{const r=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(o(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)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):M(3,"[cli] No resources found.")};function K(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 J=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]=J(e[r]));return t},z=(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 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[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(L).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(L[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(o(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 re=()=>te,oe=(e,t,r=[])=>{const o=J(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]:oe(o[e],s,r);var i;return o};function ie(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ie(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function se(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:se(o);return t}function ne(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ne(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ae(e,t={}){return new Promise(((r,o)=>{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||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(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,r,o=!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(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)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,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",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,r,o,i)=>{let s;const n=o.host,a=o.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:D.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...r.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(r,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async r=>{const{highcharts:i,server:n}=r,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(o(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:s,indicatorScripts:a}=i,l=r.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=o(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};ce.activeManifest=r,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,re().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(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 ye=o(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}=re();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"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.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,r,o)=>e.evaluate(ve,t,r,o);var xe=async(e,t,r)=>{let i=[];try{M(4,"[export] Determining export path.");const s=r.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}},r,a):(t.chart.height=s.height,t.chart.width=s.width,await Se(e,t,r,a));i=await async function(e,t){const r=[],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:o(e,"utf8")}:{url:e})}for(const t of s)try{r.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 o=i.css.match(/@import\s*([^;]*);/g);if(o)for(let e of o)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{r.push(await e.addStyleTag(t))}catch(e){F(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return r}(e,r);const c=l?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await 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:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,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,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 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,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 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 Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=v(),r=(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()-r} 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()*(Oe.workLimit/2))}},validate:async e=>!(Oe.workLimit&&++e.workCount>Oe.workLimit)||(M(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Oe.workLimit}).`),!1),destroy:async e=>{M(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},ke=async e=>{if(Oe=e&&e.pool?{...e.pool}:{},await async function(e){const{enable:t,...r}=re().debug,o={headless:"shell",userDataDir:"./tmp/",args:e,handleSIGINT:!1,handleSIGTERM:!1,handleSIGHUP:!1,waitForInitialPage:!1,defaultViewport:null,...t&&r};if(!be){let e=0;const r=async()=>{try{M(3,`[browser] Attempting to get a browser instance (try ${++e}).`),be=await y.launch(o)}catch(t){if(F(1,t,"[browser] Failed to launch a browser instance."),!(e<25))throw t;M(3,`[browser] Retry to open a browser (${e} out of 25).`),await new Promise((e=>setTimeout(e,4e3))),await r()}};try{await r(),t&&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 ${Oe.minWorkers}, max ${Oe.maxWorkers}.`),Re)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Oe.minWorkers)>parseInt(Oe.maxWorkers)&&(Oe.minWorkers=Oe.maxWorkers);try{Re=new f({..._e,min:parseInt(Oe.minWorkers),max:parseInt(Oe.maxWorkers),acquireTimeoutMillis:Oe.acquireTimeout,createTimeoutMillis:Oe.createTimeout,destroyTimeoutMillis:Oe.destroyTimeout,idleTimeoutMillis:Oe.idleTimeout,createRetryIntervalMillis:Oe.createRetryInterval,reapIntervalMillis:Oe.reaperInterval,propagateCreateError:!1}),Re.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}.`)})),Re.on("destroySuccess",((e,t)=>{M(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Re.release(e)})),M(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new le("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(M(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),M(4,"[browser] Destroyed the pool of resources."))}await async function(){be?.connected&&await be.close(),M(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let r;try{if(M(4,"[pool] Work received, starting to process."),++Le.exportAttempts,Oe.benchmarking&&Ne(),!Re)throw new le("Work received, but pool has not been started.");const o=ee();try{M(4,"[pool] Acquiring a worker handle."),r=await Re.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!r.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 ${r.id}.`);const s=ee(),n=await xe(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.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.`),Re.release(r);const a=(new Date).getTime()-i;return Le.timeSpent+=a,Le.spentAverage=Le.timeSpent/++Le.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Le.droppedExports,r&&Re.release(r),new le(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ne(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ae();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: ${r}.`),M(5,`[pool] The number of available resources: ${o}.`),M(5,`[pool] The number of acquired resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Pe=Ae,He=()=>Le;let $e=!1;const De=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=J(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=oe(t,e,_),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,re()),i=r.export;if(r.payload?.svg&&""!==r.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"]})}(r.payload.svg),r,t);return++Le.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."),r.export.instr=o(i.infile,"utf8"),Me(r.export.instr.trim(),r,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(r.customLogic?.allowCodeExecution)?je(r,t):"string"==typeof i.instr?Me(i.instr.trim(),r,t):Ge(r,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'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||K(e.export?.instr),o=K(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},Ge=async(e,t,r,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=o("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 r(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(o(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=o(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,...Ue(e)};try{return r(!1,await Ce(s.strInj||t||i,e))}catch(e){return r(e)}},je=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=z(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,Ge(e,!1,t)}catch(r){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(r))}},Me=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ge(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ge(t,o,r)}catch(e){return Q(o)?je(t,r):r(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,r,o)=>{F(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},qe=(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 Be=(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=x({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&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.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,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Xe("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 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=re();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){r(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,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},et=async(e,t,r)=>{try{const r=ee(),i=v().replace(/-/g,""),s=re(),n=e.body,a=++ze;let l=B(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).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=oe(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 De(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return M(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;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){r(e)}var o};const tt=JSON.parse(o(a(q,"package.json"))),rt=new Date,ot=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ot.push(t),ot.length>30&&ot.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=He(),o=ot.length,i=ot.reduce(((e,t)=>e+t),0)/ot.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:rt,uptime:Math.floor(((new Date).getTime()-rt.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.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,r;try{t=await i.readFile(l.join(e.ssl.certPath,"server.key"),"utf8"),r=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&&r){const o=m.createServer({key:t,cert:r},nt);ct(o),o.listen(e.ssl.port,e.host),st.set(e.ssl.port,o),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=>{W(e&&parseInt(e.level)),e&&e.dest&&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 De(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;s(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await Ie()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(De({...e,export:{...e.export,infile:r[0],outfile:r[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:De,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 r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(o(r))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ie(L,te),te=se(L),e&&(te=oe(te,e,_)),t?.length&&(te=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]=Q(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Y();return e}(te,t,L)),te),shutdownCleanUp:dt,log:M,logWithStack:F,setLogLevel:W,enableFileLogging:V,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=k[r]?k[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(t)&&(r=JSON.parse(o(t,"utf8")));const s=Object.keys(O).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:s},{onSubmit:async(e,o)=>{let s=0,n=[];for(const e of o)O[e]=O[e].map((t=>({...t,section:e}))),n=[...n,...O[e]];return await p(n,{onSubmit:async(e,o)=>{if("moduleScripts"===e.name?(o=o.length?o.map((t=>e.choices[t])):e.choices,r[e.section][e.name]=o):r[e.section]=ne(Object.assign({},r[e.section]||{}),e.name.split("."),e.choices?e.choices[o]:o),++s===n.length){try{await i.writeFile(t,JSON.stringify(r,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(o(a(q,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(o(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 r,readFileSync as o,promises as i,writeFileSync as s}from"fs";import n,{join as a,posix as l}from"path";import{HttpsProxyAgent as c}from"https-proxy-agent";import p from"prompts";import h from"dotenv";import{z as u}from"zod";import{fileURLToPath as d}from"url";import g from"http";import m from"https";import{Pool as f}from"tarn";import{v4 as v}from"uuid";import y from"puppeteer";import{JSDOM as b}from"jsdom";import w from"dompurify";import E from"cors";import T from"express";import S from"multer";import x from"express-rate-limit";const R={core:["highcharts","highcharts-more","highcharts-3d"],modules:["stock","map","gantt","exporting","export-data","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","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"],indicators:["indicators-all"]},L={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:["https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js","https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js"],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 logDest option also needs to be set to enable file logging."},dest:{value:"log/",type:"string",envLink:"LOGGING_DEST",cliName:"logDest",description:"The path to store log files. This also enables file logging."}},ui:{enable:{value:!1,type:"boolean",envLink:"UI_ENABLE",cliName:"enableUi",description:"Enables or disables the user interface (UI) for the export server."},route:{value:"/",type:"string",envLink:"UI_ROUTE",cliName:"uiRoute",description:"The endpoint route to which the user interface (UI) should be attached."}},other:{nodeEnv:{value:"production",type:"string",envLink:"OTHER_NODE_ENV",description:"The type of Node.js environment."},listenToProcessExits:{value:!0,type:"boolean",envLink:"OTHER_LISTEN_TO_PROCESS_EXITS",description:"Decides whether or not to attach process.exit handlers."},noLogo:{value:!1,type:"boolean",envLink:"OTHER_NO_LOGO",description:"Skip printing the logo on a startup. Will be replaced by a simple text."},hardResetPage:{value:!1,type:"boolean",envLink:"OTHER_HARD_RESET_PAGE",description:"Decides if the page content should be reset entirely."},browserShellMode:{value:!0,type:"boolean",envLink:"OTHER_BROWSER_SHELL_MODE",description:"Decides if the browser runs in the shell mode."}},debug:{enable:{value:!1,type:"boolean",envLink:"DEBUG_ENABLE",cliName:"enableDebug",description:"Enables or disables debug mode for the underlying browser."},headless:{value:!0,type:"boolean",envLink:"DEBUG_HEADLESS",description:"Controls the mode in which the browser is launched when in the debug mode."},devtools:{value:!1,type:"boolean",envLink:"DEBUG_DEVTOOLS",description:"Decides whether to enable DevTools when the browser is in a headful state."},listenToConsole:{value:!1,type:"boolean",envLink:"DEBUG_LISTEN_TO_CONSOLE",description:"Decides whether to enable a listener for console messages sent from the browser."},dumpio:{value:!1,type:"boolean",envLink:"DEBUG_DUMPIO",description:"Redirects browser process stdout and stderr to process.stdout and process.stderr."},slowMo:{value:0,type:"number",envLink:"DEBUG_SLOW_MO",description:"Slows down Puppeteer operations by the specified number of milliseconds."},debuggingPort:{value:9222,type:"number",envLink:"DEBUG_DEBUGGING_PORT",description:"Specifies the debugging port."}}},O={puppeteer:[{type:"list",name:"args",message:"Puppeteer arguments",initial:L.puppeteer.args.value.join(","),separator:","}],highcharts:[{type:"text",name:"version",message:"Highcharts version",initial:L.highcharts.version.value},{type:"text",name:"cdnURL",message:"The URL of CDN",initial:L.highcharts.cdnURL.value},{type:"multiselect",name:"coreScripts",message:"Available core scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.coreScripts.value},{type:"multiselect",name:"moduleScripts",message:"Available module scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.moduleScripts.value},{type:"multiselect",name:"indicatorScripts",message:"Available indicator scripts",instructions:"Space: Select specific, A: Select all, Enter: Confirm.",choices:L.highcharts.indicatorScripts.value},{type:"list",name:"customScripts",message:"Custom scripts",initial:L.highcharts.customScripts.value.join(","),separator:","},{type:"toggle",name:"forceFetch",message:"Force re-fetch the scripts",initial:L.highcharts.forceFetch.value},{type:"text",name:"cachePath",message:"The path to the cache directory",initial:L.highcharts.cachePath.value}],export:[{type:"select",name:"type",message:"The default export file type",hint:`Default: ${L.export.type.value}`,initial:0,choices:["png","jpeg","pdf","svg"]},{type:"select",name:"constr",message:"The default constructor for Highcharts",hint:`Default: ${L.export.constr.value}`,initial:0,choices:["chart","stockChart","mapChart","ganttChart"]},{type:"number",name:"defaultHeight",message:"The default fallback height of the exported chart",initial:L.export.defaultHeight.value},{type:"number",name:"defaultWidth",message:"The default fallback width of the exported chart",initial:L.export.defaultWidth.value},{type:"number",name:"defaultScale",message:"The default fallback scale of the exported chart",initial:L.export.defaultScale.value,min:.1,max:5},{type:"number",name:"rasterizationTimeout",message:"The rendering webpage timeout in milliseconds",initial:L.export.rasterizationTimeout.value}],customLogic:[{type:"toggle",name:"allowCodeExecution",message:"Enable execution of custom code",initial:L.customLogic.allowCodeExecution.value},{type:"toggle",name:"allowFileResources",message:"Enable file resources",initial:L.customLogic.allowFileResources.value}],server:[{type:"toggle",name:"enable",message:"Starts the server on 0.0.0.0",initial:L.server.enable.value},{type:"text",name:"host",message:"Server hostname",initial:L.server.host.value},{type:"number",name:"port",message:"Server port",initial:L.server.port.value},{type:"toggle",name:"benchmarking",message:"Enable server benchmarking",initial:L.server.benchmarking.value},{type:"text",name:"proxy.host",message:"The host of the proxy server to use",initial:L.server.proxy.host.value},{type:"number",name:"proxy.port",message:"The port of the proxy server to use",initial:L.server.proxy.port.value},{type:"number",name:"proxy.timeout",message:"The timeout for the proxy server to use",initial:L.server.proxy.timeout.value},{type:"toggle",name:"rateLimiting.enable",message:"Enable rate limiting",initial:L.server.rateLimiting.enable.value},{type:"number",name:"rateLimiting.maxRequests",message:"The maximum requests allowed per minute",initial:L.server.rateLimiting.maxRequests.value},{type:"number",name:"rateLimiting.window",message:"The rate-limiting time window in minutes",initial:L.server.rateLimiting.window.value},{type:"number",name:"rateLimiting.delay",message:"The delay for each successive request before reaching the maximum",initial:L.server.rateLimiting.delay.value},{type:"toggle",name:"rateLimiting.trustProxy",message:"Set to true if behind a load balancer",initial:L.server.rateLimiting.trustProxy.value},{type:"text",name:"rateLimiting.skipKey",message:"Allows bypassing the rate limiter when provided with the skipToken argument",initial:L.server.rateLimiting.skipKey.value},{type:"text",name:"rateLimiting.skipToken",message:"Allows bypassing the rate limiter when provided with the skipKey argument",initial:L.server.rateLimiting.skipToken.value},{type:"toggle",name:"ssl.enable",message:"Enable SSL protocol",initial:L.server.ssl.enable.value},{type:"toggle",name:"ssl.force",message:"Force serving only over HTTPS",initial:L.server.ssl.force.value},{type:"number",name:"ssl.port",message:"SSL server port",initial:L.server.ssl.port.value},{type:"text",name:"ssl.certPath",message:"The path to find the SSL certificate/key",initial:L.server.ssl.certPath.value}],pool:[{type:"number",name:"minWorkers",message:"The initial number of workers to spawn",initial:L.pool.minWorkers.value},{type:"number",name:"maxWorkers",message:"The maximum number of workers to spawn",initial:L.pool.maxWorkers.value},{type:"number",name:"workLimit",message:"The pieces of work that can be performed before restarting a Puppeteer process",initial:L.pool.workLimit.value},{type:"number",name:"acquireTimeout",message:"The number of milliseconds to wait for acquiring a resource",initial:L.pool.acquireTimeout.value},{type:"number",name:"createTimeout",message:"The number of milliseconds to wait for creating a resource",initial:L.pool.createTimeout.value},{type:"number",name:"destroyTimeout",message:"The number of milliseconds to wait for destroying a resource",initial:L.pool.destroyTimeout.value},{type:"number",name:"idleTimeout",message:"The number of milliseconds after an idle resource is destroyed",initial:L.pool.idleTimeout.value},{type:"number",name:"createRetryInterval",message:"The retry interval in milliseconds after a create process fails",initial:L.pool.createRetryInterval.value},{type:"number",name:"reaperInterval",message:"The reaper interval in milliseconds after triggering the check for idle resources to destroy",initial:L.pool.reaperInterval.value},{type:"toggle",name:"benchmarking",message:"Enable benchmarking for a resource pool",initial:L.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:L.logging.level.value,round:0,min:0,max:5},{type:"text",name:"file",message:"A log file name. Set with the --logDest to enable file logging",initial:L.logging.file.value},{type:"text",name:"dest",message:"The path to log files. Enables file logging",initial:L.logging.dest.value}],ui:[{type:"toggle",name:"enable",message:"Enable UI for the export server",initial:L.ui.enable.value},{type:"text",name:"route",message:"A route to attach the UI",initial:L.ui.route.value}],other:[{type:"text",name:"nodeEnv",message:"The type of Node.js environment",initial:L.other.nodeEnv.value},{type:"toggle",name:"listenToProcessExits",message:"Set to false to skip attaching process.exit handlers",initial:L.other.listenToProcessExits.value},{type:"toggle",name:"noLogo",message:"Skip printing the logo on startup. Replaced by simple text",initial:L.other.noLogo.value},{type:"toggle",name:"hardResetPage",message:"Decides if the page content should be reset entirely",initial:L.other.hardResetPage.value},{type:"toggle",name:"browserShellMode",message:"Decides if the browser runs in the shell mode",initial:L.other.browserShellMode.value}],debug:[{type:"toggle",name:"enable",message:"Enables debug mode for the browser instance",initial:L.debug.enable.value},{type:"toggle",name:"headless",message:"The mode setting for the browser",initial:L.debug.headless.value},{type:"toggle",name:"devtools",message:"The DevTools for the headful browser",initial:L.debug.devtools.value},{type:"toggle",name:"listenToConsole",message:"The event listener for console messages from the browser",initial:L.debug.listenToConsole.value},{type:"toggle",name:"dumpio",message:"Redirects the browser stdout and stderr to NodeJS process",initial:L.debug.dumpio.value},{type:"number",name:"slowMo",message:"Puppeteer operations slow down in milliseconds",initial:L.debug.slowMo.value},{type:"number",name:"debuggingPort",message:"The port number for debugging",initial:L.debug.debuggingPort.value}]},_=["options","globalOptions","themeOptions","resources","payload"],k={},I=(e,t="")=>{Object.keys(e).forEach((r=>{if(!["puppeteer","highcharts"].includes(r)){const o=e[r];void 0===o.value?I(o,`${t}.${r}`):(k[o.cliName||r]=`${t}.${r}`.substring(1),void 0!==o.legacyName&&(k[o.legacyName]=`${t}.${r}`.substring(1)))}}))};I(L),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)),A=()=>u.enum(["true","false",""]).transform((e=>""!==e?"true"===e:void 0)),N=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)),D=u.object({HIGHCHARTS_VERSION:u.string().trim().refine((e=>/^(latest|\d+(\.\d+){0,2})$/.test(e)||""===e),(e=>({message:`HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CDN_URL:u.string().trim().refine((e=>e.startsWith("https://")||e.startsWith("http://")||""===e),(e=>({message:`Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${e}'`}))).transform((e=>""!==e?e:void 0)),HIGHCHARTS_CORE_SCRIPTS:C(R.core),HIGHCHARTS_MODULE_SCRIPTS:C(R.modules),HIGHCHARTS_INDICATOR_SCRIPTS:C(R.indicators),HIGHCHARTS_FORCE_FETCH:A(),HIGHCHARTS_CACHE_PATH:P(),HIGHCHARTS_ADMIN_TOKEN:P(),EXPORT_TYPE:N(["jpeg","png","pdf","svg"]),EXPORT_CONSTR:N(["chart","stockChart","mapChart","ganttChart"]),EXPORT_DEFAULT_HEIGHT:H(),EXPORT_DEFAULT_WIDTH:H(),EXPORT_DEFAULT_SCALE:H(),EXPORT_RASTERIZATION_TIMEOUT:$(),CUSTOM_LOGIC_ALLOW_CODE_EXECUTION:A(),CUSTOM_LOGIC_ALLOW_FILE_RESOURCES:A(),SERVER_ENABLE:A(),SERVER_HOST:P(),SERVER_PORT:H(),SERVER_BENCHMARKING:A(),SERVER_PROXY_HOST:P(),SERVER_PROXY_PORT:H(),SERVER_PROXY_TIMEOUT:$(),SERVER_RATE_LIMITING_ENABLE:A(),SERVER_RATE_LIMITING_MAX_REQUESTS:$(),SERVER_RATE_LIMITING_WINDOW:$(),SERVER_RATE_LIMITING_DELAY:$(),SERVER_RATE_LIMITING_TRUST_PROXY:A(),SERVER_RATE_LIMITING_SKIP_KEY:P(),SERVER_RATE_LIMITING_SKIP_TOKEN:P(),SERVER_SSL_ENABLE:A(),SERVER_SSL_FORCE:A(),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:A(),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(),UI_ENABLE:A(),UI_ROUTE:P(),OTHER_NODE_ENV:N(["development","production","test"]),OTHER_LISTEN_TO_PROCESS_EXITS:A(),OTHER_NO_LOGO:A(),OTHER_HARD_RESET_PAGE:A(),OTHER_BROWSER_SHELL_MODE:A(),DEBUG_ENABLE:A(),DEBUG_HEADLESS:A(),DEBUG_DEVTOOLS:A(),DEBUG_LISTEN_TO_CONSOLE:A(),DEBUG_DUMPIO:A(),DEBUG_SLOW_MO:$(),DEBUG_DEBUGGING_PORT:H()}).partial().parse(process.env),U=["red","yellow","blue","gray","green"];let G={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:[]};for(const[e,t]of Object.entries(L.logging))G[e]=t.value;const j=(o,i)=>{G.toFile&&(G.pathCreated||(!e(G.dest)&&t(G.dest),G.pathCreated=!0),r(`${G.dest}${G.file}`,[i].concat(o).join(" ")+"\n",(e=>{e&&(console.log(`[logger] Unable to write to log file: ${e}`),G.toFile=!1)})))},M=(...e)=>{const[t,...r]=e,{level:o,levelsDesc:i}=G;if(5!==t&&(0===t||t>o||o>i.length))return;const s=`${(new Date).toString().split("(")[0].trim()} [${i[t-1].title}] -`;G.listeners.forEach((e=>{e(s,r.join(" "))})),G.toConsole&&console.log.apply(void 0,[s.toString()[G.levelsDesc[t-1].color]].concat(r)),j(r,s)},F=(e,t,r)=>{const o=r||t.message,{level:i,levelsDesc:s}=G;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];G.toConsole&&console.log.apply(void 0,[n.toString()[G.levelsDesc[e-1].color]].concat([o[U[e-1]],"\n",a])),G.listeners.forEach((e=>{e(n,l.join(" "))})),j(l,n)},W=e=>{e>=0&&e<=G.levelsDesc.length&&(G.level=e)},V=(e,t)=>{if(G={...G,dest:e||G.dest,file:t||G.file,toFile:!0},0===G.dest.length)return M(1,"[logger] File logging initialization: no path supplied.");G.dest.endsWith("/")||(G.dest+="/")},q=d(new URL("../.",import.meta.url)),B=(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"},X=(e=!1,t)=>{const r=["js","css","files"];let i=e,s=!1;if(t&&e.endsWith(".json"))try{i=K(o(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)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):M(3,"[cli] No resources found.")};function K(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 J=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]=J(e[r]));return t},z=(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 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[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(L).forEach((t=>{["puppeteer","highcharts"].includes(t)||(console.log(`\n${t.toUpperCase()}`.red),e(L[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(o(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 re=()=>te,oe=(e,t,r=[])=>{const o=J(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]:oe(o[e],s,r);var i;return o};function ie(e,t={},r=""){Object.keys(e).forEach((o=>{const i=e[o],s=t&&t[o];void 0===i.value?ie(i,s,`${r}.${o}`):(void 0!==s&&(i.value=s),i.envLink in D&&void 0!==D[i.envLink]&&(i.value=D[i.envLink]))}))}function se(e){let t={};for(const[r,o]of Object.entries(e))t[r]=Object.prototype.hasOwnProperty.call(o,"value")?o.value:se(o);return t}function ne(e,t,r){for(;t.length>1;){const o=t.shift();return Object.prototype.hasOwnProperty.call(e,o)||(e[o]={}),e[o]=ne(Object.assign({},e[o]),t,r),e}return e[t[0]]=r,e}async function ae(e,t={}){return new Promise(((r,o)=>{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||o("Nothing was fetched from the URL."),e.text=t,r(e)}))})).on("error",(e=>{o(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,r,o=!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(r){r[e.replace(/(.*)\/|(.*)modules\/|stock\/(.*)indicators\/|maps\/(.*)modules\//gi,"")]=1}return i.text}if(o)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,r)=>{const o=e.version,i="latest"!==o&&o?`${o}/`:"",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,r,o,i)=>{let s;const n=o.host,a=o.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:D.SERVER_PROXY_TIMEOUT}:{},p=[...e.map((e=>he(`${e}`,l,i,!0))),...t.map((e=>he(`${e}`,l,i))),...r.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(r,ce.sources),a}catch(e){throw new le("[cache] Unable to update the local Highcharts cache.").setError(e)}},de=async r=>{const{highcharts:i,server:n}=r,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(o(p));if(t.modules&&Array.isArray(t.modules)){const e={};t.modules.forEach((t=>e[t]=1)),t.modules=e}const{coreScripts:r,moduleScripts:s,indicatorScripts:a}=i,l=r.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=o(h,"utf8"),c=t.modules,ce.hcVersion=pe(ce))}await(async(e,t)=>{const r={version:e.version,modules:t||{}};ce.activeManifest=r,M(3,"[cache] Writing a new manifest.");try{s(a(q,e.cachePath,"manifest.json"),JSON.stringify(r),"utf8")}catch(e){throw new le("[cache] Error writing the cache manifest.").setError(e)}})(i,c)},ge=()=>a(q,re().highcharts.cachePath),me=()=>ce.hcVersion;function fe(){Highcharts.animObject=function(){return{duration:0}}}async function ve(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 ye=o(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}=re();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"),[...r]=document.getElementsByTagName("link");for(const o of[...e,...t,...r])o.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,r,o)=>e.evaluate(ve,t,r,o);var xe=async(e,t,r)=>{let i=[];try{M(4,"[export] Determining export path.");const s=r.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}},r,a):(t.chart.height=s.height,t.chart.width=s.width,await Se(e,t,r,a));i=await async function(e,t){const r=[],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:o(e,"utf8")}:{url:e})}for(const t of s)try{r.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 o=i.css.match(/@import\s*([^;]*);/g);if(o)for(let e of o)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{r.push(await e.addStyleTag(t))}catch(e){F(2,e,"[export] The CSS resource cannot be loaded.")}a.length=0}}return r}(e,r);const c=l?await e.evaluate((e=>{const t=document.querySelector("#chart-container svg:first-of-type"),r=t.height.baseVal.value*e,o=t.width.baseVal.value*e;return document.body.style.zoom=e,document.body.style.margin="0px",{chartHeight:r,chartWidth:o}}),parseFloat(s.scale)):await 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:r,width:o,height:i}=e.getBoundingClientRect();return{x:t,y:r,width:o,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,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 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,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 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 Re=!1;const Le={performedExports:0,exportAttempts:0,exportFromSvgAttempts:0,timeSpent:0,droppedExports:0,spentAverage:0};let Oe={};const _e={create:async()=>{let e=!1;const t=v(),r=(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()-r} 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()*(Oe.workLimit/2))}},validate:async e=>!(Oe.workLimit&&++e.workCount>Oe.workLimit)||(M(3,`[pool] Worker failed validation: exceeded work limit (limit is ${Oe.workLimit}).`),!1),destroy:async e=>{M(3,`[pool] Destroying pool entry ${e.id}.`),e.page&&await e.page.close()}},ke=async e=>{if(Oe=e&&e.pool?{...e.pool}:{},await async function(e){const{debug:t,other:r}=re(),{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(!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(r){if(F(1,r,"[browser] Failed to launch a browser instance."),!(e<25))throw r;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."),o&&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 ${Oe.minWorkers}, max ${Oe.maxWorkers}.`),Re)return M(4,"[pool] Already initialized, please kill it before creating a new one.");parseInt(Oe.minWorkers)>parseInt(Oe.maxWorkers)&&(Oe.minWorkers=Oe.maxWorkers);try{Re=new f({..._e,min:parseInt(Oe.minWorkers),max:parseInt(Oe.maxWorkers),acquireTimeoutMillis:Oe.acquireTimeout,createTimeoutMillis:Oe.createTimeout,destroyTimeoutMillis:Oe.destroyTimeout,idleTimeoutMillis:Oe.idleTimeout,createRetryIntervalMillis:Oe.createRetryInterval,reapIntervalMillis:Oe.reaperInterval,propagateCreateError:!1}),Re.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}.`)})),Re.on("destroySuccess",((e,t)=>{M(4,`[pool] Destroyed a worker with ID ${t.id}.`)}));const e=[];for(let t=0;t{Re.release(e)})),M(3,"[pool] The pool is ready"+(e.length?` with ${e.length} initial resources waiting.`:"."))}catch(e){throw new le("[pool] Could not create the pool of workers.").setError(e)}};async function Ie(){if(M(3,"[pool] Killing pool with all workers and closing browser."),Re){for(const e of Re.used)Re.release(e.resource);Re.destroyed||(await Re.destroy(),M(4,"[browser] Destroyed the pool of resources."))}await async function(){be?.connected&&await be.close(),M(4,"[browser] Closed the browser.")}()}const Ce=async(e,t)=>{let r;try{if(M(4,"[pool] Work received, starting to process."),++Le.exportAttempts,Oe.benchmarking&&Ne(),!Re)throw new le("Work received, but pool has not been started.");const o=ee();try{M(4,"[pool] Acquiring a worker handle."),r=await Re.acquire().promise,t.server.benchmarking&&M(5,t.payload?.requestId?`[benchmark] Request with ID ${t.payload?.requestId} -`:"[benchmark]",`Acquired a worker handle: ${o()}ms.`)}catch(e){throw new le((t.payload?.requestId?`For request with ID ${t.payload?.requestId} - `:"")+`Error encountered when acquiring an available entry: ${o()}ms.`).setError(e)}if(M(4,"[pool] Acquired a worker handle."),!r.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 ${r.id}.`);const s=ee(),n=await xe(r.page,e,t);if(n instanceof Error)throw"Rasterization timeout"===n.message&&(r.page.close(),r.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.`),Re.release(r);const a=(new Date).getTime()-i;return Le.timeSpent+=a,Le.spentAverage=Le.timeSpent/++Le.performedExports,M(4,`[pool] Work completed in ${a} ms.`),{result:n,options:t}}catch(e){throw++Le.droppedExports,r&&Re.release(r),new le(`[pool] In pool.postWork: ${e.message}`).setError(e)}},Ae=()=>({min:Re.min,max:Re.max,all:Re.numFree()+Re.numUsed(),available:Re.numFree(),used:Re.numUsed(),pending:Re.numPendingAcquires()});function Ne(){const{min:e,max:t,all:r,available:o,used:i,pending:s}=Ae();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: ${r}.`),M(5,`[pool] The number of available resources: ${o}.`),M(5,`[pool] The number of acquired resources: ${i}.`),M(5,`[pool] The number of resources waiting to be acquired: ${s}.`)}var Pe=Ae,He=()=>Le;let $e=!1;const De=async(e,t)=>{M(4,"[chart] Starting the exporting process.");const r=((e,t={})=>{let r={};return e.svg?(r=J(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=oe(t,e,_),r.export.outfile=r.export?.outfile||`chart.${r.export?.type||"png"}`,r})(e,re()),i=r.export;if(r.payload?.svg&&""!==r.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"]})}(r.payload.svg),r,t);return++Le.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."),r.export.instr=o(i.infile,"utf8"),Me(r.export.instr.trim(),r,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(r.customLogic?.allowCodeExecution)?je(r,t):"string"==typeof i.instr?Me(i.instr.trim(),r,t):Ge(r,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'."))},Ue=e=>{const{chart:t,exporting:r}=e.export?.options||K(e.export?.instr),o=K(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},Ge=async(e,t,r,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=o("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 r(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(o(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=o(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,...Ue(e)};try{return r(!1,await Ce(s.strInj||t||i,e))}catch(e){return r(e)}},je=(e,t)=>{try{let r,o=e.export.instr||e.export.options;return"string"!=typeof o&&(r=o=z(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,Ge(e,!1,t)}catch(r){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(r))}},Me=(e,t,r)=>{const{allowCodeExecution:o}=t.customLogic;if(e.indexOf("=0||e.indexOf("=0)return M(4,"[chart] Parsing input as SVG."),Ge(t,!1,r,e);try{const o=JSON.parse(e.replaceAll(/\t|\n|\r/g," "));return Ge(t,o,r)}catch(e){return Q(o)?je(t,r):r(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,r,o)=>{F(1,e),"development"!==D.OTHER_NODE_ENV&&delete e.stack,o(e)},qe=(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 Be=(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=x({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&&(M(4,"[rate limiting] Skipping rate limiter."),!0)});e.use(i),M(3,`[rate limiting] Enabled rate limiting with ${o.max} requests per ${o.window} minute for each IP, trusting proxy: ${o.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,r)=>{try{const r=D.HIGHCHARTS_ADMIN_TOKEN;if(!r||!r.length)throw new Xe("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 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=re();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){r(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,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},et=async(e,t,r)=>{try{const r=ee(),i=v().replace(/-/g,""),s=re(),n=e.body,a=++ze;let l=B(n.type);if(!n||"object"==typeof(o=n)&&!Array.isArray(o)&&null!==o&&0===Object.keys(o).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=oe(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 De(d,((o,c)=>{if(e.socket.removeAllListeners("close"),s.server.benchmarking&&M(5,`[benchmark] Request with ID ${i} - After the whole exporting process: ${r()}ms.`),h)return M(3,"[export] The client closed the connection before the chart finished processing.");if(o)throw o;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){r(e)}var o};const tt=JSON.parse(o(a(q,"package.json"))),rt=new Date,ot=[];function it(e){if(!e)return!1;var t;t=setInterval((()=>{const e=He(),t=0===e.exportAttempts?1:e.performedExports/e.exportAttempts*100;ot.push(t),ot.length>30&&ot.shift()}),6e4),Fe.push(t),e.get("/health",((e,t)=>{const r=He(),o=ot.length,i=ot.reduce(((e,t)=>e+t),0)/ot.length;M(4,"[health.js] GET /health [200] - returning server health."),t.send({status:"OK",bootTime:rt,uptime:Math.floor(((new Date).getTime()-rt.getTime())/1e3/60)+" minutes",version:tt.version,highchartsVersion:me(),averageProcessingTime:r.spentAverage,performedExports:r.performedExports,failedExports:r.droppedExports,exportAttempts:r.exportAttempts,sucessRatio:r.performedExports/r.exportAttempts*100,pool:Pe(),period:o,movingAverage:i,message:`Last ${o} minutes had a success rate of ${i.toFixed(2)}%.`,svgExportAttempts:r.exportFromSvgAttempts,jsonExportAttempts:r.performedExports-r.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,r;try{t=await i.readFile(l.join(e.ssl.certPath,"server.key"),"utf8"),r=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&&r){const o=m.createServer({key:t,cert:r},nt);ct(o),o.listen(e.ssl.port,e.host),st.set(e.ssl.port,o),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=>{W(e&&parseInt(e.level)),e&&e.dest&&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 De(e,(async(e,t)=>{if(e)throw e;const{outfile:r,type:o}=t.options.export;s(r||`chart.${o}`,"svg"!==o?Buffer.from(t.result,"base64"):t.result),await Ie()}))},batchExport:async e=>{const t=[];for(let r of e.export.batch.split(";"))r=r.split("="),2===r.length&&t.push(De({...e,export:{...e.export,infile:r[0],outfile:r[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:De,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 r=e[t+1];try{if(r&&r.endsWith(".json"))return JSON.parse(o(r))}catch(e){F(2,e,`[config] Unable to load the configuration from the ${r} file.`)}}return{}}(t)),ie(L,te),te=se(L),e&&(te=oe(te,e,_)),t?.length&&(te=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]=Q(t[i]):"number"===a?e[r]=+t[i]:a.indexOf("]")>=0?e[r]=t[i].split(","):e[r]=t[i]:(M(2,`[config] Missing value for the '${s}' argument. Using the default value.`),o=!0)),e[r])),e)}o&&Y();return e}(te,t,L)),te),shutdownCleanUp:dt,log:M,logWithStack:F,setLogLevel:W,enableFileLogging:V,mapToNewConfig:e=>{const t={};for(const[r,o]of Object.entries(e)){const e=k[r]?k[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(t)&&(r=JSON.parse(o(t,"utf8")));const s=Object.keys(O).map((e=>({title:`${e} options`,value:e})));return p({type:"multiselect",name:"category",message:"Which category do you want to configure?",hint:"Space: Select specific, A: Select all, Enter: Confirm.",instructions:"",choices:s},{onSubmit:async(e,o)=>{let s=0,n=[];for(const e of o)O[e]=O[e].map((t=>({...t,section:e}))),n=[...n,...O[e]];return await p(n,{onSubmit:async(e,o)=>{if("moduleScripts"===e.name?(o=o.length?o.map((t=>e.choices[t])):e.choices,r[e.section][e.name]=o):r[e.section]=ne(Object.assign({},r[e.section]||{}),e.name.split("."),e.choices?e.choices[o]:o),++s===n.length){try{await i.writeFile(t,JSON.stringify(r,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(o(a(q,"package.json"))).version;e?console.log(`Starting Highcharts Export Server v${t}...`):console.log(o(q+"/msg/startup.msg").toString().bold.yellow,`v${t}\n`.bold)},printUsage:Y};export{gt as default}; //# sourceMappingURL=index.esm.js.map diff --git a/dist/index.esm.js.map b/dist/index.esm.js.map index b14a474e..b146c1ba 100644 --- a/dist/index.esm.js.map +++ b/dist/index.esm.js.map @@ -1 +1 @@ -{"version":3,"file":"index.esm.js","sources":["../lib/schemas/config.js","../lib/envs.js","../lib/logger.js","../lib/utils.js","../lib/config.js","../lib/fetch.js","../lib/errors/ExportError.js","../lib/cache.js","../lib/highcharts.js","../lib/browser.js","../lib/export.js","../templates/svg_export/svg_export.js","../lib/pool.js","../lib/chart.js","../lib/sanitize.js","../lib/intervals.js","../lib/server/error.js","../lib/server/rate_limit.js","../lib/errors/HttpError.js","../lib/server/routes/change_hc_version.js","../lib/server/routes/export.js","../lib/server/routes/health.js","../lib/server/server.js","../lib/server/routes/ui.js","../lib/resource_release.js","../lib/index.js"],"sourcesContent":["/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// Possible names for Highcharts scripts\r\nexport const scriptsNames = {\r\n core: ['highcharts', 'highcharts-more', 'highcharts-3d'],\r\n modules: [\r\n 'stock',\r\n 'map',\r\n 'gantt',\r\n 'exporting',\r\n 'export-data',\r\n 'parallel-coordinates',\r\n 'accessibility',\r\n // 'annotations-advanced',\r\n 'boost-canvas',\r\n 'boost',\r\n 'data',\r\n 'data-tools',\r\n 'draggable-points',\r\n 'static-scale',\r\n 'broken-axis',\r\n 'heatmap',\r\n 'tilemap',\r\n 'tiledwebmap',\r\n 'timeline',\r\n 'treemap',\r\n 'treegraph',\r\n 'item-series',\r\n 'drilldown',\r\n 'histogram-bellcurve',\r\n 'bullet',\r\n 'funnel',\r\n 'funnel3d',\r\n 'geoheatmap',\r\n 'pyramid3d',\r\n 'networkgraph',\r\n 'overlapping-datalabels',\r\n 'pareto',\r\n 'pattern-fill',\r\n 'pictorial',\r\n 'price-indicator',\r\n 'sankey',\r\n 'arc-diagram',\r\n 'dependency-wheel',\r\n 'series-label',\r\n 'solid-gauge',\r\n 'sonification',\r\n // 'stock-tools',\r\n 'streamgraph',\r\n 'sunburst',\r\n 'variable-pie',\r\n 'variwide',\r\n 'vector',\r\n 'venn',\r\n 'windbarb',\r\n 'wordcloud',\r\n 'xrange',\r\n 'no-data-to-display',\r\n 'drag-panes',\r\n 'debugger',\r\n 'dumbbell',\r\n 'lollipop',\r\n 'cylinder',\r\n 'organization',\r\n 'dotplot',\r\n 'marker-clusters',\r\n 'hollowcandlestick',\r\n 'heikinashi',\r\n 'flowmap'\r\n ],\r\n indicators: ['indicators-all']\r\n};\r\n\r\n// This is the configuration object with all options and their default values,\r\n// also from the .env file if one exists\r\nexport const defaultConfig = {\r\n puppeteer: {\r\n args: {\r\n value: [\r\n '--allow-running-insecure-content',\r\n '--ash-no-nudges',\r\n '--autoplay-policy=user-gesture-required',\r\n '--block-new-web-contents',\r\n '--disable-accelerated-2d-canvas',\r\n '--disable-background-networking',\r\n '--disable-background-timer-throttling',\r\n '--disable-backgrounding-occluded-windows',\r\n '--disable-breakpad',\r\n '--disable-checker-imaging',\r\n '--disable-client-side-phishing-detection',\r\n '--disable-component-extensions-with-background-pages',\r\n '--disable-component-update',\r\n '--disable-default-apps',\r\n '--disable-dev-shm-usage',\r\n '--disable-domain-reliability',\r\n '--disable-extensions',\r\n '--disable-features=CalculateNativeWinOcclusion,InterestFeedContentSuggestions,WebOTP',\r\n '--disable-hang-monitor',\r\n '--disable-ipc-flooding-protection',\r\n '--disable-logging',\r\n '--disable-notifications',\r\n '--disable-offer-store-unmasked-wallet-cards',\r\n '--disable-popup-blocking',\r\n '--disable-print-preview',\r\n '--disable-prompt-on-repost',\r\n '--disable-renderer-backgrounding',\r\n '--disable-search-engine-choice-screen',\r\n '--disable-session-crashed-bubble',\r\n '--disable-setuid-sandbox',\r\n '--disable-site-isolation-trials',\r\n '--disable-speech-api',\r\n '--disable-sync',\r\n '--enable-unsafe-webgpu',\r\n '--hide-crash-restore-bubble',\r\n '--hide-scrollbars',\r\n '--metrics-recording-only',\r\n '--mute-audio',\r\n '--no-default-browser-check',\r\n '--no-first-run',\r\n '--no-pings',\r\n '--no-sandbox',\r\n '--no-startup-window',\r\n '--no-zygote',\r\n '--password-store=basic',\r\n '--process-per-tab',\r\n '--use-mock-keychain'\r\n ],\r\n type: 'string[]',\r\n description: 'Arguments array to send to Puppeteer.'\r\n }\r\n },\r\n highcharts: {\r\n version: {\r\n value: 'latest',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_VERSION',\r\n description: 'The Highcharts version to be used.'\r\n },\r\n cdnURL: {\r\n value: 'https://code.highcharts.com/',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CDN_URL',\r\n description: 'The CDN URL for Highcharts scripts to be used.'\r\n },\r\n coreScripts: {\r\n value: scriptsNames.core,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_CORE_SCRIPTS',\r\n description: 'The core Highcharts scripts to fetch.'\r\n },\r\n moduleScripts: {\r\n value: scriptsNames.modules,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_MODULE_SCRIPTS',\r\n description: 'The modules of Highcharts to fetch.'\r\n },\r\n indicatorScripts: {\r\n value: scriptsNames.indicators,\r\n type: 'string[]',\r\n envLink: 'HIGHCHARTS_INDICATOR_SCRIPTS',\r\n description: 'The indicators of Highcharts to fetch.'\r\n },\r\n customScripts: {\r\n value: [\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.4/moment.min.js',\r\n 'https://cdnjs.cloudflare.com/ajax/libs/moment-timezone/0.5.34/moment-timezone-with-data.min.js'\r\n ],\r\n type: 'string[]',\r\n description: 'Additional custom scripts or dependencies to fetch.'\r\n },\r\n forceFetch: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'HIGHCHARTS_FORCE_FETCH',\r\n description:\r\n 'The flag to determine whether to refetch all scripts after each server rerun.'\r\n },\r\n cachePath: {\r\n value: '.cache',\r\n type: 'string',\r\n envLink: 'HIGHCHARTS_CACHE_PATH',\r\n description:\r\n 'The path to the cache directory. It is used to store the Highcharts scripts and custom scripts.'\r\n }\r\n },\r\n export: {\r\n infile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The input file should include a name and a type (json or svg). It must be correctly formatted as a JSON or SVG file.'\r\n },\r\n instr: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Input, provided in the form of a stringified JSON or SVG file, will override the --infile option.'\r\n },\r\n options: {\r\n value: false,\r\n type: 'string',\r\n description: 'An alias for the --instr option.'\r\n },\r\n outfile: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'The output filename along with a type (jpeg, png, pdf, or svg). This will ignore the --type flag.'\r\n },\r\n type: {\r\n value: 'png',\r\n type: 'string',\r\n envLink: 'EXPORT_TYPE',\r\n description: 'The file export format. It can be jpeg, png, pdf, or svg.'\r\n },\r\n constr: {\r\n value: 'chart',\r\n type: 'string',\r\n envLink: 'EXPORT_CONSTR',\r\n description:\r\n 'The constructor to use. Can be chart, stockChart, mapChart, or ganttChart.'\r\n },\r\n defaultHeight: {\r\n value: 400,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_HEIGHT',\r\n description:\r\n 'the default height of the exported chart. Used when no value is set.'\r\n },\r\n defaultWidth: {\r\n value: 600,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_WIDTH',\r\n description:\r\n 'The default width of the exported chart. Used when no value is set.'\r\n },\r\n defaultScale: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'EXPORT_DEFAULT_SCALE',\r\n description:\r\n 'The default scale of the exported chart. Used when no value is set.'\r\n },\r\n height: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The height of the exported chart, overriding the option in the chart settings.'\r\n },\r\n width: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The width of the exported chart, overriding the option in the chart settings.'\r\n },\r\n scale: {\r\n value: false,\r\n type: 'number',\r\n description:\r\n 'The scale of the exported chart, overriding the option in the chart settings. Ranges between 0.1 and 5.0.'\r\n },\r\n globalOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing options to be passed into the Highcharts.setOptions.'\r\n },\r\n themeOptions: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Either a stringified JSON or a filename containing theme options to be passed into the Highcharts.setOptions.'\r\n },\r\n batch: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Initiates a batch job with a string containing input/output pairs: \"in=out;in=out;...\".'\r\n },\r\n rasterizationTimeout: {\r\n value: 1500,\r\n type: 'number',\r\n envLink: 'EXPORT_RASTERIZATION_TIMEOUT',\r\n description:\r\n 'The duration in milliseconds to wait for rendering a webpage.'\r\n }\r\n },\r\n customLogic: {\r\n allowCodeExecution: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_CODE_EXECUTION',\r\n description:\r\n 'Controls whether the execution of arbitrary code is allowed during the exporting process.'\r\n },\r\n allowFileResources: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'CUSTOM_LOGIC_ALLOW_FILE_RESOURCES',\r\n description:\r\n 'Controls the ability to inject resources from the filesystem. This setting has no effect when running as a server.'\r\n },\r\n customCode: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Custom code to execute before chart initialization. It can be a function, code wrapped within a function, or a filename with the .js extension.'\r\n },\r\n callback: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'JavaScript code to run during construction. It can be a function or a filename with the .js extension.'\r\n },\r\n resources: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Additional resource in the form of a stringified JSON, which may contain files, js, and css sections.'\r\n },\r\n loadConfig: {\r\n value: false,\r\n type: 'string',\r\n legacyName: 'fromFile',\r\n description: 'A file containing a pre-defined configuration to use.'\r\n },\r\n createConfig: {\r\n value: false,\r\n type: 'string',\r\n description:\r\n 'Enables setting options through a prompt and saving them in a provided config file.'\r\n }\r\n },\r\n server: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_ENABLE',\r\n cliName: 'enableServer',\r\n description:\r\n 'When set to true, the server starts on the local IP address 0.0.0.0.'\r\n },\r\n host: {\r\n value: '0.0.0.0',\r\n type: 'string',\r\n envLink: 'SERVER_HOST',\r\n description:\r\n 'The hostname of the server. Additionally, it starts a server on the provided hostname.'\r\n },\r\n port: {\r\n value: 7801,\r\n type: 'number',\r\n envLink: 'SERVER_PORT',\r\n description: 'The server port when enabled.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_BENCHMARKING',\r\n cliName: 'serverBenchmarking',\r\n description:\r\n 'Indicates whether to display the duration, in milliseconds, of specific actions that occur on the server while serving a request.'\r\n },\r\n proxy: {\r\n host: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_PROXY_HOST',\r\n cliName: 'proxyHost',\r\n description: 'The host of the proxy server to use, if it exists.'\r\n },\r\n port: {\r\n value: 8080,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_PORT',\r\n cliName: 'proxyPort',\r\n description: 'The port of the proxy server to use, if it exists.'\r\n },\r\n timeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'SERVER_PROXY_TIMEOUT',\r\n cliName: 'proxyTimeout',\r\n description: 'The timeout for the proxy server to use, if it exists.'\r\n }\r\n },\r\n rateLimiting: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_ENABLE',\r\n cliName: 'enableRateLimiting',\r\n description: 'Enables rate limiting for the server.'\r\n },\r\n maxRequests: {\r\n value: 10,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_MAX_REQUESTS',\r\n legacyName: 'rateLimit',\r\n description: 'The maximum number of requests allowed in one minute.'\r\n },\r\n window: {\r\n value: 1,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_WINDOW',\r\n description: 'The time window, in minutes, for the rate limiting.'\r\n },\r\n delay: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'SERVER_RATE_LIMITING_DELAY',\r\n description:\r\n 'The delay duration for each successive request before reaching the maximum limit.'\r\n },\r\n trustProxy: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_RATE_LIMITING_TRUST_PROXY',\r\n description: 'Set this to true if the server is behind a load balancer.'\r\n },\r\n skipKey: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_KEY',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipToken argument.'\r\n },\r\n skipToken: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_RATE_LIMITING_SKIP_TOKEN',\r\n description:\r\n 'Allows bypassing the rate limiter and should be provided with the skipKey argument.'\r\n }\r\n },\r\n ssl: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_ENABLE',\r\n cliName: 'enableSsl',\r\n description: 'Enables or disables the SSL protocol.'\r\n },\r\n force: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'SERVER_SSL_FORCE',\r\n cliName: 'sslForce',\r\n legacyName: 'sslOnly',\r\n description:\r\n 'When set to true, the server is forced to serve only over HTTPS.'\r\n },\r\n port: {\r\n value: 443,\r\n type: 'number',\r\n envLink: 'SERVER_SSL_PORT',\r\n cliName: 'sslPort',\r\n description: 'The port on which to run the SSL server.'\r\n },\r\n certPath: {\r\n value: false,\r\n type: 'string',\r\n envLink: 'SERVER_SSL_CERT_PATH',\r\n legacyName: 'sslPath',\r\n description: 'The path to the SSL certificate/key file.'\r\n }\r\n }\r\n },\r\n pool: {\r\n minWorkers: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'POOL_MIN_WORKERS',\r\n description: 'The number of minimum and initial pool workers to spawn.'\r\n },\r\n maxWorkers: {\r\n value: 8,\r\n type: 'number',\r\n envLink: 'POOL_MAX_WORKERS',\r\n legacyName: 'workers',\r\n description: 'The number of maximum pool workers to spawn.'\r\n },\r\n workLimit: {\r\n value: 40,\r\n type: 'number',\r\n envLink: 'POOL_WORK_LIMIT',\r\n description:\r\n 'The number of work pieces that can be performed before restarting the worker process.'\r\n },\r\n acquireTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_ACQUIRE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for acquiring a resource.'\r\n },\r\n createTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for creating a resource.'\r\n },\r\n destroyTimeout: {\r\n value: 5000,\r\n type: 'number',\r\n envLink: 'POOL_DESTROY_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, to wait for destroying a resource.'\r\n },\r\n idleTimeout: {\r\n value: 30000,\r\n type: 'number',\r\n envLink: 'POOL_IDLE_TIMEOUT',\r\n description:\r\n 'The duration, in milliseconds, after which an idle resource is destroyed.'\r\n },\r\n createRetryInterval: {\r\n value: 200,\r\n type: 'number',\r\n envLink: 'POOL_CREATE_RETRY_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, to wait before retrying the create process in case of a failure.'\r\n },\r\n reaperInterval: {\r\n value: 1000,\r\n type: 'number',\r\n envLink: 'POOL_REAPER_INTERVAL',\r\n description:\r\n 'The duration, in milliseconds, after which the check for idle resources to destroy is triggered.'\r\n },\r\n benchmarking: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'POOL_BENCHMARKING',\r\n cliName: 'poolBenchmarking',\r\n description:\r\n 'Indicate whether to show statistics for the pool of resources or not.'\r\n }\r\n },\r\n logging: {\r\n level: {\r\n value: 4,\r\n type: 'number',\r\n envLink: 'LOGGING_LEVEL',\r\n cliName: 'logLevel',\r\n description: 'The logging level to be used.'\r\n },\r\n file: {\r\n value: 'highcharts-export-server.log',\r\n type: 'string',\r\n envLink: 'LOGGING_FILE',\r\n cliName: 'logFile',\r\n description:\r\n 'The name of a log file. The logDest option also needs to be set to enable file logging.'\r\n },\r\n dest: {\r\n value: 'log/',\r\n type: 'string',\r\n envLink: 'LOGGING_DEST',\r\n cliName: 'logDest',\r\n description:\r\n 'The path to store log files. This also enables file logging.'\r\n }\r\n },\r\n ui: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'UI_ENABLE',\r\n cliName: 'enableUi',\r\n description:\r\n 'Enables or disables the user interface (UI) for the export server.'\r\n },\r\n route: {\r\n value: '/',\r\n type: 'string',\r\n envLink: 'UI_ROUTE',\r\n cliName: 'uiRoute',\r\n description:\r\n 'The endpoint route to which the user interface (UI) should be attached.'\r\n }\r\n },\r\n other: {\r\n nodeEnv: {\r\n value: 'production',\r\n type: 'string',\r\n envLink: 'OTHER_NODE_ENV',\r\n description: 'The type of Node.js environment.'\r\n },\r\n listenToProcessExits: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'OTHER_LISTEN_TO_PROCESS_EXITS',\r\n description: 'Decides whether or not to attach process.exit handlers.'\r\n },\r\n noLogo: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_NO_LOGO',\r\n description:\r\n 'Skip printing the logo on a startup. Will be replaced by a simple text.'\r\n },\r\n hardResetPage: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'OTHER_HARD_RESET_PAGE',\r\n description: 'Decides if the page content should be reset entirely.'\r\n }\r\n },\r\n debug: {\r\n enable: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_ENABLE',\r\n cliName: 'enableDebug',\r\n description: 'Enables or disables debug mode for the underlying browser.'\r\n },\r\n headless: {\r\n value: true,\r\n type: 'boolean',\r\n envLink: 'DEBUG_HEADLESS',\r\n description:\r\n 'Controls the mode in which the browser is launched when in the debug mode.'\r\n },\r\n devtools: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DEVTOOLS',\r\n description:\r\n 'Decides whether to enable DevTools when the browser is in a headful state.'\r\n },\r\n listenToConsole: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_LISTEN_TO_CONSOLE',\r\n description:\r\n 'Decides whether to enable a listener for console messages sent from the browser.'\r\n },\r\n dumpio: {\r\n value: false,\r\n type: 'boolean',\r\n envLink: 'DEBUG_DUMPIO',\r\n description:\r\n 'Redirects browser process stdout and stderr to process.stdout and process.stderr.'\r\n },\r\n slowMo: {\r\n value: 0,\r\n type: 'number',\r\n envLink: 'DEBUG_SLOW_MO',\r\n description:\r\n 'Slows down Puppeteer operations by the specified number of milliseconds.'\r\n },\r\n debuggingPort: {\r\n value: 9222,\r\n type: 'number',\r\n envLink: 'DEBUG_DEBUGGING_PORT',\r\n description: 'Specifies the debugging port.'\r\n }\r\n }\r\n};\r\n\r\n// The config descriptions object for the prompts functionality. It contains\r\n// information like:\r\n// * Type of a prompt\r\n// * Name of an option\r\n// * Short description of a chosen option\r\n// * Initial value\r\nexport const promptsConfig = {\r\n puppeteer: [\r\n {\r\n type: 'list',\r\n name: 'args',\r\n message: 'Puppeteer arguments',\r\n initial: defaultConfig.puppeteer.args.value.join(','),\r\n separator: ','\r\n }\r\n ],\r\n highcharts: [\r\n {\r\n type: 'text',\r\n name: 'version',\r\n message: 'Highcharts version',\r\n initial: defaultConfig.highcharts.version.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cdnURL',\r\n message: 'The URL of CDN',\r\n initial: defaultConfig.highcharts.cdnURL.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'coreScripts',\r\n message: 'Available core scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.coreScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'moduleScripts',\r\n message: 'Available module scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.moduleScripts.value\r\n },\r\n {\r\n type: 'multiselect',\r\n name: 'indicatorScripts',\r\n message: 'Available indicator scripts',\r\n instructions: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n choices: defaultConfig.highcharts.indicatorScripts.value\r\n },\r\n {\r\n type: 'list',\r\n name: 'customScripts',\r\n message: 'Custom scripts',\r\n initial: defaultConfig.highcharts.customScripts.value.join(','),\r\n separator: ','\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'forceFetch',\r\n message: 'Force re-fetch the scripts',\r\n initial: defaultConfig.highcharts.forceFetch.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'cachePath',\r\n message: 'The path to the cache directory',\r\n initial: defaultConfig.highcharts.cachePath.value\r\n }\r\n ],\r\n export: [\r\n {\r\n type: 'select',\r\n name: 'type',\r\n message: 'The default export file type',\r\n hint: `Default: ${defaultConfig.export.type.value}`,\r\n initial: 0,\r\n choices: ['png', 'jpeg', 'pdf', 'svg']\r\n },\r\n {\r\n type: 'select',\r\n name: 'constr',\r\n message: 'The default constructor for Highcharts',\r\n hint: `Default: ${defaultConfig.export.constr.value}`,\r\n initial: 0,\r\n choices: ['chart', 'stockChart', 'mapChart', 'ganttChart']\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultHeight',\r\n message: 'The default fallback height of the exported chart',\r\n initial: defaultConfig.export.defaultHeight.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultWidth',\r\n message: 'The default fallback width of the exported chart',\r\n initial: defaultConfig.export.defaultWidth.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'defaultScale',\r\n message: 'The default fallback scale of the exported chart',\r\n initial: defaultConfig.export.defaultScale.value,\r\n min: 0.1,\r\n max: 5\r\n },\r\n {\r\n type: 'number',\r\n name: 'rasterizationTimeout',\r\n message: 'The rendering webpage timeout in milliseconds',\r\n initial: defaultConfig.export.rasterizationTimeout.value\r\n }\r\n ],\r\n customLogic: [\r\n {\r\n type: 'toggle',\r\n name: 'allowCodeExecution',\r\n message: 'Enable execution of custom code',\r\n initial: defaultConfig.customLogic.allowCodeExecution.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'allowFileResources',\r\n message: 'Enable file resources',\r\n initial: defaultConfig.customLogic.allowFileResources.value\r\n }\r\n ],\r\n server: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Starts the server on 0.0.0.0',\r\n initial: defaultConfig.server.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'host',\r\n message: 'Server hostname',\r\n initial: defaultConfig.server.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'port',\r\n message: 'Server port',\r\n initial: defaultConfig.server.port.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable server benchmarking',\r\n initial: defaultConfig.server.benchmarking.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'proxy.host',\r\n message: 'The host of the proxy server to use',\r\n initial: defaultConfig.server.proxy.host.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.port',\r\n message: 'The port of the proxy server to use',\r\n initial: defaultConfig.server.proxy.port.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'proxy.timeout',\r\n message: 'The timeout for the proxy server to use',\r\n initial: defaultConfig.server.proxy.timeout.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.enable',\r\n message: 'Enable rate limiting',\r\n initial: defaultConfig.server.rateLimiting.enable.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.maxRequests',\r\n message: 'The maximum requests allowed per minute',\r\n initial: defaultConfig.server.rateLimiting.maxRequests.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.window',\r\n message: 'The rate-limiting time window in minutes',\r\n initial: defaultConfig.server.rateLimiting.window.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'rateLimiting.delay',\r\n message:\r\n 'The delay for each successive request before reaching the maximum',\r\n initial: defaultConfig.server.rateLimiting.delay.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'rateLimiting.trustProxy',\r\n message: 'Set to true if behind a load balancer',\r\n initial: defaultConfig.server.rateLimiting.trustProxy.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipKey',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipToken argument',\r\n initial: defaultConfig.server.rateLimiting.skipKey.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'rateLimiting.skipToken',\r\n message:\r\n 'Allows bypassing the rate limiter when provided with the skipKey argument',\r\n initial: defaultConfig.server.rateLimiting.skipToken.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.enable',\r\n message: 'Enable SSL protocol',\r\n initial: defaultConfig.server.ssl.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'ssl.force',\r\n message: 'Force serving only over HTTPS',\r\n initial: defaultConfig.server.ssl.force.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'ssl.port',\r\n message: 'SSL server port',\r\n initial: defaultConfig.server.ssl.port.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'ssl.certPath',\r\n message: 'The path to find the SSL certificate/key',\r\n initial: defaultConfig.server.ssl.certPath.value\r\n }\r\n ],\r\n pool: [\r\n {\r\n type: 'number',\r\n name: 'minWorkers',\r\n message: 'The initial number of workers to spawn',\r\n initial: defaultConfig.pool.minWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'maxWorkers',\r\n message: 'The maximum number of workers to spawn',\r\n initial: defaultConfig.pool.maxWorkers.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'workLimit',\r\n message:\r\n 'The pieces of work that can be performed before restarting a Puppeteer process',\r\n initial: defaultConfig.pool.workLimit.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'acquireTimeout',\r\n message: 'The number of milliseconds to wait for acquiring a resource',\r\n initial: defaultConfig.pool.acquireTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createTimeout',\r\n message: 'The number of milliseconds to wait for creating a resource',\r\n initial: defaultConfig.pool.createTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'destroyTimeout',\r\n message: 'The number of milliseconds to wait for destroying a resource',\r\n initial: defaultConfig.pool.destroyTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'idleTimeout',\r\n message: 'The number of milliseconds after an idle resource is destroyed',\r\n initial: defaultConfig.pool.idleTimeout.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'createRetryInterval',\r\n message:\r\n 'The retry interval in milliseconds after a create process fails',\r\n initial: defaultConfig.pool.createRetryInterval.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'reaperInterval',\r\n message:\r\n 'The reaper interval in milliseconds after triggering the check for idle resources to destroy',\r\n initial: defaultConfig.pool.reaperInterval.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'benchmarking',\r\n message: 'Enable benchmarking for a resource pool',\r\n initial: defaultConfig.pool.benchmarking.value\r\n }\r\n ],\r\n logging: [\r\n {\r\n type: 'number',\r\n name: 'level',\r\n message:\r\n 'The log level (0: silent, 1: error, 2: warning, 3: notice, 4: verbose, 5: benchmark)',\r\n initial: defaultConfig.logging.level.value,\r\n round: 0,\r\n min: 0,\r\n max: 5\r\n },\r\n {\r\n type: 'text',\r\n name: 'file',\r\n message: 'A log file name. Set with the --logDest to enable file logging',\r\n initial: defaultConfig.logging.file.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'dest',\r\n message: 'The path to log files. Enables file logging',\r\n initial: defaultConfig.logging.dest.value\r\n }\r\n ],\r\n ui: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enable UI for the export server',\r\n initial: defaultConfig.ui.enable.value\r\n },\r\n {\r\n type: 'text',\r\n name: 'route',\r\n message: 'A route to attach the UI',\r\n initial: defaultConfig.ui.route.value\r\n }\r\n ],\r\n other: [\r\n {\r\n type: 'text',\r\n name: 'nodeEnv',\r\n message: 'The type of Node.js environment',\r\n initial: defaultConfig.other.nodeEnv.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToProcessExits',\r\n message: 'Set to false to skip attaching process.exit handlers',\r\n initial: defaultConfig.other.listenToProcessExits.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'noLogo',\r\n message: 'Skip printing the logo on startup. Replaced by simple text',\r\n initial: defaultConfig.other.noLogo.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'hardResetPage',\r\n message: 'Decides if the page content should be reset entirely',\r\n initial: defaultConfig.other.hardResetPage.value\r\n }\r\n ],\r\n debug: [\r\n {\r\n type: 'toggle',\r\n name: 'enable',\r\n message: 'Enables debug mode for the browser instance',\r\n initial: defaultConfig.debug.enable.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'headless',\r\n message: 'The mode setting for the browser',\r\n initial: defaultConfig.debug.headless.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'devtools',\r\n message: 'The DevTools for the headful browser',\r\n initial: defaultConfig.debug.devtools.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'listenToConsole',\r\n message: 'The event listener for console messages from the browser',\r\n initial: defaultConfig.debug.listenToConsole.value\r\n },\r\n {\r\n type: 'toggle',\r\n name: 'dumpio',\r\n message: 'Redirects the browser stdout and stderr to NodeJS process',\r\n initial: defaultConfig.debug.dumpio.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'slowMo',\r\n message: 'Puppeteer operations slow down in milliseconds',\r\n initial: defaultConfig.debug.slowMo.value\r\n },\r\n {\r\n type: 'number',\r\n name: 'debuggingPort',\r\n message: 'The port number for debugging',\r\n initial: defaultConfig.debug.debuggingPort.value\r\n }\r\n ]\r\n};\r\n\r\n// Absolute props that, in case of merging recursively, need to be force merged\r\nexport const absoluteProps = [\r\n 'options',\r\n 'globalOptions',\r\n 'themeOptions',\r\n 'resources',\r\n 'payload'\r\n];\r\n\r\n// Argument nesting level of all export server options\r\nexport const nestedArgs = {};\r\n\r\n/**\r\n * Recursively creates a chain of nested arguments from an object.\r\n *\r\n * @param {Object} obj - The object containing nested arguments.\r\n * @param {string} propChain - The current chain of nested properties\r\n * (used internally during recursion).\r\n */\r\nconst createNestedArgs = (obj, propChain = '') => {\r\n Object.keys(obj).forEach((k) => {\r\n if (!['puppeteer', 'highcharts'].includes(k)) {\r\n const entry = obj[k];\r\n if (typeof entry.value === 'undefined') {\r\n // Go deeper in the nested arguments\r\n createNestedArgs(entry, `${propChain}.${k}`);\r\n } else {\r\n // Create the chain of nested arguments\r\n nestedArgs[entry.cliName || k] = `${propChain}.${k}`.substring(1);\r\n\r\n // Support for the legacy, PhantomJS properties names\r\n if (entry.legacyName !== undefined) {\r\n nestedArgs[entry.legacyName] = `${propChain}.${k}`.substring(1);\r\n }\r\n }\r\n }\r\n });\r\n};\r\n\r\ncreateNestedArgs(defaultConfig);\r\n","/**\r\n * @fileoverview\r\n * This file is responsible for parsing the environment variables with the 'zod'\r\n * library. The parsed environment variables are then exported to be used\r\n * in the application as \"envs\". We should not use process.env directly\r\n * in the application as these would not be parsed properly.\r\n *\r\n * The environment variables are parsed and validated only once when\r\n * the application starts. We should write a custom validator or a transformer\r\n * for each of the options.\r\n */\r\n\r\nimport dotenv from 'dotenv';\r\nimport { z } from 'zod';\r\n\r\nimport { scriptsNames } from './schemas/config.js';\r\n\r\n// Load .env into environment variables\r\ndotenv.config();\r\n\r\n// Object with custom validators and transformers, to avoid repetition\r\n// in the Config object\r\nconst v = {\r\n // Splits string value into elements in an array, trims every element, checks\r\n // if an array is correct, if it is empty, and if it is, returns undefined\r\n array: (filterArray) =>\r\n z\r\n .string()\r\n .transform((value) =>\r\n value\r\n .split(',')\r\n .map((value) => value.trim())\r\n .filter((value) => filterArray.includes(value))\r\n )\r\n .transform((value) => (value.length ? value : undefined)),\r\n\r\n // Allows only true, false and correctly parse the value to boolean\r\n // or no value in which case the returned value will be undefined\r\n boolean: () =>\r\n z\r\n .enum(['true', 'false', ''])\r\n .transform((value) => (value !== '' ? value === 'true' : undefined)),\r\n\r\n // Allows passed values or no value in which case the returned value will\r\n // be undefined\r\n enum: (values) =>\r\n z\r\n .enum([...values, ''])\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Trims the string value and checks if it is empty or contains stringified\r\n // values such as false, undefined, null, NaN, if it does, returns undefined\r\n string: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n !['false', 'undefined', 'null', 'NaN'].includes(value) ||\r\n value === '',\r\n (value) => ({\r\n message: `The string contains forbidden values, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n\r\n // Allows positive numbers or no value in which case the returned value will\r\n // be undefined\r\n positiveNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) > 0),\r\n (value) => ({\r\n message: `The value must be numeric and positive, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n\r\n // Allows non-negative numbers or no value in which case the returned value\r\n // will be undefined\r\n nonNegativeNum: () =>\r\n z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' || (!isNaN(parseFloat(value)) && parseFloat(value) >= 0),\r\n (value) => ({\r\n message: `The value must be numeric and non-negative, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined))\r\n};\r\n\r\nexport const Config = z.object({\r\n // highcharts\r\n HIGHCHARTS_VERSION: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) => /^(latest|\\d+(\\.\\d+){0,2})$/.test(value) || value === '',\r\n (value) => ({\r\n message: `HIGHCHARTS_VERSION must be 'latest', a major version, or in the form XX.YY.ZZ, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CDN_URL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value.startsWith('https://') ||\r\n value.startsWith('http://') ||\r\n value === '',\r\n (value) => ({\r\n message: `Invalid value for HIGHCHARTS_CDN_URL. It should start with http:// or https://, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? value : undefined)),\r\n HIGHCHARTS_CORE_SCRIPTS: v.array(scriptsNames.core),\r\n HIGHCHARTS_MODULE_SCRIPTS: v.array(scriptsNames.modules),\r\n HIGHCHARTS_INDICATOR_SCRIPTS: v.array(scriptsNames.indicators),\r\n HIGHCHARTS_FORCE_FETCH: v.boolean(),\r\n HIGHCHARTS_CACHE_PATH: v.string(),\r\n HIGHCHARTS_ADMIN_TOKEN: v.string(),\r\n\r\n // export\r\n EXPORT_TYPE: v.enum(['jpeg', 'png', 'pdf', 'svg']),\r\n EXPORT_CONSTR: v.enum(['chart', 'stockChart', 'mapChart', 'ganttChart']),\r\n EXPORT_DEFAULT_HEIGHT: v.positiveNum(),\r\n EXPORT_DEFAULT_WIDTH: v.positiveNum(),\r\n EXPORT_DEFAULT_SCALE: v.positiveNum(),\r\n EXPORT_RASTERIZATION_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // custom\r\n CUSTOM_LOGIC_ALLOW_CODE_EXECUTION: v.boolean(),\r\n CUSTOM_LOGIC_ALLOW_FILE_RESOURCES: v.boolean(),\r\n\r\n // server\r\n SERVER_ENABLE: v.boolean(),\r\n SERVER_HOST: v.string(),\r\n SERVER_PORT: v.positiveNum(),\r\n SERVER_BENCHMARKING: v.boolean(),\r\n\r\n // server proxy\r\n SERVER_PROXY_HOST: v.string(),\r\n SERVER_PROXY_PORT: v.positiveNum(),\r\n SERVER_PROXY_TIMEOUT: v.nonNegativeNum(),\r\n\r\n // server rate limiting\r\n SERVER_RATE_LIMITING_ENABLE: v.boolean(),\r\n SERVER_RATE_LIMITING_MAX_REQUESTS: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_WINDOW: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_DELAY: v.nonNegativeNum(),\r\n SERVER_RATE_LIMITING_TRUST_PROXY: v.boolean(),\r\n SERVER_RATE_LIMITING_SKIP_KEY: v.string(),\r\n SERVER_RATE_LIMITING_SKIP_TOKEN: v.string(),\r\n\r\n // server ssl\r\n SERVER_SSL_ENABLE: v.boolean(),\r\n SERVER_SSL_FORCE: v.boolean(),\r\n SERVER_SSL_PORT: v.positiveNum(),\r\n SERVER_SSL_CERT_PATH: v.string(),\r\n\r\n // pool\r\n POOL_MIN_WORKERS: v.nonNegativeNum(),\r\n POOL_MAX_WORKERS: v.nonNegativeNum(),\r\n POOL_WORK_LIMIT: v.positiveNum(),\r\n POOL_ACQUIRE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_DESTROY_TIMEOUT: v.nonNegativeNum(),\r\n POOL_IDLE_TIMEOUT: v.nonNegativeNum(),\r\n POOL_CREATE_RETRY_INTERVAL: v.nonNegativeNum(),\r\n POOL_REAPER_INTERVAL: v.nonNegativeNum(),\r\n POOL_BENCHMARKING: v.boolean(),\r\n\r\n // logger\r\n LOGGING_LEVEL: z\r\n .string()\r\n .trim()\r\n .refine(\r\n (value) =>\r\n value === '' ||\r\n (!isNaN(parseFloat(value)) &&\r\n parseFloat(value) >= 0 &&\r\n parseFloat(value) <= 5),\r\n (value) => ({\r\n message: `Invalid value for LOGGING_LEVEL. We only accept values from 0 to 5 as logging levels, received '${value}'`\r\n })\r\n )\r\n .transform((value) => (value !== '' ? parseFloat(value) : undefined)),\r\n LOGGING_FILE: v.string(),\r\n LOGGING_DEST: v.string(),\r\n\r\n // ui\r\n UI_ENABLE: v.boolean(),\r\n UI_ROUTE: v.string(),\r\n\r\n // other\r\n OTHER_NODE_ENV: v.enum(['development', 'production', 'test']),\r\n OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(),\r\n OTHER_NO_LOGO: v.boolean(),\r\n OTHER_HARD_RESET_PAGE: v.boolean(),\r\n\r\n // debugger\r\n DEBUG_ENABLE: v.boolean(),\r\n DEBUG_HEADLESS: v.boolean(),\r\n DEBUG_DEVTOOLS: v.boolean(),\r\n DEBUG_LISTEN_TO_CONSOLE: v.boolean(),\r\n DEBUG_DUMPIO: v.boolean(),\r\n DEBUG_SLOW_MO: v.nonNegativeNum(),\r\n DEBUG_DEBUGGING_PORT: v.positiveNum()\r\n});\r\n\r\nexport const envs = Config.partial().parse(process.env);\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { appendFile, existsSync, mkdirSync } from 'fs';\r\n\r\nimport { defaultConfig } from './schemas/config.js';\r\n\r\n// The available colors\r\nconst colors = ['red', 'yellow', 'blue', 'gray', 'green'];\r\n\r\n// The default logging config\r\nlet logging = {\r\n // Flags for logging status\r\n toConsole: true,\r\n toFile: false,\r\n pathCreated: false,\r\n // Log levels\r\n levelsDesc: [\r\n {\r\n title: 'error',\r\n color: colors[0]\r\n },\r\n {\r\n title: 'warning',\r\n color: colors[1]\r\n },\r\n {\r\n title: 'notice',\r\n color: colors[2]\r\n },\r\n {\r\n title: 'verbose',\r\n color: colors[3]\r\n },\r\n {\r\n title: 'benchmark',\r\n color: colors[4]\r\n }\r\n ],\r\n // Log listeners\r\n listeners: []\r\n};\r\n\r\n// Gather init logging options\r\nfor (const [key, option] of Object.entries(defaultConfig.logging)) {\r\n logging[key] = option.value;\r\n}\r\n\r\n/**\r\n * Logs the provided texts to a file, if file logging is enabled. It creates\r\n * the necessary directory structure if not already created and appends the\r\n * content, including an optional prefix, to the specified log file.\r\n *\r\n * @param {string[]} texts - An array of texts to be logged.\r\n * @param {string} prefix - An optional prefix to be added to each log entry.\r\n */\r\nconst logToFile = (texts, prefix) => {\r\n if (logging.toFile) {\r\n if (!logging.pathCreated) {\r\n // Create if does not exist\r\n !existsSync(logging.dest) && mkdirSync(logging.dest);\r\n\r\n // We now assume the path is available, e.g. it's the responsibility\r\n // of the user to create the path with the correct access rights.\r\n logging.pathCreated = true;\r\n }\r\n\r\n // Add the content to a file\r\n appendFile(\r\n `${logging.dest}${logging.file}`,\r\n [prefix].concat(texts).join(' ') + '\\n',\r\n (error) => {\r\n if (error) {\r\n console.log(`[logger] Unable to write to log file: ${error}`);\r\n logging.toFile = false;\r\n }\r\n }\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Logs a message. Accepts a variable amount of arguments. Arguments after\r\n * `level` will be passed directly to console.log, and/or will be joined\r\n * and appended to the log file.\r\n *\r\n * @param {any} args - An array of arguments where the first is the log level\r\n * and the rest are strings to build a message with.\r\n */\r\nexport const log = (...args) => {\r\n const [newLevel, ...texts] = args;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range or is a benchmark log\r\n if (\r\n newLevel !== 5 &&\r\n (newLevel === 0 || newLevel > level || level > levelsDesc.length)\r\n ) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat(texts)\r\n );\r\n }\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Logs an error message with its stack trace. Optionally, a custom message\r\n * can be provided.\r\n *\r\n * @param {number} level - The log level.\r\n * @param {Error} error - The error object.\r\n * @param {string} customMessage - An optional custom message to be logged along\r\n * with the error.\r\n */\r\nexport const logWithStack = (newLevel, error, customMessage) => {\r\n // Get the main message\r\n const mainMessage = customMessage || error.message;\r\n\r\n // Current logging options\r\n const { level, levelsDesc } = logging;\r\n\r\n // Check if log level is within a correct range\r\n if (newLevel === 0 || newLevel > level || level > levelsDesc.length) {\r\n return;\r\n }\r\n\r\n // Get rid of the GMT text information\r\n const newDate = new Date().toString().split('(')[0].trim();\r\n\r\n // Create a message's prefix\r\n const prefix = `${newDate} [${levelsDesc[newLevel - 1].title}] -`;\r\n\r\n // If the customMessage exists, we want to display the whole stack message\r\n const stackMessage =\r\n error.message !== error.stackMessage || error.stackMessage === undefined\r\n ? error.stack\r\n : error.stack.split('\\n').slice(1).join('\\n');\r\n\r\n // Combine custom message or error message with error stack message\r\n const texts = [mainMessage, '\\n', stackMessage];\r\n\r\n // Log to console\r\n if (logging.toConsole) {\r\n console.log.apply(\r\n undefined,\r\n [prefix.toString()[logging.levelsDesc[newLevel - 1].color]].concat([\r\n mainMessage[colors[newLevel - 1]],\r\n '\\n',\r\n stackMessage\r\n ])\r\n );\r\n }\r\n\r\n // Call available log listeners\r\n logging.listeners.forEach((fn) => {\r\n fn(prefix, texts.join(' '));\r\n });\r\n\r\n // Log to file\r\n logToFile(texts, prefix);\r\n};\r\n\r\n/**\r\n * Sets the log level to the specified value. Log levels are (0 = no logging,\r\n * 1 = error, 2 = warning, 3 = notice, 4 = verbose or 5 = benchmark)\r\n *\r\n * @param {number} newLevel - The new log level to be set.\r\n */\r\nexport const setLogLevel = (newLevel) => {\r\n if (newLevel >= 0 && newLevel <= logging.levelsDesc.length) {\r\n logging.level = newLevel;\r\n }\r\n};\r\n\r\n/**\r\n * Enables file logging with the specified destination and log file.\r\n *\r\n * @param {string} logDest - The destination path for log files.\r\n * @param {string} logFile - The log file name.\r\n */\r\nexport const enableFileLogging = (logDest, logFile) => {\r\n // Update logging options\r\n logging = {\r\n ...logging,\r\n dest: logDest || logging.dest,\r\n file: logFile || logging.file,\r\n toFile: true\r\n };\r\n\r\n if (logging.dest.length === 0) {\r\n return log(1, '[logger] File logging initialization: no path supplied.');\r\n }\r\n\r\n if (!logging.dest.endsWith('/')) {\r\n logging.dest += '/';\r\n }\r\n};\r\n\r\n/**\r\n * Initializes logging with the specified logging configuration.\r\n *\r\n * @param {Object} logging - The logging configuration object.\r\n */\r\nexport const initLogging = (logging) => {\r\n // Set the log level\r\n setLogLevel(logging && parseInt(logging.level));\r\n\r\n // Set the log file path and name\r\n if (logging && logging.dest) {\r\n enableFileLogging(\r\n logging.dest,\r\n logging.file || 'highcharts-export-server.log'\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Adds a listener function to the logging system.\r\n *\r\n * @param {function} fn - The listener function to be added.\r\n */\r\nexport const listen = (fn) => {\r\n logging.listeners.push(fn);\r\n};\r\n\r\n/**\r\n * Toggles the standard output (console) logging.\r\n *\r\n * @param {boolean} enabled - If true, enables console logging; if false,\r\n * disables it.\r\n */\r\nexport const toggleSTDOut = (enabled) => {\r\n logging.toConsole = enabled;\r\n};\r\n\r\nexport default {\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n initLogging,\r\n listen,\r\n toggleSTDOut\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join } from 'path';\r\nimport { fileURLToPath } from 'url';\r\n\r\nimport { defaultConfig } from '../lib/schemas/config.js';\r\nimport { log, logWithStack } from './logger.js';\r\n\r\nconst MAX_BACKOFF_ATTEMPTS = 6;\r\n\r\nexport const __dirname = fileURLToPath(new URL('../.', import.meta.url));\r\n\r\n/**\r\n * Clears and standardizes text by replacing multiple consecutive whitespace\r\n * characters with a single space and trimming any leading or trailing\r\n * whitespace.\r\n *\r\n * @param {string} text - The input text to be cleared.\r\n * @param {RegExp} [rule=/\\s\\s+/g] - The regular expression rule to match\r\n * multiple consecutive whitespace characters.\r\n * @param {string} [replacer=' '] - The string used to replace multiple\r\n * consecutive whitespace characters.\r\n *\r\n * @returns {string} - The cleared and standardized text.\r\n */\r\nexport const clearText = (text, rule = /\\s\\s+/g, replacer = ' ') =>\r\n text.replaceAll(rule, replacer).trim();\r\n\r\n/**\r\n * Implements an exponential backoff strategy for retrying a function until\r\n * a certain number of attempts are reached.\r\n *\r\n * @param {Function} fn - The function to be retried.\r\n * @param {number} [attempt=0] - The current attempt number.\r\n * @param {...any} args - Arguments to be passed to the function.\r\n *\r\n * @returns {Promise} - A promise that resolves to the result of the function\r\n * if successful.\r\n *\r\n * @throws {Error} - Throws an error if the maximum number of attempts\r\n * is reached.\r\n */\r\nexport const expBackoff = async (fn, attempt = 0, ...args) => {\r\n try {\r\n // Try to call the function\r\n return await fn(...args);\r\n } catch (error) {\r\n // Calculate delay in ms\r\n const delayInMs = 2 ** attempt * 1000;\r\n\r\n // If the attempt exceeds the maximum attempts of reapeat, throw an error\r\n if (++attempt >= MAX_BACKOFF_ATTEMPTS) {\r\n throw error;\r\n }\r\n\r\n // Wait given amount of time\r\n await new Promise((response) => setTimeout(response, delayInMs));\r\n log(\r\n 3,\r\n `[pool] Waited ${delayInMs}ms until next call for the resource id: ${args[0]}.`\r\n );\r\n\r\n // Try again\r\n return expBackoff(fn, attempt, ...args);\r\n }\r\n};\r\n\r\n/**\r\n * Fixes the export type based on MIME types and file extensions.\r\n *\r\n * @param {string} type - The original export type.\r\n * @param {string} outfile - The file path or name.\r\n *\r\n * @returns {string} - The corrected export type.\r\n */\r\nexport const fixType = (type, outfile) => {\r\n // MIME types\r\n const mimeTypes = {\r\n 'image/png': 'png',\r\n 'image/jpeg': 'jpeg',\r\n 'application/pdf': 'pdf',\r\n 'image/svg+xml': 'svg'\r\n };\r\n\r\n // Formats\r\n const formats = ['png', 'jpeg', 'pdf', 'svg'];\r\n\r\n // Check if type and outfile's extensions are the same\r\n if (outfile) {\r\n const outType = outfile.split('.').pop();\r\n\r\n if (outType === 'jpg') {\r\n type = 'jpeg';\r\n } else if (formats.includes(outType) && type !== outType) {\r\n type = outType;\r\n }\r\n }\r\n\r\n // Return a correct type\r\n return mimeTypes[type] || formats.find((t) => t === type) || 'png';\r\n};\r\n\r\n/**\r\n * Handles and validates resources for export.\r\n *\r\n * @param {Object|string} resources - The resources to be handled. Can be either\r\n * a JSON object, stringified JSON or a path to a JSON file.\r\n * @param {boolean} allowFileResources - Whether to allow loading resources from\r\n * files.\r\n *\r\n * @returns {Object|undefined} - The handled resources or undefined if no valid\r\n * resources are found.\r\n */\r\nexport const handleResources = (resources = false, allowFileResources) => {\r\n const allowedProps = ['js', 'css', 'files'];\r\n\r\n let handledResources = resources;\r\n let correctResources = false;\r\n\r\n // Try to load resources from a file\r\n if (allowFileResources && resources.endsWith('.json')) {\r\n try {\r\n handledResources = isCorrectJSON(readFileSync(resources, 'utf8'));\r\n } catch (error) {\r\n return logWithStack(2, error, `[cli] No resources found.`);\r\n }\r\n } else {\r\n // Try to get JSON\r\n handledResources = isCorrectJSON(resources);\r\n\r\n // Get rid of the files section\r\n if (handledResources && !allowFileResources) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Filter from unnecessary properties\r\n for (const propName in handledResources) {\r\n if (!allowedProps.includes(propName)) {\r\n delete handledResources[propName];\r\n } else if (!correctResources) {\r\n correctResources = true;\r\n }\r\n }\r\n\r\n // Check if at least one of allowed properties is present\r\n if (!correctResources) {\r\n return log(3, `[cli] No resources found.`);\r\n }\r\n\r\n // Handle files section\r\n if (handledResources.files) {\r\n handledResources.files = handledResources.files.map((item) => item.trim());\r\n if (!handledResources.files || handledResources.files.length <= 0) {\r\n delete handledResources.files;\r\n }\r\n }\r\n\r\n // Return resources\r\n return handledResources;\r\n};\r\n\r\n/**\r\n * Validates and parses JSON data. Checks if provided data is or can\r\n * be a correct JSON. If a primitive is provided, it is stringified and returned.\r\n *\r\n * @param {Object|string} data - The JSON data to be validated and parsed.\r\n * @param {boolean} toString - Whether to return a stringified representation\r\n * of the parsed JSON.\r\n *\r\n * @returns {Object|string|boolean} - The parsed JSON object, stringified JSON,\r\n * or false if validation fails.\r\n */\r\nexport function isCorrectJSON(data, toString) {\r\n try {\r\n // Get the string representation if not already before parsing\r\n const parsedData = JSON.parse(\r\n typeof data !== 'string' ? JSON.stringify(data) : data\r\n );\r\n\r\n // Return a stringified representation of a JSON if required\r\n if (typeof parsedData !== 'string' && toString) {\r\n return JSON.stringify(parsedData);\r\n }\r\n\r\n // Return a JSON\r\n return parsedData;\r\n } catch {\r\n return false;\r\n }\r\n}\r\n\r\n/**\r\n * Checks if the given item is an object.\r\n *\r\n * @param {any} item - The item to be checked.\r\n *\r\n * @returns {boolean} - True if the item is an object, false otherwise.\r\n */\r\nexport const isObject = (item) =>\r\n typeof item === 'object' && !Array.isArray(item) && item !== null;\r\n\r\n/**\r\n * Checks if the given object is empty.\r\n *\r\n * @param {Object} item - The object to be checked.\r\n *\r\n * @returns {boolean} - True if the object is empty, false otherwise.\r\n */\r\nexport const isObjectEmpty = (item) =>\r\n typeof item === 'object' &&\r\n !Array.isArray(item) &&\r\n item !== null &&\r\n Object.keys(item).length === 0;\r\n\r\n/**\r\n * Checks if a private IP range URL is found in the given string.\r\n *\r\n * @param {string} item - The string to be checked for a private IP range URL.\r\n *\r\n * @returns {boolean} - True if a private IP range URL is found, false\r\n * otherwise.\r\n */\r\nexport const isPrivateRangeUrlFound = (item) => {\r\n const regexPatterns = [\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?localhost\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?10\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?127\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?172\\.(1[6-9]|2[0-9]|3[0-1])\\.\\d{1,3}\\.\\d{1,3}\\b/,\r\n /xlink:href=\"(?:http:\\/\\/|https:\\/\\/)?192\\.168\\.\\d{1,3}\\.\\d{1,3}\\b/\r\n ];\r\n\r\n return regexPatterns.some((pattern) => pattern.test(item));\r\n};\r\n\r\n/**\r\n * Creates a deep copy of the given object or array.\r\n *\r\n * @param {Object|Array} obj - The object or array to be deeply copied.\r\n *\r\n * @returns {Object|Array} - The deep copy of the provided object or array.\r\n */\r\nexport const deepCopy = (obj) => {\r\n if (obj === null || typeof obj !== 'object') {\r\n return obj;\r\n }\r\n\r\n const copy = Array.isArray(obj) ? [] : {};\r\n\r\n for (const key in obj) {\r\n if (Object.prototype.hasOwnProperty.call(obj, key)) {\r\n copy[key] = deepCopy(obj[key]);\r\n }\r\n }\r\n\r\n return copy;\r\n};\r\n\r\n/**\r\n * Converts the provided options object to a JSON-formatted string with the\r\n * option to preserve functions.\r\n *\r\n * @param {Object} options - The options object to be converted to a string.\r\n * @param {boolean} allowFunctions - If set to true, functions are preserved\r\n * in the output.\r\n *\r\n * @returns {string} - The JSON-formatted string representing the options.\r\n */\r\nexport const optionsStringify = (options, allowFunctions) => {\r\n const replacerCallback = (name, value) => {\r\n if (typeof value === 'string') {\r\n value = value.trim();\r\n\r\n // If allowFunctions is set to true, preserve functions\r\n if (\r\n (value.startsWith('function(') || value.startsWith('function (')) &&\r\n value.endsWith('}')\r\n ) {\r\n value = allowFunctions\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : undefined;\r\n }\r\n }\r\n\r\n return typeof value === 'function'\r\n ? `EXP_FUN${(value + '').replaceAll(/\\n|\\t|\\r/g, ' ')}EXP_FUN`\r\n : value;\r\n };\r\n\r\n // Stringify options and if required, replace special functions marks\r\n return JSON.stringify(options, replacerCallback).replaceAll(\r\n /\"EXP_FUN|EXP_FUN\"/g,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Prints the Highcharts Export Server logo and version information.\r\n *\r\n * @param {boolean} noLogo - If true, only prints version information without\r\n * the logo.\r\n */\r\nexport const printLogo = (noLogo) => {\r\n // Get package version either from env or from package.json\r\n const packageVersion = JSON.parse(\r\n readFileSync(join(__dirname, 'package.json'))\r\n ).version;\r\n\r\n // Print text only\r\n if (noLogo) {\r\n console.log(`Starting Highcharts Export Server v${packageVersion}...`);\r\n return;\r\n }\r\n\r\n // Print the logo\r\n console.log(\r\n readFileSync(__dirname + '/msg/startup.msg').toString().bold.yellow,\r\n `v${packageVersion}\\n`.bold\r\n );\r\n};\r\n\r\n/**\r\n * Prints the usage information for CLI arguments. If required, it can list\r\n * properties recursively\r\n */\r\nexport function printUsage() {\r\n const pad = 48;\r\n const readme = 'https://github.com/highcharts/node-export-server#readme';\r\n\r\n // Display readme information\r\n console.log(\r\n '\\nUsage of CLI arguments:'.bold,\r\n '\\n------',\r\n `\\nFor more detailed information, visit the readme at: ${readme.bold.yellow}.`\r\n );\r\n\r\n const cycleCategories = (options) => {\r\n for (const [name, option] of Object.entries(options)) {\r\n // If category has more levels, go further\r\n if (!Object.prototype.hasOwnProperty.call(option, 'value')) {\r\n cycleCategories(option);\r\n } else {\r\n let descName = ` --${option.cliName || name} ${\r\n ('<' + option.type + '>').green\r\n } `;\r\n if (descName.length < pad) {\r\n for (let i = descName.length; i < pad; i++) {\r\n descName += '.';\r\n }\r\n }\r\n\r\n // Display correctly aligned messages\r\n console.log(\r\n descName,\r\n option.description,\r\n `[Default: ${option.value.toString().bold}]`.blue\r\n );\r\n }\r\n }\r\n };\r\n\r\n // Cycle through options of each categories and display the usage info\r\n Object.keys(defaultConfig).forEach((category) => {\r\n // Only puppeteer and highcharts categories cannot be configured through CLI\r\n if (!['puppeteer', 'highcharts'].includes(category)) {\r\n console.log(`\\n${category.toUpperCase()}`.red);\r\n cycleCategories(defaultConfig[category]);\r\n }\r\n });\r\n console.log('\\n');\r\n}\r\n\r\n/**\r\n * Rounds a number to the specified precision.\r\n *\r\n * @param {number} value - The number to be rounded.\r\n * @param {number} precision - The number of decimal places to round to.\r\n *\r\n * @returns {number} - The rounded number.\r\n */\r\nexport const roundNumber = (value, precision = 1) => {\r\n const multiplier = Math.pow(10, precision || 0);\r\n return Math.round(+value * multiplier) / multiplier;\r\n};\r\n\r\n/**\r\n * Converts a value to a boolean.\r\n *\r\n * @param {any} item - The value to be converted to a boolean.\r\n *\r\n * @returns {boolean} - The boolean representation of the input value.\r\n */\r\nexport const toBoolean = (item) =>\r\n ['false', 'undefined', 'null', 'NaN', '0', ''].includes(item)\r\n ? false\r\n : !!item;\r\n\r\n/**\r\n * Wraps custom code to execute it safely.\r\n *\r\n * @param {string} customCode - The custom code to be wrapped.\r\n * @param {boolean} allowFileResources - Flag to allow loading code from a file.\r\n *\r\n * @returns {string|boolean} - The wrapped custom code or false if wrapping\r\n * fails.\r\n */\r\nexport const wrapAround = (customCode, allowFileResources) => {\r\n if (customCode && typeof customCode === 'string') {\r\n customCode = customCode.trim();\r\n\r\n if (customCode.endsWith('.js')) {\r\n return allowFileResources\r\n ? wrapAround(readFileSync(customCode, 'utf8'))\r\n : false;\r\n } else if (\r\n customCode.startsWith('function()') ||\r\n customCode.startsWith('function ()') ||\r\n customCode.startsWith('()=>') ||\r\n customCode.startsWith('() =>')\r\n ) {\r\n return `(${customCode})()`;\r\n }\r\n return customCode.replace(/;$/, '');\r\n }\r\n};\r\n\r\n/**\r\n * Utility to measure elapsed time using the Node.js process.hrtime() method.\r\n *\r\n * @returns {function(): number} - A function to calculate the elapsed time\r\n * in milliseconds.\r\n */\r\nexport const measureTime = () => {\r\n const start = process.hrtime.bigint();\r\n return () => Number(process.hrtime.bigint() - start) / 1000000;\r\n};\r\n\r\nexport default {\r\n __dirname,\r\n clearText,\r\n expBackoff,\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n isObject,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n printLogo,\r\n printUsage,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround,\r\n measureTime\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { existsSync, readFileSync, promises as fsPromises } from 'fs';\r\n\r\nimport prompts from 'prompts';\r\n\r\nimport {\r\n absoluteProps,\r\n defaultConfig,\r\n nestedArgs,\r\n promptsConfig\r\n} from './schemas/config.js';\r\nimport { envs } from './envs.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { deepCopy, isObject, printUsage, toBoolean } from './utils.js';\r\n\r\nlet generalOptions = {};\r\n\r\n/**\r\n * Retrieves and returns the general options for the export process.\r\n *\r\n * @returns {Object} The general options object.\r\n */\r\nexport const getOptions = () => generalOptions;\r\n\r\n/**\r\n * Initializes and sets the general options for the server instace, keeping\r\n * the principle of the options load priority. It accepts optional userOptions\r\n * and args from the CLI.\r\n *\r\n * @param {Object} userOptions - User-provided options for customization.\r\n * @param {Array} args - Command-line arguments for additional configuration\r\n * (CLI usage).\r\n *\r\n * @returns {Object} The updated general options object.\r\n */\r\nexport const setOptions = (userOptions, args) => {\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Get the additional options from the custom JSON file\r\n generalOptions = loadConfigFile(args);\r\n }\r\n\r\n // Update the default config with a correct option values\r\n updateDefaultConfig(defaultConfig, generalOptions);\r\n\r\n // Set values for server's options and returns them\r\n generalOptions = initOptions(defaultConfig);\r\n\r\n // Apply user options if there are any\r\n if (userOptions) {\r\n // Merge user options\r\n generalOptions = mergeConfigOptions(\r\n generalOptions,\r\n userOptions,\r\n absoluteProps\r\n );\r\n }\r\n\r\n // Only for the CLI usage\r\n if (args?.length) {\r\n // Pair provided arguments\r\n generalOptions = pairArgumentValue(generalOptions, args, defaultConfig);\r\n }\r\n\r\n // Return final general options\r\n return generalOptions;\r\n};\r\n\r\n/**\r\n * Allows manual configuration based on specified prompts and saves\r\n * the configuration to a file.\r\n *\r\n * @param {string} configFileName - The name of the configuration file.\r\n *\r\n * @returns {Promise} A Promise that resolves to true once the manual\r\n * configuration is completed and saved.\r\n */\r\nexport const manualConfig = async (configFileName) => {\r\n // Prepare a config object\r\n let configFile = {};\r\n\r\n // Check if provided config file exists\r\n if (existsSync(configFileName)) {\r\n configFile = JSON.parse(readFileSync(configFileName, 'utf8'));\r\n }\r\n\r\n // Question about a configuration category\r\n const onSubmit = async (p, categories) => {\r\n let questionsCounter = 0;\r\n let allQuestions = [];\r\n\r\n // Create a corresponding property in the manualConfig object\r\n for (const section of categories) {\r\n // Mark each option with a section\r\n promptsConfig[section] = promptsConfig[section].map((option) => ({\r\n ...option,\r\n section\r\n }));\r\n\r\n // Collect the questions\r\n allQuestions = [...allQuestions, ...promptsConfig[section]];\r\n }\r\n\r\n await prompts(allQuestions, {\r\n onSubmit: async (prompt, answer) => {\r\n // Get the default module scripts\r\n if (prompt.name === 'moduleScripts') {\r\n answer = answer.length\r\n ? answer.map((module) => prompt.choices[module])\r\n : prompt.choices;\r\n\r\n configFile[prompt.section][prompt.name] = answer;\r\n } else {\r\n configFile[prompt.section] = recursiveProps(\r\n Object.assign({}, configFile[prompt.section] || {}),\r\n prompt.name.split('.'),\r\n prompt.choices ? prompt.choices[answer] : answer\r\n );\r\n }\r\n\r\n if (++questionsCounter === allQuestions.length) {\r\n try {\r\n await fsPromises.writeFile(\r\n configFileName,\r\n JSON.stringify(configFile, null, 2),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n `[config] An error occurred while creating the ${configFileName} file.`\r\n );\r\n }\r\n return true;\r\n }\r\n }\r\n });\r\n\r\n return true;\r\n };\r\n\r\n // Find the categories\r\n const choices = Object.keys(promptsConfig).map((choice) => ({\r\n title: `${choice} options`,\r\n value: choice\r\n }));\r\n\r\n // Category prompt\r\n return prompts(\r\n {\r\n type: 'multiselect',\r\n name: 'category',\r\n message: 'Which category do you want to configure?',\r\n hint: 'Space: Select specific, A: Select all, Enter: Confirm.',\r\n instructions: '',\r\n choices\r\n },\r\n { onSubmit }\r\n );\r\n};\r\n\r\n/**\r\n * Maps old-structured (PhantomJS) options to a new configuration format\r\n * (Puppeteer).\r\n *\r\n * @param {Object} oldOptions - Old-structured options to be mapped.\r\n *\r\n * @returns {Object} New options structured based on the defined nestedArgs\r\n * mapping.\r\n */\r\nexport const mapToNewConfig = (oldOptions) => {\r\n const newOptions = {};\r\n // Cycle through old-structured options\r\n for (const [key, value] of Object.entries(oldOptions)) {\r\n const propertiesChain = nestedArgs[key] ? nestedArgs[key].split('.') : [];\r\n\r\n // Populate object in correct properties levels\r\n propertiesChain.reduce(\r\n (obj, prop, index) =>\r\n (obj[prop] =\r\n propertiesChain.length - 1 === index ? value : obj[prop] || {}),\r\n newOptions\r\n );\r\n }\r\n return newOptions;\r\n};\r\n\r\n/**\r\n * Merges two sets of configuration options, considering absolute properties.\r\n *\r\n * @param {Object} options - Original configuration options.\r\n * @param {Object} newOptions - New configuration options to be merged.\r\n * @param {Array} absoluteProps - List of properties that should\r\n * not be recursively merged.\r\n *\r\n * @returns {Object} Merged configuration options.\r\n */\r\nexport const mergeConfigOptions = (options, newOptions, absoluteProps = []) => {\r\n const mergedOptions = deepCopy(options);\r\n\r\n for (const [key, value] of Object.entries(newOptions)) {\r\n mergedOptions[key] =\r\n isObject(value) &&\r\n !absoluteProps.includes(key) &&\r\n mergedOptions[key] !== undefined\r\n ? mergeConfigOptions(mergedOptions[key], value, absoluteProps)\r\n : value !== undefined\r\n ? value\r\n : mergedOptions[key];\r\n }\r\n\r\n return mergedOptions;\r\n};\r\n\r\n/**\r\n * Initializes export settings based on provided exportOptions\r\n * and generalOptions.\r\n *\r\n * @param {Object} exportOptions - Options specific to the export process.\r\n * @param {Object} generalOptions - General configuration options.\r\n *\r\n * @returns {Object} Initialized export settings.\r\n */\r\nexport const initExportSettings = (exportOptions, generalOptions = {}) => {\r\n let options = {};\r\n\r\n if (exportOptions.svg) {\r\n options = deepCopy(generalOptions);\r\n options.export.type = exportOptions.type || exportOptions.export.type;\r\n options.export.scale = exportOptions.scale || exportOptions.export.scale;\r\n options.export.outfile =\r\n exportOptions.outfile || exportOptions.export.outfile;\r\n options.payload = {\r\n svg: exportOptions.svg\r\n };\r\n } else {\r\n options = mergeConfigOptions(\r\n generalOptions,\r\n exportOptions,\r\n // Omit going down recursively with the belows\r\n absoluteProps\r\n );\r\n }\r\n\r\n options.export.outfile =\r\n options.export?.outfile || `chart.${options.export?.type || 'png'}`;\r\n return options;\r\n};\r\n\r\n/**\r\n * Loads additional configuration from a specified file using\r\n * the --loadConfig option.\r\n *\r\n * @param {Array} args - Command-line arguments to check for\r\n * the --loadConfig option.\r\n *\r\n * @returns {Object} Additional configuration loaded from the specified file,\r\n * or an empty object if not found or invalid.\r\n */\r\nfunction loadConfigFile(args) {\r\n // Check if the --loadConfig option was used\r\n const configIndex = args.findIndex(\r\n (arg) => arg.replace(/-/g, '') === 'loadConfig'\r\n );\r\n\r\n // Check if the --loadConfig has a value\r\n if (configIndex > -1 && args[configIndex + 1]) {\r\n const fileName = args[configIndex + 1];\r\n try {\r\n // Check if an additional config file is a correct JSON file\r\n if (fileName && fileName.endsWith('.json')) {\r\n // Load an optional custom JSON config file\r\n return JSON.parse(readFileSync(fileName));\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[config] Unable to load the configuration from the ${fileName} file.`\r\n );\r\n }\r\n }\r\n\r\n // No additional options to return\r\n return {};\r\n}\r\n\r\n/**\r\n * Updates the default configuration object with values from a custom object\r\n * and environment variables.\r\n *\r\n * @param {Object} configObj - The default configuration object.\r\n * @param {Object} customObj - Custom configuration object to override defaults.\r\n * @param {string} propChain - Property chain for tracking nested properties\r\n * during recursion.\r\n */\r\nfunction updateDefaultConfig(configObj, customObj = {}, propChain = '') {\r\n Object.keys(configObj).forEach((key) => {\r\n const entry = configObj[key];\r\n const customValue = customObj && customObj[key];\r\n\r\n if (typeof entry.value === 'undefined') {\r\n updateDefaultConfig(entry, customValue, `${propChain}.${key}`);\r\n } else {\r\n // If a value from a custom JSON exists, it take precedence\r\n if (customValue !== undefined) {\r\n entry.value = customValue;\r\n }\r\n\r\n // If a value from an env variable exists, it take precedence\r\n if (entry.envLink in envs && envs[entry.envLink] !== undefined) {\r\n entry.value = envs[entry.envLink];\r\n }\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Initializes options object based on provided items, setting values from\r\n * nested properties recursively.\r\n *\r\n * @param {Object} items - Configuration items to be used for initializing\r\n * options.\r\n *\r\n * @returns {Object} Initialized options object.\r\n */\r\nfunction initOptions(items) {\r\n let options = {};\r\n for (const [name, item] of Object.entries(items)) {\r\n options[name] = Object.prototype.hasOwnProperty.call(item, 'value')\r\n ? item.value\r\n : initOptions(item);\r\n }\r\n return options;\r\n}\r\n\r\n/**\r\n * Pairs argument values with corresponding options in the configuration,\r\n * updating the options object.\r\n *\r\n * @param {Object} options - Configuration options object to be updated.\r\n * @param {Array} args - Command-line arguments containing values for specific\r\n * options.\r\n * @param {Object} defaultConfig - Default configuration object for reference.\r\n *\r\n * @returns {Object} Updated options object.\r\n */\r\nfunction pairArgumentValue(options, args, defaultConfig) {\r\n let showUsage = false;\r\n for (let i = 0; i < args.length; i++) {\r\n const option = args[i].replace(/-/g, '');\r\n\r\n // Find the right place for property's value\r\n const propertiesChain = nestedArgs[option]\r\n ? nestedArgs[option].split('.')\r\n : [];\r\n\r\n // Get the correct type for CLI args which are passed as strings\r\n let argumentType;\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n argumentType = obj[prop].type;\r\n }\r\n return obj[prop];\r\n }, defaultConfig);\r\n\r\n propertiesChain.reduce((obj, prop, index) => {\r\n if (propertiesChain.length - 1 === index) {\r\n // Finds an option and set a corresponding value\r\n if (typeof obj[prop] !== 'undefined') {\r\n if (args[++i]) {\r\n if (argumentType === 'boolean') {\r\n obj[prop] = toBoolean(args[i]);\r\n } else if (argumentType === 'number') {\r\n obj[prop] = +args[i];\r\n } else if (argumentType.indexOf(']') >= 0) {\r\n obj[prop] = args[i].split(',');\r\n } else {\r\n obj[prop] = args[i];\r\n }\r\n } else {\r\n log(\r\n 2,\r\n `[config] Missing value for the '${option}' argument. Using the default value.`\r\n );\r\n showUsage = true;\r\n }\r\n }\r\n }\r\n return obj[prop];\r\n }, options);\r\n }\r\n\r\n // Display the usage for the reference if needed\r\n if (showUsage) {\r\n printUsage(defaultConfig);\r\n }\r\n\r\n return options;\r\n}\r\n\r\n/**\r\n * Recursively updates properties in an object based on nested names and assigns\r\n * the final value.\r\n *\r\n * @param {Object} objectToUpdate - The object to be updated.\r\n * @param {Array} nestedNames - Array of nested property names.\r\n * @param {any} value - The final value to be assigned.\r\n *\r\n * @returns {Object} Updated object with assigned values.\r\n */\r\nfunction recursiveProps(objectToUpdate, nestedNames, value) {\r\n while (nestedNames.length > 1) {\r\n const propName = nestedNames.shift();\r\n\r\n // Create a property in object if it doesn't exist\r\n if (!Object.prototype.hasOwnProperty.call(objectToUpdate, propName)) {\r\n objectToUpdate[propName] = {};\r\n }\r\n\r\n // Call function again if there still names to go\r\n objectToUpdate[propName] = recursiveProps(\r\n Object.assign({}, objectToUpdate[propName]),\r\n nestedNames,\r\n value\r\n );\r\n\r\n return objectToUpdate;\r\n }\r\n\r\n // Assign the final value\r\n objectToUpdate[nestedNames[0]] = value;\r\n return objectToUpdate;\r\n}\r\n\r\nexport default {\r\n getOptions,\r\n setOptions,\r\n manualConfig,\r\n mapToNewConfig,\r\n mergeConfigOptions,\r\n initExportSettings\r\n};\r\n","/**\r\n * This module exports two functions: fetch (for GET requests) and post (for POST requests).\r\n */\r\n\r\nimport http from 'http';\r\nimport https from 'https';\r\n\r\n/**\r\n * Returns the HTTP or HTTPS protocol module based on the provided URL.\r\n *\r\n * @param {string} url - The URL to determine the protocol.\r\n *\r\n * @returns {Object} The HTTP or HTTPS protocol module (http or https).\r\n */\r\nconst getProtocol = (url) => (url.startsWith('https') ? https : http);\r\n\r\n/**\r\n * Fetches data from the specified URL using either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to fetch data from.\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object\r\n * with added 'text' property or rejecting with an error.\r\n */\r\nasync function fetch(url, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n\r\n protocol\r\n .get(url, requestOptions, (res) => {\r\n let data = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n data += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n if (!data) {\r\n reject('Nothing was fetched from the URL.');\r\n }\r\n\r\n res.text = data;\r\n resolve(res);\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n });\r\n}\r\n\r\n/**\r\n * Sends a POST request to the specified URL with the provided JSON body using\r\n * either HTTP or HTTPS protocol.\r\n *\r\n * @param {string} url - The URL to send the POST request to.\r\n * @param {Object} body - The JSON body to include in the POST request\r\n * (optional, default is an empty object).\r\n * @param {Object} requestOptions - Options for the HTTP request (optional).\r\n *\r\n * @returns {Promise} Promise resolving to the HTTP response object with\r\n * added 'text' property or rejecting with an error.\r\n */\r\nasync function post(url, body = {}, requestOptions = {}) {\r\n return new Promise((resolve, reject) => {\r\n const protocol = getProtocol(url);\r\n const data = JSON.stringify(body);\r\n\r\n // Set default headers and merge with requestOptions\r\n const options = Object.assign(\r\n {\r\n method: 'POST',\r\n headers: {\r\n 'Content-Type': 'application/json',\r\n 'Content-Length': data.length\r\n }\r\n },\r\n requestOptions\r\n );\r\n\r\n const req = protocol\r\n .request(url, options, (res) => {\r\n let responseData = '';\r\n\r\n // A chunk of data has been received.\r\n res.on('data', (chunk) => {\r\n responseData += chunk;\r\n });\r\n\r\n // The whole response has been received.\r\n res.on('end', () => {\r\n try {\r\n res.text = responseData;\r\n resolve(res);\r\n } catch (error) {\r\n reject(error);\r\n }\r\n });\r\n })\r\n .on('error', (error) => {\r\n reject(error);\r\n });\r\n\r\n // Write the request body and end the request.\r\n req.write(data);\r\n req.end();\r\n });\r\n}\r\n\r\nexport default fetch;\r\nexport { fetch, post };\r\n","class ExportError extends Error {\r\n constructor(message) {\r\n super();\r\n this.message = message;\r\n this.stackMessage = message;\r\n }\r\n\r\n setError(error) {\r\n this.error = error;\r\n if (error.name) {\r\n this.name = error.name;\r\n }\r\n if (error.statusCode) {\r\n this.statusCode = error.statusCode;\r\n }\r\n if (error.stack) {\r\n this.stackMessage = error.message;\r\n this.stack = error.stack;\r\n }\r\n return this;\r\n }\r\n}\r\n\r\nexport default ExportError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n// The cache manager manages the Highcharts library and its dependencies.\r\n// The cache itself is stored in .cache, and is checked by the config system\r\n// before starting the service\r\n\r\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';\r\nimport { join } from 'path';\r\n\r\nimport { HttpsProxyAgent } from 'https-proxy-agent';\r\n\r\nimport { getOptions } from './config.js';\r\nimport { envs } from './envs.js';\r\nimport { fetch } from './fetch.js';\r\nimport { log } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nconst cache = {\r\n cdnURL: 'https://code.highcharts.com/',\r\n activeManifest: {},\r\n sources: '',\r\n hcVersion: ''\r\n};\r\n\r\n/**\r\n * Extracts and caches the Highcharts version from the sources string.\r\n *\r\n * @returns {string} The extracted Highcharts version.\r\n */\r\nexport const extractVersion = (cache) => {\r\n return cache.sources\r\n .substring(0, cache.sources.indexOf('*/'))\r\n .replace('/*', '')\r\n .replace('*/', '')\r\n .replace(/\\n/g, '')\r\n .trim();\r\n};\r\n\r\n/**\r\n * Extracts the Highcharts module name based on the scriptPath.\r\n */\r\nexport const extractModuleName = (scriptPath) => {\r\n return scriptPath.replace(\r\n /(.*)\\/|(.*)modules\\/|stock\\/(.*)indicators\\/|maps\\/(.*)modules\\//gi,\r\n ''\r\n );\r\n};\r\n\r\n/**\r\n * Saves the provided configuration and fetched modules to the cache manifest\r\n * file.\r\n *\r\n * @param {object} config - Highcharts-related configuration object.\r\n * @param {object} fetchedModules - An object that contains mapped names of\r\n * fetched Highcharts modules to use.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs while writing\r\n * the cache manifest.\r\n */\r\nexport const saveConfigToManifest = async (config, fetchedModules) => {\r\n const newManifest = {\r\n version: config.version,\r\n modules: fetchedModules || {}\r\n };\r\n\r\n // Update cache object with the current modules\r\n cache.activeManifest = newManifest;\r\n\r\n log(3, '[cache] Writing a new manifest.');\r\n try {\r\n writeFileSync(\r\n join(__dirname, config.cachePath, 'manifest.json'),\r\n JSON.stringify(newManifest),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n throw new ExportError('[cache] Error writing the cache manifest.').setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Fetches a single script and updates the fetchedModules accordingly.\r\n *\r\n * @param {string} script - A path to script to get.\r\n * @param {Object} requestOptions - Additional options for the proxy agent\r\n * to use for a request.\r\n * @param {Object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n * @param {boolean} shouldThrowError - A flag to indicate if the error should be\r\n * thrown. This should be used only for the core scripts.\r\n *\r\n * @returns {Promise} A Promise resolving to the text representation\r\n * of the fetched script.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is a problem with\r\n * fetching the script.\r\n */\r\nexport const fetchAndProcessScript = async (\r\n script,\r\n requestOptions,\r\n fetchedModules,\r\n shouldThrowError = false\r\n) => {\r\n // Get rid of the .js from the custom strings\r\n if (script.endsWith('.js')) {\r\n script = script.substring(0, script.length - 3);\r\n }\r\n\r\n log(4, `[cache] Fetching script - ${script}.js`);\r\n\r\n // Fetch the script\r\n const response = await fetch(`${script}.js`, requestOptions);\r\n\r\n // If OK, return its text representation\r\n if (response.statusCode === 200 && typeof response.text == 'string') {\r\n if (fetchedModules) {\r\n const moduleName = extractModuleName(script);\r\n fetchedModules[moduleName] = 1;\r\n }\r\n\r\n return response.text;\r\n }\r\n\r\n if (shouldThrowError) {\r\n throw new ExportError(\r\n `Could not fetch the ${script}.js. The script might not exist in the requested version (status code: ${response.statusCode}).`\r\n ).setError(response);\r\n } else {\r\n log(\r\n 2,\r\n `[cache] Could not fetch the ${script}.js. The script might not exist in the requested version.`\r\n );\r\n }\r\n\r\n return '';\r\n};\r\n\r\n/**\r\n * Fetches Highcharts scripts and customScripts from the given CDNs.\r\n *\r\n * @param {string} coreScripts - Array of Highcharts core scripts to fetch.\r\n * @param {string} moduleScripts - Array of Highcharts modules to fetch.\r\n * @param {string} customScripts - Array of custom script paths to fetch\r\n * (full URLs).\r\n * @param {object} proxyOptions - Options for the proxy agent to use for\r\n * a request.\r\n * @param {object} fetchedModules - An object which tracks which Highcharts\r\n * modules have been fetched.\r\n *\r\n * @returns {Promise} The fetched scripts content joined.\r\n */\r\nexport const fetchScripts = async (\r\n coreScripts,\r\n moduleScripts,\r\n customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n) => {\r\n // Configure proxy if exists\r\n let proxyAgent;\r\n const proxyHost = proxyOptions.host;\r\n const proxyPort = proxyOptions.port;\r\n\r\n // Try to create a Proxy Agent\r\n if (proxyHost && proxyPort) {\r\n try {\r\n proxyAgent = new HttpsProxyAgent({\r\n host: proxyHost,\r\n port: proxyPort\r\n });\r\n } catch (error) {\r\n throw new ExportError('[cache] Could not create a Proxy Agent.').setError(\r\n error\r\n );\r\n }\r\n }\r\n\r\n // If exists, add proxy agent to request options\r\n const requestOptions = proxyAgent\r\n ? {\r\n agent: proxyAgent,\r\n timeout: envs.SERVER_PROXY_TIMEOUT\r\n }\r\n : {};\r\n\r\n const allFetchPromises = [\r\n ...coreScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules, true)\r\n ),\r\n ...moduleScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions, fetchedModules)\r\n ),\r\n ...customScripts.map((script) =>\r\n fetchAndProcessScript(`${script}`, requestOptions)\r\n )\r\n ];\r\n\r\n const fetchedScripts = await Promise.all(allFetchPromises);\r\n return fetchedScripts.join(';\\n');\r\n};\r\n\r\n/**\r\n * Updates the local cache with Highcharts scripts and their versions.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n * @param {string} sourcePath - The path to the source file in the cache.\r\n *\r\n * @returns {Promise} A Promise resolving to an object representing\r\n * the fetched modules.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * the local Highcharts cache.\r\n */\r\nexport const updateCache = async (\r\n highchartsOptions,\r\n proxyOptions,\r\n sourcePath\r\n) => {\r\n const version = highchartsOptions.version;\r\n const hcVersion = version === 'latest' || !version ? '' : `${version}/`;\r\n const cdnURL = highchartsOptions.cdnURL || cache.cdnURL;\r\n\r\n log(\r\n 3,\r\n `[cache] Updating cache version to Highcharts: ${hcVersion || 'latest'}.`\r\n );\r\n\r\n const fetchedModules = {};\r\n try {\r\n cache.sources = await fetchScripts(\r\n [\r\n ...highchartsOptions.coreScripts.map((c) => `${cdnURL}${hcVersion}${c}`)\r\n ],\r\n [\r\n ...highchartsOptions.moduleScripts.map((m) =>\r\n m === 'map'\r\n ? `${cdnURL}maps/${hcVersion}modules/${m}`\r\n : `${cdnURL}${hcVersion}modules/${m}`\r\n ),\r\n ...highchartsOptions.indicatorScripts.map(\r\n (i) => `${cdnURL}stock/${hcVersion}indicators/${i}`\r\n )\r\n ],\r\n highchartsOptions.customScripts,\r\n proxyOptions,\r\n fetchedModules\r\n );\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n\r\n // Save the fetched modules into caches' source JSON\r\n writeFileSync(sourcePath, cache.sources);\r\n return fetchedModules;\r\n } catch (error) {\r\n throw new ExportError(\r\n '[cache] Unable to update the local Highcharts cache.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Updates the Highcharts version in the applied configuration and checks\r\n * the cache for the new version.\r\n *\r\n * @param {string} newVersion - The new Highcharts version to be applied.\r\n *\r\n * @returns {Promise<(object|boolean)>} A Promise resolving to the updated\r\n * configuration with the new version, or false if no applied configuration\r\n * exists.\r\n */\r\nexport const updateVersion = async (newVersion) => {\r\n const options = getOptions();\r\n if (options?.highcharts) {\r\n options.highcharts.version = newVersion;\r\n }\r\n await checkAndUpdateCache(options);\r\n};\r\n\r\n/**\r\n * Checks the cache for Highcharts dependencies, updates the cache if needed,\r\n * and loads the sources.\r\n *\r\n * @param {Object} options - Object containing all options.\r\n *\r\n * @returns {Promise} A Promise that resolves once the cache is checked\r\n * and updated.\r\n *\r\n * @throws {ExportError} Throws an ExportError if there is an issue updating\r\n * or reading the cache.\r\n */\r\nexport const checkAndUpdateCache = async (options) => {\r\n const { highcharts, server } = options;\r\n const cachePath = join(__dirname, highcharts.cachePath);\r\n\r\n let fetchedModules;\r\n // Prepare paths to manifest and sources from the .cache folder\r\n const manifestPath = join(cachePath, 'manifest.json');\r\n const sourcePath = join(cachePath, 'sources.js');\r\n\r\n // Create the cache destination if it doesn't exist already\r\n !existsSync(cachePath) && mkdirSync(cachePath);\r\n\r\n // Fetch all the scripts either if manifest.json does not exist\r\n // or if the forceFetch option is enabled\r\n if (!existsSync(manifestPath) || highcharts.forceFetch) {\r\n log(3, '[cache] Fetching and caching Highcharts dependencies.');\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n let requestUpdate = false;\r\n\r\n // Read the manifest JSON\r\n const manifest = JSON.parse(readFileSync(manifestPath));\r\n\r\n // Check if the modules is an array, if so, we rewrite it to a map to make\r\n // it easier to resolve modules.\r\n if (manifest.modules && Array.isArray(manifest.modules)) {\r\n const moduleMap = {};\r\n manifest.modules.forEach((m) => (moduleMap[m] = 1));\r\n manifest.modules = moduleMap;\r\n }\r\n\r\n const { coreScripts, moduleScripts, indicatorScripts } = highcharts;\r\n const numberOfModules =\r\n coreScripts.length + moduleScripts.length + indicatorScripts.length;\r\n\r\n // Compare the loaded highcharts config with the contents in cache.\r\n // If there are changes, fetch requested modules and products,\r\n // and bake them into a giant blob. Save the blob.\r\n if (manifest.version !== highcharts.version) {\r\n log(\r\n 2,\r\n '[cache] A Highcharts version mismatch in the cache, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else if (Object.keys(manifest.modules || {}).length !== numberOfModules) {\r\n log(\r\n 2,\r\n '[cache] The cache and the requested modules do not match, need to re-fetch.'\r\n );\r\n requestUpdate = true;\r\n } else {\r\n // Check each module, if anything is missing refetch everything\r\n requestUpdate = (moduleScripts || []).some((moduleName) => {\r\n if (!manifest.modules[moduleName]) {\r\n log(\r\n 2,\r\n `[cache] The ${moduleName} is missing in the cache, need to re-fetch.`\r\n );\r\n return true;\r\n }\r\n });\r\n }\r\n\r\n if (requestUpdate) {\r\n fetchedModules = await updateCache(highcharts, server.proxy, sourcePath);\r\n } else {\r\n log(3, '[cache] Dependency cache is up to date, proceeding.');\r\n\r\n // Load the sources\r\n cache.sources = readFileSync(sourcePath, 'utf8');\r\n\r\n // Get current modules map\r\n fetchedModules = manifest.modules;\r\n\r\n cache.hcVersion = extractVersion(cache);\r\n }\r\n }\r\n\r\n // Finally, save the new manifest, which is basically our current config\r\n // in a slightly different format\r\n await saveConfigToManifest(highcharts, fetchedModules);\r\n};\r\n\r\nexport const getCachePath = () =>\r\n join(__dirname, getOptions().highcharts.cachePath);\r\n\r\nexport const getCache = () => cache;\r\n\r\nexport const highcharts = () => cache.sources;\r\n\r\nexport const version = () => cache.hcVersion;\r\n\r\nexport default {\r\n checkAndUpdateCache,\r\n getCachePath,\r\n updateVersion,\r\n getCache,\r\n highcharts,\r\n version\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/* eslint-disable no-undef */\r\n\r\n/**\r\n * Setting the animObject. Called when initing the page.\r\n */\r\nexport function setupHighcharts() {\r\n Highcharts.animObject = function () {\r\n return { duration: 0 };\r\n };\r\n}\r\n\r\n/**\r\n * Creates the actual chart.\r\n *\r\n * @param {object} chartOptions - The options for the Highcharts chart.\r\n * @param {object} options - The export options.\r\n * @param {boolean} displayErrors - A flag indicating whether to display errors.\r\n */\r\nexport async function triggerExport(chartOptions, options, displayErrors) {\r\n // Display errors flag taken from chart options nad debugger module\r\n window._displayErrors = displayErrors;\r\n\r\n // Get required functions\r\n const { getOptions, merge, setOptions, wrap } = Highcharts;\r\n\r\n // Create a separate object for a potential setOptions usages in order to\r\n // prevent from polluting other exports that can happen on the same page\r\n Highcharts.setOptionsObj = merge(false, {}, getOptions());\r\n\r\n // Trigger custom code\r\n if (options.customLogic.customCode) {\r\n new Function(options.customLogic.customCode)();\r\n }\r\n\r\n // By default animation is disabled\r\n const chart = {\r\n animation: false\r\n };\r\n\r\n // When straight inject, the size is set through CSS only\r\n if (options.export.strInj) {\r\n chart.height = chartOptions.chart.height;\r\n chart.width = chartOptions.chart.width;\r\n }\r\n\r\n // NOTE: Is this used for anything useful?\r\n window.isRenderComplete = false;\r\n wrap(Highcharts.Chart.prototype, 'init', function (proceed, userOptions, cb) {\r\n // Override userOptions with image friendly options\r\n userOptions = merge(userOptions, {\r\n exporting: {\r\n enabled: false\r\n },\r\n plotOptions: {\r\n series: {\r\n label: {\r\n enabled: false\r\n }\r\n }\r\n },\r\n /* Expects tooltip in userOptions when forExport is true.\r\n https://github.com/highcharts/highcharts/blob/3ad430a353b8056b9e764aa4e5cd6828aa479db2/js/parts/Chart.js#L241\r\n */\r\n tooltip: {}\r\n });\r\n\r\n (userOptions.series || []).forEach(function (series) {\r\n series.animation = false;\r\n });\r\n\r\n // Add flag to know if chart render has been called.\r\n if (!window.onHighchartsRender) {\r\n window.onHighchartsRender = Highcharts.addEvent(this, 'render', () => {\r\n window.isRenderComplete = true;\r\n });\r\n }\r\n\r\n proceed.apply(this, [userOptions, cb]);\r\n });\r\n\r\n wrap(Highcharts.Series.prototype, 'init', function (proceed, chart, options) {\r\n proceed.apply(this, [chart, options]);\r\n });\r\n\r\n // Get the user options\r\n const userOptions = options.export.strInj\r\n ? new Function(`return ${options.export.strInj}`)()\r\n : chartOptions;\r\n\r\n // Merge the globalOptions, themeOptions, options from the wrapped\r\n // setOptions function and user options to create the final options object\r\n const finalOptions = merge(\r\n false,\r\n JSON.parse(options.export.themeOptions),\r\n userOptions,\r\n // Placed it here instead in the init because of the size issues\r\n { chart }\r\n );\r\n\r\n const finalCallback = options.customLogic.callback\r\n ? new Function(`return ${options.customLogic.callback}`)()\r\n : undefined;\r\n\r\n // Set the global options if exist\r\n const globalOptions = JSON.parse(options.export.globalOptions);\r\n if (globalOptions) {\r\n setOptions(globalOptions);\r\n }\r\n\r\n Highcharts[options.export.constr || 'chart'](\r\n 'container',\r\n finalOptions,\r\n finalCallback\r\n );\r\n\r\n // Get the current global options\r\n const defaultOptions = getOptions();\r\n\r\n // Clear it just in case (e.g. the setOptions was used in the customCode)\r\n for (const prop in defaultOptions) {\r\n if (typeof defaultOptions[prop] !== 'function') {\r\n delete defaultOptions[prop];\r\n }\r\n }\r\n\r\n // Set the default options back\r\n setOptions(Highcharts.setOptionsObj);\r\n\r\n // Empty the custom global options object\r\n Highcharts.setOptionsObj = {};\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport path from 'path';\r\n\r\nimport puppeteer from 'puppeteer';\r\n\r\nimport { getCachePath } from './cache.js';\r\nimport { getOptions } from './config.js';\r\nimport { setupHighcharts } from './highcharts.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { __dirname } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// Get the template for the page\r\nconst template = readFileSync(__dirname + '/templates/template.html', 'utf8');\r\n\r\nlet browser;\r\n\r\n/**\r\n * Retrieves the existing Puppeteer browser instance.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if no valid browser has been\r\n * created.\r\n */\r\nexport function get() {\r\n if (!browser) {\r\n throw new ExportError('[browser] No valid browser has been created.');\r\n }\r\n return browser;\r\n}\r\n\r\n/**\r\n * Creates a Puppeteer browser instance with the specified arguments.\r\n *\r\n * @param {Array} puppeteerArgs - Additional arguments for Puppeteer launch.\r\n *\r\n * @returns {Promise} A Promise resolving to the Puppeteer browser\r\n * instance.\r\n *\r\n * @throws {ExportError} Throws an ExportError if max retries to open a browser\r\n * instance are reached, or if no browser instance is found after retries.\r\n */\r\nexport async function create(puppeteerArgs) {\r\n // Get the debug options\r\n const { enable: enabledDebug, ...debug } = getOptions().debug;\r\n const launchOptions = {\r\n headless: 'shell',\r\n userDataDir: './tmp/',\r\n args: puppeteerArgs,\r\n handleSIGINT: false,\r\n handleSIGTERM: false,\r\n handleSIGHUP: false,\r\n waitForInitialPage: false,\r\n defaultViewport: null,\r\n ...(enabledDebug && debug)\r\n };\r\n\r\n // Create a browser\r\n if (!browser) {\r\n let tryCount = 0;\r\n\r\n const open = async () => {\r\n try {\r\n log(\r\n 3,\r\n `[browser] Attempting to get a browser instance (try ${++tryCount}).`\r\n );\r\n browser = await puppeteer.launch(launchOptions);\r\n } catch (error) {\r\n logWithStack(\r\n 1,\r\n error,\r\n '[browser] Failed to launch a browser instance.'\r\n );\r\n\r\n // Retry to launch browser until reaching max attempts\r\n if (tryCount < 25) {\r\n log(3, `[browser] Retry to open a browser (${tryCount} out of 25).`);\r\n await new Promise((response) => setTimeout(response, 4000));\r\n await open();\r\n } else {\r\n throw error;\r\n }\r\n }\r\n };\r\n\r\n try {\r\n await open();\r\n // Debug mode inform\r\n if (enabledDebug) {\r\n log(3, `[browser] Launched browser in debug mode.`);\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n '[browser] Maximum retries to open a browser instance reached.'\r\n ).setError(error);\r\n }\r\n\r\n if (!browser) {\r\n throw new ExportError('[browser] Cannot find a browser to open.');\r\n }\r\n }\r\n\r\n // Return a browser promise\r\n return browser;\r\n}\r\n\r\n/**\r\n * Closes the Puppeteer browser instance if it is connected.\r\n *\r\n * @returns {Promise} A Promise resolving to true after the browser\r\n * is closed.\r\n */\r\nexport async function close() {\r\n // Close the browser when connnected\r\n if (browser?.connected) {\r\n await browser.close();\r\n }\r\n log(4, '[browser] Closed the browser.');\r\n}\r\n\r\n/**\r\n * Creates a new Puppeteer Page within an existing browser instance.\r\n *\r\n * If the browser instance is not available, returns false.\r\n *\r\n * The function creates a new page, disables caching, sets content using\r\n * setPageContent(), and returns the created Puppeteer Page.\r\n *\r\n * @returns {(boolean|object)} Returns false if the browser instance is not\r\n * available, or a Puppeteer Page object representing the newly created page.\r\n */\r\nexport async function newPage() {\r\n if (!browser) {\r\n return false;\r\n }\r\n\r\n // Create a page\r\n const page = await browser.newPage();\r\n\r\n // Disable cache\r\n await page.setCacheEnabled(false);\r\n\r\n // Set the content\r\n await setPageContent(page);\r\n\r\n // Set page events\r\n setPageEvents(page);\r\n\r\n return page;\r\n}\r\n\r\n/**\r\n * Clears the content of a Puppeteer Page based on the specified mode.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to be cleared.\r\n * @param {boolean} hardReset - A flag indicating the type of clearing\r\n * to be performed. If true, navigates to 'about:blank' and resets content\r\n * and scripts. If false, clears the body content by setting a predefined HTML\r\n * structure.\r\n *\r\n * @throws {Error} Logs thrown error if clearing the page content fails.\r\n */\r\nexport async function clearPage(page, hardReset = false) {\r\n try {\r\n if (!page.isClosed()) {\r\n if (hardReset) {\r\n // Navigate to about:blank\r\n await page.goto('about:blank', { waitUntil: 'domcontentloaded' });\r\n\r\n // Set the content and and scripts again\r\n await setPageContent(page);\r\n } else {\r\n // Clear body content\r\n await page.evaluate(() => {\r\n document.body.innerHTML =\r\n '
';\r\n });\r\n }\r\n }\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n '[browser] Could not clear the content of the page.'\r\n );\r\n }\r\n}\r\n\r\n/**\r\n * Adds custom JS and CSS resources to a Puppeteer Page based on the specified\r\n * options.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to which resources will be\r\n * added.\r\n * @param {Object} options - All options and configuration.\r\n *\r\n * @returns {Promise>} - Promise resolving to an array of injected\r\n * resources.\r\n */\r\nexport async function addPageResources(page, options) {\r\n // Injected resources array\r\n const injectedResources = [];\r\n\r\n // Use resources\r\n const resources = options.customLogic.resources;\r\n if (resources) {\r\n const injectedJs = [];\r\n\r\n // Load custom JS code\r\n if (resources.js) {\r\n injectedJs.push({\r\n content: resources.js\r\n });\r\n }\r\n\r\n // Load scripts from all custom files\r\n if (resources.files) {\r\n for (const file of resources.files) {\r\n const isLocal = !file.startsWith('http') ? true : false;\r\n\r\n // Add each custom script from resources' files\r\n injectedJs.push(\r\n isLocal\r\n ? {\r\n content: readFileSync(file, 'utf8')\r\n }\r\n : {\r\n url: file\r\n }\r\n );\r\n }\r\n }\r\n\r\n for (const jsResource of injectedJs) {\r\n try {\r\n injectedResources.push(await page.addScriptTag(jsResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The JS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedJs.length = 0;\r\n\r\n // Load CSS\r\n const injectedCss = [];\r\n if (resources.css) {\r\n let cssImports = resources.css.match(/@import\\s*([^;]*);/g);\r\n if (cssImports) {\r\n // Handle css section\r\n for (let cssImportPath of cssImports) {\r\n if (cssImportPath) {\r\n cssImportPath = cssImportPath\r\n .replace('url(', '')\r\n .replace('@import', '')\r\n .replace(/\"/g, '')\r\n .replace(/'/g, '')\r\n .replace(/;/, '')\r\n .replace(/\\)/g, '')\r\n .trim();\r\n\r\n // Add each custom css from resources\r\n if (cssImportPath.startsWith('http')) {\r\n injectedCss.push({\r\n url: cssImportPath\r\n });\r\n } else if (options.customLogic.allowFileResources) {\r\n injectedCss.push({\r\n path: path.join(__dirname, cssImportPath)\r\n });\r\n }\r\n }\r\n }\r\n }\r\n\r\n // The rest of the CSS section will be content by now\r\n injectedCss.push({\r\n content: resources.css.replace(/@import\\s*([^;]*);/g, '') || ' '\r\n });\r\n\r\n for (const cssResource of injectedCss) {\r\n try {\r\n injectedResources.push(await page.addStyleTag(cssResource));\r\n } catch (error) {\r\n logWithStack(2, error, `[export] The CSS resource cannot be loaded.`);\r\n }\r\n }\r\n injectedCss.length = 0;\r\n }\r\n }\r\n return injectedResources;\r\n}\r\n\r\n/**\r\n * Clears out all state set on the page with addScriptTag/addStyleTag. Removes\r\n * injected resources and resets CSS and script tags on the page. Additionally,\r\n * it destroys previously existing charts.\r\n *\r\n * @param {Object} page - The Puppeteer Page object from which resources will\r\n * be cleared.\r\n * @param {Array} injectedResources - Array of injected resources\r\n * to be cleared.\r\n */\r\nexport async function clearPageResources(page, injectedResources) {\r\n for (const resource of injectedResources) {\r\n await resource.dispose();\r\n }\r\n\r\n // Destroy old charts after export is done and reset all CSS and script tags\r\n await page.evaluate(() => {\r\n // We are not guaranteed that Highcharts is loaded, e,g, when doing SVG\r\n // exports\r\n if (typeof Highcharts !== 'undefined') {\r\n // eslint-disable-next-line no-undef\r\n const oldCharts = Highcharts.charts;\r\n\r\n // Check in any already existing charts\r\n if (Array.isArray(oldCharts) && oldCharts.length) {\r\n // Destroy old charts\r\n for (const oldChart of oldCharts) {\r\n oldChart && oldChart.destroy();\r\n // eslint-disable-next-line no-undef\r\n Highcharts.charts.shift();\r\n }\r\n }\r\n }\r\n\r\n // eslint-disable-next-line no-undef\r\n const [...scriptsToRemove] = document.getElementsByTagName('script');\r\n // eslint-disable-next-line no-undef\r\n const [, ...stylesToRemove] = document.getElementsByTagName('style');\r\n // eslint-disable-next-line no-undef\r\n const [...linksToRemove] = document.getElementsByTagName('link');\r\n\r\n // Remove tags\r\n for (const element of [\r\n ...scriptsToRemove,\r\n ...stylesToRemove,\r\n ...linksToRemove\r\n ]) {\r\n element.remove();\r\n }\r\n });\r\n}\r\n\r\n/**\r\n * Sets the content for a Puppeteer Page using a predefined template\r\n * and additional scripts. Also, sets the pageerror in order to catch\r\n * and display errors from the window context.\r\n *\r\n * @param {Object} page - The Puppeteer Page object for which the content\r\n * is being set.\r\n */\r\nasync function setPageContent(page) {\r\n await page.setContent(template, { waitUntil: 'domcontentloaded' });\r\n\r\n // Add all registered Higcharts scripts, quite demanding\r\n await page.addScriptTag({ path: `${getCachePath()}/sources.js` });\r\n\r\n // Set the initial animObject\r\n await page.evaluate(setupHighcharts);\r\n}\r\n\r\n/**\r\n * Set events for a Puppeteer Page.\r\n *\r\n * @param {Object} page - The Puppeteer Page object to set events to.\r\n */\r\nfunction setPageEvents(page) {\r\n // Get debug options\r\n const { debug } = getOptions();\r\n\r\n // Set the console listener, if needed\r\n if (debug.enable && debug.listenToConsole) {\r\n page.on('console', (message) => {\r\n console.log(`[debug] ${message.text()}`);\r\n });\r\n }\r\n\r\n // Set the pageerror listener\r\n page.on('pageerror', async (error) => {\r\n // TODO: Consider adding a switch here that turns on log(0) logging\r\n // on page errors.\r\n await page.$eval(\r\n '#container',\r\n (element, errorMessage) => {\r\n // eslint-disable-next-line no-undef\r\n if (window._displayErrors) {\r\n element.innerHTML = errorMessage;\r\n }\r\n },\r\n `

Chart input data error:

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

Chart input data error:

${error.toString()}`\r\n );\r\n });\r\n}\r\n\r\nexport default {\r\n get,\r\n create,\r\n close,\r\n newPage,\r\n clearPage,\r\n addPageResources,\r\n clearPageResources\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { addPageResources, clearPageResources } from './browser.js';\r\nimport { getCache } from './cache.js';\r\nimport { triggerExport } from './highcharts.js';\r\nimport { log } from './logger.js';\r\n\r\nimport svgTemplate from './../templates/svg_export/svg_export.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n/**\r\n * Retrieves the clipping region coordinates of the specified page element with\r\n * the id 'chart-container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to an object containing\r\n * x, y, width, and height properties.\r\n */\r\nconst getClipRegion = (page) =>\r\n page.$eval('#chart-container', (element) => {\r\n const { x, y, width, height } = element.getBoundingClientRect();\r\n return {\r\n x,\r\n y,\r\n width,\r\n height: Math.trunc(height > 1 ? height : 500)\r\n };\r\n });\r\n\r\n/**\r\n * Creates an image using Puppeteer's page screenshot functionality with\r\n * specified options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {string} type - Image type.\r\n * @param {string} encoding - Image encoding.\r\n * @param {Object} clip - Clipping region coordinates.\r\n * @param {number} rasterizationTimeout - Timeout for rasterization\r\n * in milliseconds.\r\n *\r\n * @returns {Promise} Promise resolving to the image buffer or rejecting\r\n * with an ExportError for timeout.\r\n */\r\nconst createImage = (page, type, encoding, clip, rasterizationTimeout) =>\r\n Promise.race([\r\n page.screenshot({\r\n type,\r\n encoding,\r\n clip,\r\n captureBeyondViewport: true,\r\n fullPage: false,\r\n optimizeForSpeed: true,\r\n ...(type !== 'png' ? { quality: 80 } : {}),\r\n\r\n // #447, #463 - always render on a transparent page if the expected type\r\n // format is PNG\r\n omitBackground: type == 'png'\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n\r\n/**\r\n * Creates a PDF using Puppeteer's page pdf functionality with specified\r\n * options.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {number} height - PDF height.\r\n * @param {number} width - PDF width.\r\n * @param {string} encoding - PDF encoding.\r\n *\r\n * @returns {Promise} Promise resolving to the PDF buffer.\r\n */\r\nconst createPDF = async (\r\n page,\r\n height,\r\n width,\r\n encoding,\r\n rasterizationTimeout\r\n) => {\r\n await page.emulateMediaType('screen');\r\n return Promise.race([\r\n page.pdf({\r\n // This will remove an extra empty page in PDF exports\r\n height: height + 1,\r\n width,\r\n encoding\r\n }),\r\n new Promise((_resolve, reject) =>\r\n setTimeout(\r\n () => reject(new ExportError('Rasterization timeout')),\r\n rasterizationTimeout || 1500\r\n )\r\n )\r\n ]);\r\n};\r\n\r\n/**\r\n * Creates an SVG string by evaluating the outerHTML of the first 'svg' element\r\n * inside an element with the id 'container'.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n *\r\n * @returns {Promise} Promise resolving to the SVG string.\r\n */\r\nconst createSVG = (page) =>\r\n page.$eval('#container svg:first-of-type', (element) => element.outerHTML);\r\n\r\n/**\r\n * Sets the specified chart and options as configuration into the triggerExport\r\n * function within the window context using page.evaluate.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object to be configured.\r\n * @param {Object} options - Configuration options for the chart.\r\n *\r\n * @returns {Promise} Promise resolving after the configuration is set.\r\n */\r\nconst setAsConfig = async (page, chart, options, displayErrors) =>\r\n page.evaluate(triggerExport, chart, options, displayErrors);\r\n\r\n/**\r\n * Exports to a chart from a page using Puppeteer.\r\n *\r\n * @param {Object} page - Puppeteer page object.\r\n * @param {any} chart - The chart object or SVG configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} Promise resolving to\r\n * the exported data or rejecting with an ExportError.\r\n */\r\nexport default async (page, chart, options) => {\r\n // Injected resources array (additional JS and CSS)\r\n let injectedResources = [];\r\n\r\n try {\r\n log(4, '[export] Determining export path.');\r\n\r\n const exportOptions = options.export;\r\n\r\n // Decide whether display error or debbuger wrapper around it\r\n const displayErrors =\r\n exportOptions?.options?.chart?.displayErrors &&\r\n getCache().activeManifest.modules.debugger;\r\n\r\n let isSVG;\r\n if (\r\n chart.indexOf &&\r\n (chart.indexOf('= 0 || chart.indexOf('= 0)\r\n ) {\r\n // SVG input handling\r\n log(4, '[export] Treating as SVG.');\r\n\r\n // If input is also SVG, just return it\r\n if (exportOptions.type === 'svg') {\r\n return chart;\r\n }\r\n\r\n isSVG = true;\r\n await page.setContent(svgTemplate(chart), {\r\n waitUntil: 'domcontentloaded'\r\n });\r\n } else {\r\n // JSON config handling\r\n log(4, '[export] Treating as config.');\r\n\r\n // Need to perform straight inject\r\n if (exportOptions.strInj) {\r\n // Injection based configuration export\r\n await setAsConfig(\r\n page,\r\n {\r\n chart: {\r\n height: exportOptions.height,\r\n width: exportOptions.width\r\n }\r\n },\r\n options,\r\n displayErrors\r\n );\r\n } else {\r\n // Basic configuration export\r\n chart.chart.height = exportOptions.height;\r\n chart.chart.width = exportOptions.width;\r\n\r\n await setAsConfig(page, chart, options, displayErrors);\r\n }\r\n }\r\n\r\n // Keeps track of all resources added on the page with addXXXTag. etc\r\n // It's VITAL that all added resources ends up here so we can clear things\r\n // out when doing a new export in the same page!\r\n injectedResources = await addPageResources(page, options);\r\n\r\n // Get the real chart size and set the zoom accordingly\r\n const size = isSVG\r\n ? await page.evaluate((scale) => {\r\n const svgElement = document.querySelector(\r\n '#chart-container svg:first-of-type'\r\n );\r\n\r\n // Get the values correctly scaled\r\n const chartHeight = svgElement.height.baseVal.value * scale;\r\n const chartWidth = svgElement.width.baseVal.value * scale;\r\n\r\n // In case of SVG the zoom must be set directly for body\r\n // Set the zoom as scale\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = scale;\r\n\r\n // Set the margin to 0px\r\n // eslint-disable-next-line no-undef\r\n document.body.style.margin = '0px';\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n }, parseFloat(exportOptions.scale))\r\n : await page.evaluate(() => {\r\n // eslint-disable-next-line no-undef\r\n const { chartHeight, chartWidth } = window.Highcharts.charts[0];\r\n\r\n // No need for such scale manipulation in case of other types of exports\r\n // Reset the zoom for other exports than to SVGs\r\n // eslint-disable-next-line no-undef\r\n document.body.style.zoom = 1;\r\n\r\n return {\r\n chartHeight,\r\n chartWidth\r\n };\r\n });\r\n\r\n // Set final height and width for viewport\r\n const viewportHeight = Math.ceil(size.chartHeight || exportOptions.height);\r\n const viewportWidth = Math.ceil(size.chartWidth || exportOptions.width);\r\n\r\n // Get the clip region for the page\r\n const { x, y } = await getClipRegion(page);\r\n\r\n // Set the final viewport now that we have the real height\r\n await page.setViewport({\r\n height: viewportHeight,\r\n width: viewportWidth,\r\n deviceScaleFactor: isSVG ? 1 : parseFloat(exportOptions.scale)\r\n });\r\n\r\n let data;\r\n // Rasterization process\r\n if (exportOptions.type === 'svg') {\r\n // SVG\r\n data = await createSVG(page);\r\n } else if (['png', 'jpeg'].includes(exportOptions.type)) {\r\n // PNG or JPEG\r\n data = await createImage(\r\n page,\r\n exportOptions.type,\r\n 'base64',\r\n {\r\n width: viewportWidth,\r\n height: viewportHeight,\r\n x,\r\n y\r\n },\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else if (exportOptions.type === 'pdf') {\r\n // PDF\r\n data = await createPDF(\r\n page,\r\n viewportHeight,\r\n viewportWidth,\r\n 'base64',\r\n exportOptions.rasterizationTimeout\r\n );\r\n } else {\r\n throw new ExportError(\r\n `[export] Unsupported output format ${exportOptions.type}.`\r\n );\r\n }\r\n\r\n // Clear previously injected JS and CSS resources\r\n await clearPageResources(page, injectedResources);\r\n return data;\r\n } catch (error) {\r\n await clearPageResources(page, injectedResources);\r\n return error;\r\n }\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport cssTemplate from './css.js';\r\n\r\nexport default (chart) => `\r\n\r\n\r\n \r\n \r\n Highcharts Export\r\n \r\n \r\n \r\n
\r\n ${chart}\r\n
\r\n \r\n\r\n\r\n`;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { Pool } from 'tarn';\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport {\r\n create as createBrowser,\r\n close as closeBrowser,\r\n newPage,\r\n clearPage\r\n} from './browser.js';\r\nimport puppeteerExport from './export.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { measureTime } from './utils.js';\r\n\r\nimport ExportError from './errors/ExportError.js';\r\n\r\n// The pool instance\r\nlet pool = false;\r\n\r\n// Pool statistics\r\nexport const stats = {\r\n performedExports: 0,\r\n exportAttempts: 0,\r\n exportFromSvgAttempts: 0,\r\n timeSpent: 0,\r\n droppedExports: 0,\r\n spentAverage: 0\r\n};\r\n\r\nlet poolConfig = {};\r\n\r\nconst factory = {\r\n /**\r\n * Creates a new worker page for the export pool.\r\n *\r\n * @returns {Object} - An object containing the worker ID, a reference to the\r\n * browser page, and initial work count.\r\n *\r\n * @throws {ExportError} - If there's an error during the creation of the new\r\n * page.\r\n */\r\n create: async () => {\r\n let page = false;\r\n\r\n const id = uuid();\r\n const startDate = new Date().getTime();\r\n\r\n try {\r\n page = await newPage();\r\n\r\n if (!page || page.isClosed()) {\r\n throw new ExportError('The page is invalid or closed.');\r\n }\r\n\r\n log(\r\n 3,\r\n `[pool] Successfully created a worker ${id} - took ${\r\n new Date().getTime() - startDate\r\n } ms.`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n 'Error encountered when creating a new page.'\r\n ).setError(error);\r\n }\r\n\r\n return {\r\n id,\r\n page,\r\n // Try to distribute the initial work count\r\n workCount: Math.round(Math.random() * (poolConfig.workLimit / 2))\r\n };\r\n },\r\n\r\n /**\r\n * Validates a worker page in the export pool, checking if it has exceeded\r\n * the work limit.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing the\r\n * worker's ID, a reference to the browser page, and work count.\r\n *\r\n * @returns {boolean} - Returns true if the worker is valid and within\r\n * the work limit; otherwise, returns false.\r\n */\r\n validate: async (workerHandle) => {\r\n if (\r\n poolConfig.workLimit &&\r\n ++workerHandle.workCount > poolConfig.workLimit\r\n ) {\r\n log(\r\n 3,\r\n `[pool] Worker failed validation: exceeded work limit (limit is ${poolConfig.workLimit}).`\r\n );\r\n return false;\r\n }\r\n return true;\r\n },\r\n\r\n /**\r\n * Destroys a worker entry in the export pool, closing its associated page.\r\n *\r\n * @param {Object} workerHandle - The handle to the worker, containing\r\n * the worker's ID and a reference to the browser page.\r\n */\r\n destroy: async (workerHandle) => {\r\n log(3, `[pool] Destroying pool entry ${workerHandle.id}.`);\r\n\r\n if (workerHandle.page) {\r\n // We don't really need to wait around for this\r\n await workerHandle.page.close();\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Initializes the export pool with the provided configuration, creating\r\n * a browser instance and setting up worker resources.\r\n *\r\n * @param {Object} config - Configuration options for the export pool along\r\n * with custom puppeteer arguments for the puppeteer.launch function.\r\n */\r\nexport const initPool = async (config) => {\r\n // For the module scope usage\r\n poolConfig = config && config.pool ? { ...config.pool } : {};\r\n\r\n // Create a browser instance with the puppeteer arguments\r\n await createBrowser(config.puppeteerArgs);\r\n\r\n log(\r\n 3,\r\n `[pool] Initializing pool with workers: min ${poolConfig.minWorkers}, max ${poolConfig.maxWorkers}.`\r\n );\r\n\r\n if (pool) {\r\n return log(\r\n 4,\r\n '[pool] Already initialized, please kill it before creating a new one.'\r\n );\r\n }\r\n\r\n if (parseInt(poolConfig.minWorkers) > parseInt(poolConfig.maxWorkers)) {\r\n poolConfig.minWorkers = poolConfig.maxWorkers;\r\n }\r\n\r\n try {\r\n // Create a pool along with a minimal number of resources\r\n pool = new Pool({\r\n // Get the create/validate/destroy/log functions\r\n ...factory,\r\n min: parseInt(poolConfig.minWorkers),\r\n max: parseInt(poolConfig.maxWorkers),\r\n acquireTimeoutMillis: poolConfig.acquireTimeout,\r\n createTimeoutMillis: poolConfig.createTimeout,\r\n destroyTimeoutMillis: poolConfig.destroyTimeout,\r\n idleTimeoutMillis: poolConfig.idleTimeout,\r\n createRetryIntervalMillis: poolConfig.createRetryInterval,\r\n reapIntervalMillis: poolConfig.reaperInterval,\r\n propagateCreateError: false\r\n });\r\n\r\n // Set events\r\n pool.on('release', async (resource) => {\r\n // Clear page\r\n await clearPage(resource.page, false);\r\n log(4, `[pool] Releasing a worker with ID ${resource.id}.`);\r\n });\r\n\r\n pool.on('destroySuccess', (eventId, resource) => {\r\n log(4, `[pool] Destroyed a worker with ID ${resource.id}.`);\r\n });\r\n\r\n const initialResources = [];\r\n // Create an initial number of resources\r\n for (let i = 0; i < poolConfig.minWorkers; i++) {\r\n try {\r\n const resource = await pool.acquire().promise;\r\n initialResources.push(resource);\r\n } catch (error) {\r\n logWithStack(2, error, '[pool] Could not create an initial resource.');\r\n }\r\n }\r\n\r\n // Release the initial number of resources back to the pool\r\n initialResources.forEach((resource) => {\r\n pool.release(resource);\r\n });\r\n\r\n log(\r\n 3,\r\n `[pool] The pool is ready${initialResources.length ? ` with ${initialResources.length} initial resources waiting.` : '.'}`\r\n );\r\n } catch (error) {\r\n throw new ExportError(\r\n '[pool] Could not create the pool of workers.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Kills all workers in the pool, destroys the pool, and closes the browser\r\n * instance.\r\n *\r\n * @returns {Promise} A promise that resolves after the workers are\r\n * killed, the pool is destroyed, and the browser is closed.\r\n */\r\nexport async function killPool() {\r\n log(3, '[pool] Killing pool with all workers and closing browser.');\r\n\r\n // If still alive, destroy the pool of pages before closing a browser\r\n if (pool) {\r\n // Free up not released workers\r\n for (const worker of pool.used) {\r\n pool.release(worker.resource);\r\n }\r\n\r\n // Destroy the pool if it is still available\r\n if (!pool.destroyed) {\r\n await pool.destroy();\r\n log(4, '[browser] Destroyed the pool of resources.');\r\n }\r\n }\r\n\r\n // Close the browser instance\r\n await closeBrowser();\r\n}\r\n\r\n/**\r\n * Processes the export work using a worker from the pool. Acquires a worker\r\n * handle from the pool, performs the export using puppeteer, and releases\r\n * the worker handle back to the pool.\r\n *\r\n * @param {string} chart - The chart data or configuration to be exported.\r\n * @param {Object} options - Export options and configuration.\r\n *\r\n * @returns {Promise} A promise that resolves with the export resultand\r\n * options.\r\n *\r\n * @throws {ExportError} If an error occurs during the export process.\r\n */\r\nexport const postWork = async (chart, options) => {\r\n let workerHandle;\r\n\r\n try {\r\n log(4, '[pool] Work received, starting to process.');\r\n\r\n ++stats.exportAttempts;\r\n if (poolConfig.benchmarking) {\r\n getPoolInfo();\r\n }\r\n\r\n if (!pool) {\r\n throw new ExportError('Work received, but pool has not been started.');\r\n }\r\n\r\n // Acquire the worker along with the id of resource and work count\r\n const acquireCounter = measureTime();\r\n try {\r\n log(4, '[pool] Acquiring a worker handle.');\r\n workerHandle = await pool.acquire().promise;\r\n\r\n // Check the page acquire time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Acquired a worker handle: ${acquireCounter()}ms.`\r\n );\r\n }\r\n } catch (error) {\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') +\r\n `Error encountered when acquiring an available entry: ${acquireCounter()}ms.`\r\n ).setError(error);\r\n }\r\n log(4, '[pool] Acquired a worker handle.');\r\n\r\n if (!workerHandle.page) {\r\n throw new ExportError(\r\n 'Resolved worker page is invalid: the pool setup is wonky.'\r\n );\r\n }\r\n\r\n // Save the start time\r\n let workStart = new Date().getTime();\r\n\r\n log(4, `[pool] Starting work on pool entry with ID ${workerHandle.id}.`);\r\n\r\n // Perform an export on a puppeteer level\r\n const exportCounter = measureTime();\r\n const result = await puppeteerExport(workerHandle.page, chart, options);\r\n\r\n // Check if it's an error\r\n if (result instanceof Error) {\r\n // 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.\r\n if (result.message === 'Rasterization timeout') {\r\n workerHandle.page.close();\r\n workerHandle.page = await newPage();\r\n }\r\n\r\n throw new ExportError(\r\n (options.payload?.requestId\r\n ? `For request with ID ${options.payload?.requestId} - `\r\n : '') + `Error encountered during export: ${exportCounter()}ms.`\r\n ).setError(result);\r\n }\r\n\r\n // Check the Puppeteer export time\r\n if (options.server.benchmarking) {\r\n log(\r\n 5,\r\n options.payload?.requestId\r\n ? `[benchmark] Request with ID ${options.payload?.requestId} -`\r\n : '[benchmark]',\r\n `Exported a chart sucessfully: ${exportCounter()}ms.`\r\n );\r\n }\r\n\r\n // Release the resource back to the pool\r\n pool.release(workerHandle);\r\n\r\n // Used for statistics in averageTime and processedWorkCount, which\r\n // in turn is used by the /health route.\r\n const workEnd = new Date().getTime();\r\n const exportTime = workEnd - workStart;\r\n stats.timeSpent += exportTime;\r\n stats.spentAverage = stats.timeSpent / ++stats.performedExports;\r\n\r\n log(4, `[pool] Work completed in ${exportTime} ms.`);\r\n\r\n // Otherwise return the result\r\n return {\r\n result,\r\n options\r\n };\r\n } catch (error) {\r\n ++stats.droppedExports;\r\n\r\n if (workerHandle) {\r\n pool.release(workerHandle);\r\n }\r\n\r\n throw new ExportError(`[pool] In pool.postWork: ${error.message}`).setError(\r\n error\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves the current pool instance.\r\n *\r\n * @returns {Object|null} The current pool instance if initialized, or null\r\n * if the pool has not been created.\r\n */\r\nexport const getPool = () => pool;\r\n\r\n/**\r\n * Retrieves pool information in JSON format, including minimum and maximum\r\n * workers, available workers, workers in use, and pending acquire requests.\r\n *\r\n * @returns {Object} Pool information in JSON format.\r\n */\r\nexport const getPoolInfoJSON = () => ({\r\n min: pool.min,\r\n max: pool.max,\r\n all: pool.numFree() + pool.numUsed(),\r\n available: pool.numFree(),\r\n used: pool.numUsed(),\r\n pending: pool.numPendingAcquires()\r\n});\r\n\r\n/**\r\n * Logs information about the current state of the pool, including the minimum\r\n * and maximum workers, available workers, workers in use, and pending acquire\r\n * requests.\r\n */\r\nexport function getPoolInfo() {\r\n const { min, max, all, available, used, pending } = getPoolInfoJSON();\r\n\r\n log(5, `[pool] The minimum number of resources allowed by pool: ${min}.`);\r\n log(5, `[pool] The maximum number of resources allowed by pool: ${max}.`);\r\n log(5, `[pool] The number of all created resources: ${all}.`);\r\n log(5, `[pool] The number of available resources: ${available}.`);\r\n log(5, `[pool] The number of acquired resources: ${used}.`);\r\n log(5, `[pool] The number of resources waiting to be acquired: ${pending}.`);\r\n}\r\n\r\nexport default {\r\n initPool,\r\n killPool,\r\n postWork,\r\n getPool,\r\n getPoolInfo,\r\n getPoolInfoJSON,\r\n getStats: () => stats\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync, writeFileSync } from 'fs';\r\n\r\nimport { getOptions, initExportSettings } from './config.js';\r\nimport { log, logWithStack } from './logger.js';\r\nimport { killPool, postWork, stats } from './pool.js';\r\nimport {\r\n fixType,\r\n handleResources,\r\n isCorrectJSON,\r\n optionsStringify,\r\n roundNumber,\r\n toBoolean,\r\n wrapAround\r\n} from './utils.js';\r\nimport { sanitize } from './sanitize.js';\r\nimport ExportError from './errors/ExportError.js';\r\n\r\nlet allowCodeExecution = false;\r\n\r\n/**\r\n * Starts an export process. The `settings` contains final options gathered\r\n * from all possible sources (config, env, cli, json). The `endCallback` is\r\n * called when the export is completed, with an error object as the first\r\n * argument and the second containing the base64 respresentation of a chart.\r\n *\r\n * @param {Object} settings - The settings object containing export\r\n * configuration.\r\n * @param {function} endCallback - The callback function to be invoked upon\r\n * finalizing work or upon error occurance of the exporting process.\r\n *\r\n * @returns {void} This function does not return a value directly; instead,\r\n * it communicates results via the endCallback.\r\n */\r\nexport const startExport = async (settings, endCallback) => {\r\n // Starting exporting process message\r\n log(4, '[chart] Starting the exporting process.');\r\n\r\n // Initialize options\r\n const options = initExportSettings(settings, getOptions());\r\n\r\n // Get the export options\r\n const exportOptions = options.export;\r\n\r\n // If SVG is an input (argument can be sent only by the request)\r\n if (options.payload?.svg && options.payload.svg !== '') {\r\n try {\r\n log(4, '[chart] Attempting to export from a SVG input.');\r\n\r\n const result = exportAsString(\r\n sanitize(options.payload.svg), // #209\r\n options,\r\n endCallback\r\n );\r\n\r\n ++stats.exportFromSvgAttempts;\r\n return result;\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading SVG input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export using options from the file\r\n if (exportOptions.infile && exportOptions.infile.length) {\r\n // Try to read the file to get the string representation\r\n try {\r\n log(4, '[chart] Attempting to export from an input file.');\r\n options.export.instr = readFileSync(exportOptions.infile, 'utf8');\r\n return exportAsString(options.export.instr.trim(), options, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading input file.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // Export with options from the raw representation\r\n if (\r\n (exportOptions.instr && exportOptions.instr !== '') ||\r\n (exportOptions.options && exportOptions.options !== '')\r\n ) {\r\n try {\r\n log(4, '[chart] Attempting to export from a raw input.');\r\n\r\n // Perform a direct inject when forced\r\n if (toBoolean(options.customLogic?.allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n }\r\n\r\n // Either try to parse to JSON first or do the direct export\r\n return typeof exportOptions.instr === 'string'\r\n ? exportAsString(exportOptions.instr.trim(), options, endCallback)\r\n : doExport(\r\n options,\r\n exportOptions.instr || exportOptions.options,\r\n endCallback\r\n );\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError('[chart] Error loading raw input.').setError(error)\r\n );\r\n }\r\n }\r\n\r\n // No input specified, pass an error message to the callback\r\n return endCallback(\r\n new ExportError(\r\n `[chart] No valid input specified. Check if at least one of the following parameters is correctly set: 'infile', 'instr', 'options', or 'svg'.`\r\n )\r\n );\r\n};\r\n\r\n/**\r\n * Starts a batch export process for multiple charts based on the information\r\n * in the batch option. The batch is a string in the following format:\r\n * \"infile1.json=outfile1.png;infile2.json=outfile2.png;...\"\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a batch export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the batch export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * any of the batch export process.\r\n */\r\nexport const batchExport = async (options) => {\r\n const batchFunctions = [];\r\n\r\n // Split and pair the --batch arguments\r\n for (let pair of options.export.batch.split(';')) {\r\n pair = pair.split('=');\r\n if (pair.length === 2) {\r\n batchFunctions.push(\r\n startExport(\r\n {\r\n ...options,\r\n export: {\r\n ...options.export,\r\n infile: pair[0],\r\n outfile: pair[1]\r\n }\r\n },\r\n (error, info) => {\r\n // Throw an error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n info.options.export.outfile,\r\n info.options.export.type !== 'svg'\r\n ? Buffer.from(info.result, 'base64')\r\n : info.result\r\n );\r\n }\r\n )\r\n );\r\n }\r\n }\r\n\r\n try {\r\n // Await all exports are done\r\n await Promise.all(batchFunctions);\r\n\r\n // Kill pool and close browser after finishing batch export\r\n await killPool();\r\n } catch (error) {\r\n throw new ExportError(\r\n '[chart] Error encountered during batch export.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Starts a single export process based on the specified options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * a single export.\r\n *\r\n * @returns {Promise} A Promise that resolves once the single export\r\n * process is completed.\r\n *\r\n * @throws {ExportError} Throws an ExportError if an error occurs during\r\n * the single export process.\r\n */\r\nexport const singleExport = async (options) => {\r\n // Use instr or its alias, options\r\n options.export.instr = options.export.instr || options.export.options;\r\n\r\n // Perform an export\r\n await startExport(options, async (error, info) => {\r\n // Exit process when error\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n const { outfile, type } = info.options.export;\r\n\r\n // Save the base64 from a buffer to a correct image file\r\n writeFileSync(\r\n outfile || `chart.${type}`,\r\n type !== 'svg' ? Buffer.from(info.result, 'base64') : info.result\r\n );\r\n\r\n // Kill pool and close browser after finishing single export\r\n await killPool();\r\n });\r\n};\r\n\r\n/**\r\n * Determines the size and scale for chart export based on the provided options.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * chart export.\r\n *\r\n * @returns {Object} An object containing the calculated height, width,\r\n * and scale for the chart export.\r\n */\r\nexport const findChartSize = (options) => {\r\n const { chart, exporting } =\r\n options.export?.options || isCorrectJSON(options.export?.instr);\r\n\r\n // See if globalOptions holds chart or exporting size\r\n const globalOptions = isCorrectJSON(options.export?.globalOptions);\r\n\r\n // Secure scale value\r\n let scale =\r\n options.export?.scale ||\r\n exporting?.scale ||\r\n globalOptions?.exporting?.scale ||\r\n options.export?.defaultScale ||\r\n 1;\r\n\r\n // the scale cannot be lower than 0.1 and cannot be higher than 5.0\r\n scale = Math.max(0.1, Math.min(scale, 5.0));\r\n\r\n // we want to round the numbers like 0.23234 -> 0.23\r\n scale = roundNumber(scale, 2);\r\n\r\n // Find chart size and scale\r\n const size = {\r\n height:\r\n options.export?.height ||\r\n exporting?.sourceHeight ||\r\n chart?.height ||\r\n globalOptions?.exporting?.sourceHeight ||\r\n globalOptions?.chart?.height ||\r\n options.export?.defaultHeight ||\r\n 400,\r\n width:\r\n options.export?.width ||\r\n exporting?.sourceWidth ||\r\n chart?.width ||\r\n globalOptions?.exporting?.sourceWidth ||\r\n globalOptions?.chart?.width ||\r\n options.export?.defaultWidth ||\r\n 600,\r\n scale\r\n };\r\n\r\n // Get rid of potential px and %\r\n for (let [param, value] of Object.entries(size)) {\r\n size[param] =\r\n typeof value === 'string' ? +value.replace(/px|%/gi, '') : value;\r\n }\r\n return size;\r\n};\r\n\r\n/**\r\n * Function for finalizing options before export.\r\n *\r\n * @param {Object} options - The options object containing configuration for\r\n * the export process.\r\n * @param {Object} chartJson - The JSON representation of the chart.\r\n * @param {Function} endCallback - The callback function to be called upon\r\n * completion or error.\r\n * @param {string} svg - The SVG representation of the chart.\r\n *\r\n * @returns {Promise} A Promise that resolves once the export process\r\n * is completed.\r\n */\r\nconst doExport = async (options, chartJson, endCallback, svg) => {\r\n let { export: exportOptions, customLogic: customLogicOptions } = options;\r\n\r\n const allowCodeExecutionScoped =\r\n typeof customLogicOptions.allowCodeExecution === 'boolean'\r\n ? customLogicOptions.allowCodeExecution\r\n : allowCodeExecution;\r\n\r\n if (!customLogicOptions) {\r\n customLogicOptions = options.customLogic = {};\r\n } else if (allowCodeExecutionScoped) {\r\n if (typeof options.customLogic.resources === 'string') {\r\n // Process resources\r\n options.customLogic.resources = handleResources(\r\n options.customLogic.resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } else if (!options.customLogic.resources) {\r\n try {\r\n const resources = readFileSync('resources.json', 'utf8');\r\n options.customLogic.resources = handleResources(\r\n resources,\r\n toBoolean(options.customLogic.allowFileResources)\r\n );\r\n } catch (error) {\r\n logWithStack(\r\n 2,\r\n error,\r\n `[chart] Unable to load the default resources.json file.`\r\n );\r\n }\r\n }\r\n }\r\n\r\n // If the allowCodeExecution flag isn't set, we should refuse the usage\r\n // of callback, resources, and custom code. Additionally, the worker will\r\n // refuse to run arbitrary JavaScript. Prioritized should be the scoped\r\n // option, then we should take a look at the overall pool option.\r\n if (!allowCodeExecutionScoped && customLogicOptions) {\r\n if (\r\n customLogicOptions.callback ||\r\n customLogicOptions.resources ||\r\n customLogicOptions.customCode\r\n ) {\r\n // Send back a friendly message saying that the exporter does not support\r\n // these settings.\r\n return endCallback(\r\n new ExportError(\r\n `[chart] The 'callback', 'resources' and 'customCode' options have been disabled for this server.`\r\n )\r\n );\r\n }\r\n\r\n // Reset all additional custom code\r\n customLogicOptions.callback = false;\r\n customLogicOptions.resources = false;\r\n customLogicOptions.customCode = false;\r\n }\r\n\r\n // Clean properties to keep it lean and mean\r\n if (chartJson) {\r\n chartJson.chart = chartJson.chart || {};\r\n chartJson.exporting = chartJson.exporting || {};\r\n chartJson.exporting.enabled = false;\r\n }\r\n\r\n exportOptions.constr = exportOptions.constr || 'chart';\r\n exportOptions.type = fixType(exportOptions.type, exportOptions.outfile);\r\n if (exportOptions.type === 'svg') {\r\n exportOptions.width = false;\r\n }\r\n\r\n // Prepare global and theme options\r\n ['globalOptions', 'themeOptions'].forEach((optionsName) => {\r\n try {\r\n if (exportOptions && exportOptions[optionsName]) {\r\n if (\r\n typeof exportOptions[optionsName] === 'string' &&\r\n exportOptions[optionsName].endsWith('.json')\r\n ) {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n readFileSync(exportOptions[optionsName], 'utf8'),\r\n true\r\n );\r\n } else {\r\n exportOptions[optionsName] = isCorrectJSON(\r\n exportOptions[optionsName],\r\n true\r\n );\r\n }\r\n }\r\n } catch (error) {\r\n exportOptions[optionsName] = {};\r\n logWithStack(2, error, `[chart] The '${optionsName}' cannot be loaded.`);\r\n }\r\n });\r\n\r\n // Prepare the customCode\r\n if (customLogicOptions.allowCodeExecution) {\r\n try {\r\n customLogicOptions.customCode = wrapAround(\r\n customLogicOptions.customCode,\r\n customLogicOptions.allowFileResources\r\n );\r\n } catch (error) {\r\n logWithStack(2, error, `[chart] The 'customCode' cannot be loaded.`);\r\n }\r\n }\r\n\r\n // Get the callback\r\n if (\r\n customLogicOptions &&\r\n customLogicOptions.callback &&\r\n customLogicOptions.callback?.indexOf('{') < 0\r\n ) {\r\n // The allowFileResources is always set to false for HTTP requests to avoid\r\n // injecting arbitrary files from the fs\r\n if (customLogicOptions.allowFileResources) {\r\n try {\r\n customLogicOptions.callback = readFileSync(\r\n customLogicOptions.callback,\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n customLogicOptions.callback = false;\r\n logWithStack(2, error, `[chart] The 'callback' cannot be loaded.`);\r\n }\r\n } else {\r\n customLogicOptions.callback = false;\r\n }\r\n }\r\n\r\n // Size search\r\n options.export = {\r\n ...options.export,\r\n ...findChartSize(options)\r\n };\r\n\r\n // Post the work to the pool\r\n try {\r\n const result = await postWork(\r\n exportOptions.strInj || chartJson || svg,\r\n options\r\n );\r\n return endCallback(false, result);\r\n } catch (error) {\r\n return endCallback(error);\r\n }\r\n};\r\n\r\n/**\r\n * Performs a direct inject of options before export. The function attempts\r\n * to stringify the provided options and removes unnecessary characters,\r\n * ensuring a clean and formatted input. The resulting string is saved as\r\n * a \"stright inject\" string in the export options. It then invokes the\r\n * doExport function with the updated options.\r\n *\r\n * IMPORTANT: Dangerous and must be used deliberately by someone who sets up\r\n * a server (see the --allowCodeExecution option).\r\n *\r\n * @param {Object} options - The export options containing the input\r\n * to be injected.\r\n * @param {function} endCallback - The callback function to be invoked\r\n * at the end of the process.\r\n *\r\n * @returns {Promise} A Promise that resolves with the result of the export\r\n * operation or rejects with an error if any issues occur during the process.\r\n */\r\nconst doStraightInject = (options, endCallback) => {\r\n try {\r\n let strInj;\r\n let instr = options.export.instr || options.export.options;\r\n\r\n if (typeof instr !== 'string') {\r\n // Try to stringify options\r\n strInj = instr = optionsStringify(\r\n instr,\r\n options.customLogic?.allowCodeExecution\r\n );\r\n }\r\n strInj = instr.replaceAll(/\\t|\\n|\\r/g, '').trim();\r\n\r\n // Get rid of the ;\r\n if (strInj[strInj.length - 1] === ';') {\r\n strInj = strInj.substring(0, strInj.length - 1);\r\n }\r\n\r\n // Save as stright inject string\r\n options.export.strInj = strInj;\r\n return doExport(options, false, endCallback);\r\n } catch (error) {\r\n return endCallback(\r\n new ExportError(\r\n `[chart] Malformed input detected for ${options.export?.requestId || '?'}. Please make sure that your JSON/JavaScript options are sent using the \"options\" attribute, and that if you're using SVG, it is unescaped.`\r\n ).setError(error)\r\n );\r\n }\r\n};\r\n\r\n/**\r\n * Exports a string based on the provided options and invokes an end callback.\r\n *\r\n * @param {string} stringToExport - The string content to be exported.\r\n * @param {Object} options - Export options, including customLogic with\r\n * allowCodeExecution flag.\r\n * @param {Function} endCallback - Callback function to be invoked at the end\r\n * of the export process.\r\n *\r\n * @returns {any} Result of the export process or an error if encountered.\r\n */\r\nconst exportAsString = (stringToExport, options, endCallback) => {\r\n const { allowCodeExecution } = options.customLogic;\r\n\r\n // Check if it is SVG\r\n if (\r\n stringToExport.indexOf('= 0 ||\r\n stringToExport.indexOf('= 0\r\n ) {\r\n log(4, '[chart] Parsing input as SVG.');\r\n return doExport(options, false, endCallback, stringToExport);\r\n }\r\n\r\n try {\r\n // Try to parse to JSON and call the doExport function\r\n const chartJSON = JSON.parse(stringToExport.replaceAll(/\\t|\\n|\\r/g, ' '));\r\n\r\n // If a correct JSON, do the export\r\n return doExport(options, chartJSON, endCallback);\r\n } catch (error) {\r\n // Not a valid JSON\r\n if (toBoolean(allowCodeExecution)) {\r\n return doStraightInject(options, endCallback);\r\n } else {\r\n // Do not allow straight injection without the allowCodeExecution flag\r\n return endCallback(\r\n new ExportError(\r\n '[chart] Only JSON configurations and SVG are allowed for this server. If this is your server, JavaScript custom code can be enabled by starting the server with the --allowCodeExecution flag.'\r\n ).setError(error)\r\n );\r\n }\r\n }\r\n};\r\n\r\n/**\r\n * Retrieves and returns the current status of code execution permission.\r\n *\r\n * @returns {any} The value of allowCodeExecution.\r\n */\r\nexport const getAllowCodeExecution = () => allowCodeExecution;\r\n\r\n/**\r\n * Sets the code execution permission based on the provided boolean value.\r\n *\r\n * @param {any} value - The value to be converted and assigned\r\n * to allowCodeExecution.\r\n */\r\nexport const setAllowCodeExecution = (value) => {\r\n allowCodeExecution = toBoolean(value);\r\n};\r\n\r\nexport default {\r\n batchExport,\r\n singleExport,\r\n getAllowCodeExecution,\r\n setAllowCodeExecution,\r\n startExport,\r\n findChartSize\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\n/**\r\n * @overview Used to sanitize the strings coming from the exporting module\r\n * to prevent XSS attacks (with the DOMPurify library).\r\n **/\r\n\r\nimport { JSDOM } from 'jsdom';\r\nimport DOMPurify from 'dompurify';\r\n\r\n/**\r\n * Sanitizes a given HTML string by removing tags and any content within them.\r\n *\r\n * @param {string} input The HTML string to be sanitized.\r\n * @returns {string} The sanitized HTML string.\r\n */\r\nexport function sanitize(input) {\r\n const window = new JSDOM('').window;\r\n const purify = DOMPurify(window);\r\n return purify.sanitize(input, { ADD_TAGS: ['foreignObject'] });\r\n}\r\n\r\nexport default sanitize;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { log } from './logger.js';\r\n\r\n// Array that contains ids of all ongoing intervals\r\nconst intervalIds = [];\r\n\r\n/**\r\n * Adds id of a setInterval to the intervalIds array.\r\n *\r\n * @param {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const addInterval = (id) => {\r\n intervalIds.push(id);\r\n};\r\n\r\n/**\r\n * Clears all of ongoing intervals by ids gathered in the intervalIds array.\r\n */\r\nexport const clearAllIntervals = () => {\r\n log(4, `[server] Clearing all registered intervals.`);\r\n for (const id of intervalIds) {\r\n clearInterval(id);\r\n }\r\n};\r\n\r\nexport default {\r\n addInterval,\r\n clearAllIntervals\r\n};\r\n","import { envs } from '../envs.js';\r\nimport { logWithStack } from '../logger.js';\r\n\r\n/**\r\n * Middleware for logging errors with stack trace and handling error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst logErrorMiddleware = (error, req, res, next) => {\r\n // Display the error with stack in a correct format\r\n logWithStack(1, error);\r\n\r\n // Delete the stack for the environment other than the development\r\n if (envs.OTHER_NODE_ENV !== 'development') {\r\n delete error.stack;\r\n }\r\n\r\n // Call the returnErrorMiddleware\r\n next(error);\r\n};\r\n\r\n/**\r\n * Middleware for returning error response.\r\n *\r\n * @param {Error} error - The error object.\r\n * @param {Express.Request} req - The Express request object.\r\n * @param {Express.Response} res - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n */\r\nconst returnErrorMiddleware = (error, req, res, next) => {\r\n // Gather all requied information for the response\r\n const { statusCode: stCode, status, message, stack } = error;\r\n const statusCode = stCode || status || 500;\r\n\r\n // Set and return response\r\n res.status(statusCode).json({ statusCode, message, stack });\r\n};\r\n\r\nexport default (app) => {\r\n // Add log error middleware\r\n app.use(logErrorMiddleware);\r\n\r\n // Add set status and return error middleware\r\n app.use(returnErrorMiddleware);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport rateLimit from 'express-rate-limit';\r\n\r\nimport { log } from '../logger.js';\r\n\r\n/**\r\n * Middleware for enabling rate limiting on the specified Express app.\r\n *\r\n * @param {Express} app - The Express app instance.\r\n * @param {Object} limitConfig - Configuration options for rate limiting.\r\n */\r\nexport default (app, limitConfig) => {\r\n const msg =\r\n 'Too many requests, you have been rate limited. Please try again later.';\r\n\r\n // Options for the rate limiter\r\n const rateOptions = {\r\n max: limitConfig.maxRequests || 30,\r\n window: limitConfig.window || 1,\r\n delay: limitConfig.delay || 0,\r\n trustProxy: limitConfig.trustProxy || false,\r\n skipKey: limitConfig.skipKey || false,\r\n skipToken: limitConfig.skipToken || false\r\n };\r\n\r\n // Set if behind a proxy\r\n if (rateOptions.trustProxy) {\r\n app.enable('trust proxy');\r\n }\r\n\r\n // Create a limiter\r\n const limiter = rateLimit({\r\n windowMs: rateOptions.window * 60 * 1000,\r\n // Limit each IP to 100 requests per windowMs\r\n max: rateOptions.max,\r\n // Disable delaying, full speed until the max limit is reached\r\n delayMs: rateOptions.delay,\r\n handler: (request, response) => {\r\n response.format({\r\n json: () => {\r\n response.status(429).send({ message: msg });\r\n },\r\n default: () => {\r\n response.status(429).send(msg);\r\n }\r\n });\r\n },\r\n skip: (request) => {\r\n // Allow bypassing the limiter if a valid key/token has been sent\r\n if (\r\n rateOptions.skipKey !== false &&\r\n rateOptions.skipToken !== false &&\r\n request.query.key === rateOptions.skipKey &&\r\n request.query.access_token === rateOptions.skipToken\r\n ) {\r\n log(4, '[rate limiting] Skipping rate limiter.');\r\n return true;\r\n }\r\n return false;\r\n }\r\n });\r\n\r\n // Use a limiter as a middleware\r\n app.use(limiter);\r\n\r\n log(\r\n 3,\r\n `[rate limiting] Enabled rate limiting with ${rateOptions.max} requests per ${rateOptions.window} minute for each IP, trusting proxy: ${rateOptions.trustProxy}.`\r\n );\r\n};\r\n","import ExportError from './ExportError.js';\r\n\r\nclass HttpError extends ExportError {\r\n constructor(message, status) {\r\n super(message);\r\n this.status = this.statusCode = status;\r\n }\r\n\r\n setStatus(status) {\r\n this.status = status;\r\n return this;\r\n }\r\n}\r\n\r\nexport default HttpError;\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { updateVersion, version } from '../../cache.js';\r\nimport { envs } from '../../envs.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n/**\r\n * Adds the POST /change_hc_version/:newVersion route that can be utilized to modify\r\n * the Highcharts version on the server.\r\n *\r\n * TODO: Add auth token and connect to API\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.post(\r\n '/version/change/:newVersion',\r\n async (request, response, next) => {\r\n try {\r\n const adminToken = envs.HIGHCHARTS_ADMIN_TOKEN;\r\n\r\n // Check the existence of the token\r\n if (!adminToken || !adminToken.length) {\r\n throw new HttpError(\r\n 'The server is not configured to perform run-time version changes: HIGHCHARTS_ADMIN_TOKEN is not set.',\r\n 401\r\n );\r\n }\r\n\r\n // Check if the hc-auth header contain a correct token\r\n const token = request.get('hc-auth');\r\n if (!token || token !== adminToken) {\r\n throw new HttpError(\r\n 'Invalid or missing token: Set the token in the hc-auth header.',\r\n 401\r\n );\r\n }\r\n\r\n // Compare versions\r\n const newVersion = request.params.newVersion;\r\n if (newVersion) {\r\n try {\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n await updateVersion(newVersion);\r\n } catch (error) {\r\n throw new HttpError(\r\n `Version change: ${error.message}`,\r\n error.statusCode\r\n ).setError(error);\r\n }\r\n\r\n // Success\r\n response.status(200).send({\r\n statusCode: 200,\r\n version: version(),\r\n message: `Successfully updated Highcharts to version: ${newVersion}.`\r\n });\r\n } else {\r\n // No version specified\r\n throw new HttpError('No new version supplied.', 400);\r\n }\r\n } catch (error) {\r\n next(error);\r\n }\r\n }\r\n );\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { v4 as uuid } from 'uuid';\r\n\r\nimport { getAllowCodeExecution, startExport } from '../../chart.js';\r\nimport { getOptions, mergeConfigOptions } from '../../config.js';\r\nimport { log } from '../../logger.js';\r\nimport {\r\n fixType,\r\n isCorrectJSON,\r\n isObjectEmpty,\r\n isPrivateRangeUrlFound,\r\n optionsStringify,\r\n measureTime\r\n} from '../../utils.js';\r\n\r\nimport HttpError from '../../errors/HttpError.js';\r\n\r\n// Reversed MIME types\r\nconst reversedMime = {\r\n png: 'image/png',\r\n jpeg: 'image/jpeg',\r\n gif: 'image/gif',\r\n pdf: 'application/pdf',\r\n svg: 'image/svg+xml'\r\n};\r\n\r\n// The requests counter\r\nlet requestsCounter = 0;\r\n\r\n// The array of callbacks to call before a request\r\nconst beforeRequest = [];\r\n\r\n// The array of callbacks to call after a request\r\nconst afterRequest = [];\r\n\r\n/**\r\n * Invokes an array of callback functions with specified parameters, allowing\r\n * customization of request handling.\r\n *\r\n * @param {Function[]} callbacks - An array of callback functions\r\n * to be executed.\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Object} data - An object containing parameters like id, uniqueId,\r\n * type, and body.\r\n *\r\n * @returns {boolean} - Returns a boolean indicating the overall result\r\n * of the callback invocations.\r\n */\r\nconst doCallbacks = (callbacks, request, response, data) => {\r\n let result = true;\r\n const { id, uniqueId, type, body } = data;\r\n\r\n callbacks.some((callback) => {\r\n if (callback) {\r\n let callResponse = callback(request, response, id, uniqueId, type, body);\r\n\r\n if (callResponse !== undefined && callResponse !== true) {\r\n result = callResponse;\r\n }\r\n\r\n return true;\r\n }\r\n });\r\n\r\n return result;\r\n};\r\n\r\n/**\r\n * Handles the export requests from the client.\r\n *\r\n * @param {Express.Request} request - The Express request object.\r\n * @param {Express.Response} response - The Express response object.\r\n * @param {Function} next - The next middleware function.\r\n *\r\n * @returns {Promise} - A promise that resolves once the export process\r\n * is complete.\r\n */\r\nconst exportHandler = async (request, response, next) => {\r\n try {\r\n // Start counting time\r\n const stopCounter = measureTime();\r\n\r\n // Create a unique ID for a request\r\n const uniqueId = uuid().replace(/-/g, '');\r\n\r\n // Get the current server's general options\r\n const defaultOptions = getOptions();\r\n\r\n const body = request.body;\r\n const id = ++requestsCounter;\r\n\r\n let type = fixType(body.type);\r\n\r\n // Throw 'Bad Request' if there's no body\r\n if (!body || isObjectEmpty(body)) {\r\n throw new HttpError(\r\n 'The request body is required. Please ensure that your Content-Type header is correct (accepted types are application/json and multipart/form-data).',\r\n 400\r\n );\r\n }\r\n\r\n // All of the below can be used\r\n let instr = isCorrectJSON(body.infile || body.options || body.data);\r\n\r\n // Throw 'Bad Request' if there's no JSON or SVG to export\r\n if (!instr && !body.svg) {\r\n log(\r\n 2,\r\n `The request with ID ${uniqueId} from ${\r\n request.headers['x-forwarded-for'] || request.connection.remoteAddress\r\n } was incorrect. Payload received: ${JSON.stringify(body)}.`\r\n );\r\n\r\n throw new HttpError(\r\n \"No correct chart data found. Ensure that you are using either application/json or multipart/form-data headers. If sending JSON, make sure the chart data is in the 'infile', 'options', or 'data' attribute. If sending SVG, ensure it is in the 'svg' attribute.\",\r\n 400\r\n );\r\n }\r\n\r\n let callResponse = false;\r\n\r\n // Call the before request functions\r\n callResponse = doCallbacks(beforeRequest, request, response, {\r\n id,\r\n uniqueId,\r\n type,\r\n body\r\n });\r\n\r\n // Block the request if one of a callbacks failed\r\n if (callResponse !== true) {\r\n return response.send(callResponse);\r\n }\r\n\r\n let connectionAborted = false;\r\n\r\n // In case the connection is closed, force to abort further actions\r\n request.socket.on('close', () => {\r\n connectionAborted = true;\r\n });\r\n\r\n log(4, `[export] Got an incoming HTTP request with ID ${uniqueId}.`);\r\n\r\n body.constr = (typeof body.constr === 'string' && body.constr) || 'chart';\r\n\r\n // Gather and organize options from the payload\r\n const requestOptions = {\r\n export: {\r\n instr,\r\n type,\r\n constr: body.constr[0].toLowerCase() + body.constr.substr(1),\r\n height: body.height,\r\n width: body.width,\r\n scale: body.scale || defaultOptions.export.scale,\r\n globalOptions: isCorrectJSON(body.globalOptions, true),\r\n themeOptions: isCorrectJSON(body.themeOptions, true)\r\n },\r\n customLogic: {\r\n allowCodeExecution: getAllowCodeExecution(),\r\n allowFileResources: false,\r\n resources: isCorrectJSON(body.resources, true),\r\n callback: body.callback,\r\n customCode: body.customCode\r\n }\r\n };\r\n\r\n if (instr) {\r\n // Stringify JSON with options\r\n requestOptions.export.instr = optionsStringify(\r\n instr,\r\n requestOptions.customLogic.allowCodeExecution\r\n );\r\n }\r\n\r\n // Merge the request options into default ones\r\n const options = mergeConfigOptions(defaultOptions, requestOptions);\r\n\r\n // Save the JSON if exists\r\n options.export.options = instr;\r\n\r\n // Lastly, add the server specific arguments into options as payload\r\n options.payload = {\r\n svg: body.svg || false,\r\n b64: body.b64 || false,\r\n noDownload: body.noDownload || false,\r\n requestId: uniqueId\r\n };\r\n\r\n // Test xlink:href elements from payload's SVG\r\n if (body.svg && isPrivateRangeUrlFound(options.payload.svg)) {\r\n throw new HttpError(\r\n 'SVG potentially contain at least one forbidden URL in xlink:href element. Please review the SVG content and ensure that all referenced URLs comply with security policies.',\r\n 400\r\n );\r\n }\r\n\r\n // Start the export process\r\n await startExport(options, (error, info) => {\r\n // Remove the close event from the socket\r\n request.socket.removeAllListeners('close');\r\n\r\n // After the whole exporting process\r\n if (defaultOptions.server.benchmarking) {\r\n log(\r\n 5,\r\n `[benchmark] Request with ID ${uniqueId} - After the whole exporting process: ${stopCounter()}ms.`\r\n );\r\n }\r\n\r\n // If the connection was closed, do nothing\r\n if (connectionAborted) {\r\n return log(\r\n 3,\r\n `[export] The client closed the connection before the chart finished processing.`\r\n );\r\n }\r\n\r\n // If error, log it and send it to the error middleware\r\n if (error) {\r\n throw error;\r\n }\r\n\r\n // If data is missing, log the message and send it to the error middleware\r\n if (!info || !info.result) {\r\n throw new HttpError(\r\n `Unexpected return from chart generation. Please check your request data. For the request with ID ${uniqueId}, the result is ${info.result}.`,\r\n 400\r\n );\r\n }\r\n\r\n // Get the type from options\r\n type = info.options.export.type;\r\n\r\n // The after request callbacks\r\n doCallbacks(afterRequest, request, response, { id, body: info.result });\r\n\r\n if (info.result) {\r\n // If only base64 is required, return it\r\n if (body.b64) {\r\n // SVG Exception for the Highcharts 11.3.0 version\r\n if (type === 'pdf' || type == 'svg') {\r\n return response.send(\r\n Buffer.from(info.result, 'utf8').toString('base64')\r\n );\r\n }\r\n\r\n return response.send(info.result);\r\n }\r\n\r\n // Set correct content type\r\n response.header('Content-Type', reversedMime[type] || 'image/png');\r\n\r\n // Decide whether to download or not chart file\r\n if (!body.noDownload) {\r\n response.attachment(\r\n `${request.params.filename || request.body.filename || 'chart'}.${\r\n type || 'png'\r\n }`\r\n );\r\n }\r\n\r\n // If SVG, return plain content\r\n return type === 'svg'\r\n ? response.send(info.result)\r\n : response.send(Buffer.from(info.result, 'base64'));\r\n }\r\n });\r\n } catch (error) {\r\n next(error);\r\n }\r\n};\r\n\r\nexport default (app) => {\r\n /**\r\n * Adds the POST / a route for handling POST requests at the root endpoint.\r\n */\r\n app.post('/', exportHandler);\r\n\r\n /**\r\n * Adds the POST /:filename a route for handling POST requests with\r\n * a specified filename parameter.\r\n */\r\n app.post('/:filename', exportHandler);\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { readFileSync } from 'fs';\r\nimport { join as pather } from 'path';\r\nimport { log } from '../../logger.js';\r\n\r\nimport { version } from '../../cache.js';\r\nimport { addInterval } from '../../intervals.js';\r\nimport pool from '../../pool.js';\r\nimport { __dirname } from '../../utils.js';\r\n\r\nconst pkgFile = JSON.parse(readFileSync(pather(__dirname, 'package.json')));\r\n\r\nconst serverStartTime = new Date();\r\n\r\nconst successRates = [];\r\nconst recordInterval = 60 * 1000; // record every minute\r\nconst windowSize = 30; // 30 minutes\r\n\r\n/**\r\n * Calculates moving average indicator based on the data from the successRates\r\n * array.\r\n *\r\n * @returns {number} - A moving average for success ratio of the server exports.\r\n */\r\nfunction calculateMovingAverage() {\r\n const sum = successRates.reduce((a, b) => a + b, 0);\r\n return sum / successRates.length;\r\n}\r\n\r\n/**\r\n * Starts the interval responsible for calculating current success rate ratio\r\n * and gathers\r\n *\r\n * @returns {NodeJS.Timeout} id - Id of an interval.\r\n */\r\nexport const startSuccessRate = () =>\r\n setInterval(() => {\r\n const stats = pool.getStats();\r\n const successRatio =\r\n stats.exportAttempts === 0\r\n ? 1\r\n : (stats.performedExports / stats.exportAttempts) * 100;\r\n\r\n successRates.push(successRatio);\r\n if (successRates.length > windowSize) {\r\n successRates.shift();\r\n }\r\n }, recordInterval);\r\n\r\n/**\r\n * Adds the /health and /success-moving-average routes\r\n * which output basic stats for the server.\r\n */\r\nexport default function addHealthRoutes(app) {\r\n if (!app) {\r\n return false;\r\n }\r\n\r\n // Start processing success rate ratio interval and save its id to the array\r\n // for the graceful clearing on shutdown with injected addInterval funtion\r\n addInterval(startSuccessRate());\r\n\r\n app.get('/health', (_, res) => {\r\n const stats = pool.getStats();\r\n const period = successRates.length;\r\n const movingAverage = calculateMovingAverage();\r\n\r\n log(4, '[health.js] GET /health [200] - returning server health.');\r\n\r\n res.send({\r\n status: 'OK',\r\n bootTime: serverStartTime,\r\n uptime:\r\n Math.floor(\r\n (new Date().getTime() - serverStartTime.getTime()) / 1000 / 60\r\n ) + ' minutes',\r\n version: pkgFile.version,\r\n highchartsVersion: version(),\r\n averageProcessingTime: stats.spentAverage,\r\n performedExports: stats.performedExports,\r\n failedExports: stats.droppedExports,\r\n exportAttempts: stats.exportAttempts,\r\n sucessRatio: (stats.performedExports / stats.exportAttempts) * 100,\r\n // eslint-disable-next-line import/no-named-as-default-member\r\n pool: pool.getPoolInfoJSON(),\r\n\r\n // Moving average\r\n period,\r\n movingAverage,\r\n message: `Last ${period} minutes had a success rate of ${movingAverage.toFixed(2)}%.`,\r\n\r\n // SVG/JSON attempts\r\n svgExportAttempts: stats.exportFromSvgAttempts,\r\n jsonExportAttempts: stats.performedExports - stats.exportFromSvgAttempts\r\n });\r\n });\r\n}\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { promises as fsPromises } from 'fs';\r\nimport { posix } from 'path';\r\n\r\nimport cors from 'cors';\r\nimport express from 'express';\r\nimport http from 'http';\r\nimport https from 'https';\r\nimport multer from 'multer';\r\n\r\nimport errorHandler from './error.js';\r\nimport rateLimit from './rate_limit.js';\r\nimport { log, logWithStack } from '../logger.js';\r\nimport { __dirname } from '../utils.js';\r\n\r\nimport vSwitchRoute from './routes/change_hc_version.js';\r\nimport exportRoutes from './routes/export.js';\r\nimport healthRoute from './routes/health.js';\r\nimport uiRoute from './routes/ui.js';\r\n\r\nimport ExportError from '../errors/ExportError.js';\r\n\r\n// Array of an active servers\r\nconst activeServers = new Map();\r\n\r\n// Create express app\r\nconst app = express();\r\n\r\n// Disable the X-Powered-By header\r\napp.disable('x-powered-by');\r\n\r\n// Enable CORS support\r\napp.use(cors());\r\n\r\n// Enable parsing of form data (files) with Multer package\r\nconst storage = multer.memoryStorage();\r\nconst upload = multer({\r\n storage,\r\n limits: {\r\n fieldSize: 50 * 1024 * 1024\r\n }\r\n});\r\n\r\n// Enable body parser\r\napp.use(express.json({ limit: 50 * 1024 * 1024 }));\r\napp.use(express.urlencoded({ extended: true, limit: 50 * 1024 * 1024 }));\r\n\r\n// Use only non-file multipart form fields\r\napp.use(upload.none());\r\n\r\n/**\r\n * Attach error handlers to the server.\r\n *\r\n * @param {http.Server} server - The HTTP/HTTPS server instance.\r\n */\r\nconst attachServerErrorHandlers = (server) => {\r\n server.on('clientError', (error) => {\r\n logWithStack(1, error, `[server] Client error: ${error.message}`);\r\n });\r\n\r\n server.on('error', (error) => {\r\n logWithStack(1, error, `[server] Server error: ${error.message}`);\r\n });\r\n\r\n server.on('connection', (socket) => {\r\n socket.on('error', (error) => {\r\n logWithStack(1, error, `[server] Socket error: ${error.message}`);\r\n });\r\n });\r\n};\r\n\r\n/**\r\n * Starts an HTTP server based on the provided configuration. The `serverConfig`\r\n * object contains all server related properties (see the `server` section\r\n * in the `lib/schemas/config.js` file for a reference).\r\n *\r\n * @param {Object} serverConfig - The server configuration object.\r\n *\r\n * @throws {ExportError} - Throws an error if the server cannot be configured\r\n * and started.\r\n */\r\nexport const startServer = async (serverConfig) => {\r\n try {\r\n // Stop if not enabled\r\n if (!serverConfig.enable) {\r\n return false;\r\n }\r\n\r\n // Listen HTTP server\r\n if (!serverConfig.ssl.force) {\r\n // Main server instance (HTTP)\r\n const httpServer = http.createServer(app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpServer);\r\n\r\n // Listen\r\n httpServer.listen(serverConfig.port, serverConfig.host);\r\n\r\n // Save the reference to HTTP server\r\n activeServers.set(serverConfig.port, httpServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTP server on ${serverConfig.host}:${serverConfig.port}.`\r\n );\r\n }\r\n\r\n // Listen HTTPS server\r\n if (serverConfig.ssl.enable) {\r\n // Set up an SSL server also\r\n let key, cert;\r\n\r\n try {\r\n // Get the SSL key\r\n key = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.key'),\r\n 'utf8'\r\n );\r\n\r\n // Get the SSL certificate\r\n cert = await fsPromises.readFile(\r\n posix.join(serverConfig.ssl.certPath, 'server.crt'),\r\n 'utf8'\r\n );\r\n } catch (error) {\r\n log(\r\n 2,\r\n `[server] Unable to load key/certificate from the '${serverConfig.ssl.certPath}' path. Could not run secured layer server.`\r\n );\r\n }\r\n\r\n if (key && cert) {\r\n // Main server instance (HTTPS)\r\n const httpsServer = https.createServer({ key, cert }, app);\r\n\r\n // Attach error handlers and listen to the server\r\n attachServerErrorHandlers(httpsServer);\r\n\r\n // Listen\r\n httpsServer.listen(serverConfig.ssl.port, serverConfig.host);\r\n\r\n // Save the reference to HTTPS server\r\n activeServers.set(serverConfig.ssl.port, httpsServer);\r\n\r\n log(\r\n 3,\r\n `[server] Started HTTPS server on ${serverConfig.host}:${serverConfig.ssl.port}.`\r\n );\r\n }\r\n }\r\n\r\n // Enable the rate limiter if config says so\r\n if (\r\n serverConfig.rateLimiting &&\r\n serverConfig.rateLimiting.enable &&\r\n ![0, NaN].includes(serverConfig.rateLimiting.maxRequests)\r\n ) {\r\n rateLimit(app, serverConfig.rateLimiting);\r\n }\r\n\r\n // Set up static folder's route\r\n app.use(express.static(posix.join(__dirname, 'public')));\r\n\r\n // Set up routes\r\n healthRoute(app);\r\n exportRoutes(app);\r\n uiRoute(app);\r\n vSwitchRoute(app);\r\n\r\n // Set up centralized error handler\r\n errorHandler(app);\r\n } catch (error) {\r\n throw new ExportError(\r\n '[server] Could not configure and start the server.'\r\n ).setError(error);\r\n }\r\n};\r\n\r\n/**\r\n * Closes all servers associated with Express app instance.\r\n */\r\nexport const closeServers = () => {\r\n log(4, `[server] Closing all servers.`);\r\n for (const [port, server] of activeServers) {\r\n server.close(() => {\r\n activeServers.delete(port);\r\n log(4, `[server] Closed server on port: ${port}.`);\r\n });\r\n }\r\n};\r\n\r\n/**\r\n * Get all servers associated with Express app instance.\r\n *\r\n * @returns {Array} - Servers associated with Express app instance.\r\n */\r\nexport const getServers = () => activeServers;\r\n\r\n/**\r\n * Enable rate limiting for the server.\r\n *\r\n * @param {Object} limitConfig - Configuration object for rate limiting.\r\n */\r\nexport const enableRateLimiting = (limitConfig) => rateLimit(app, limitConfig);\r\n\r\n/**\r\n * Get the Express instance.\r\n *\r\n * @returns {Object} - The Express instance.\r\n */\r\nexport const getExpress = () => express;\r\n\r\n/**\r\n * Get the Express app instance.\r\n *\r\n * @returns {Object} - The Express app instance.\r\n */\r\nexport const getApp = () => app;\r\n\r\n/**\r\n * Apply middleware(s) to a specific path.\r\n *\r\n * @param {string} path - The path to which the middleware(s) should be applied.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const use = (path, ...middlewares) => {\r\n app.use(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with GET method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const get = (path, ...middlewares) => {\r\n app.get(path, ...middlewares);\r\n};\r\n\r\n/**\r\n * Set up a route with POST method and apply middleware(s).\r\n *\r\n * @param {string} path - The route path.\r\n * @param {...Function} middlewares - The middleware functions to be applied.\r\n */\r\nexport const post = (path, ...middlewares) => {\r\n app.post(path, ...middlewares);\r\n};\r\n\r\nexport default {\r\n startServer,\r\n closeServers,\r\n getServers,\r\n enableRateLimiting,\r\n getExpress,\r\n getApp,\r\n use,\r\n get,\r\n post\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { join } from 'path';\r\n\r\nimport { __dirname } from '../../utils.js';\r\n\r\n/**\r\n * Adds the GET / route for a UI when enabled on the export server.\r\n */\r\nexport default (app) =>\r\n !app\r\n ? false\r\n : app.get('/', (request, response) => {\r\n response.sendFile(join(__dirname, 'public', 'index.html'));\r\n });\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport { clearAllIntervals } from './intervals.js';\r\nimport { killPool } from './pool.js';\r\nimport { closeServers } from './server/server.js';\r\n\r\n/**\r\n * Clean up function to trigger before ending process for the graceful shutdown.\r\n *\r\n * @param {number} exitCode - An exit code for the process.exit() function.\r\n */\r\nexport const shutdownCleanUp = async (exitCode) => {\r\n // Await freeing all resources\r\n await Promise.allSettled([\r\n // Clear all ongoing intervals\r\n clearAllIntervals(),\r\n\r\n // Get available server instances (HTTP/HTTPS) and close them\r\n closeServers(),\r\n\r\n // Close pool along with its workers and the browser instance, if exists\r\n killPool()\r\n ]);\r\n\r\n // Exit process with a correct code\r\n process.exit(exitCode);\r\n};\r\n\r\nexport default {\r\n shutdownCleanUp\r\n};\r\n","/*******************************************************************************\r\n\r\nHighcharts Export Server\r\n\r\nCopyright (c) 2016-2024, Highsoft\r\n\r\nLicenced under the MIT licence.\r\n\r\nAdditionally a valid Highcharts license is required for use.\r\n\r\nSee LICENSE file in root for details.\r\n\r\n*******************************************************************************/\r\n\r\nimport 'colors';\r\n\r\nimport { checkAndUpdateCache } from './cache.js';\r\nimport {\r\n batchExport,\r\n setAllowCodeExecution,\r\n singleExport,\r\n startExport\r\n} from './chart.js';\r\nimport { mapToNewConfig, manualConfig, setOptions } from './config.js';\r\nimport {\r\n initLogging,\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging\r\n} from './logger.js';\r\nimport { initPool, killPool } from './pool.js';\r\nimport { shutdownCleanUp } from './resource_release.js';\r\nimport server, { startServer } from './server/server.js';\r\nimport { printLogo, printUsage } from './utils.js';\r\n\r\n/**\r\n * Attaches exit listeners to the process, ensuring proper cleanup of resources\r\n * and termination on exit signals. Handles 'exit', 'SIGINT', 'SIGTERM', and\r\n * 'uncaughtException' events.\r\n */\r\nconst attachProcessExitListeners = () => {\r\n log(3, '[process] Attaching exit listeners to the process.');\r\n\r\n // Handler for the 'exit'\r\n process.on('exit', (code) => {\r\n log(4, `Process exited with code ${code}.`);\r\n });\r\n\r\n // Handler for the 'SIGINT'\r\n process.on('SIGINT', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGTERM'\r\n process.on('SIGTERM', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'SIGHUP'\r\n process.on('SIGHUP', async (name, code) => {\r\n log(4, `The ${name} event with code: ${code}.`);\r\n await shutdownCleanUp(0);\r\n });\r\n\r\n // Handler for the 'uncaughtException'\r\n process.on('uncaughtException', async (error, name) => {\r\n logWithStack(1, error, `The ${name} error.`);\r\n await shutdownCleanUp(1);\r\n });\r\n};\r\n\r\n/**\r\n * Initializes the export process. Tasks such as configuring logging, checking\r\n * cache and sources, and initializing the pool of resources happen during\r\n * this stage. Function that is required to be called before trying to export charts or setting a server. The `options` is an object that contains all options.\r\n *\r\n * @param {Object} options - All export options.\r\n *\r\n * @returns {Promise} Promise resolving to the updated export options.\r\n */\r\nconst initExport = async (options) => {\r\n // Set the allowCodeExecution per export module scope\r\n setAllowCodeExecution(\r\n options.customLogic && options.customLogic.allowCodeExecution\r\n );\r\n\r\n // Init the logging\r\n initLogging(options.logging);\r\n\r\n // Attach process' exit listeners\r\n if (options.other.listenToProcessExits) {\r\n attachProcessExitListeners();\r\n }\r\n\r\n // Check if cache needs to be updated\r\n await checkAndUpdateCache(options);\r\n\r\n // Init the pool\r\n await initPool({\r\n pool: options.pool || {\r\n minWorkers: 1,\r\n maxWorkers: 1\r\n },\r\n puppeteerArgs: options.puppeteer.args || []\r\n });\r\n\r\n // Return updated options\r\n return options;\r\n};\r\n\r\nexport default {\r\n // Server\r\n server,\r\n startServer,\r\n\r\n // Exporting\r\n initExport,\r\n singleExport,\r\n batchExport,\r\n startExport,\r\n\r\n // Pool\r\n initPool,\r\n killPool,\r\n\r\n // Other\r\n setOptions,\r\n shutdownCleanUp,\r\n\r\n // Logs\r\n log,\r\n logWithStack,\r\n setLogLevel,\r\n enableFileLogging,\r\n\r\n // Utils\r\n mapToNewConfig,\r\n manualConfig,\r\n printLogo,\r\n printUsage\r\n};\r\n"],"names":["scriptsNames","core","modules","indicators","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","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","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","toConsole","toFile","pathCreated","levelsDesc","title","color","listeners","key","option","entries","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","prototype","hasOwnProperty","call","optionsStringify","allowFunctions","replaceAll","printUsage","bold","yellow","cycleCategories","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","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,cACA,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,cACA,eAEA,cACA,WACA,eACA,WACA,SACA,OACA,WACA,YACA,SACA,qBACA,aACA,WACA,WACA,WACA,WACA,eACA,UACA,kBACA,oBACA,aACA,WAEFC,WAAY,CAAC,mBAKFC,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,MAAOP,EAAaC,KACpBO,KAAM,WACNI,QAAS,0BACTH,YAAa,yCAEfM,cAAe,CACbR,MAAOP,EAAaE,QACpBM,KAAM,WACNI,QAAS,4BACTH,YAAa,uCAEfO,iBAAkB,CAChBT,MAAOP,EAAaG,WACpBK,KAAM,WACNI,QAAS,+BACTH,YAAa,0CAEfQ,cAAe,CACbV,MAAO,CACL,wEACA,kGAEFC,KAAM,WACNC,YAAa,uDAEfS,WAAY,CACVX,OAAO,EACPC,KAAM,UACNI,QAAS,yBACTH,YACE,iFAEJU,UAAW,CACTZ,MAAO,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"} \ No newline at end of file diff --git a/lib/browser.js b/lib/browser.js index 6c4d9d40..bd42990d 100644 --- a/lib/browser.js +++ b/lib/browser.js @@ -58,10 +58,14 @@ export function get() { * instance are reached, or if no browser instance is found after retries. */ export async function create(puppeteerArgs) { + // Get debug and other options + const { debug, other } = getOptions(); + // Get the debug options - const { enable: enabledDebug, ...debug } = getOptions().debug; + const { enable: enabledDebug, ...debugOptions } = debug; + const launchOptions = { - headless: 'shell', + headless: other.browserShellMode ? 'shell' : true, userDataDir: './tmp/', args: puppeteerArgs, handleSIGINT: false, @@ -69,7 +73,7 @@ export async function create(puppeteerArgs) { handleSIGHUP: false, waitForInitialPage: false, defaultViewport: null, - ...(enabledDebug && debug) + ...(enabledDebug && debugOptions) }; // Create a browser @@ -103,6 +107,12 @@ export async function create(puppeteerArgs) { try { await open(); + + // Shell mode inform + if (launchOptions.headless === 'shell') { + log(3, `[browser] Launched browser in shell mode.`); + } + // Debug mode inform if (enabledDebug) { log(3, `[browser] Launched browser in debug mode.`); diff --git a/lib/envs.js b/lib/envs.js index 3b380b38..d1f288ec 100644 --- a/lib/envs.js +++ b/lib/envs.js @@ -204,6 +204,7 @@ export const Config = z.object({ OTHER_LISTEN_TO_PROCESS_EXITS: v.boolean(), OTHER_NO_LOGO: v.boolean(), OTHER_HARD_RESET_PAGE: v.boolean(), + OTHER_BROWSER_SHELL_MODE: v.boolean(), // debugger DEBUG_ENABLE: v.boolean(), diff --git a/lib/schemas/config.js b/lib/schemas/config.js index 3669cc54..b280f729 100644 --- a/lib/schemas/config.js +++ b/lib/schemas/config.js @@ -618,6 +618,12 @@ export const defaultConfig = { type: 'boolean', envLink: 'OTHER_HARD_RESET_PAGE', description: 'Decides if the page content should be reset entirely.' + }, + browserShellMode: { + value: true, + type: 'boolean', + envLink: 'OTHER_BROWSER_SHELL_MODE', + description: 'Decides if the browser runs in the shell mode.' } }, debug: { @@ -1040,6 +1046,12 @@ export const promptsConfig = { name: 'hardResetPage', message: 'Decides if the page content should be reset entirely', initial: defaultConfig.other.hardResetPage.value + }, + { + type: 'toggle', + name: 'browserShellMode', + message: 'Decides if the browser runs in the shell mode', + initial: defaultConfig.other.browserShellMode.value } ], debug: [ diff --git a/package-lock.json b/package-lock.json index f3f97151..6b7bf248 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,7 +12,7 @@ "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.3", + "dompurify": "^3.1.4", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0", @@ -36,10 +36,10 @@ "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "jest": "^29.7.0", - "lint-staged": "^15.2.2", + "lint-staged": "^15.2.4", "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.17.2" + "rollup": "^4.18.0" }, "engines": { "node": ">=18.12.0" @@ -1269,208 +1269,224 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.17.2.tgz", - "integrity": "sha512-NM0jFxY8bB8QLkoKxIQeObCaDlJKewVlIEkuyYKm5An1tdVZ966w2+MPQ2l8LBZLjR+SgyV+nRkTIunzOYBMLQ==", + "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==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.17.2.tgz", - "integrity": "sha512-yeX/Usk7daNIVwkq2uGoq2BYJKZY1JfyLTaHO/jaiSwi/lsf8fTFoQW/n6IdAsx5tx+iotu2zCJwz8MxI6D/Bw==", + "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==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.17.2.tgz", - "integrity": "sha512-kcMLpE6uCwls023+kknm71ug7MZOrtXo+y5p/tsg6jltpDtgQY1Eq5sGfHcQfb+lfuKwhBmEURDga9N0ol4YPw==", + "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==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.17.2.tgz", - "integrity": "sha512-AtKwD0VEx0zWkL0ZjixEkp5tbNLzX+FCqGG1SvOu993HnSz4qDI6S4kGzubrEJAljpVkhRSlg5bzpV//E6ysTQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.17.2.tgz", - "integrity": "sha512-3reX2fUHqN7sffBNqmEyMQVj/CKhIHZd4y631duy0hZqI8Qoqf6lTtmAKvJFYa6bhU95B1D0WgzHkmTg33In0A==", + "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==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.17.2.tgz", - "integrity": "sha512-uSqpsp91mheRgw96xtyAGP9FW5ChctTFEoXP0r5FAzj/3ZRv3Uxjtc7taRQSaQM/q85KEKjKsZuiZM3GyUivRg==", + "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==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "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==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "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==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.17.2.tgz", - "integrity": "sha512-T19My13y8uYXPw/L/k0JYaX1fJKFT/PWdXiHr8mTbXWxjVF1t+8Xl31DgBBvEKclw+1b00Chg0hxE2O7bTG7GQ==", + "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==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.17.2.tgz", - "integrity": "sha512-BOaNfthf3X3fOWAB+IJ9kxTgPmMqPPH5f5k2DcCsRrBIbWnaJCgX2ll77dV1TdSy9SaXTR5iDXRL8n7AnoP5cg==", + "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==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.17.2.tgz", - "integrity": "sha512-W0UP/x7bnn3xN2eYMql2T/+wpASLE5SjObXILTMPUBDB/Fg/FxC+gX4nvCfPBCbNhz51C+HcqQp2qQ4u25ok6g==", + "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==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.17.2.tgz", - "integrity": "sha512-Hy7pLwByUOuyaFC6mAr7m+oMC+V7qyifzs/nW2OJfC8H4hbCzOX07Ov0VFk/zP3kBsELWNFi7rJtgbKYsav9QQ==", + "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==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.17.2.tgz", - "integrity": "sha512-h1+yTWeYbRdAyJ/jMiVw0l6fOOm/0D1vNLui9iPuqgRGnXA0u21gAqOyB5iHjlM9MMfNOm9RHCQ7zLIzT0x11Q==", + "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==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.17.2.tgz", - "integrity": "sha512-tmdtXMfKAjy5+IQsVtDiCfqbynAQE/TQRpWdVataHmhMb9DCoJxp9vLcCBjEQWMiUYxO1QprH/HbY9ragCEFLA==", + "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==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.17.2.tgz", - "integrity": "sha512-7II/QCSTAHuE5vdZaQEwJq2ZACkBpQDOmQsE6D6XUbnBHW8IAhm4eTufL6msLJorzrHDFv3CF8oCA/hSIRuZeQ==", + "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==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.17.2.tgz", - "integrity": "sha512-TGGO7v7qOq4CYmSBVEYpI1Y5xDuCEnbVC5Vth8mOsW0gDSzxNrVERPc790IGHsrT2dQSimgMr9Ub3Y1Jci5/8w==", + "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==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2163,12 +2179,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2433,6 +2450,7 @@ "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-4.0.0.tgz", "integrity": "sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==", "dev": true, + "license": "MIT", "dependencies": { "restore-cursor": "^4.0.0" }, @@ -2448,6 +2466,7 @@ "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-4.0.0.tgz", "integrity": "sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==", "dev": true, + "license": "MIT", "dependencies": { "slice-ansi": "^5.0.0", "string-width": "^7.0.0" @@ -2550,7 +2569,8 @@ "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/colors": { "version": "1.4.0", @@ -2572,12 +2592,13 @@ } }, "node_modules/commander": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", - "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/concat-map": { @@ -2954,9 +2975,10 @@ } }, "node_modules/dompurify": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.3.tgz", - "integrity": "sha512-5sOWYSNPaxz6o2MUPvtyxTTqR4D3L77pr5rUQoWgD5ROQtVIZQgJkXbo1DLlK3vj11YGw5+LnF4SYti4gZmwng==" + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.4.tgz", + "integrity": "sha512-2gnshi6OshmuKil8rMZuQCGiUF3cUxHY3NGDzUAdUx/NPEe5DVnO8BDoAQouvgwnx0R/+a6jUn36Z0FSdq8vww==", + "license": "(MPL-2.0 OR Apache-2.0)" }, "node_modules/dotenv": { "version": "16.4.5", @@ -2996,7 +3018,8 @@ "version": "10.3.0", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.3.0.tgz", "integrity": "sha512-QpLs9D9v9kArv4lfDEgg1X/gN5XLnf/A6l9cs8SPZLRZR3ZkY9+kwIQTxm+fsSej5UMYGE8fdoaZVIBlqG0XTw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/encodeurl": { "version": "1.0.2", @@ -3521,7 +3544,8 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.1.tgz", "integrity": "sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/execa": { "version": "5.1.1", @@ -3740,10 +3764,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3945,6 +3970,7 @@ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.2.0.tgz", "integrity": "sha512-2nk+7SIVb14QrgXFHcm84tD4bKQz0RxPuMT8Ag5KPOq7J5fEmAg0UbXdTOSHqNuHSU28k55qnceesxXRZGzKWA==", "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -4530,6 +4556,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-4.0.0.tgz", "integrity": "sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -4575,6 +4602,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -5522,12 +5550,16 @@ } }, "node_modules/lilconfig": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.0.0.tgz", - "integrity": "sha512-K2U4W2Ff5ibV7j7ydLr+zLAkIg5JJ4lPn1Ltsdt+Tz/IjQ8buJ55pZAxoP34lqIiwtF9iAvtLv3JGv7CAyAg+g==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.1.tgz", + "integrity": "sha512-O18pf7nyvHTckunPWCV1XUNXU1piu01y2b7ATJ0ppkUkk8ocqVWBrYjJBCwHDjD/ZWcfyrA0P4gKhzWGi5EINQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antonk52" } }, "node_modules/lines-and-columns": { @@ -5536,21 +5568,22 @@ "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" }, "node_modules/lint-staged": { - "version": "15.2.2", - "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.2.tgz", - "integrity": "sha512-TiTt93OPh1OZOsb5B7k96A/ATl2AjIZo+vnzFZ6oHK5FuTk63ByDtxGQpHm+kFETjEWqgkF95M8FRXKR/LEBcw==", + "version": "15.2.4", + "resolved": "https://registry.npmjs.org/lint-staged/-/lint-staged-15.2.4.tgz", + "integrity": "sha512-3F9KRQIS2fVDGtCkBp4Bx0jswjX7zUcKx6OF0ZeY1prksUyKPRIIUqZhIUYAstJfvj6i48VFs4dwVIbCYwvTYQ==", "dev": true, + "license": "MIT", "dependencies": { "chalk": "5.3.0", - "commander": "11.1.0", + "commander": "12.1.0", "debug": "4.3.4", "execa": "8.0.1", - "lilconfig": "3.0.0", - "listr2": "8.0.1", - "micromatch": "4.0.5", + "lilconfig": "3.1.1", + "listr2": "8.2.1", + "micromatch": "4.0.6", "pidtree": "0.6.0", "string-argv": "0.3.2", - "yaml": "2.3.4" + "yaml": "2.4.2" }, "bin": { "lint-staged": "bin/lint-staged.js" @@ -5709,16 +5742,17 @@ } }, "node_modules/listr2": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.0.1.tgz", - "integrity": "sha512-ovJXBXkKGfq+CwmKTjluEqFi3p4h8xvkxGQQAQan22YCgef4KZ1mKGjzfGh6PL6AW5Csw0QiQPNuQyH+6Xk3hA==", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-8.2.1.tgz", + "integrity": "sha512-irTfvpib/rNiD637xeevjO2l3Z5loZmuaRi0L0YE5LfijwVY96oyVn0DFD3o/teAok7nfobMG1THvvcHh/BP6g==", "dev": true, + "license": "MIT", "dependencies": { "cli-truncate": "^4.0.0", "colorette": "^2.0.20", "eventemitter3": "^5.0.1", "log-update": "^6.0.0", - "rfdc": "^1.3.0", + "rfdc": "^1.3.1", "wrap-ansi": "^9.0.0" }, "engines": { @@ -5751,6 +5785,7 @@ "resolved": "https://registry.npmjs.org/log-update/-/log-update-6.0.0.tgz", "integrity": "sha512-niTvB4gqvtof056rRIrTZvjNYE4rCUzO6X/X+kYjd7WFxXeJ0NwEFnRxX6ehkvv3jTwrXnNdtAak5XYZuIyPFw==", "dev": true, + "license": "MIT", "dependencies": { "ansi-escapes": "^6.2.0", "cli-cursor": "^4.0.0", @@ -5770,6 +5805,7 @@ "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.2.1.tgz", "integrity": "sha512-4nJ3yixlEthEJ9Rk4vPcdBRkZvQZlYyu8j4/Mqz5sgIkddmEnH2Yj2ZrnP9S3tQOvSNRUIgVNF/1yPpRAGNRig==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.16" }, @@ -5782,6 +5818,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5794,6 +5831,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -5806,6 +5844,7 @@ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.0.0.tgz", "integrity": "sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==", "dev": true, + "license": "MIT", "dependencies": { "get-east-asian-width": "^1.0.0" }, @@ -5821,6 +5860,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.0.tgz", "integrity": "sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "is-fullwidth-code-point": "^5.0.0" @@ -5837,6 +5877,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -5920,18 +5961,32 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.6.tgz", + "integrity": "sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" + "braces": "^3.0.3", + "picomatch": "^4.0.2" }, "engines": { "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -6973,6 +7028,7 @@ "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-4.0.0.tgz", "integrity": "sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==", "dev": true, + "license": "MIT", "dependencies": { "onetime": "^5.1.0", "signal-exit": "^3.0.2" @@ -6998,7 +7054,8 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.1.tgz", "integrity": "sha512-r5a3l5HzYlIC68TpmYKlxWjmOP6wiPJ1vWv2HeLhNsRZMrCkxeqxiHlQ21oXmQ4F3SiryXBHhAD7JZqvOJjFmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", @@ -7016,10 +7073,11 @@ } }, "node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "1.0.5" }, @@ -7031,22 +7089,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", + "@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", "fsevents": "~2.3.2" } }, @@ -7350,6 +7408,7 @@ "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-5.0.0.tgz", "integrity": "sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.0.0", "is-fullwidth-code-point": "^4.0.0" @@ -7366,6 +7425,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -7527,6 +7587,7 @@ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.1.0.tgz", "integrity": "sha512-SEIJCWiX7Kg4c129n48aDRwLbFb2LJmXXFrWBG4NGaRtMQ3myKPKbwrD1BKqQn74oCoNMBVrfDEr5M9YxCsrkw==", "dev": true, + "license": "MIT", "dependencies": { "emoji-regex": "^10.3.0", "get-east-asian-width": "^1.0.0", @@ -7544,6 +7605,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -7556,6 +7618,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -7811,6 +7874,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -8315,6 +8379,7 @@ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.0.tgz", "integrity": "sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^6.2.1", "string-width": "^7.0.0", @@ -8332,6 +8397,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8344,6 +8410,7 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -8356,6 +8423,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -8440,10 +8508,14 @@ "dev": true }, "node_modules/yaml": { - "version": "2.3.4", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", - "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.2.tgz", + "integrity": "sha512-B3VqDZ+JAg1nZpaEmWtTXUlBneoGx6CPM9b0TENK6aoSu5t73dItudwdgmi6tHlIZZId4dZ9skcAQ2UbcyAeVA==", "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, "engines": { "node": ">= 14" } diff --git a/package.json b/package.json index 0db2a73b..b44fb8ae 100644 --- a/package.json +++ b/package.json @@ -46,15 +46,15 @@ "eslint-plugin-prettier": "^5.1.3", "husky": "^9.0.11", "jest": "^29.7.0", - "lint-staged": "^15.2.2", + "lint-staged": "^15.2.4", "nodemon": "^3.1.0", "prettier": "^3.2.5", - "rollup": "^4.17.2" + "rollup": "^4.18.0" }, "dependencies": { "colors": "1.4.0", "cors": "^2.8.5", - "dompurify": "^3.1.3", + "dompurify": "^3.1.4", "dotenv": "^16.4.5", "express": "^4.19.2", "express-rate-limit": "^7.2.0",