PHP WebShell

Текущая директория: /opt/BitGoJS/modules/express/dist

Просмотр файла: expressApp.js

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.startup = startup;
exports.createServer = createServer;
exports.createBaseUri = createBaseUri;
exports.setupRoutes = setupRoutes;
exports.app = app;
exports.prepareIpc = prepareIpc;
exports.init = init;
/**
 * @prettier
 */
const express = require("express");
const path = require("path");
const _ = require("lodash");
const debugLib = require("debug");
const https = require("https");
const http = require("http");
const morgan = require("morgan");
const fs = require("fs");
const timeout = require("connect-timeout");
const config_1 = require("./config");
const debug = debugLib('bitgo:express');
const constants_1 = require("constants");
const errors_1 = require("./errors");
const bitgo_1 = require("bitgo");
const clientRoutes = require("./clientRoutes");
/**
 * Set up the logging middleware provided by morgan
 *
 * @param app
 * @param config
 */
function setupLogging(app, config) {
    // Set up morgan for logging, with optional logging into a file
    let middleware;
    if (config.logFile) {
        // create a write stream (in append mode)
        const accessLogPath = path.resolve(config.logFile);
        const accessLogStream = fs.createWriteStream(accessLogPath, { flags: 'a' });
        /* eslint-disable-next-line no-console */
        console.log('Log location: ' + accessLogPath);
        // setup the logger
        middleware = morgan('combined', { stream: accessLogStream });
    }
    else {
        middleware = morgan('combined');
    }
    app.use(middleware);
    morgan.token('remote-user', function (req) {
        return req.isProxy ? 'proxy' : 'local_express';
    });
}
/**
 * If we're running in a custom env, set the appropriate environment URI and network properties
 *
 * @param config
 */
function configureEnvironment(config) {
    const { customRootUri, customBitcoinNetwork } = config;
    if (customRootUri) {
        bitgo_1.Environments['custom'].uri = customRootUri;
    }
    if (customBitcoinNetwork) {
        bitgo_1.Environments['custom'].network = customBitcoinNetwork;
    }
}
/**
 * Create an HTTP server configured for accepting HTTPS connections
 *
 * @param config application configuration
 * @param app
 * @return {Server}
 */
async function createHttpsServer(app, config) {
    const { keyPath, crtPath, sslKey, sslCert } = config;
    let key;
    let cert;
    if (sslKey && sslCert) {
        key = sslKey;
        cert = sslCert;
    }
    else if (keyPath && crtPath) {
        const privateKeyPromise = fs.promises.readFile(keyPath, 'utf8');
        const certificatePromise = fs.promises.readFile(crtPath, 'utf8');
        [key, cert] = await Promise.all([privateKeyPromise, certificatePromise]);
    }
    else {
        throw new Error('Failed to get ssl key and certificate');
    }
    return https.createServer({ secureOptions: constants_1.SSL_OP_NO_TLSv1, key, cert }, app);
}
/**
 * Create an HTTP server configured for accepting plain old HTTP connections
 *
 * @param app
 * @return {Server}
 */
function createHttpServer(app) {
    return http.createServer(app);
}
/**
 * Create a startup function which will be run upon server initialization
 *
 * @param config
 * @param baseUri
 * @return {Function}
 */
function startup(config, baseUri) {
    return function () {
        const { env, ipc, customRootUri, customBitcoinNetwork, signerMode, lightningSignerFileSystemPath } = config;
        /* eslint-disable no-console */
        console.log('BitGo-Express running');
        console.log(`Environment: ${env}`);
        if (ipc) {
            console.log(`IPC path: ${ipc}`);
        }
        else {
            console.log(`Base URI: ${baseUri}`);
        }
        if (customRootUri) {
            console.log(`Custom root URI: ${customRootUri}`);
        }
        if (customBitcoinNetwork) {
            console.log(`Custom bitcoin network: ${customBitcoinNetwork}`);
        }
        if (signerMode) {
            console.log(`External signer mode: ${signerMode}`);
        }
        if (lightningSignerFileSystemPath) {
            console.log(`Lightning signer file system path: ${lightningSignerFileSystemPath}`);
        }
        /* eslint-enable no-console */
    };
}
/**
 * helper function to determine whether we should run the server over TLS or not
 */
function isTLS(config) {
    const { keyPath, crtPath, sslKey, sslCert } = config;
    return Boolean((keyPath && crtPath) || (sslKey && sslCert));
}
/**
 * Create either a HTTP or HTTPS server
 */
async function createServer(config, app) {
    const server = isTLS(config) ? await createHttpsServer(app, config) : createHttpServer(app);
    // Set keepAliveTimeout and headersTimeout if specified in config
    if (config.keepAliveTimeout !== undefined) {
        server.keepAliveTimeout = config.keepAliveTimeout;
    }
    if (config.headersTimeout !== undefined) {
        server.headersTimeout = config.headersTimeout;
    }
    return server;
}
/**
 * Create the base URI where the BitGoExpress server will be available once started
 * @return {string}
 */
function createBaseUri(config) {
    const { bind, port } = config;
    const tls = isTLS(config);
    const isStandardPort = (port === 80 && !tls) || (port === 443 && tls);
    return `http${tls ? 's' : ''}://${bind}${!isStandardPort ? ':' + port : ''}`;
}
/**
 * Check the that the json file exists
 * @param path
 */
function checkJsonFilePath(path) {
    try {
        const jsonFile = fs.readFileSync(path, { encoding: 'utf8' });
        JSON.parse(jsonFile);
    }
    catch (e) {
        throw new Error(`Failed to parse ${path} - ${e.message}`);
    }
}
/**
 * Check environment and other preconditions to ensure bitgo-express can start safely
 * @param config
 */
