Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
"use strict";
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
const async_middleware_1 = require("async-middleware");
const compression = require("compression");
const continuation_local_storage_1 = require("continuation-local-storage");
const express = require("express");
const HttpStatus = require("http-status-codes");
require("log-timestamp");
const Mustache = require("mustache");
const raynor_1 = require("raynor");
const React = require("react");
const ReactDOMServer = require("react-dom/server");
const react_helmet_1 = require("react-helmet");
const react_redux_1 = require("react-redux");
const react_router_dom_1 = require("react-router-dom");
const webpack = require("webpack");
const theWebpackDevMiddleware = require("webpack-dev-middleware");
const serializeJavascript = require("serialize-javascript");
const business_rules_js_1 = require("@truesparrow/business-rules-js");
const common_js_1 = require("@truesparrow/common-js");
const common_server_js_1 = require("@truesparrow/common-server-js");
const content_sdk_js_1 = require("@truesparrow/content-sdk-js");
const identity_sdk_js_1 = require("@truesparrow/identity-sdk-js");
const server_1 = require("@truesparrow/identity-sdk-js/server");
const bundles_1 = require("./bundles");
const app_frame_1 = require("../shared/app-frame");
const config = require("../shared/config");
const client_data_1 = require("../shared/client-data");
const store_1 = require("../shared/store");
function main() {
    return __awaiter(this, void 0, void 0, function* () {
        // Global setup, but hidden inside main()
        // ********************
        const webpackConfig = require('../../webpack.config.js');
        const clientConfigMarshaller = new (raynor_1.MarshalFrom(client_data_1.ClientConfig))();
        const clientInitialStateMarshaller = new (raynor_1.MarshalFrom(client_data_1.ClientInitialState))();
        const internalWebFetcher = new common_js_1.InternalWebFetcher();
        const identityClient = identity_sdk_js_1.newIdentityClient(config.INTERNAL_ORIGIN, `${config.IDENTITY_SERVICE_HOST}:${config.IDENTITY_SERVICE_PORT}`, internalWebFetcher);
        const contentPrivateClient = content_sdk_js_1.newContentPrivateClient(config.INTERNAL_ORIGIN, `${config.CONTENT_SERVICE_HOST}:${config.CONTENT_SERVICE_PORT}`, internalWebFetcher);
        const bundles = common_js_1.isLocal(config.ENV)
            ? new bundles_1.WebpackDevBundles(theWebpackDevMiddleware(webpack(webpackConfig), {
                //Different because we're mounting on /real/client to boot webpackConfig.output.publicPath,
                publicPath: '/',
                serverSideRender: false
            }))
            : new bundles_1.CompiledBundles();
        const namespace = continuation_local_storage_1.createNamespace(config.CLS_NAMESPACE_NAME);
        console.log('Starting up');
        function serverSideRender(url, session, clientInitialState) {
            const language = business_rules_js_1.inferLanguage(session);
            const store = store_1.createStoreFromInitialState(store_1.reducers, clientInitialState);
            const clientConfig = {
                allowedPaths: config.ALLOWED_PATHS,
                env: config.ENV,
                internalOrigin: config.INTERNAL_ORIGIN,
                externalOrigin: config.EXTERNAL_ORIGIN,
                seoFacebookHandle: config.SEO_FACEBOOK_HANDLE,
                seoTwitterHandle: config.SEO_TWITTER_HANDLE,
                contactEmail: config.CONTACT_EMAIL,
                demoSiteUri: config.DEMO_SITE_URI,
                styleApplicationName: config.STYLE_APPLICATION_NAME,
                styleLogoUri: config.STYLE_LOGO_URI,
                stylePrimaryColor: config.STYLE_PRIMARY_COLOR,
                styleLoadingImageBase: config.STYLE_LOADING_IMAGE_BASE,
                siteFeExternalHost: config.SITEFE_EXTERNAL_HOST,
                contentServiceHost: config.CONTENT_SERVICE_HOST,
                contentServicePort: config.CONTENT_SERVICE_PORT,
                auth0ClientId: config.AUTH0_CLIENT_CONFIG.clientId,
                auth0Domain: config.AUTH0_CLIENT_CONFIG.domain,
                auth0LoginCallbackUri: config.AUTH0_CLIENT_CONFIG.loginCallbackUri,
                logoutRoutePath: config.LOGOUT_ROUTE_PATH,
                facebookAppId: config.FACEBOOK_APP_ID,
                googleAnalyticsAccountId: config.GOOGLE_ANALYTICS_ACCOUNT_ID,
                fileStackApiKey: config.FILESTACK_API_KEY,
                rollbarClientToken: null,
                session: session,
                language: language
            };
            namespace.set('SESSION', session);
            namespace.set('LANG', language);
            const staticContext = {};
            const appHtml = ReactDOMServer.renderToString(React.createElement(react_redux_1.Provider, { store: store },
                React.createElement(react_router_dom_1.StaticRouter, { location: url, context: staticContext },
                    React.createElement(app_frame_1.AppFrame, null))));
            const specialStatus = staticContext.status == HttpStatus.NOT_FOUND ? HttpStatus.NOT_FOUND : null;
            const helmetData = react_helmet_1.Helmet.renderStatic();
            return [Mustache.render(bundles.getHtmlIndexTemplate(), {
                    LANGUAGE: language,
                    GOOGLE_MAPS_API_KEY: config.GOOGLE_MAPS_API_KEY,
                    SEO_KEYWORDS: config.SEO_KEYWORDS,
                    CONTACT_AUTHORS: config.CONTACT_AUTHORS,
                    PAGE_TITLE_HTML: helmetData.title,
                    PAGE_META_HTML: helmetData.meta,
                    PAGE_LINK_HTML: helmetData.link,
                    PAGE_MICRODATA_SCRIPT_HTML: helmetData.script,
                    STYLE_PRIMARY_COLOR: config.STYLE_PRIMARY_COLOR,
                    STYLE_GRAY_COLOR: config.STYLE_GRAY_COLOR,
                    APP_HTML: appHtml,
                    CLIENT_CONFIG: serializeJavascript(clientConfigMarshaller.pack(clientConfig), { isJSON: true }),
                    CLIENT_INITIAL_STATE: serializeJavascript(clientInitialStateMarshaller.pack(clientInitialState), { isJSON: true }),
                    WEBPACK_MANIFEST_JS: bundles.getManifestJs(),
                }), specialStatus];
        }
        console.log('Starting web server');
        const app = express();
        // Setup global properties and behaviours of the application
        // ********************
        app.disable('x-powered-by');
        app.use(common_server_js_1.newNamespaceMiddleware(namespace));
        if (true || common_js_1.isNotOnServer(config.ENV)) {
            app.use(common_server_js_1.newLocalCommonServerMiddleware(config.NAME, config.ENV, false));
        }
        else {
            // app.use(newCommonServerMiddleware(
            //     config.NAME,
            //     config.ENV,
            //     config.LOGGLY_TOKEN as string,
            //     config.LOGGLY_SUBDOMAIN as string,
            //     config.ROLLBAR_SERVER_TOKEN as string));
        }
        app.use(common_server_js_1.newCommonFrontendServerMiddleware(config.ENV, ['/status/check']));
        app.use(compression({ threshold: 0 }));
        // Setup the /real portion of the path-space. Here are things which don't belong to the client-side
        // interaction, but rather to the server-side one, callbacks from other services etc.
        // ********************
        // Setup the auth0 authentication flow. Has a complex dance wrt sessions.
        app.use('/real/auth0-auth-flow', server_1.newAuth0AuthFlowRouter(config.ENV, config.ALLOWED_PATHS, config.AUTH0_SERVER_CONFIG, internalWebFetcher, identityClient));
        // An API gateway for the client side code. Needs session to exist in the request.
        app.use('/real/api-gateway', server_1.newApiGatewayRouter(config.INTERNAL_ORIGIN, internalWebFetcher));
        // Static serving of the client side code assets (index.html, vendor.js etc). No session. Derived
        // from the bundles.
        app.use('/real/client', bundles.getOtherBundlesRouter());
        // Still a service after all and this will allow health checks & metrics etc.
        app.use('/status', common_server_js_1.newHealthCheckRouter());
        // Setup serving of a bunch of files for interacting with the web at large, such as robots.txt,
        // sitemaps etc. These are derived from the bundles, with some extra data baked in. No session.
        // ********************
        const siteInfoRouter = express.Router();
        siteInfoRouter.get('/robots.txt', (_req, res) => {
            res.status(HttpStatus.OK);
            res.type('.txt');
            res.write(Mustache.render(bundles.getRobotsTxt(), {
                EXTERNAL_ORIGIN: config.EXTERNAL_ORIGIN
            }));
            res.end();
        });
        siteInfoRouter.get('/humans.txt', (_req, res) => {
            res.status(HttpStatus.OK);
            res.type('.txt');
            res.write(Mustache.render(bundles.getHumansTxt(), {
                CONTACT_AUTHORS: config.CONTACT_AUTHORS,
                CONTACT_EMAIL: config.CONTACT_EMAIL
            }));
            res.end();
        });
        siteInfoRouter.get('/sitemap.xml', (_req, res) => {
            res.status(HttpStatus.OK);
            res.type('application/xml; charset=utf-8');
            res.write(Mustache.render(bundles.getSitemapXml(), {
                EXTERNAL_ORIGIN: config.EXTERNAL_ORIGIN,
                LAST_MOD: new Date().toISOString()
            }));
            res.end();
        });
        siteInfoRouter.get('/browserconfig.xml', (_req, res) => {
            res.status(HttpStatus.OK);
            res.type('application/xml; charset=utf-8');
            res.write(Mustache.render(bundles.getBrowserConfigXml(), {
                STYLE_PRIMARY_COLOR: config.STYLE_PRIMARY_COLOR
            }));
            res.end();
        });
        siteInfoRouter.get('/site.webmanifest', (_req, res) => {
            res.status(HttpStatus.OK);
            res.type('application/manifest+json; charset=utf-8');
            res.write(Mustache.render(bundles.getSiteWebManifest(), {
                EXTERNAL_ORIGIN: config.EXTERNAL_ORIGIN,
                STYLE_APPLICATION_NAME: config.STYLE_APPLICATION_NAME,
                STYLE_PRIMARY_COLOR: config.STYLE_PRIMARY_COLOR
            }));
            res.end();
        });
        app.use('/', siteInfoRouter);
        // Setup serving for all all client application level routes. Any path a user enters, which
        // doesn't match the ones from above (so /real ones or standard web ones) will be handled
        // by serving the "client application". This translated to doing a server-side render of the
        // application and serving that embedded into {@link src/shared/static/index.html}, which
        // will reference /real/client/client.js and other static resources in order to boot it up.
        // ********************
        const appRouter = express.Router();
        appRouter.use(server_1.newSessionMiddleware(server_1.SessionLevel.None, server_1.SessionInfoSource.Cookie, config.ENV, identityClient));
        appRouter.get('*', async_middleware_1.wrap((req, res) => __awaiter(this, void 0, void 0, function* () {
            let event = null;
            let chargebeeManageAccountUri = null;
            if (req.session.hasUser()) {
                try {
                    event = yield contentPrivateClient.withContext(req.sessionToken).getEvent();
                    chargebeeManageAccountUri = yield contentPrivateClient.withContext(req.sessionToken).getChargebeeManagePageUri();
                }
                catch (e) {
                    if (e.name == 'EventNotFoundError') {
                        try {
                            const plan = req.query.plan || content_sdk_js_1.EventPlan.QuickStarter;
                            event = yield contentPrivateClient.withContext(req.sessionToken).createEvent(req.session, plan);
                            chargebeeManageAccountUri = yield contentPrivateClient.withContext(req.sessionToken).getChargebeeManagePageUri();
                        }
                        catch (e) {
                            // Nothing happens here. We'll try again on the client. But we do log the error.
                            req.log.warn(e);
                            req.errorLog.warn(e);
                        }
                    }
                    else {
                        // Nothing happens here. We'll try again on the client. But we do log the error.
                        req.log.warn(e);
                        req.errorLog.warn(e);
                    }
                }
            }
            const initialState = {
                event: event,
                chargebeeManageAccountUri: chargebeeManageAccountUri
            };
            const [content, specialStatus] = serverSideRender(req.url, req.session, initialState);
            res.status(specialStatus != null ? specialStatus : HttpStatus.OK);
            res.type('html');
            res.write(content);
            res.end();
        })));
        app.use('/', appRouter);
        // Start serving
        // ********************
        app.listen(config.PORT, '0.0.0.0', () => {
            console.log(`Started ${config.NAME} service on ${config.PORT}`);
        });
    });
}
main();
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2VydmVyL2luZGV4LnRzeCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7O0FBQUEsdURBQXVDO0FBQ3ZDLDJDQUEwQztBQUMxQywyRUFBNEQ7QUFDNUQsbUNBQWtDO0FBQ2xDLGdEQUErQztBQUMvQyx5QkFBc0I7QUFDdEIscUNBQW9DO0FBQ3BDLG1DQUFvQztBQUNwQywrQkFBOEI7QUFDOUIsbURBQWtEO0FBQ2xELCtDQUFxQztBQUNyQyw2Q0FBc0M7QUFDdEMsdURBQStDO0FBQy9DLG1DQUFrQztBQUNsQyxrRUFBaUU7QUFDakUsNERBQTJEO0FBRTNELHNFQUE4RDtBQUM5RCxzREFLK0I7QUFDL0Isb0VBT3NDO0FBQ3RDLGdFQUtvQztBQUNwQyxrRUFLcUM7QUFDckMsZ0VBTTRDO0FBRTVDLHVDQUF1RTtBQUN2RSxtREFBOEM7QUFDOUMsMkNBQTBDO0FBQzFDLHVEQUF3RTtBQUN4RSwyQ0FBdUU7QUFHdkU7O1FBQ0kseUNBQXlDO1FBQ3pDLHVCQUF1QjtRQUV2QixNQUFNLGFBQWEsR0FBRyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQztRQUV6RCxNQUFNLHNCQUFzQixHQUFHLElBQUksQ0FBQyxvQkFBVyxDQUFDLDBCQUFZLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDakUsTUFBTSw0QkFBNEIsR0FBRyxJQUFJLENBQUMsb0JBQVcsQ0FBQyxnQ0FBa0IsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUU3RSxNQUFNLGtCQUFrQixHQUFlLElBQUksOEJBQWtCLEVBQUUsQ0FBQztRQUNoRSxNQUFNLGNBQWMsR0FBbUIsbUNBQWlCLENBQ3BELE1BQU0sQ0FBQyxlQUFlLEVBQ3RCLEdBQUcsTUFBTSxDQUFDLHFCQUFxQixJQUFJLE1BQU0sQ0FBQyxxQkFBcUIsRUFBRSxFQUNqRSxrQkFBa0IsQ0FBQyxDQUFDO1FBQ3hCLE1BQU0sb0JBQW9CLEdBQXlCLHdDQUF1QixDQUN0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Q0FBQztZQUVGLE1BQU0sQ0FBQyxPQUFPLEVBQUUsYUFBYSxDQUFDLEdBQUcsZ0JBQWdCLENBQzdDLEdBQUcsQ0FBQyxHQUFHLEVBQ1AsR0FBRyxDQUFDLE9BQU8sRUFDWCxZQUFZLENBQ2YsQ0FBQztZQUVGLEdBQUcsQ0FBQyxNQUFNLENBQUMsYUFBYSxJQUFJLElBQUksQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUM7WUFDbEUsR0FBRyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNqQixHQUFHLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQ25CLEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQztRQUNkLENBQUMsQ0FBQSxDQUFDLENBQUMsQ0FBQztRQUVKLEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRXhCLGdCQUFnQjtRQUNoQix1QkFBdUI7UUFFdkIsR0FBRyxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsSUFBSSxFQUFFLFNBQVMsRUFBRSxHQUFHLEVBQUU7WUFDcEMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxXQUFXLE1BQU0sQ0FBQyxJQUFJLGVBQWUsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFDLENBQUM7UUFDcEUsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0NBQUE7QUFHRCxJQUFJLEVBQUUsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHdyYXAgfSBmcm9tICdhc3luYy1taWRkbGV3YXJlJ1xuaW1wb3J0ICogYXMgY29tcHJlc3Npb24gZnJvbSAnY29tcHJlc3Npb24nXG5pbXBvcnQgeyBjcmVhdGVOYW1lc3BhY2UgfSBmcm9tICdjb250aW51YXRpb24tbG9jYWwtc3RvcmFnZSdcbmltcG9ydCAqIGFzIGV4cHJlc3MgZnJvbSAnZXhwcmVzcydcbmltcG9ydCAqIGFzIEh0dHBTdGF0dXMgZnJvbSAnaHR0cC1zdGF0dXMtY29kZXMnXG5pbXBvcnQgJ2xvZy10aW1lc3RhbXAnXG5pbXBvcnQgKiBhcyBNdXN0YWNoZSBmcm9tICdtdXN0YWNoZSdcbmltcG9ydCB7IE1hcnNoYWxGcm9tIH0gZnJvbSAncmF5bm9yJ1xuaW1wb3J0ICogYXMgUmVhY3QgZnJvbSAncmVhY3QnXG5pbXBvcnQgKiBhcyBSZWFjdERPTVNlcnZlciBmcm9tICdyZWFjdC1kb20vc2VydmVyJ1xuaW1wb3J0IHsgSGVsbWV0IH0gZnJvbSAncmVhY3QtaGVsbWV0J1xuaW1wb3J0IHsgUHJvdmlkZXIgfSBmcm9tICdyZWFjdC1yZWR1eCdcbmltcG9ydCB7IFN0YXRpY1JvdXRlciB9IGZyb20gJ3JlYWN0LXJvdXRlci1kb20nXG5pbXBvcnQgKiBhcyB3ZWJwYWNrIGZyb20gJ3dlYnBhY2snXG5pbXBvcnQgKiBhcyB0aGVXZWJwYWNrRGV2TWlkZGxld2FyZSBmcm9tICd3ZWJwYWNrLWRldi1taWRkbGV3YXJlJ1xuaW1wb3J0ICogYXMgc2VyaWFsaXplSmF2YXNjcmlwdCBmcm9tICdzZXJpYWxpemUtamF2YXNjcmlwdCdcblxuaW1wb3J0IHsgaW5mZXJMYW5ndWFnZSB9IGZyb20gJ0B0cnVlc3BhcnJvdy9idXNpbmVzcy1ydWxlcy1qcydcbmltcG9ydCB7XG4gICAgSW50ZXJuYWxXZWJGZXRjaGVyLFxuICAgIGlzTG9jYWwsXG4gICAgaXNOb3RPblNlcnZlcixcbiAgICBXZWJGZXRjaGVyXG59IGZyb20gJ0B0cnVlc3BhcnJvdy9jb21tb24tanMnXG5pbXBvcnQge1xuICAgIC8vICAgIG5ld0NvbW1vblNlcnZlck1pZGRsZXdhcmUsXG4gICAgbmV3Q29tbW9uRnJvbnRlbmRTZXJ2ZXJNaWRkbGV3YXJlLFxuICAgIG5ld0hlYWx0aENoZWNrUm91dGVyLFxuICAgIG5ld0xvY2FsQ29tbW9uU2VydmVyTWlkZGxld2FyZSxcbiAgICBuZXdOYW1lc3BhY2VNaWRkbGV3YXJlLFxuICAgIFJlcXVlc3Rcbn0gZnJvbSAnQHRydWVzcGFycm93L2NvbW1vbi1zZXJ2ZXItanMnXG5pbXBvcnQge1xuICAgIENvbnRlbnRQcml2YXRlQ2xpZW50LFxuICAgIEV2ZW50LFxuICAgIEV2ZW50UGxhbixcbiAgICBuZXdDb250ZW50UHJpdmF0ZUNsaWVudFxufSBmcm9tICdAdHJ1ZXNwYXJyb3cvY29udGVudC1zZGstanMnXG5pbXBvcnQge1xuICAgIElkZW50aXR5Q2xpZW50LFxuICAgIG5ld0lkZW50aXR5Q2xpZW50LFxuICAgIFJlcXVlc3RXaXRoSWRlbnRpdHksXG4gICAgU2Vzc2lvblxufSBmcm9tICdAdHJ1ZXNwYXJyb3cvaWRlbnRpdHktc2RrLWpzJ1xuaW1wb3J0IHtcbiAgICBuZXdBdXRoMEF1dGhGbG93Um91dGVyLFxuICAgIG5ld0FwaUdhdGV3YXlSb3V0ZXIsXG4gICAgbmV3U2Vzc2lvbk1pZGRsZXdhcmUsXG4gICAgU2Vzc2lvbkxldmVsLFxuICAgIFNlc3Npb25JbmZvU291cmNlXG59IGZyb20gJ0B0cnVlc3BhcnJvdy9pZGVudGl0eS1zZGstanMvc2VydmVyJ1xuXG5pbXBvcnQgeyBDb21waWxlZEJ1bmRsZXMsIEJ1bmRsZXMsIFdlYnBhY2tEZXZCdW5kbGVzIH0gZnJvbSAnLi9idW5kbGVzJ1xuaW1wb3J0IHsgQXBwRnJhbWUgfSBmcm9tICcuLi9zaGFyZWQvYXBwLWZyYW1lJ1xuaW1wb3J0ICogYXMgY29uZmlnIGZyb20gJy4uL3NoYXJlZC9jb25maWcnXG5pbXBvcnQgeyBDbGllbnRDb25maWcsIENsaWVudEluaXRpYWxTdGF0ZSB9IGZyb20gJy4uL3NoYXJlZC9jbGllbnQtZGF0YSdcbmltcG9ydCB7IGNyZWF0ZVN0b3JlRnJvbUluaXRpYWxTdGF0ZSwgcmVkdWNlcnMgfSBmcm9tICcuLi9zaGFyZWQvc3RvcmUnXG5cblxuYXN5bmMgZnVuY3Rpb24gbWFpbigpIHtcbiAgICAvLyBHbG9iYWwgc2V0dXAsIGJ1dCBoaWRkZW4gaW5zaWRlIG1haW4oKVxuICAgIC8vICoqKioqKioqKioqKioqKioqKioqXG5cbiAgICBjb25zdCB3ZWJwYWNrQ29uZmlnID0gcmVxdWlyZSgnLi4vLi4vd2VicGFjay5jb25maWcuanMnKTtcblxuICAgIGNvbnN0IGNsaWVudENvbmZpZ01hcnNoYWxsZXIgPSBuZXcgKE1hcnNoYWxGcm9tKENsaWVudENvbmZpZykpKCk7XG4gICAgY29uc3QgY2xpZW50SW5pdGlhbFN0YXRlTWFyc2hhbGxlciA9IG5ldyAoTWFyc2hhbEZyb20oQ2xpZW50SW5pdGlhbFN0YXRlKSkoKTtcblxuICAgIGNvbnN0IGludGVybmFsV2ViRmV0Y2hlcjogV2ViRmV0Y2hlciA9IG5ldyBJbnRlcm5hbFdlYkZldGNoZXIoKTtcbiAgICBjb25zdCBpZGVudGl0eUNsaWVudDogSWRlbnRpdHlDbGllbnQgPSBuZXdJZGVudGl0eUNsaWVudChcbiAgICAgICAgY29uZmlnLklOVEVSTkFMX09SSUdJTixcbiAgICAgICAgYCR7Y29uZmlnLklERU5USVRZX1NFUlZJQ0VfSE9TVH06JHtjb25maWcuSURFTlRJVFlfU0VSVklDRV9QT1JUfWAsXG4gICAgICAgIGludGVybmFsV2ViRmV0Y2hlcik7XG4gICAgY29uc3QgY29udGVudFByaXZhdGVDbGllbnQ6IENvbnRlbnRQcml2YXRlQ2xpZW50ID0gbmV3Q29udGVudFByaXZhdGVDbGllbnQoXG4gICAgICAgIGNvbmZpZy5JTlRFUk5BTF9PUklHSU4sXG4gICAgICAgIGAke2NvbmZpZy5DT05URU5UX1NFUlZJQ0VfSE9TVH06JHtjb25maWcuQ09OVEVOVF9TRVJWSUNFX1BPUlR9YCxcbiAgICAgICAgaW50ZXJuYWxXZWJGZXRjaGVyKTtcblxuICAgIGNvbnN0IGJ1bmRsZXM6IEJ1bmRsZXMgPSBpc0xvY2FsKGNvbmZpZy5FTlYpXG4gICAgICAgID8gbmV3IFdlYnBhY2tEZXZCdW5kbGVzKHRoZVdlYnBhY2tEZXZNaWRkbGV3YXJlKHdlYnBhY2sod2VicGFja0NvbmZpZyksIHtcbiAgICAgICAgICAgIC8vRGlmZmVyZW50IGJlY2F1c2Ugd2UncmUgbW91bnRpbmcgb24gL3JlYWwvY2xpZW50IHRvIGJvb3Qgd2VicGFja0NvbmZpZy5vdXRwdXQucHVibGljUGF0aCxcbiAgICAgICAgICAgIHB1YmxpY1BhdGg6ICcvJyxcbiAgICAgICAgICAgIHNlcnZlclNpZGVSZW5kZXI6IGZhbHNlXG4gICAgICAgIH0pKVxuICAgICAgICA6IG5ldyBDb21waWxlZEJ1bmRsZXMoKTtcblxuICAgIGNvbnN0IG5hbWVzcGFjZSA9IGNyZWF0ZU5hbWVzcGFjZShjb25maWcuQ0xTX05BTUVTUEFDRV9OQU1FKTtcblxuICAgIGNvbnNvbGUubG9nKCdTdGFydGluZyB1cCcpO1xuXG4gICAgZnVuY3Rpb24gc2VydmVyU2lkZVJlbmRlcih1cmw6IHN0cmluZywgc2Vzc2lvbjogU2Vzc2lvbiwgY2xpZW50SW5pdGlhbFN0YXRlOiBDbGllbnRJbml0aWFsU3RhdGUpOiBbc3RyaW5nLCBudW1iZXIgfCBudWxsXSB7XG4gICAgICAgIGNvbnN0IGxhbmd1YWdlID0gaW5mZXJMYW5ndWFnZShzZXNzaW9uKTtcbiAgICAgICAgY29uc3Qgc3RvcmUgPSBjcmVhdGVTdG9yZUZyb21Jbml0aWFsU3RhdGUocmVkdWNlcnMsIGNsaWVudEluaXRpYWxTdGF0ZSk7XG5cbiAgICAgICAgY29uc3QgY2xpZW50Q29uZmlnID0ge1xuICAgICAgICAgICAgYWxsb3dlZFBhdGhzOiBjb25maWcuQUxMT1dFRF9QQVRIUyxcbiAgICAgICAgICAgIGVudjogY29uZmlnLkVOVixcbiAgICAgICAgICAgIGludGVybmFsT3JpZ2luOiBjb25maWcuSU5URVJOQUxfT1JJR0lOLFxuICAgICAgICAgICAgZXh0ZXJuYWxPcmlnaW46IGNvbmZpZy5FWFRFUk5BTF9PUklHSU4sXG4gICAgICAgICAgICBzZW9GYWNlYm9va0hhbmRsZTogY29uZmlnLlNFT19GQUNFQk9PS19IQU5ETEUsXG4gICAgICAgICAgICBzZW9Ud2l0dGVySGFuZGxlOiBjb25maWcuU0VPX1RXSVRURVJfSEFORExFLFxuICAgICAgICAgICAgY29udGFjdEVtYWlsOiBjb25maWcuQ09OVEFDVF9FTUFJTCxcbiAgICAgICAgICAgIGRlbW9TaXRlVXJpOiBjb25maWcuREVNT19TSVRFX1VSSSxcbiAgICAgICAgICAgIHN0eWxlQXBwbGljYXRpb25OYW1lOiBjb25maWcuU1RZTEVfQVBQTElDQVRJT05fTkFNRSxcbiAgICAgICAgICAgIHN0eWxlTG9nb1VyaTogY29uZmlnLlNUWUxFX0xPR09fVVJJLFxuICAgICAgICAgICAgc3R5bGVQcmltYXJ5Q29sb3I6IGNvbmZpZy5TVFlMRV9QUklNQVJZX0NPTE9SLFxuICAgICAgICAgICAgc3R5bGVMb2FkaW5nSW1hZ2VCYXNlOiBjb25maWcuU1RZTEVfTE9BRElOR19JTUFHRV9CQVNFLFxuICAgICAgICAgICAgc2l0ZUZlRXh0ZXJuYWxIb3N0OiBjb25maWcuU0lURUZFX0VYVEVSTkFMX0hPU1QsXG4gICAgICAgICAgICBjb250ZW50U2VydmljZUhvc3Q6IGNvbmZpZy5DT05URU5UX1NFUlZJQ0VfSE9TVCxcbiAgICAgICAgICAgIGNvbnRlbnRTZXJ2aWNlUG9ydDogY29uZmlnLkNPTlRFTlRfU0VSVklDRV9QT1JULFxuICAgICAgICAgICAgYXV0aDBDbGllbnRJZDogY29uZmlnLkFVVEgwX0NMSUVOVF9DT05GSUcuY2xpZW50SWQsXG4gICAgICAgICAgICBhdXRoMERvbWFpbjogY29uZmlnLkFVVEgwX0NMSUVOVF9DT05GSUcuZG9tYWluLFxuICAgICAgICAgICAgYXV0aDBMb2dpbkNhbGxiYWNrVXJpOiBjb25maWcuQVVUSDBfQ0xJRU5UX0NPTkZJRy5sb2dpbkNhbGxiYWNrVXJpLFxuICAgICAgICAgICAgbG9nb3V0Um91dGVQYXRoOiBjb25maWcuTE9HT1VUX1JPVVRFX1BBVEgsXG4gICAgICAgICAgICBmYWNlYm9va0FwcElkOiBjb25maWcuRkFDRUJPT0tfQVBQX0lELFxuICAgICAgICAgICAgZ29vZ2xlQW5hbHl0aWNzQWNjb3VudElkOiBjb25maWcuR09PR0xFX0FOQUxZVElDU19BQ0NPVU5UX0lELFxuICAgICAgICAgICAgZmlsZVN0YWNrQXBpS2V5OiBjb25maWcuRklMRVNUQUNLX0FQSV9LRVksXG4gICAgICAgICAgICByb2xsYmFyQ2xpZW50VG9rZW46IG51bGwsXG4gICAgICAgICAgICBzZXNzaW9uOiBzZXNzaW9uLFxuICAgICAgICAgICAgbGFuZ3VhZ2U6IGxhbmd1YWdlXG4gICAgICAgIH07XG5cbiAgICAgICAgbmFtZXNwYWNlLnNldCgnU0VTU0lPTicsIHNlc3Npb24pO1xuICAgICAgICBuYW1lc3BhY2Uuc2V0KCdMQU5HJywgbGFuZ3VhZ2UpO1xuXG4gICAgICAgIGNvbnN0IHN0YXRpY0NvbnRleHQ6IGFueSA9IHt9O1xuICAgICAgICBjb25zdCBhcHBIdG1sID0gUmVhY3RET01TZXJ2ZXIucmVuZGVyVG9TdHJpbmcoXG4gICAgICAgICAgICA8UHJvdmlkZXIgc3RvcmU9e3N0b3JlfT5cbiAgICAgICAgICAgICAgICA8U3RhdGljUm91dGVyIGxvY2F0aW9uPXt1cmx9IGNvbnRleHQ9e3N0YXRpY0NvbnRleHR9PlxuICAgICAgICAgICAgICAgICAgICA8QXBwRnJhbWUgLz5cbiAgICAgICAgICAgICAgICA8L1N0YXRpY1JvdXRlcj5cbiAgICAgICAgICAgIDwvUHJvdmlkZXI+XG4gICAgICAgICk7XG5cbiAgICAgICAgY29uc3Qgc3BlY2lhbFN0YXR1cyA9IHN0YXRpY0NvbnRleHQuc3RhdHVzID09IEh0dHBTdGF0dXMuTk9UX0ZPVU5EID8gSHR0cFN0YXR1cy5OT1RfRk9VTkQgOiBudWxsO1xuXG4gICAgICAgIGNvbnN0IGhlbG1ldERhdGEgPSBIZWxtZXQucmVuZGVyU3RhdGljKCk7XG5cbiAgICAgICAgcmV0dXJuIFtNdXN0YWNoZS5yZW5kZXIoYnVuZGxlcy5nZXRIdG1sSW5kZXhUZW1wbGF0ZSgpLCB7XG4gICAgICAgICAgICBMQU5HVUFHRTogbGFuZ3VhZ2UsXG4gICAgICAgICAgICBHT09HTEVfTUFQU19BUElfS0VZOiBjb25maWcuR09PR0xFX01BUFNfQVBJX0tFWSxcbiAgICAgICAgICAgIFNFT19LRVlXT1JEUzogY29uZmlnLlNFT19LRVlXT1JEUyxcbiAgICAgICAgICAgIENPTlRBQ1RfQVVUSE9SUzogY29uZmlnLkNPTlRBQ1RfQVVUSE9SUyxcbiAgICAgICAgICAgIFBBR0VfVElUTEVfSFRNTDogaGVsbWV0RGF0YS50aXRsZSxcbiAgICAgICAgICAgIFBBR0VfTUVUQV9IVE1MOiBoZWxtZXREYXRhLm1ldGEsXG4gICAgICAgICAgICBQQUdFX0xJTktfSFRNTDogaGVsbWV0RGF0YS5saW5rLFxuICAgICAgICAgICAgUEFHRV9NSUNST0RBVEFfU0NSSVBUX0hUTUw6IGhlbG1ldERhdGEuc2NyaXB0LFxuICAgICAgICAgICAgU1RZTEVfUFJJTUFSWV9DT0xPUjogY29uZmlnLlNUWUxFX1BSSU1BUllfQ09MT1IsXG4gICAgICAgICAgICBTVFlMRV9HUkFZX0NPTE9SOiBjb25maWcuU1RZTEVfR1JBWV9DT0xPUixcbiAgICAgICAgICAgIEFQUF9IVE1MOiBhcHBIdG1sLFxuICAgICAgICAgICAgQ0xJRU5UX0NPTkZJRzogc2VyaWFsaXplSmF2YXNjcmlwdChjbGllbnRDb25maWdNYXJzaGFsbGVyLnBhY2soY2xpZW50Q29uZmlnKSwgeyBpc0pTT046IHRydWUgfSksXG4gICAgICAgICAgICBDTElFTlRfSU5JVElBTF9TVEFURTogc2VyaWFsaXplSmF2YXNjcmlwdChjbGllbnRJbml0aWFsU3RhdGVNYXJzaGFsbGVyLnBhY2soY2xpZW50SW5pdGlhbFN0YXRlKSwgeyBpc0pTT046IHRydWUgfSksXG4gICAgICAgICAgICBXRUJQQUNLX01BTklGRVNUX0pTOiBidW5kbGVzLmdldE1hbmlmZXN0SnMoKSxcbiAgICAgICAgfSksIHNwZWNpYWxTdGF0dXNdO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKCdTdGFydGluZyB3ZWIgc2VydmVyJyk7XG5cbiAgICBjb25zdCBhcHAgPSBleHByZXNzKCk7XG5cbiAgICAvLyBTZXR1cCBnbG9iYWwgcHJvcGVydGllcyBhbmQgYmVoYXZpb3VycyBvZiB0aGUgYXBwbGljYXRpb25cbiAgICAvLyAqKioqKioqKioqKioqKioqKioqKlxuXG4gICAgYXBwLmRpc2FibGUoJ3gtcG93ZXJlZC1ieScpO1xuICAgIGFwcC51c2UobmV3TmFtZXNwYWNlTWlkZGxld2FyZShuYW1lc3BhY2UpKVxuICAgIGlmICh0cnVlIHx8IGlzTm90T25TZXJ2ZXIoY29uZmlnLkVOVikpIHtcbiAgICAgICAgYXBwLnVzZShuZXdMb2NhbENvbW1vblNlcnZlck1pZGRsZXdhcmUoY29uZmlnLk5BTUUsIGNvbmZpZy5FTlYsIGZhbHNlKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy8gYXBwLnVzZShuZXdDb21tb25TZXJ2ZXJNaWRkbGV3YXJlKFxuICAgICAgICAvLyAgICAgY29uZmlnLk5BTUUsXG4gICAgICAgIC8vICAgICBjb25maWcuRU5WLFxuICAgICAgICAvLyAgICAgY29uZmlnLkxPR0dMWV9UT0tFTiBhcyBzdHJpbmcsXG4gICAgICAgIC8vICAgICBjb25maWcuTE9HR0xZX1NVQkRPTUFJTiBhcyBzdHJpbmcsXG4gICAgICAgIC8vICAgICBjb25maWcuUk9MTEJBUl9TRVJWRVJfVE9LRU4gYXMgc3RyaW5nKSk7XG4gICAgfVxuICAgIGFwcC51c2UobmV3Q29tbW9uRnJvbnRlbmRTZXJ2ZXJNaWRkbGV3YXJlKGNvbmZpZy5FTlYsIFsnL3N0YXR1cy9jaGVjayddKSk7XG4gICAgYXBwLnVzZShjb21wcmVzc2lvbih7IHRocmVzaG9sZDogMCB9KSk7XG5cbiAgICAvLyBTZXR1cCB0aGUgL3JlYWwgcG9ydGlvbiBvZiB0aGUgcGF0aC1zcGFjZS4gSGVyZSBhcmUgdGhpbmdzIHdoaWNoIGRvbid0IGJlbG9uZyB0byB0aGUgY2xpZW50LXNpZGVcbiAgICAvLyBpbnRlcmFjdGlvbiwgYnV0IHJhdGhlciB0byB0aGUgc2VydmVyLXNpZGUgb25lLCBjYWxsYmFja3MgZnJvbSBvdGhlciBzZXJ2aWNlcyBldGMuXG4gICAgLy8gKioqKioqKioqKioqKioqKioqKipcblxuICAgIC8vIFNldHVwIHRoZSBhdXRoMCBhdXRoZW50aWNhdGlvbiBmbG93LiBIYXMgYSBjb21wbGV4IGRhbmNlIHdydCBzZXNzaW9ucy5cbiAgICBhcHAudXNlKCcvcmVhbC9hdXRoMC1hdXRoLWZsb3cnLCBuZXdBdXRoMEF1dGhGbG93Um91dGVyKFxuICAgICAgICBjb25maWcuRU5WLCBjb25maWcuQUxMT1dFRF9QQVRIUywgY29uZmlnLkFVVEgwX1NFUlZFUl9DT05GSUcsIGludGVybmFsV2ViRmV0Y2hlciwgaWRlbnRpdHlDbGllbnQpKTtcblxuICAgIC8vIEFuIEFQSSBnYXRld2F5IGZvciB0aGUgY2xpZW50IHNpZGUgY29kZS4gTmVlZHMgc2Vzc2lvbiB0byBleGlzdCBpbiB0aGUgcmVxdWVzdC5cbiAgICBhcHAudXNlKCcvcmVhbC9hcGktZ2F0ZXdheScsIG5ld0FwaUdhdGV3YXlSb3V0ZXIoY29uZmlnLklOVEVSTkFMX09SSUdJTiwgaW50ZXJuYWxXZWJGZXRjaGVyKSk7XG5cbiAgICAvLyBTdGF0aWMgc2VydmluZyBvZiB0aGUgY2xpZW50IHNpZGUgY29kZSBhc3NldHMgKGluZGV4Lmh0bWwsIHZlbmRvci5qcyBldGMpLiBObyBzZXNzaW9uLiBEZXJpdmVkXG4gICAgLy8gZnJvbSB0aGUgYnVuZGxlcy5cbiAgICBhcHAudXNlKCcvcmVhbC9jbGllbnQnLCBidW5kbGVzLmdldE90aGVyQnVuZGxlc1JvdXRlcigpKTtcblxuICAgIC8vIFN0aWxsIGEgc2VydmljZSBhZnRlciBhbGwgYW5kIHRoaXMgd2lsbCBhbGxvdyBoZWFsdGggY2hlY2tzICYgbWV0cmljcyBldGMuXG4gICAgYXBwLnVzZSgnL3N0YXR1cycsIG5ld0hlYWx0aENoZWNrUm91dGVyKCkpO1xuXG4gICAgLy8gU2V0dXAgc2VydmluZyBvZiBhIGJ1bmNoIG9mIGZpbGVzIGZvciBpbnRlcmFjdGluZyB3aXRoIHRoZSB3ZWIgYXQgbGFyZ2UsIHN1Y2ggYXMgcm9ib3RzLnR4dCxcbiAgICAvLyBzaXRlbWFwcyBldGMuIFRoZXNlIGFyZSBkZXJpdmVkIGZyb20gdGhlIGJ1bmRsZXMsIHdpdGggc29tZSBleHRyYSBkYXRhIGJha2VkIGluLiBObyBzZXNzaW9uLlxuICAgIC8vICoqKioqKioqKioqKioqKioqKioqXG5cbiAgICBjb25zdCBzaXRlSW5mb1JvdXRlciA9IGV4cHJlc3MuUm91dGVyKCk7XG5cbiAgICBzaXRlSW5mb1JvdXRlci5nZXQoJy9yb2JvdHMudHh0JywgKF9yZXE6IFJlcXVlc3QsIHJlczogZXhwcmVzcy5SZXNwb25zZSkgPT4ge1xuICAgICAgICByZXMuc3RhdHVzKEh0dHBTdGF0dXMuT0spO1xuICAgICAgICByZXMudHlwZSgnLnR4dCcpO1xuICAgICAgICByZXMud3JpdGUoTXVzdGFjaGUucmVuZGVyKGJ1bmRsZXMuZ2V0Um9ib3RzVHh0KCksIHtcbiAgICAgICAgICAgIEVYVEVSTkFMX09SSUdJTjogY29uZmlnLkVYVEVSTkFMX09SSUdJTlxuICAgICAgICB9KSk7XG4gICAgICAgIHJlcy5lbmQoKTtcbiAgICB9KTtcblxuICAgIHNpdGVJbmZvUm91dGVyLmdldCgnL2h1bWFucy50eHQnLCAoX3JlcTogUmVxdWVzdCwgcmVzOiBleHByZXNzLlJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHJlcy5zdGF0dXMoSHR0cFN0YXR1cy5PSyk7XG4gICAgICAgIHJlcy50eXBlKCcudHh0Jyk7XG4gICAgICAgIHJlcy53cml0ZShNdXN0YWNoZS5yZW5kZXIoYnVuZGxlcy5nZXRIdW1hbnNUeHQoKSwge1xuICAgICAgICAgICAgQ09OVEFDVF9BVVRIT1JTOiBjb25maWcuQ09OVEFDVF9BVVRIT1JTLFxuICAgICAgICAgICAgQ09OVEFDVF9FTUFJTDogY29uZmlnLkNPTlRBQ1RfRU1BSUxcbiAgICAgICAgfSkpO1xuICAgICAgICByZXMuZW5kKCk7XG4gICAgfSk7XG5cbiAgICBzaXRlSW5mb1JvdXRlci5nZXQoJy9zaXRlbWFwLnhtbCcsIChfcmVxOiBSZXF1ZXN0LCByZXM6IGV4cHJlc3MuUmVzcG9uc2UpID0+IHtcbiAgICAgICAgcmVzLnN0YXR1cyhIdHRwU3RhdHVzLk9LKTtcbiAgICAgICAgcmVzLnR5cGUoJ2FwcGxpY2F0aW9uL3htbDsgY2hhcnNldD11dGYtOCcpO1xuICAgICAgICByZXMud3JpdGUoTXVzdGFjaGUucmVuZGVyKGJ1bmRsZXMuZ2V0U2l0ZW1hcFhtbCgpLCB7XG4gICAgICAgICAgICBFWFRFUk5BTF9PUklHSU46IGNvbmZpZy5FWFRFUk5BTF9PUklHSU4sXG4gICAgICAgICAgICBMQVNUX01PRDogbmV3IERhdGUoKS50b0lTT1N0cmluZygpXG4gICAgICAgIH0pKTtcbiAgICAgICAgcmVzLmVuZCgpO1xuICAgIH0pO1xuXG4gICAgc2l0ZUluZm9Sb3V0ZXIuZ2V0KCcvYnJvd3NlcmNvbmZpZy54bWwnLCAoX3JlcTogUmVxdWVzdCwgcmVzOiBleHByZXNzLlJlc3BvbnNlKSA9PiB7XG4gICAgICAgIHJlcy5zdGF0dXMoSHR0cFN0YXR1cy5PSyk7XG4gICAgICAgIHJlcy50eXBlKCdhcHBsaWNhdGlvbi94bWw7IGNoYXJzZXQ9dXRmLTgnKTtcbiAgICAgICAgcmVzLndyaXRlKE11c3RhY2hlLnJlbmRlcihidW5kbGVzLmdldEJyb3dzZXJDb25maWdYbWwoKSwge1xuICAgICAgICAgICAgU1RZTEVfUFJJTUFSWV9DT0xPUjogY29uZmlnLlNUWUxFX1BSSU1BUllfQ09MT1JcbiAgICAgICAgfSkpO1xuICAgICAgICByZXMuZW5kKCk7XG4gICAgfSk7XG5cbiAgICBzaXRlSW5mb1JvdXRlci5nZXQoJy9zaXRlLndlYm1hbmlmZXN0JywgKF9yZXE6IFJlcXVlc3QsIHJlczogZXhwcmVzcy5SZXNwb25zZSkgPT4ge1xuICAgICAgICByZXMuc3RhdHVzKEh0dHBTdGF0dXMuT0spO1xuICAgICAgICByZXMudHlwZSgnYXBwbGljYXRpb24vbWFuaWZlc3QranNvbjsgY2hhcnNldD11dGYtOCcpO1xuICAgICAgICByZXMud3JpdGUoTXVzdGFjaGUucmVuZGVyKGJ1bmRsZXMuZ2V0U2l0ZVdlYk1hbmlmZXN0KCksIHtcbiAgICAgICAgICAgIEVYVEVSTkFMX09SSUdJTjogY29uZmlnLkVYVEVSTkFMX09SSUdJTixcbiAgICAgICAgICAgIFNUWUxFX0FQUExJQ0FUSU9OX05BTUU6IGNvbmZpZy5TVFlMRV9BUFBMSUNBVElPTl9OQU1FLFxuICAgICAgICAgICAgU1RZTEVfUFJJTUFSWV9DT0xPUjogY29uZmlnLlNUWUxFX1BSSU1BUllfQ09MT1JcbiAgICAgICAgfSkpO1xuICAgICAgICByZXMuZW5kKCk7XG4gICAgfSk7XG5cbiAgICBhcHAudXNlKCcvJywgc2l0ZUluZm9Sb3V0ZXIpO1xuXG4gICAgLy8gU2V0dXAgc2VydmluZyBmb3IgYWxsIGFsbCBjbGllbnQgYXBwbGljYXRpb24gbGV2ZWwgcm91dGVzLiBBbnkgcGF0aCBhIHVzZXIgZW50ZXJzLCB3aGljaFxuICAgIC8vIGRvZXNuJ3QgbWF0Y2ggdGhlIG9uZXMgZnJvbSBhYm92ZSAoc28gL3JlYWwgb25lcyBvciBzdGFuZGFyZCB3ZWIgb25lcykgd2lsbCBiZSBoYW5kbGVkXG4gICAgLy8gYnkgc2VydmluZyB0aGUgXCJjbGllbnQgYXBwbGljYXRpb25cIi4gVGhpcyB0cmFuc2xhdGVkIHRvIGRvaW5nIGEgc2VydmVyLXNpZGUgcmVuZGVyIG9mIHRoZVxuICAgIC8vIGFwcGxpY2F0aW9uIGFuZCBzZXJ2aW5nIHRoYXQgZW1iZWRkZWQgaW50byB7QGxpbmsgc3JjL3NoYXJlZC9zdGF0aWMvaW5kZXguaHRtbH0sIHdoaWNoXG4gICAgLy8gd2lsbCByZWZlcmVuY2UgL3JlYWwvY2xpZW50L2NsaWVudC5qcyBhbmQgb3RoZXIgc3RhdGljIHJlc291cmNlcyBpbiBvcmRlciB0byBib290IGl0IHVwLlxuICAgIC8vICoqKioqKioqKioqKioqKioqKioqXG5cbiAgICBjb25zdCBhcHBSb3V0ZXIgPSBleHByZXNzLlJvdXRlcigpO1xuXG4gICAgYXBwUm91dGVyLnVzZShuZXdTZXNzaW9uTWlkZGxld2FyZShTZXNzaW9uTGV2ZWwuTm9uZSwgU2Vzc2lvbkluZm9Tb3VyY2UuQ29va2llLCBjb25maWcuRU5WLCBpZGVudGl0eUNsaWVudCkpO1xuICAgIGFwcFJvdXRlci5nZXQoJyonLCB3cmFwKGFzeW5jIChyZXE6IFJlcXVlc3RXaXRoSWRlbnRpdHksIHJlczogZXhwcmVzcy5SZXNwb25zZSkgPT4ge1xuICAgICAgICBsZXQgZXZlbnQ6IEV2ZW50IHwgbnVsbCA9IG51bGw7XG4gICAgICAgIGxldCBjaGFyZ2ViZWVNYW5hZ2VBY2NvdW50VXJpOiBzdHJpbmcgfCBudWxsID0gbnVsbDtcblxuICAgICAgICBpZiAocmVxLnNlc3Npb24uaGFzVXNlcigpKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGV2ZW50ID0gYXdhaXQgY29udGVudFByaXZhdGVDbGllbnQud2l0aENvbnRleHQocmVxLnNlc3Npb25Ub2tlbikuZ2V0RXZlbnQoKTtcbiAgICAgICAgICAgICAgICBjaGFyZ2ViZWVNYW5hZ2VBY2NvdW50VXJpID0gYXdhaXQgY29udGVudFByaXZhdGVDbGllbnQud2l0aENvbnRleHQocmVxLnNlc3Npb25Ub2tlbikuZ2V0Q2hhcmdlYmVlTWFuYWdlUGFnZVVyaSgpO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGlmIChlLm5hbWUgPT0gJ0V2ZW50Tm90Rm91bmRFcnJvcicpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnN0IHBsYW4gPSAocmVxLnF1ZXJ5LnBsYW4gYXMgRXZlbnRQbGFuKSB8fCBFdmVudFBsYW4uUXVpY2tTdGFydGVyO1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQgPSBhd2FpdCBjb250ZW50UHJpdmF0ZUNsaWVudC53aXRoQ29udGV4dChyZXEuc2Vzc2lvblRva2VuKS5jcmVhdGVFdmVudChyZXEuc2Vzc2lvbiwgcGxhbik7XG4gICAgICAgICAgICAgICAgICAgICAgICBjaGFyZ2ViZWVNYW5hZ2VBY2NvdW50VXJpID0gYXdhaXQgY29udGVudFByaXZhdGVDbGllbnQud2l0aENvbnRleHQocmVxLnNlc3Npb25Ub2tlbikuZ2V0Q2hhcmdlYmVlTWFuYWdlUGFnZVVyaSgpO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBOb3RoaW5nIGhhcHBlbnMgaGVyZS4gV2UnbGwgdHJ5IGFnYWluIG9uIHRoZSBjbGllbnQuIEJ1dCB3ZSBkbyBsb2cgdGhlIGVycm9yLlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVxLmxvZy53YXJuKGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVxLmVycm9yTG9nLndhcm4oZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAvLyBOb3RoaW5nIGhhcHBlbnMgaGVyZS4gV2UnbGwgdHJ5IGFnYWluIG9uIHRoZSBjbGllbnQuIEJ1dCB3ZSBkbyBsb2cgdGhlIGVycm9yLlxuICAgICAgICAgICAgICAgICAgICByZXEubG9nLndhcm4oZSk7XG4gICAgICAgICAgICAgICAgICAgIHJlcS5lcnJvckxvZy53YXJuKGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IGluaXRpYWxTdGF0ZTogQ2xpZW50SW5pdGlhbFN0YXRlID0ge1xuICAgICAgICAgICAgZXZlbnQ6IGV2ZW50LFxuICAgICAgICAgICAgY2hhcmdlYmVlTWFuYWdlQWNjb3VudFVyaTogY2hhcmdlYmVlTWFuYWdlQWNjb3VudFVyaVxuICAgICAgICB9O1xuXG4gICAgICAgIGNvbnN0IFtjb250ZW50LCBzcGVjaWFsU3RhdHVzXSA9IHNlcnZlclNpZGVSZW5kZXIoXG4gICAgICAgICAgICByZXEudXJsLFxuICAgICAgICAgICAgcmVxLnNlc3Npb24sXG4gICAgICAgICAgICBpbml0aWFsU3RhdGVcbiAgICAgICAgKTtcblxuICAgICAgICByZXMuc3RhdHVzKHNwZWNpYWxTdGF0dXMgIT0gbnVsbCA/IHNwZWNpYWxTdGF0dXMgOiBIdHRwU3RhdHVzLk9LKTtcbiAgICAgICAgcmVzLnR5cGUoJ2h0bWwnKTtcbiAgICAgICAgcmVzLndyaXRlKGNvbnRlbnQpO1xuICAgICAgICByZXMuZW5kKCk7XG4gICAgfSkpO1xuXG4gICAgYXBwLnVzZSgnLycsIGFwcFJvdXRlcik7XG5cbiAgICAvLyBTdGFydCBzZXJ2aW5nXG4gICAgLy8gKioqKioqKioqKioqKioqKioqKipcblxuICAgIGFwcC5saXN0ZW4oY29uZmlnLlBPUlQsICcwLjAuMC4wJywgKCkgPT4ge1xuICAgICAgICBjb25zb2xlLmxvZyhgU3RhcnRlZCAke2NvbmZpZy5OQU1FfSBzZXJ2aWNlIG9uICR7Y29uZmlnLlBPUlR9YCk7XG4gICAgfSk7XG59XG5cblxubWFpbigpO1xuIl19