function checkPreconditions(config) {
    const { env, disableEnvCheck, bind, ipc, disableSSL, keyPath, crtPath, sslKey, sslCert, customRootUri, customBitcoinNetwork, externalSignerUrl, signerMode, signerFileSystemPath, lightningSignerFileSystemPath, } = config;
    // warn or throw if the NODE_ENV is not production when BITGO_ENV is production - this can leak system info from express
    if (env === 'prod' && process.env.NODE_ENV !== 'production') {
        if (!disableEnvCheck) {
            throw new errors_1.NodeEnvironmentError('NODE_ENV should be set to production when running against prod environment. Use --disableenvcheck if you really want to run in a non-production node configuration.');
        }
        else {
            console.warn(`warning: unsafe NODE_ENV '${process.env.NODE_ENV}'. NODE_ENV must be set to 'production' when running against BitGo production environment.`);
        }
    }
    const needsTLS = !ipc && env === 'prod' && bind !== 'localhost' && !disableSSL;
    // make sure keyPath and crtPath are set when running over TLS
    if (needsTLS && !(keyPath && crtPath) && !(sslKey && sslCert)) {
        throw new errors_1.TlsConfigurationError('Must enable TLS when running against prod and listening on external interfaces!');
    }
    if (Boolean(keyPath) !== Boolean(crtPath) || Boolean(sslKey) !== Boolean(sslCert)) {
        throw new errors_1.TlsConfigurationError('Must provide both keypath and crtpath when running in TLS mode!');
    }
    if ((customRootUri || customBitcoinNetwork) && env !== 'custom') {
        console.warn(`customRootUri or customBitcoinNetwork is set, but env is '${env}'. Setting env to 'custom'.`);
        config.env = 'custom';
    }
    if (externalSignerUrl !== undefined && (signerMode !== undefined || signerFileSystemPath !== undefined)) {
        throw new errors_1.ExternalSignerConfigError('signerMode or signerFileSystemPath is set, but externalSignerUrl is also set.');
    }
    if ((signerMode !== undefined || signerFileSystemPath !== undefined) && !(signerMode && signerFileSystemPath)) {
        throw new errors_1.ExternalSignerConfigError('signerMode and signerFileSystemPath must both be set in order to run in external signing mode.');
    }
    if (signerMode !== undefined && lightningSignerFileSystemPath !== undefined) {
        throw new errors_1.LightningSignerConfigError('signerMode and lightningSignerFileSystemPath cannot be set at the same time.');
    }
    if (signerFileSystemPath !== undefined) {
        checkJsonFilePath(signerFileSystemPath);
    }
    if (lightningSignerFileSystemPath !== undefined) {
        checkJsonFilePath(lightningSignerFileSystemPath);
    }
}
function setupRoutes(app, config) {
    if (config.signerMode) {
        clientRoutes.setupSigningRoutes(app, config);
    }
    else {
        if (config.lightningSignerFileSystemPath) {
            clientRoutes.setupLightningSignerNodeRoutes(app, config);
        }
        clientRoutes.setupAPIRoutes(app, config);
    }
}
function app(cfg) {
    debug('app is initializing');
    const app = express();
    setupLogging(app, cfg);
    debug('logging setup');
    const { debugNamespace } = cfg;
    // enable specified debug namespaces
    if (_.isArray(debugNamespace)) {
        for (const ns of debugNamespace) {
            if (ns && !debugLib.enabled(ns)) {
                debugLib.enable(ns);
            }
        }
    }
    checkPreconditions(cfg);
    debug('preconditions satisfied');
    // Be more robust about accepting URLs with double slashes
    app.use(function replaceUrlSlashes(req, res, next) {
        req.url = req.url.replace(/\/\//g, '/');
        next();
    });
    app.use(timeout(cfg.timeout));
    // Decorate the client routes
    setupRoutes(app, cfg);
    configureEnvironment(cfg);
    return app;
}
/**
 * Prepare to listen on an IPC (unix domain) socket instead of a normal TCP port.
 * @param ipcSocketFilePath path to file where IPC socket should be created
 */
async function prepareIpc(ipcSocketFilePath) {
    if (process.platform === 'win32') {
        throw new errors_1.IpcError(`IPC option is not supported on platform ${process.platform}`);
    }
    try {
        const stat = fs.statSync(ipcSocketFilePath);
        if (!stat.isSocket()) {
            throw new errors_1.IpcError('IPC socket is not actually a socket');
        }
        // ipc socket does exist and is indeed a socket. However, the socket cannot already exist prior
        // to being bound since it will be created by express internally when binding. If there's a stale
        // socket from the last run, clean it up before attempting to bind to it again. Arguably, it would
        // be better to do this before exiting, but that gets a bit more complicated when all exit paths
        // need to clean up the socket file correctly.
        fs.unlinkSync(ipcSocketFilePath);
    }
    catch (e) {
        if (e.code !== 'ENOENT') {
            throw e;
        }
    }
}
async function init() {
    const cfg = (0, config_1.config)();
    const expressApp = app(cfg);
    const server = await createServer(cfg, expressApp);
    const { port, bind, ipc } = cfg;
    const baseUri = createBaseUri(cfg);
    if (ipc) {
        await prepareIpc(ipc);
        server.listen(ipc, startup(cfg, baseUri));
    }
    else {
        server.listen(port, bind, startup(cfg, baseUri));
    }
}
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXhwcmVzc0FwcC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9leHByZXNzQXBwLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7O0FBb0hBLDBCQXlCQztBQWFELG9DQVdDO0FBTUQsc0NBS0M7QUE4RkQsa0NBU0M7QUFFRCxrQkFvQ0M7QUFNRCxnQ0FxQkM7QUFFRCxvQkFlQztBQXpXRDs7R0FFRztBQUNILG1DQUFtQztBQUNuQyw2QkFBNkI7QUFDN0IsNEJBQTRCO0FBQzVCLGtDQUFrQztBQUNsQywrQkFBK0I7QUFDL0IsNkJBQTZCO0FBQzdCLGlDQUFpQztBQUNqQyx5QkFBeUI7QUFFekIsMkNBQTJDO0FBRTNDLHFDQUEwQztBQUUxQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsZUFBZSxDQUFDLENBQUM7QUFFeEMseUNBQTRDO0FBQzVDLHFDQU1rQjtBQUVsQixpQ0FBcUM7QUFDckMsK0NBQStDO0FBRS9DOzs7OztHQUtHO0FBQ0gsU0FBUyxZQUFZLENBQUMsR0FBd0IsRUFBRSxNQUFjO0lBQzVELCtEQUErRDtJQUMvRCxJQUFJLFVBQVUsQ0FBQztJQUNmLElBQUksTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO1FBQ25CLHlDQUF5QztRQUN6QyxNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNuRCxNQUFNLGVBQWUsR0FBRyxFQUFFLENBQUMsaUJBQWlCLENBQUMsYUFBYSxFQUFFLEVBQUUsS0FBSyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDNUUseUNBQXlDO1FBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLENBQUM7UUFDOUMsbUJBQW1CO1FBQ25CLFVBQVUsR0FBRyxNQUFNLENBQUMsVUFBVSxFQUFFLEVBQUUsTUFBTSxFQUFFLGVBQWUsRUFBRSxDQUFDLENBQUM7SUFDL0QsQ0FBQztTQUFNLENBQUM7UUFDTixVQUFV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Q0FBQztJQUVuRCxNQUFNLEVBQUUsSUFBSSxFQUFFLElBQUksRUFBRSxHQUFHLEVBQUUsR0FBRyxHQUFHLENBQUM7SUFDaEMsTUFBTSxPQUFPLEdBQUcsYUFBYSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBRW5DLElBQUksR0FBRyxFQUFFLENBQUM7UUFDUixNQUFNLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0QixNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsR0FBRyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDNUMsQ0FBQztTQUFNLENBQUM7UUFDTixNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxJQUFJLEVBQUUsT0FBTyxDQUFDLEdBQUcsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDO0lBQ25ELENBQUM7QUFDSCxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAcHJldHRpZXJcbiAqL1xuaW1wb3J0ICogYXMgZXhwcmVzcyBmcm9tICdleHByZXNzJztcbmltcG9ydCAqIGFzIHBhdGggZnJvbSAncGF0aCc7XG5pbXBvcnQgKiBhcyBfIGZyb20gJ2xvZGFzaCc7XG5pbXBvcnQgKiBhcyBkZWJ1Z0xpYiBmcm9tICdkZWJ1Zyc7XG5pbXBvcnQgKiBhcyBodHRwcyBmcm9tICdodHRwcyc7XG5pbXBvcnQgKiBhcyBodHRwIGZyb20gJ2h0dHAnO1xuaW1wb3J0ICogYXMgbW9yZ2FuIGZyb20gJ21vcmdhbic7XG5pbXBvcnQgKiBhcyBmcyBmcm9tICdmcyc7XG5pbXBvcnQgdHlwZSB7IFJlcXVlc3QgYXMgU3RhdGljUmVxdWVzdCB9IGZyb20gJ2V4cHJlc3Mtc2VydmUtc3RhdGljLWNvcmUnO1xuaW1wb3J0ICogYXMgdGltZW91dCBmcm9tICdjb25uZWN0LXRpbWVvdXQnO1xuXG5pbXBvcnQgeyBDb25maWcsIGNvbmZpZyB9IGZyb20gJy4vY29uZmlnJztcblxuY29uc3QgZGVidWcgPSBkZWJ1Z0xpYignYml0Z286ZXhwcmVzcycpO1xuXG5pbXBvcnQgeyBTU0xfT1BfTk9fVExTdjEgfSBmcm9tICdjb25zdGFudHMnO1xuaW1wb3J0IHtcbiAgSXBjRXJyb3IsXG4gIE5vZGVFbnZpcm9ubWVudEVycm9yLFxuICBUbHNDb25maWd1cmF0aW9uRXJyb3IsXG4gIEV4dGVybmFsU2lnbmVyQ29uZmlnRXJyb3IsXG4gIExpZ2h0bmluZ1NpZ25lckNvbmZpZ0Vycm9yLFxufSBmcm9tICcuL2Vycm9ycyc7XG5cbmltcG9ydCB7IEVudmlyb25tZW50cyB9IGZyb20gJ2JpdGdvJztcbmltcG9ydCAqIGFzIGNsaWVudFJvdXRlcyBmcm9tICcuL2NsaWVudFJvdXRlcyc7XG5cbi8qKlxuICogU2V0IHVwIHRoZSBsb2dnaW5nIG1pZGRsZXdhcmUgcHJvdmlkZWQgYnkgbW9yZ2FuXG4gKlxuICogQHBhcmFtIGFwcFxuICogQHBhcmFtIGNvbmZpZ1xuICovXG5mdW5jdGlvbiBzZXR1cExvZ2dpbmcoYXBwOiBleHByZXNzLkFwcGxpY2F0aW9uLCBjb25maWc6IENvbmZpZyk6IHZvaWQge1xuICAvLyBTZXQgdXAgbW9yZ2FuIGZvciBsb2dnaW5nLCB3aXRoIG9wdGlvbmFsIGxvZ2dpbmcgaW50byBhIGZpbGVcbiAgbGV0IG1pZGRsZXdhcmU7XG4gIGlmIChjb25maWcubG9nRmlsZSkge1xuICAgIC8vIGNyZWF0ZSBhIHdyaXRlIHN0cmVhbSAoaW4gYXBwZW5kIG1vZGUpXG4gICAgY29uc3QgYWNjZXNzTG9nUGF0aCA9IHBhdGgucmVzb2x2ZShjb25maWcubG9nRmlsZSk7XG4gICAgY29uc3QgYWNjZXNzTG9nU3RyZWFtID0gZnMuY3JlYXRlV3JpdGVTdHJlYW0oYWNjZXNzTG9nUGF0aCwgeyBmbGFnczogJ2EnIH0pO1xuICAgIC8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuby1jb25zb2xlICovXG4gICAgY29uc29sZS5sb2coJ0xvZyBsb2NhdGlvbjogJyArIGFjY2Vzc0xvZ1BhdGgpO1xuICAgIC8vIHNldHVwIHRoZSBsb2dnZXJcbiAgICBtaWRkbGV3YXJlID0gbW9yZ2FuKCdjb21iaW5lZCcsIHsgc3RyZWFtOiBhY2Nlc3NMb2dTdHJlYW0gfSk7XG4gIH0gZWxzZSB7XG4gICAgbWlkZGxld2FyZSA9IG1vcmdhbignY29tYmluZWQnKTtcbiAgfVxuXG4gIGFwcC51c2UobWlkZGxld2FyZSk7XG4gIG1vcmdhbi50b2tlbigncmVtb3RlLXVzZXInLCBmdW5jdGlvbiAocmVxOiBTdGF0aWNSZXF1ZXN0KSB7XG4gICAgcmV0dXJuIHJlcS5pc1Byb3h5ID8gJ3Byb3h5JyA6ICdsb2NhbF9leHByZXNzJztcbiAgfSk7XG59XG5cbi8qKlxuICogSWYgd2UncmUgcnVubmluZyBpbiBhIGN1c3RvbSBlbnYsIHNldCB0aGUgYXBwcm9wcmlhdGUgZW52aXJvbm1lbnQgVVJJIGFuZCBuZXR3b3JrIHByb3BlcnRpZXNcbiAqXG4gKiBAcGFyYW0gY29uZmlnXG4gKi9cbmZ1bmN0aW9uIGNvbmZpZ3VyZUVudmlyb25tZW50KGNvbmZpZzogQ29uZmlnKTogdm9pZCB7XG4gIGNvbnN0IHsgY3VzdG9tUm9vdFVyaSwgY3VzdG9tQml0Y29pbk5ldHdvcmsgfSA9IGNvbmZpZztcbiAgaWYgKGN1c3RvbVJvb3RVcmkpIHtcbiAgICBFbnZpcm9ubWVudHNbJ2N1c3RvbSddLnVyaSA9IGN1c3RvbVJvb3RVcmk7XG4gIH1cblxuICBpZiAoY3VzdG9tQml0Y29pbk5ldHdvcmspIHtcbiAgICBFbnZpcm9ubWVudHNbJ2N1c3RvbSddLm5ldHdvcmsgPSBjdXN0b21CaXRjb2luTmV0d29yaztcbiAgfVxufVxuXG4vKipcbiAqIENyZWF0ZSBhbiBIVFRQIHNlcnZlciBjb25maWd1cmVkIGZvciBhY2NlcHRpbmcgSFRUUFMgY29ubmVjdGlvbnNcbiAqXG4gKiBAcGFyYW0gY29uZmlnIGFwcGxpY2F0aW9uIGNvbmZpZ3VyYXRpb25cbiAqIEBwYXJhbSBhcHBcbiAqIEByZXR1cm4ge1NlcnZlcn1cbiAqL1xuYXN5bmMgZnVuY3Rpb24gY3JlYXRlSHR0cHNTZXJ2ZXIoYXBwOiBleHByZXNzLkFwcGxpY2F0aW9uLCBjb25maWc6IENvbmZpZyk6IFByb21pc2U8aHR0cHMuU2VydmVyPiB7XG4gIGNvbnN0IHsga2V5UGF0aCwgY3J0UGF0aCwgc3NsS2V5LCBzc2xDZXJ0IH0gPSBjb25maWc7XG4gIGxldCBrZXk6IHN0cmluZztcbiAgbGV0IGNlcnQ6IHN0cmluZztcbiAgaWYgKHNzbEtleSAmJiBzc2xDZXJ0KSB7XG4gICAga2V5ID0gc3NsS2V5O1xuICAgIGNlcnQgPSBzc2xDZXJ0O1xuICB9IGVsc2UgaWYgKGtleVBhdGggJiYgY3J0UGF0aCkge1xuICAgIGNvbnN0IHByaXZhdGVLZXlQcm9taXNlID0gZnMucHJvbWlzZXMucmVhZEZpbGUoa2V5UGF0aCwgJ3V0ZjgnKTtcbiAgICBjb25zdCBjZXJ0aWZpY2F0ZVByb21pc2UgPSBmcy5wcm9taXNlcy5yZWFkRmlsZShjcnRQYXRoLCAndXRmOCcpO1xuXG4gICAgW2tleSwgY2VydF0gPSBhd2FpdCBQcm9taXNlLmFsbChbcHJpdmF0ZUtleVByb21pc2UsIGNlcnRpZmljYXRlUHJvbWlzZV0pO1xuICB9IGVsc2Uge1xuICAgIHRocm93IG5ldyBFcnJvcignRmFpbGVkIHRvIGdldCBzc2wga2V5IGFuZCBjZXJ0aWZpY2F0ZScpO1xuICB9XG5cbiAgcmV0dXJuIGh0dHBzLmNyZWF0ZVNlcnZlcih7IHNlY3VyZU9wdGlvbnM6IFNTTF9PUF9OT19UTFN2MSwga2V5LCBjZXJ0IH0sIGFwcCk7XG59XG5cbi8qKlxuICogQ3JlYXRlIGFuIEhUVFAgc2VydmVyIGNvbmZpZ3VyZWQgZm9yIGFjY2VwdGluZyBwbGFpbiBvbGQgSFRUUCBjb25uZWN0aW9uc1xuICpcbiAqIEBwYXJhbSBhcHBcbiAqIEByZXR1cm4ge1NlcnZlcn1cbiAqL1xuZnVuY3Rpb24gY3JlYXRlSHR0cFNlcnZlcihhcHA6IGV4cHJlc3MuQXBwbGljYXRpb24pOiBodHRwLlNlcnZlciB7XG4gIHJldHVybiBodHRwLmNyZWF0ZVNlcnZlcihhcHApO1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIHN0YXJ0dXAgZnVuY3Rpb24gd2hpY2ggd2lsbCBiZSBydW4gdXBvbiBzZXJ2ZXIgaW5pdGlhbGl6YXRpb25cbiAqXG4gKiBAcGFyYW0gY29uZmlnXG4gKiBAcGFyYW0gYmFzZVVyaVxuICogQHJldHVybiB7RnVuY3Rpb259XG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBzdGFydHVwKGNvbmZpZzogQ29uZmlnLCBiYXNlVXJpOiBzdHJpbmcpOiAoKSA9PiB2b2lkIHtcbiAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICBjb25zdCB7IGVudiwgaXBjLCBjdXN0b21Sb290VXJpLCBjdXN0b21CaXRjb2luTmV0d29yaywgc2lnbmVyTW9kZSwgbGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGggfSA9IGNvbmZpZztcbiAgICAvKiBlc2xpbnQtZGlzYWJsZSBuby1jb25zb2xlICovXG4gICAgY29uc29sZS5sb2coJ0JpdEdvLUV4cHJlc3MgcnVubmluZycpO1xuICAgIGNvbnNvbGUubG9nKGBFbnZpcm9ubWVudDogJHtlbnZ9YCk7XG4gICAgaWYgKGlwYykge1xuICAgICAgY29uc29sZS5sb2coYElQQyBwYXRoOiAke2lwY31gKTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc29sZS5sb2coYEJhc2UgVVJJOiAke2Jhc2VVcml9YCk7XG4gICAgfVxuICAgIGlmIChjdXN0b21Sb290VXJpKSB7XG4gICAgICBjb25zb2xlLmxvZyhgQ3VzdG9tIHJvb3QgVVJJOiAke2N1c3RvbVJvb3RVcml9YCk7XG4gICAgfVxuICAgIGlmIChjdXN0b21CaXRjb2luTmV0d29yaykge1xuICAgICAgY29uc29sZS5sb2coYEN1c3RvbSBiaXRjb2luIG5ldHdvcms6ICR7Y3VzdG9tQml0Y29pbk5ldHdvcmt9YCk7XG4gICAgfVxuICAgIGlmIChzaWduZXJNb2RlKSB7XG4gICAgICBjb25zb2xlLmxvZyhgRXh0ZXJuYWwgc2lnbmVyIG1vZGU6ICR7c2lnbmVyTW9kZX1gKTtcbiAgICB9XG4gICAgaWYgKGxpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRoKSB7XG4gICAgICBjb25zb2xlLmxvZyhgTGlnaHRuaW5nIHNpZ25lciBmaWxlIHN5c3RlbSBwYXRoOiAke2xpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRofWApO1xuICAgIH1cbiAgICAvKiBlc2xpbnQtZW5hYmxlIG5vLWNvbnNvbGUgKi9cbiAgfTtcbn1cblxuLyoqXG4gKiBoZWxwZXIgZnVuY3Rpb24gdG8gZGV0ZXJtaW5lIHdoZXRoZXIgd2Ugc2hvdWxkIHJ1biB0aGUgc2VydmVyIG92ZXIgVExTIG9yIG5vdFxuICovXG5mdW5jdGlvbiBpc1RMUyhjb25maWc6IENvbmZpZyk6IGNvbmZpZyBpcyBDb25maWcgJiB7IGtleVBhdGg6IHN0cmluZzsgY3J0UGF0aDogc3RyaW5nIH0ge1xuICBjb25zdCB7IGtleVBhdGgsIGNydFBhdGgsIHNzbEtleSwgc3NsQ2VydCB9ID0gY29uZmlnO1xuICByZXR1cm4gQm9vbGVhbigoa2V5UGF0aCAmJiBjcnRQYXRoKSB8fCAoc3NsS2V5ICYmIHNzbENlcnQpKTtcbn1cblxuLyoqXG4gKiBDcmVhdGUgZWl0aGVyIGEgSFRUUCBvciBIVFRQUyBzZXJ2ZXJcbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVNlcnZlcihjb25maWc6IENvbmZpZywgYXBwOiBleHByZXNzLkFwcGxpY2F0aW9uKTogUHJvbWlzZTxodHRwcy5TZXJ2ZXIgfCBodHRwLlNlcnZlcj4ge1xuICBjb25zdCBzZXJ2ZXIgPSBpc1RMUyhjb25maWcpID8gYXdhaXQgY3JlYXRlSHR0cHNTZXJ2ZXIoYXBwLCBjb25maWcpIDogY3JlYXRlSHR0cFNlcnZlcihhcHApO1xuXG4gIC8vIFNldCBrZWVwQWxpdmVUaW1lb3V0IGFuZCBoZWFkZXJzVGltZW91dCBpZiBzcGVjaWZpZWQgaW4gY29uZmlnXG4gIGlmIChjb25maWcua2VlcEFsaXZlVGltZW91dCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgc2VydmVyLmtlZXBBbGl2ZVRpbWVvdXQgPSBjb25maWcua2VlcEFsaXZlVGltZW91dDtcbiAgfVxuICBpZiAoY29uZmlnLmhlYWRlcnNUaW1lb3V0ICE9PSB1bmRlZmluZWQpIHtcbiAgICBzZXJ2ZXIuaGVhZGVyc1RpbWVvdXQgPSBjb25maWcuaGVhZGVyc1RpbWVvdXQ7XG4gIH1cbiAgcmV0dXJuIHNlcnZlcjtcbn1cblxuLyoqXG4gKiBDcmVhdGUgdGhlIGJhc2UgVVJJIHdoZXJlIHRoZSBCaXRHb0V4cHJlc3Mgc2VydmVyIHdpbGwgYmUgYXZhaWxhYmxlIG9uY2Ugc3RhcnRlZFxuICogQHJldHVybiB7c3RyaW5nfVxuICovXG5leHBvcnQgZnVuY3Rpb24gY3JlYXRlQmFzZVVyaShjb25maWc6IENvbmZpZyk6IHN0cmluZyB7XG4gIGNvbnN0IHsgYmluZCwgcG9ydCB9ID0gY29uZmlnO1xuICBjb25zdCB0bHMgPSBpc1RMUyhjb25maWcpO1xuICBjb25zdCBpc1N0YW5kYXJkUG9ydCA9IChwb3J0ID09PSA4MCAmJiAhdGxzKSB8fCAocG9ydCA9PT0gNDQzICYmIHRscyk7XG4gIHJldHVybiBgaHR0cCR7dGxzID8gJ3MnIDogJyd9Oi8vJHtiaW5kfSR7IWlzU3RhbmRhcmRQb3J0ID8gJzonICsgcG9ydCA6ICcnfWA7XG59XG5cbi8qKlxuICogQ2hlY2sgdGhlIHRoYXQgdGhlIGpzb24gZmlsZSBleGlzdHNcbiAqIEBwYXJhbSBwYXRoXG4gKi9cbmZ1bmN0aW9uIGNoZWNrSnNvbkZpbGVQYXRoKHBhdGg6IHN0cmluZykge1xuICB0cnkge1xuICAgIGNvbnN0IGpzb25GaWxlID0gZnMucmVhZEZpbGVTeW5jKHBhdGgsIHsgZW5jb2Rpbmc6ICd1dGY4JyB9KTtcbiAgICBKU09OLnBhcnNlKGpzb25GaWxlKTtcbiAgfSBjYXRjaCAoZSkge1xuICAgIHRocm93IG5ldyBFcnJvcihgRmFpbGVkIHRvIHBhcnNlICR7cGF0aH0gLSAke2UubWVzc2FnZX1gKTtcbiAgfVxufVxuXG4vKipcbiAqIENoZWNrIGVudmlyb25tZW50IGFuZCBvdGhlciBwcmVjb25kaXRpb25zIHRvIGVuc3VyZSBiaXRnby1leHByZXNzIGNhbiBzdGFydCBzYWZlbHlcbiAqIEBwYXJhbSBjb25maWdcbiAqL1xuZnVuY3Rpb24gY2hlY2tQcmVjb25kaXRpb25zKGNvbmZpZzogQ29uZmlnKSB7XG4gIGNvbnN0IHtcbiAgICBlbnYsXG4gICAgZGlzYWJsZUVudkNoZWNrLFxuICAgIGJpbmQsXG4gICAgaXBjLFxuICAgIGRpc2FibGVTU0wsXG4gICAga2V5UGF0aCxcbiAgICBjcnRQYXRoLFxuICAgIHNzbEtleSxcbiAgICBzc2xDZXJ0LFxuICAgIGN1c3RvbVJvb3RVcmksXG4gICAgY3VzdG9tQml0Y29pbk5ldHdvcmssXG4gICAgZXh0ZXJuYWxTaWduZXJVcmwsXG4gICAgc2lnbmVyTW9kZSxcbiAgICBzaWduZXJGaWxlU3lzdGVtUGF0aCxcbiAgICBsaWdodG5pbmdTaWduZXJGaWxlU3lzdGVtUGF0aCxcbiAgfSA9IGNvbmZpZztcblxuICAvLyB3YXJuIG9yIHRocm93IGlmIHRoZSBOT0RFX0VOViBpcyBub3QgcHJvZHVjdGlvbiB3aGVuIEJJVEdPX0VOViBpcyBwcm9kdWN0aW9uIC0gdGhpcyBjYW4gbGVhayBzeXN0ZW0gaW5mbyBmcm9tIGV4cHJlc3NcbiAgaWYgKGVudiA9PT0gJ3Byb2QnICYmIHByb2Nlc3MuZW52Lk5PREVfRU5WICE9PSAncHJvZHVjdGlvbicpIHtcbiAgICBpZiAoIWRpc2FibGVFbnZDaGVjaykge1xuICAgICAgdGhyb3cgbmV3IE5vZGVFbnZpcm9ubWVudEVycm9yKFxuICAgICAgICAnTk9ERV9FTlYgc2hvdWxkIGJlIHNldCB0byBwcm9kdWN0aW9uIHdoZW4gcnVubmluZyBhZ2FpbnN0IHByb2QgZW52aXJvbm1lbnQuIFVzZSAtLWRpc2FibGVlbnZjaGVjayBpZiB5b3UgcmVhbGx5IHdhbnQgdG8gcnVuIGluIGEgbm9uLXByb2R1Y3Rpb24gbm9kZSBjb25maWd1cmF0aW9uLidcbiAgICAgICk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnNvbGUud2FybihcbiAgICAgICAgYHdhcm5pbmc6IHVuc2FmZSBOT0RFX0VOViAnJHtwcm9jZXNzLmVudi5OT0RFX0VOVn0nLiBOT0RFX0VOViBtdXN0IGJlIHNldCB0byAncHJvZHVjdGlvbicgd2hlbiBydW5uaW5nIGFnYWluc3QgQml0R28gcHJvZHVjdGlvbiBlbnZpcm9ubWVudC5gXG4gICAgICApO1xuICAgIH1cbiAgfVxuXG4gIGNvbnN0IG5lZWRzVExTID0gIWlwYyAmJiBlbnYgPT09ICdwcm9kJyAmJiBiaW5kICE9PSAnbG9jYWxob3N0JyAmJiAhZGlzYWJsZVNTTDtcblxuICAvLyBtYWtlIHN1cmUga2V5UGF0aCBhbmQgY3J0UGF0aCBhcmUgc2V0IHdoZW4gcnVubmluZyBvdmVyIFRMU1xuICBpZiAobmVlZHNUTFMgJiYgIShrZXlQYXRoICYmIGNydFBhdGgpICYmICEoc3NsS2V5ICYmIHNzbENlcnQpKSB7XG4gICAgdGhyb3cgbmV3IFRsc0NvbmZpZ3VyYXRpb25FcnJvcignTXVzdCBlbmFibGUgVExTIHdoZW4gcnVubmluZyBhZ2FpbnN0IHByb2QgYW5kIGxpc3RlbmluZyBvbiBleHRlcm5hbCBpbnRlcmZhY2VzIScpO1xuICB9XG5cbiAgaWYgKEJvb2xlYW4oa2V5UGF0aCkgIT09IEJvb2xlYW4oY3J0UGF0aCkgfHwgQm9vbGVhbihzc2xLZXkpICE9PSBCb29sZWFuKHNzbENlcnQpKSB7XG4gICAgdGhyb3cgbmV3IFRsc0NvbmZpZ3VyYXRpb25FcnJvcignTXVzdCBwcm92aWRlIGJvdGgga2V5cGF0aCBhbmQgY3J0cGF0aCB3aGVuIHJ1bm5pbmcgaW4gVExTIG1vZGUhJyk7XG4gIH1cblxuICBpZiAoKGN1c3RvbVJvb3RVcmkgfHwgY3VzdG9tQml0Y29pbk5ldHdvcmspICYmIGVudiAhPT0gJ2N1c3RvbScpIHtcbiAgICBjb25zb2xlLndhcm4oYGN1c3RvbVJvb3RVcmkgb3IgY3VzdG9tQml0Y29pbk5ldHdvcmsgaXMgc2V0LCBidXQgZW52IGlzICcke2Vudn0nLiBTZXR0aW5nIGVudiB0byAnY3VzdG9tJy5gKTtcbiAgICBjb25maWcuZW52ID0gJ2N1c3RvbSc7XG4gIH1cblxuICBpZiAoZXh0ZXJuYWxTaWduZXJVcmwgIT09IHVuZGVmaW5lZCAmJiAoc2lnbmVyTW9kZSAhPT0gdW5kZWZpbmVkIHx8IHNpZ25lckZpbGVTeXN0ZW1QYXRoICE9PSB1bmRlZmluZWQpKSB7XG4gICAgdGhyb3cgbmV3IEV4dGVybmFsU2lnbmVyQ29uZmlnRXJyb3IoXG4gICAgICAnc2lnbmVyTW9kZSBvciBzaWduZXJGaWxlU3lzdGVtUGF0aCBpcyBzZXQsIGJ1dCBleHRlcm5hbFNpZ25lclVybCBpcyBhbHNvIHNldC4nXG4gICAgKTtcbiAgfVxuXG4gIGlmICgoc2lnbmVyTW9kZSAhPT0gdW5kZWZpbmVkIHx8IHNpZ25lckZpbGVTeXN0ZW1QYXRoICE9PSB1bmRlZmluZWQpICYmICEoc2lnbmVyTW9kZSAmJiBzaWduZXJGaWxlU3lzdGVtUGF0aCkpIHtcbiAgICB0aHJvdyBuZXcgRXh0ZXJuYWxTaWduZXJDb25maWdFcnJvcihcbiAgICAgICdzaWduZXJNb2RlIGFuZCBzaWduZXJGaWxlU3lzdGVtUGF0aCBtdXN0IGJvdGggYmUgc2V0IGluIG9yZGVyIHRvIHJ1biBpbiBleHRlcm5hbCBzaWduaW5nIG1vZGUuJ1xuICAgICk7XG4gIH1cblxuICBpZiAoc2lnbmVyTW9kZSAhPT0gdW5kZWZpbmVkICYmIGxpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRoICE9PSB1bmRlZmluZWQpIHtcbiAgICB0aHJvdyBuZXcgTGlnaHRuaW5nU2lnbmVyQ29uZmlnRXJyb3IoXG4gICAgICAnc2lnbmVyTW9kZSBhbmQgbGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGggY2Fubm90IGJlIHNldCBhdCB0aGUgc2FtZSB0aW1lLidcbiAgICApO1xuICB9XG5cbiAgaWYgKHNpZ25lckZpbGVTeXN0ZW1QYXRoICE9PSB1bmRlZmluZWQpIHtcbiAgICBjaGVja0pzb25GaWxlUGF0aChzaWduZXJGaWxlU3lzdGVtUGF0aCk7XG4gIH1cblxuICBpZiAobGlnaHRuaW5nU2lnbmVyRmlsZVN5c3RlbVBhdGggIT09IHVuZGVmaW5lZCkge1xuICAgIGNoZWNrSnNvbkZpbGVQYXRoKGxpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRoKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gc2V0dXBSb3V0ZXMoYXBwOiBleHByZXNzLkFwcGxpY2F0aW9uLCBjb25maWc6IENvbmZpZyk6IHZvaWQge1xuICBpZiAoY29uZmlnLnNpZ25lck1vZGUpIHtcbiAgICBjbGllbnRSb3V0ZXMuc2V0dXBTaWduaW5nUm91dGVzKGFwcCwgY29uZmlnKTtcbiAgfSBlbHNlIHtcbiAgICBpZiAoY29uZmlnLmxpZ2h0bmluZ1NpZ25lckZpbGVTeXN0ZW1QYXRoKSB7XG4gICAgICBjbGllbnRSb3V0ZXMuc2V0dXBMaWdodG5pbmdTaWduZXJOb2RlUm91dGVzKGFwcCwgY29uZmlnKTtcbiAgICB9XG4gICAgY2xpZW50Um91dGVzLnNldHVwQVBJUm91dGVzKGFwcCwgY29uZmlnKTtcbiAgfVxufVxuXG5leHBvcnQgZnVuY3Rpb24gYXBwKGNmZzogQ29uZmlnKTogZXhwcmVzcy5BcHBsaWNhdGlvbiB7XG4gIGRlYnVnKCdhcHAgaXMgaW5pdGlhbGl6aW5nJyk7XG5cbiAgY29uc3QgYXBwID0gZXhwcmVzcygpO1xuXG4gIHNldHVwTG9nZ2luZyhhcHAsIGNmZyk7XG4gIGRlYnVnKCdsb2dnaW5nIHNldHVwJyk7XG5cbiAgY29uc3QgeyBkZWJ1Z05hbWVzcGFjZSB9ID0gY2ZnO1xuXG4gIC8vIGVuYWJsZSBzcGVjaWZpZWQgZGVidWcgbmFtZXNwYWNlc1xuICBpZiAoXy5pc0FycmF5KGRlYnVnTmFtZXNwYWNlKSkge1xuICAgIGZvciAoY29uc3QgbnMgb2YgZGVidWdOYW1lc3BhY2UpIHtcbiAgICAgIGlmIChucyAmJiAhZGVidWdMaWIuZW5hYmxlZChucykpIHtcbiAgICAgICAgZGVidWdMaWIuZW5hYmxlKG5zKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjaGVja1ByZWNvbmRpdGlvbnMoY2ZnKTtcbiAgZGVidWcoJ3ByZWNvbmRpdGlvbnMgc2F0aXNmaWVkJyk7XG5cbiAgLy8gQmUgbW9yZSByb2J1c3QgYWJvdXQgYWNjZXB0aW5nIFVSTHMgd2l0aCBkb3VibGUgc2xhc2hlc1xuICBhcHAudXNlKGZ1bmN0aW9uIHJlcGxhY2VVcmxTbGFzaGVzKHJlcSwgcmVzLCBuZXh0KSB7XG4gICAgcmVxLnVybCA9IHJlcS51cmwucmVwbGFjZSgvXFwvXFwvL2csICcvJyk7XG4gICAgbmV4dCgpO1xuICB9KTtcblxuICBhcHAudXNlKHRpbWVvdXQoY2ZnLnRpbWVvdXQpKTtcblxuICAvLyBEZWNvcmF0ZSB0aGUgY2xpZW50IHJvdXRlc1xuICBzZXR1cFJvdXRlcyhhcHAsIGNmZyk7XG5cbiAgY29uZmlndXJlRW52aXJvbm1lbnQoY2ZnKTtcblxuICByZXR1cm4gYXBwO1xufVxuXG4vKipcbiAqIFByZXBhcmUgdG8gbGlzdGVuIG9uIGFuIElQQyAodW5peCBkb21haW4pIHNvY2tldCBpbnN0ZWFkIG9mIGEgbm9ybWFsIFRDUCBwb3J0LlxuICogQHBhcmFtIGlwY1NvY2tldEZpbGVQYXRoIHBhdGggdG8gZmlsZSB3aGVyZSBJUEMgc29ja2V0IHNob3VsZCBiZSBjcmVhdGVkXG4gKi9cbmV4cG9ydCBhc3luYyBmdW5jdGlvbiBwcmVwYXJlSXBjKGlwY1NvY2tldEZpbGVQYXRoOiBzdHJpbmcpIHtcbiAgaWYgKHByb2Nlc3MucGxhdGZvcm0gPT09ICd3aW4zMicpIHtcbiAgICB0aHJvdyBuZXcgSXBjRXJyb3IoYElQQyBvcHRpb24gaXMgbm90IHN1cHBvcnRlZCBvbiBwbGF0Zm9ybSAke3Byb2Nlc3MucGxhdGZvcm19YCk7XG4gIH1cblxuICB0cnkge1xuICAgIGNvbnN0IHN0YXQgPSBmcy5zdGF0U3luYyhpcGNTb2NrZXRGaWxlUGF0aCk7XG4gICAgaWYgKCFzdGF0LmlzU29ja2V0KCkpIHtcbiAgICAgIHRocm93IG5ldyBJcGNFcnJvcignSVBDIHNvY2tldCBpcyBub3QgYWN0dWFsbHkgYSBzb2NrZXQnKTtcbiAgICB9XG4gICAgLy8gaXBjIHNvY2tldCBkb2VzIGV4aXN0IGFuZCBpcyBpbmRlZWQgYSBzb2NrZXQuIEhvd2V2ZXIsIHRoZSBzb2NrZXQgY2Fubm90IGFscmVhZHkgZXhpc3QgcHJpb3JcbiAgICAvLyB0byBiZWluZyBib3VuZCBzaW5jZSBpdCB3aWxsIGJlIGNyZWF0ZWQgYnkgZXhwcmVzcyBpbnRlcm5hbGx5IHdoZW4gYmluZGluZy4gSWYgdGhlcmUncyBhIHN0YWxlXG4gICAgLy8gc29ja2V0IGZyb20gdGhlIGxhc3QgcnVuLCBjbGVhbiBpdCB1cCBiZWZvcmUgYXR0ZW1wdGluZyB0byBiaW5kIHRvIGl0IGFnYWluLiBBcmd1YWJseSwgaXQgd291bGRcbiAgICAvLyBiZSBiZXR0ZXIgdG8gZG8gdGhpcyBiZWZvcmUgZXhpdGluZywgYnV0IHRoYXQgZ2V0cyBhIGJpdCBtb3JlIGNvbXBsaWNhdGVkIHdoZW4gYWxsIGV4aXQgcGF0aHNcbiAgICAvLyBuZWVkIHRvIGNsZWFuIHVwIHRoZSBzb2NrZXQgZmlsZSBjb3JyZWN0bHkuXG4gICAgZnMudW5saW5rU3luYyhpcGNTb2NrZXRGaWxlUGF0aCk7XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICBpZiAoZS5jb2RlICE9PSAnRU5PRU5UJykge1xuICAgICAgdGhyb3cgZTtcbiAgICB9XG4gIH1cbn1cblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGluaXQoKTogUHJvbWlzZTx2b2lkPiB7XG4gIGNvbnN0IGNmZyA9IGNvbmZpZygpO1xuICBjb25zdCBleHByZXNzQXBwID0gYXBwKGNmZyk7XG5cbiAgY29uc3Qgc2VydmVyID0gYXdhaXQgY3JlYXRlU2VydmVyKGNmZywgZXhwcmVzc0FwcCk7XG5cbiAgY29uc3QgeyBwb3J0LCBiaW5kLCBpcGMgfSA9IGNmZztcbiAgY29uc3QgYmFzZVVyaSA9IGNyZWF0ZUJhc2VVcmkoY2ZnKTtcblxuICBpZiAoaXBjKSB7XG4gICAgYXdhaXQgcHJlcGFyZUlwYyhpcGMpO1xuICAgIHNlcnZlci5saXN0ZW4oaXBjLCBzdGFydHVwKGNmZywgYmFzZVVyaSkpO1xuICB9IGVsc2Uge1xuICAgIHNlcnZlci5saXN0ZW4ocG9ydCwgYmluZCwgc3RhcnR1cChjZmcsIGJhc2VVcmkpKTtcbiAgfVxufVxuIl19

Выполнить команду


Для локальной разработки. Не используйте в интернете!