UNPKG

react-static

Version:

A progressive static site generator for React

819 lines (662 loc) 62.2 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.getRouteInfo = getRouteInfo; exports.prefetchData = prefetchData; exports.prefetchTemplate = prefetchTemplate; exports.prefetch = prefetch; exports.isPrefetchableRoute = isPrefetchableRoute; exports.plugins = exports.onReloadClientData = exports.registerTemplateForPath = exports.registerTemplates = exports.onReloadTemplates = exports.templateErrorByPath = exports.templatesByPath = exports.templates = exports.registerPlugins = exports.pluginHooks = exports.addPrefetchExcludes = exports.sharedDataByHash = exports.routeErrorByPath = exports.routeInfoByPath = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof")); var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator")); var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator")); var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray")); var _axios = _interopRequireDefault(require("axios")); var _utils = require("./utils"); var _Visibility = _interopRequireDefault(require("./utils/Visibility")); // // RouteInfo / RouteData var routeInfoByPath = {}; exports.routeInfoByPath = routeInfoByPath; var routeErrorByPath = {}; exports.routeErrorByPath = routeErrorByPath; var sharedDataByHash = {}; exports.sharedDataByHash = sharedDataByHash; var inflightRouteInfo = {}; var inflightPropHashes = {}; var prefetchExcludes = []; var addPrefetchExcludes = function addPrefetchExcludes(excludes) { if (!Array.isArray(excludes)) { throw new Error('Excludes must be an array of strings/regex!'); } prefetchExcludes = [].concat((0, _toConsumableArray2["default"])(prefetchExcludes), (0, _toConsumableArray2["default"])(excludes)); }; exports.addPrefetchExcludes = addPrefetchExcludes; var requestPool = (0, _utils.createPool)({ concurrency: Number(process.env.REACT_STATIC_PREFETCH_RATE) }); // Plugins var pluginHooks = []; exports.pluginHooks = pluginHooks; var registerPlugins = function registerPlugins(newPlugins) { pluginHooks.splice.apply(pluginHooks, [0, Infinity].concat((0, _toConsumableArray2["default"])(newPlugins))); }; // Templates exports.registerPlugins = registerPlugins; var templates = {}; exports.templates = templates; var templatesByPath = {}; exports.templatesByPath = templatesByPath; var templateErrorByPath = {}; exports.templateErrorByPath = templateErrorByPath; var onReloadTemplates = function onReloadTemplates(fn) { onReloadTemplates.listeners.push(fn); return function () { onReloadTemplates.listeners = onReloadTemplates.listeners.filter(function (d) { return d !== fn; }); }; }; exports.onReloadTemplates = onReloadTemplates; onReloadTemplates.listeners = []; var registerTemplates = /*#__PURE__*/function () { var _ref = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(tmps, notFoundKey) { return _regenerator["default"].wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: Object.keys(templatesByPath).forEach(function (key) { delete templatesByPath[key]; }); Object.keys(templateErrorByPath).forEach(function (key) { delete templateErrorByPath[key]; }); Object.keys(templates).forEach(function (key) { delete templates[key]; }); Object.keys(tmps).forEach(function (key) { templates[key] = tmps[key]; if (!templates[key]) { console.warn("Template registered without default export: ".concat(key.replace(/__react_static_root__\//, ''))); } }); templatesByPath[_utils.PATH_404] = templates[notFoundKey]; if (!(process.env.NODE_ENV === 'development' && typeof document !== 'undefined')) { _context.next = 8; break; } _context.next = 8; return prefetch(window.location.pathname); case 8: onReloadTemplates.listeners.forEach(function (fn) { return fn(); }); if (typeof document !== 'undefined' && process.env.REACT_STATIC_SILENT !== 'true') { console.log('React Static: Templates Reloaded'); } case 10: case "end": return _context.stop(); } } }, _callee); })); return function registerTemplates(_x, _x2) { return _ref.apply(this, arguments); }; }(); exports.registerTemplates = registerTemplates; var registerTemplateForPath = function registerTemplateForPath(path, template) { path = (0, _utils.getRoutePath)(path); templatesByPath[path] = templates[template]; }; exports.registerTemplateForPath = registerTemplateForPath; var onReloadClientData = function onReloadClientData(fn) { Object.keys(routeErrorByPath).forEach(function (key) { delete routeErrorByPath[key]; }); onReloadClientData.listeners.push(fn); return function () { onReloadClientData.listeners = onReloadClientData.listeners.filter(function (d) { return d !== fn; }); }; }; exports.onReloadClientData = onReloadClientData; onReloadClientData.listeners = []; if (typeof document !== 'undefined') { init(); } // When in development, init a socket to listen for data changes // When the data changes, we invalidate and reload all of the route data function init() { // In development, we need to open a socket to listen for changes to data if (process.env.REACT_STATIC_ENV === 'development') { var io = require('socket.io-client'); var run = /*#__PURE__*/function () { var _ref2 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee2() { var socket; return _regenerator["default"].wrap(function _callee2$(_context2) { while (1) { switch (_context2.prev = _context2.next) { case 0: try { socket = io(); socket.on('connect', function () {// Do nothing }); socket.on('message', function (_ref3) { var type = _ref3.type; if (type === 'reloadClientData') { reloadClientData(); } }); } catch (err) { console.log('React-Static data hot-loader websocket encountered the following error:'); console.error(err); } case 1: case "end": return _context2.stop(); } } }, _callee2); })); return function run() { return _ref2.apply(this, arguments); }; }(); run(); } if (process.env.REACT_STATIC_DISABLE_PRELOAD === 'false') { startPreloader(); } } /** * The preloader searches for all anchor elements on the page every poll * interval, and, unless specified by data-prefetch, start a visibility observer * for that element. * * The href of the anchor is preloaded when the element becomes visible. */ function startPreloader() { if (typeof document === 'undefined') { return; } var run = function run() { var els = [].slice.call(document.getElementsByTagName('a')); els.forEach(function (el) { var href = el.getAttribute('href'); var prefetchOption = el.getAttribute('data-prefetch'); var shouldPrefetch = !prefetchOption || prefetchOption === 'true' || prefetchOption === 'visible'; if (href && shouldPrefetch) { (0, _Visibility["default"])(el, function () { return prefetch(href); }); } }); }; setInterval(run, Number(process.env.REACT_STATIC_PRELOAD_POLL_INTERVAL)); } function reloadClientData() { return _reloadClientData.apply(this, arguments); } function _reloadClientData() { _reloadClientData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee3() { return _regenerator["default"].wrap(function _callee3$(_context3) { while (1) { switch (_context3.prev = _context3.next) { case 0: console.log('React Static: Reloading Data...') // Delete all cached data ; [routeInfoByPath, sharedDataByHash, routeErrorByPath, inflightRouteInfo, inflightPropHashes].forEach(function (part) { Object.keys(part).forEach(function (key) { delete part[key]; }); }); // Prefetch the current route's data before you reload routes _context3.next = 4; return prefetch(window.location.pathname); case 4: onReloadClientData.listeners.forEach(function (fn) { return fn(); }); case 5: case "end": return _context3.stop(); } } }, _callee3); })); return _reloadClientData.apply(this, arguments); } function getRouteInfo(_x3) { return _getRouteInfo.apply(this, arguments); } function _getRouteInfo() { _getRouteInfo = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee4(path) { var _ref4, priority, routeInfo, _yield$inflightRouteI, data, routeInfoRoot, getPath, _yield$axios$get, _data, _yield$inflightRouteI2, _data2, _args4 = arguments; return _regenerator["default"].wrap(function _callee4$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: _ref4 = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {}, priority = _ref4.priority; path = (0, _utils.getRoutePath)(path); // Check if we should fetch RouteData for this url et all. if (isPrefetchableRoute(path)) { _context4.next = 4; break; } return _context4.abrupt("return"); case 4: if (!routeInfoByPath[path]) { _context4.next = 6; break; } return _context4.abrupt("return", routeInfoByPath[path]); case 6: if (!routeErrorByPath[path]) { _context4.next = 8; break; } return _context4.abrupt("return"); case 8: _context4.prev = 8; if (!(process.env.REACT_STATIC_ENV === 'development')) { _context4.next = 18; break; } // In dev, request from the webpack dev server if (!inflightRouteInfo[path]) { inflightRouteInfo[path] = _axios["default"].get("/__react-static__/routeInfo/".concat(path === '/' ? '' : path)); } _context4.next = 13; return inflightRouteInfo[path]; case 13: _yield$inflightRouteI = _context4.sent; data = _yield$inflightRouteI.data; routeInfo = data; _context4.next = 34; break; case 18: // In production, fetch the JSON file // Find the location of the routeInfo.json file routeInfoRoot = (process.env.REACT_STATIC_DISABLE_ROUTE_PREFIXING === 'true' ? process.env.REACT_STATIC_SITE_ROOT : process.env.REACT_STATIC_PUBLIC_PATH) || '/'; getPath = "".concat(routeInfoRoot).concat((0, _utils.pathJoin)(path, 'routeInfo.json')); // If this is a priority call bypass the queue if (!priority) { _context4.next = 28; break; } _context4.next = 23; return _axios["default"].get(getPath); case 23: _yield$axios$get = _context4.sent; _data = _yield$axios$get.data; routeInfo = _data; _context4.next = 34; break; case 28: // Otherwise, add it to the queue if (!inflightRouteInfo[path]) { inflightRouteInfo[path] = requestPool.add(function () { return _axios["default"].get(getPath); }); } _context4.next = 31; return inflightRouteInfo[path]; case 31: _yield$inflightRouteI2 = _context4.sent; _data2 = _yield$inflightRouteI2.data; routeInfo = _data2; case 34: _context4.next = 43; break; case 36: _context4.prev = 36; _context4.t0 = _context4["catch"](8); // If there was an error, mark the path as errored routeErrorByPath[path] = true; // Unless we already fetched the 404 page, // try to load info for the 404 page if (!(!routeInfoByPath[_utils.PATH_404] && !routeErrorByPath[_utils.PATH_404])) { _context4.next = 42; break; } getRouteInfo(_utils.PATH_404, { priority: priority }); return _context4.abrupt("return"); case 42: return _context4.abrupt("return"); case 43: if (!priority) { delete inflightRouteInfo[path]; } if ((0, _typeof2["default"])(routeInfo) !== 'object' || !routeInfo.path) { // routeInfo must have returned 200, but is not actually // a routeInfo object. Mark it as an error and move on silently routeErrorByPath[path] = true; } else { routeInfoByPath[path] = routeInfo; } return _context4.abrupt("return", routeInfoByPath[path]); case 46: case "end": return _context4.stop(); } } }, _callee4, null, [[8, 36]]); })); return _getRouteInfo.apply(this, arguments); } function prefetchData(_x4) { return _prefetchData.apply(this, arguments); } function _prefetchData() { _prefetchData = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee6(path) { var _ref5, priority, routeInfo, _args6 = arguments; return _regenerator["default"].wrap(function _callee6$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: _ref5 = _args6.length > 1 && _args6[1] !== undefined ? _args6[1] : {}, priority = _ref5.priority; _context6.next = 3; return getRouteInfo(path, { priority: priority }); case 3: routeInfo = _context6.sent; if (routeInfo) { _context6.next = 6; break; } return _context6.abrupt("return"); case 6: if (!routeInfo.sharedData) { _context6.next = 8; break; } return _context6.abrupt("return", (0, _utils.getFullRouteData)(routeInfo)); case 8: // Request and build the props one by one routeInfo.sharedData = {}; // Request the template and loop over the routeInfo.sharedHashesByProp, requesting each prop _context6.next = 11; return Promise.all(Object.keys(routeInfo.sharedHashesByProp).map( /*#__PURE__*/function () { var _ref7 = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee5(key) { var hash, staticDataPath, absoluteStaticDataPath, _yield$axios$get2, prop, _yield$inflightPropHa, _prop; return _regenerator["default"].wrap(function _callee5$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: hash = routeInfo.sharedHashesByProp[key]; // Check the sharedDataByHash first if (sharedDataByHash[hash]) { _context5.next = 26; break; } _context5.prev = 2; staticDataPath = (0, _utils.pathJoin)(process.env.REACT_STATIC_ASSETS_PATH, "staticData/".concat(hash, ".json")); absoluteStaticDataPath = (0, _utils.makePathAbsolute)(staticDataPath); // If priority, get it immediately if (!priority) { _context5.next = 13; break; } _context5.next = 8; return _axios["default"].get(absoluteStaticDataPath); case 8: _yield$axios$get2 = _context5.sent; prop = _yield$axios$get2.data; sharedDataByHash[hash] = prop; _context5.next = 19; break; case 13: // Non priority, share inflight requests and use pool if (!inflightPropHashes[hash]) { inflightPropHashes[hash] = requestPool.add(function () { return _axios["default"].get(absoluteStaticDataPath); }); } _context5.next = 16; return inflightPropHashes[hash]; case 16: _yield$inflightPropHa = _context5.sent; _prop = _yield$inflightPropHa.data; // Place it in the cache sharedDataByHash[hash] = _prop; case 19: _context5.next = 25; break; case 21: _context5.prev = 21; _context5.t0 = _context5["catch"](2); console.log('Error: There was an error retrieving a prop for this route! hashID:', hash); console.error(_context5.t0); case 25: if (!priority) { delete inflightPropHashes[hash]; } case 26: // Otherwise, just set it as the key routeInfo.sharedData[key] = sharedDataByHash[hash]; case 27: case "end": return _context5.stop(); } } }, _callee5, null, [[2, 21]]); })); return function (_x7) { return _ref7.apply(this, arguments); }; }())); case 11: return _context6.abrupt("return", (0, _utils.getFullRouteData)(routeInfo)); case 12: case "end": return _context6.stop(); } } }, _callee6); })); return _prefetchData.apply(this, arguments); } function prefetchTemplate(_x5) { return _prefetchTemplate.apply(this, arguments); } function _prefetchTemplate() { _prefetchTemplate = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee7(path) { var _ref6, priority, routeInfo, Template, _args7 = arguments; return _regenerator["default"].wrap(function _callee7$(_context7) { while (1) { switch (_context7.prev = _context7.next) { case 0: _ref6 = _args7.length > 1 && _args7[1] !== undefined ? _args7[1] : {}, priority = _ref6.priority; // Clean the path path = (0, _utils.getRoutePath)(path); // Get route info so we can check if path has any data _context7.next = 4; return getRouteInfo(path, { priority: priority }); case 4: routeInfo = _context7.sent; if (routeInfo) { // Make sure to use the path as defined in the routeInfo object here. // This will make sure 404 route info returned from getRouteInfo is handled correctly. registerTemplateForPath(routeInfo.path, routeInfo.template); } // Preload the template if available Template = templatesByPath[path]; if (Template) { _context7.next = 10; break; } // If no template was found, mark it with an error templateErrorByPath[path] = true; return _context7.abrupt("return"); case 10: if (routeInfo) { _context7.next = 12; break; } return _context7.abrupt("return", Template); case 12: if (!(!routeInfo.templateLoaded && Template.preload)) { _context7.next = 21; break; } if (!priority) { _context7.next = 18; break; } _context7.next = 16; return Template.preload(); case 16: _context7.next = 20; break; case 18: _context7.next = 20; return requestPool.add(function () { return Template.preload(); }); case 20: routeInfo.templateLoaded = true; case 21: return _context7.abrupt("return", Template); case 22: case "end": return _context7.stop(); } } }, _callee7); })); return _prefetchTemplate.apply(this, arguments); } function prefetch(_x6) { return _prefetch.apply(this, arguments); } function _prefetch() { _prefetch = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee8(path) { var options, type, data, _yield$Promise$all, _yield$Promise$all2, _args8 = arguments; return _regenerator["default"].wrap(function _callee8$(_context8) { while (1) { switch (_context8.prev = _context8.next) { case 0: options = _args8.length > 1 && _args8[1] !== undefined ? _args8[1] : {}; // Clean the path path = (0, _utils.getRoutePath)(path); type = options.type; // If it's priority, we stop the queue temporarily if (options.priority) { requestPool.stop(); } if (!(type === 'data')) { _context8.next = 10; break; } _context8.next = 7; return prefetchData(path, options); case 7: data = _context8.sent; _context8.next = 21; break; case 10: if (!(type === 'template')) { _context8.next = 15; break; } _context8.next = 13; return prefetchTemplate(path, options); case 13: _context8.next = 21; break; case 15: ; _context8.next = 18; return Promise.all([prefetchData(path, options), prefetchTemplate(path, options)]); case 18: _yield$Promise$all = _context8.sent; _yield$Promise$all2 = (0, _slicedToArray2["default"])(_yield$Promise$all, 1); data = _yield$Promise$all2[0]; case 21: // If it was priority, start the queue again if (options.priority) { requestPool.start(); } return _context8.abrupt("return", data); case 23: case "end": return _context8.stop(); } } }, _callee8); })); return _prefetch.apply(this, arguments); } function isPrefetchableRoute(path) { // when rendering static pages we dont need this at all if (typeof document === 'undefined') { return false; } if (prefetchExcludes.some(function (exclude) { if (typeof exclude === 'string' && path.startsWith(exclude)) { return true; } if ((0, _typeof2["default"])(exclude) === 'object' && exclude.test(path)) { return true; } return false; })) { return false; } var _document = document, location = _document.location; var link; try { link = new URL(path, location.href); } catch (e) { if (typeof URL !== 'function') { console.error('URL polyfill is required for this browser. https://github.com/react-static/react-static/blob/master/docs/concepts.md#browser-support'); } // Return false on invalid URLs return false; } // if the hostname/port/protocol doesn't match its not a route link if (location.host !== link.host || location.protocol !== link.protocol) { return false; } // deny all files with extension other than .html // Reverting this change because of issue #1354 // if (link.pathname.includes('.') && !link.pathname.includes('.html')) { // return false // } return true; } var plugins = { Root: function Root(Comp) { var hooks = (0, _utils.getHooks)(pluginHooks, 'Root'); return (0, _utils.reduceHooks)(hooks, { sync: true })(Comp); }, Routes: function Routes(Comp) { var hooks = (0, _utils.getHooks)(pluginHooks, 'Routes'); return (0, _utils.reduceHooks)(hooks, { sync: true })(Comp); } }; exports.plugins = plugins; //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9icm93c2VyL2luZGV4LmpzIl0sIm5hbWVzIjpbInJvdXRlSW5mb0J5UGF0aCIsInJvdXRlRXJyb3JCeVBhdGgiLCJzaGFyZWREYXRhQnlIYXNoIiwiaW5mbGlnaHRSb3V0ZUluZm8iLCJpbmZsaWdodFByb3BIYXNoZXMiLCJwcmVmZXRjaEV4Y2x1ZGVzIiwiYWRkUHJlZmV0Y2hFeGNsdWRlcyIsImV4Y2x1ZGVzIiwiQXJyYXkiLCJpc0FycmF5IiwiRXJyb3IiLCJyZXF1ZXN0UG9vbCIsImNvbmN1cnJlbmN5IiwiTnVtYmVyIiwicHJvY2VzcyIsImVudiIsIlJFQUNUX1NUQVRJQ19QUkVGRVRDSF9SQVRFIiwicGx1Z2luSG9va3MiLCJyZWdpc3RlclBsdWdpbnMiLCJuZXdQbHVnaW5zIiwic3BsaWNlIiwiSW5maW5pdHkiLCJ0ZW1wbGF0ZXMiLCJ0ZW1wbGF0ZXNCeVBhdGgiLCJ0ZW1wbGF0ZUVycm9yQnlQYXRoIiwib25SZWxvYWRUZW1wbGF0ZXMiLCJmbiIsImxpc3RlbmVycyIsInB1c2giLCJmaWx0ZXIiLCJkIiwicmVnaXN0ZXJUZW1wbGF0ZXMiLCJ0bXBzIiwibm90Rm91bmRLZXkiLCJPYmplY3QiLCJrZXlzIiwiZm9yRWFjaCIsImtleSIsImNvbnNvbGUiLCJ3YXJuIiwicmVwbGFjZSIsIlBBVEhfNDA0IiwiTk9ERV9FTlYiLCJkb2N1bWVudCIsInByZWZldGNoIiwid2luZG93IiwibG9jYXRpb24iLCJwYXRobmFtZSIsIlJFQUNUX1NUQVRJQ19TSUxFTlQiLCJsb2ciLCJyZWdpc3RlclRlbXBsYXRlRm9yUGF0aCIsInBhdGgiLCJ0ZW1wbGF0ZSIsIm9uUmVsb2FkQ2xpZW50RGF0YSIsImluaXQiLCJSRUFDVF9TVEFUSUNfRU5WIiwiaW8iLCJyZXF1aXJlIiwicnVuIiwic29ja2V0Iiwib24iLCJ0eXBlIiwicmVsb2FkQ2xpZW50RGF0YSIsImVyciIsImVycm9yIiwiUkVBQ1RfU1RBVElDX0RJU0FCTEVfUFJFTE9BRCIsInN0YXJ0UHJlbG9hZGVyIiwiZWxzIiwic2xpY2UiLCJjYWxsIiwiZ2V0RWxlbWVudHNCeVRhZ05hbWUiLCJlbCIsImhyZWYiLCJnZXRBdHRyaWJ1dGUiLCJwcmVmZXRjaE9wdGlvbiIsInNob3VsZFByZWZldGNoIiwic2V0SW50ZXJ2YWwiLCJSRUFDVF9TVEFUSUNfUFJFTE9BRF9QT0xMX0lOVEVSVkFMIiwicGFydCIsImdldFJvdXRlSW5mbyIsInByaW9yaXR5IiwiaXNQcmVmZXRjaGFibGVSb3V0ZSIsImF4aW9zIiwiZ2V0IiwiZGF0YSIsInJvdXRlSW5mbyIsInJvdXRlSW5mb1Jvb3QiLCJSRUFDVF9TVEFUSUNfRElTQUJMRV9ST1VURV9QUkVGSVhJTkciLCJSRUFDVF9TVEFUSUNfU0lURV9ST09UIiwiUkVBQ1RfU1RBVElDX1BVQkxJQ19QQVRIIiwiZ2V0UGF0aCIsImFkZCIsInByZWZldGNoRGF0YSIsInNoYXJlZERhdGEiLCJQcm9taXNlIiwiYWxsIiwic2hhcmVkSGFzaGVzQnlQcm9wIiwibWFwIiwiaGFzaCIsInN0YXRpY0RhdGFQYXRoIiwiUkVBQ1RfU1RBVElDX0FTU0VUU19QQVRIIiwiYWJzb2x1dGVTdGF0aWNEYXRhUGF0aCIsInByb3AiLCJwcmVmZXRjaFRlbXBsYXRlIiwiVGVtcGxhdGUiLCJ0ZW1wbGF0ZUxvYWRlZCIsInByZWxvYWQiLCJvcHRpb25zIiwic3RvcCIsInN0YXJ0Iiwic29tZSIsImV4Y2x1ZGUiLCJzdGFydHNXaXRoIiwidGVzdCIsImxpbmsiLCJVUkwiLCJlIiwiaG9zdCIsInByb3RvY29sIiwicGx1Z2lucyIsIlJvb3QiLCJDb21wIiwiaG9va3MiLCJzeW5jIiwiUm91dGVzIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQTs7QUFFQTs7QUFVQTs7QUFYQTtBQWFBO0FBQ08sSUFBTUEsZUFBZSxHQUFHLEVBQXhCOztBQUNBLElBQU1DLGdCQUFnQixHQUFHLEVBQXpCOztBQUNBLElBQU1DLGdCQUFnQixHQUFHLEVBQXpCOztBQUNQLElBQU1DLGlC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QVEsQ0FBQ3dFLFFBQVQsS0FBc0JKLElBQUksQ0FBQ0ksUUFBOUQsRUFBd0U7QUFDdEUsV0FBTyxLQUFQO0FBQ0QsR0F0Q3VDLENBd0N4QztBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFFQSxTQUFPLElBQVA7QUFDRDs7QUFFTSxJQUFNQyxPQUFPLEdBQUc7QUFDckJDLEVBQUFBLElBQUksRUFBRSxjQUFBQyxJQUFJLEVBQUk7QUFDWixRQUFNQyxLQUFLLEdBQUcscUJBQVN6RyxXQUFULEVBQXNCLE1BQXRCLENBQWQ7QUFDQSxXQUFPLHdCQUFZeUcsS0FBWixFQUFtQjtBQUFFQyxNQUFBQSxJQUFJLEVBQUU7QUFBUixLQUFuQixFQUFtQ0YsSUFBbkMsQ0FBUDtBQUNELEdBSm9CO0FBS3JCRyxFQUFBQSxNQUFNLEVBQUUsZ0JBQUFILElBQUksRUFBSTtBQUNkLFFBQU1DLEtBQUssR0FBRyxxQkFBU3pHLFdBQVQsRUFBc0IsUUFBdEIsQ0FBZDtBQUNBLFdBQU8sd0JBQVl5RyxLQUFaLEVBQW1CO0FBQUVDLE1BQUFBLElBQUksRUFBRTtBQUFSLEtBQW5CLEVBQW1DRixJQUFuQyxDQUFQO0FBQ0Q7QUFSb0IsQ0FBaEIiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgYXhpb3MgZnJvbSAnYXhpb3MnXG4vL1xuaW1wb3J0IHtcbiAgY3JlYXRlUG9vbCxcbiAgZ2V0Um91dGVQYXRoLFxuICBwYXRoSm9pbixcbiAgZ2V0RnVsbFJvdXRlRGF0YSxcbiAgbWFrZVBhdGhBYnNvbHV0ZSxcbiAgZ2V0SG9va3MsXG4gIHJlZHVjZUhvb2tzLFxuICBQQVRIXzQwNCxcbn0gZnJvbSAnLi91dGlscydcbmltcG9ydCBvblZpc2libGUgZnJvbSAnLi91dGlscy9WaXNpYmlsaXR5J1xuXG4vLyBSb3V0ZUluZm8gLyBSb3V0ZURhdGFcbmV4cG9ydCBjb25zdCByb3V0ZUluZm9CeVBhdGggPSB7fVxuZXhwb3J0IGNvbnN0IHJvdXRlRXJyb3JCeVBhdGggPSB7fVxuZXhwb3J0IGNvbnN0IHNoYXJlZERhdGFCeUhhc2ggPSB7fVxuY29uc3QgaW5mbGlnaHRSb3V0ZUluZm8gPSB7fVxuY29uc3QgaW5mbGlnaHRQcm9wSGFzaGVzID0ge31cbmxldCBwcmVmZXRjaEV4Y2x1ZGVzID0gW11cblxuZXhwb3J0IGNvbnN0IGFkZFByZWZldGNoRXhjbHVkZXMgPSBleGNsdWRlcyA9PiB7XG4gIGlmICghQXJyYXkuaXNBcnJheShleGNsdWRlcykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0V4Y2x1ZGVzIG11c3QgYmUgYW4gYXJyYXkgb2Ygc3RyaW5ncy9yZWdleCEnKVxuICB9XG4gIHByZWZldGNoRXhjbHVkZXMgPSBbLi4ucHJlZmV0Y2hFeGNsdWRlcywgLi4uZXhjbHVkZXNdXG59XG5cbmNvbnN0IHJlcXVlc3RQb29sID0gY3JlYXRlUG9vbCh7XG4gIGNvbmN1cnJlbmN5OiBOdW1iZXIocHJvY2Vzcy5lbnYuUkVBQ1RfU1RBVElDX1BSRUZFVENIX1JBVEUpLFxufSlcblxuLy8gUGx1Z2luc1xuZXhwb3J0IGNvbnN0IHBsdWdpbkhvb2tzID0gW11cbmV4cG9ydCBjb25zdCByZWdpc3RlclBsdWdpbnMgPSBuZXdQbHVnaW5zID0+IHtcbiAgcGx1Z2luSG9va3Muc3BsaWNlKDAsIEluZmluaXR5LCAuLi5uZXdQbHVnaW5zKVxufVxuXG4vLyBUZW1wbGF0ZXNcbmV4cG9ydCBjb25zdCB0ZW1wbGF0ZXMgPSB7fVxuZXhwb3J0IGNvbnN0IHRlbXBsYXRlc0J5UGF0aCA9IHt9XG5leHBvcnQgY29uc3QgdGVtcGxhdGVFcnJvckJ5UGF0aCA9IHt9XG5leHBvcnQgY29uc3Qgb25SZWxvYWRUZW1wbGF0ZXMgPSBmbiA9PiB7XG4gIG9uUmVsb2FkVGVtcGxhdGVzLmxpc3RlbmVycy5wdXNoKGZuKVxuICByZXR1cm4gKCkgPT4ge1xuICAgIG9uUmVsb2FkVGVtcGxhdGVzLmxpc3RlbmVycyA9IG9uUmVsb2FkVGVtcGxhdGVzLmxpc3RlbmVycy5maWx0ZXIoXG4gICAgICBkID0+IGQgIT09IGZuXG4gICAgKVxuICB9XG59XG5vblJlbG9hZFRlbXBsYXRlcy5saXN0ZW5lcnMgPSBbXVxuXG5leHBvcnQgY29uc3QgcmVnaXN0ZXJUZW1wbGF0ZXMgPSBhc3luYyAodG1wcywgbm90Rm91bmRLZXkpID0+IHtcbiAgT2JqZWN0LmtleXModGVtcGxhdGVzQnlQYXRoKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgZGVsZXRlIHRlbXBsYXRlc0J5UGF0aFtrZXldXG4gIH0pXG4gIE9iamVjdC5rZXlzKHRlbXBsYXRlRXJyb3JCeVBhdGgpLmZvckVhY2goa2V5ID0+IHtcbiAgICBkZWxldGUgdGVtcGxhdGVFcnJvckJ5UGF0aFtrZXldXG4gIH0pXG4gIE9iamVjdC5rZXlzKHRlbXBsYXRlcykuZm9yRWFjaChrZXkgPT4ge1xuICAgIGRlbGV0ZSB0ZW1wbGF0ZXNba2V5XVxuICB9KVxuICBPYmplY3Qua2V5cyh0bXBzKS5mb3JFYWNoKGtleSA9PiB7XG4gICAgdGVtcGxhdGVzW2tleV0gPSB0bXBzW2tleV1cbiAgICBpZiAoIXRlbXBsYXRlc1trZXldKSB7XG4gICAgICBjb25zb2xlLndhcm4oXG4gICAgICAgIGBUZW1wbGF0ZSByZWdpc3RlcmVkIHdpdGhvdXQgZGVmYXVsdCBleHBvcnQ6ICR7a2V5LnJlcGxhY2UoXG4gICAgICAgICAgL19fcmVhY3Rfc3RhdGljX3Jvb3RfX1xcLy8sXG4gICAgICAgICAgJydcbiAgICAgICAgKX1gXG4gICAgICApXG4gICAgfVxuICB9KVxuICB0ZW1wbGF0ZXNCeVBhdGhbUEFUSF80MDRdID0gdGVtcGxhdGVzW25vdEZvdW5kS2V5XVxuXG4gIGlmIChcbiAgICBwcm9jZXNzLmVudi5OT0RFX0VOViA9PT0gJ2RldmVsb3BtZW50JyAmJlxuICAgIHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCdcbiAgKSB7XG4gICAgYXdhaXQgcHJlZmV0Y2god2luZG93LmxvY2F0aW9uLnBhdGhuYW1lKVxuICB9XG5cbiAgb25SZWxvYWRUZW1wbGF0ZXMubGlzdGVuZXJzLmZvckVhY2goZm4gPT4gZm4oKSlcblxuICBpZiAoXG4gICAgdHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJlxuICAgIHByb2Nlc3MuZW52LlJFQUNUX1NUQVRJQ19TSUxFTlQgIT09ICd0cnVlJ1xuICApIHtcbiAgICBjb25zb2xlLmxvZygnUmVhY3QgU3RhdGljOiBUZW1wbGF0ZXMgUmVsb2FkZWQnKVxuICB9XG59XG5cbmV4cG9ydCBjb25zdCByZWdpc3RlclRlbXBsYXRlRm9yUGF0aCA9IChwYXRoLCB0ZW1wbGF0ZSkgPT4ge1xuICBwYXRoID0gZ2V0Um91dGVQYXRoKHBhdGgpXG4gIHRlbXBsYXRlc0J5UGF0aFtwYXRoXSA9IHRlbXBsYXRlc1t0ZW1wbGF0ZV1cbn1cblxuZXhwb3J0IGNvbnN0IG9uUmVsb2FkQ2xpZW50RGF0YSA9IGZuID0+IHtcbiAgT2JqZWN0LmtleXMocm91dGVFcnJvckJ5UGF0aCkuZm9yRWFjaChrZXkgPT4ge1xuICAgIGRlbGV0ZSByb3V0ZUVycm9yQnlQYXRoW2tleV1cbiAgfSlcbiAgb25SZWxvYWRDbGllbnREYXRhLmxpc3RlbmVycy5wdXNoKGZuKVxuICByZXR1cm4gKCkgPT4ge1xuICAgIG9uUmVsb2FkQ2xpZW50RGF0YS5saXN0ZW5lcnMgPSBvblJlbG9hZENsaWVudERhdGEubGlzdGVuZXJzLmZpbHRlcihcbiAgICAgIGQgPT4gZCAhPT0gZm5cbiAgICApXG4gIH1cbn1cbm9uUmVsb2FkQ2xpZW50RGF0YS5saXN0ZW5lcnMgPSBbXVxuXG5pZiAodHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJykge1xuICBpbml0KClcbn1cblxuLy8gV2hlbiBpbiBkZXZlbG9wbWVudCwgaW5pdCBhIHNvY2tldCB0byBsaXN0ZW4gZm9yIGRhdGEgY2hhbmdlc1xuLy8gV2hlbiB0aGUgZGF0YSBjaGFuZ2VzLCB3ZSBpbnZhbGlkYXRlIGFuZCByZWxvYWQgYWxsIG9mIHRoZSByb3V0ZSBkYXRhXG5mdW5jdGlvbiBpbml0KCkge1xuICAvLyBJbiBkZXZlbG9wbWVudCwgd2UgbmVlZCB0byBvcGVuIGEgc29ja2V0IHRvIGxpc3RlbiBmb3IgY2hhbmdlcyB0byBkYXRhXG4gIGlmIChwcm9jZXNzLmVudi5SRUFDVF9TVEFUSUNfRU5WID09PSAnZGV2ZWxvcG1lbnQnKSB7XG4gICAgY29uc3QgaW8gPSByZXF1aXJlKCdzb2NrZXQuaW8tY2xpZW50JylcbiAgICBjb25zdCBydW4gPSBhc3luYyAoKSA9PiB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCBzb2NrZXQgPSBpbygpXG4gICAgICAgIHNvY2tldC5vbignY29ubmVjdCcsICgpID0+IHtcbiAgICAgICAgICAvLyBEbyBub3RoaW5nXG4gICAgICAgIH0pXG4gICAgICAgIHNvY2tldC5vbignbWVzc2FnZScsICh7IHR5cGUgfSkgPT4ge1xuICAgICAgICAgIGlmICh0eXBlID09PSAncmVsb2FkQ2xpZW50RGF0YScpIHtcbiAgICAgICAgICAgIHJlbG9hZENsaWVudERhdGEoKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAnUmVhY3QtU3RhdGljIGRhdGEgaG90LWxvYWRlciB3ZWJzb2NrZXQgZW5jb3VudGVyZWQgdGhlIGZvbGxvd2luZyBlcnJvcjonXG4gICAgICAgIClcbiAgICAgICAgY29uc29sZS5lcnJvcihlcnIpXG4gICAgICB9XG4gICAgfVxuICAgIHJ1bigpXG4gIH1cblxuICBpZiAocHJvY2Vzcy5lbnYuUkVBQ1RfU1RBVElDX0RJU0FCTEVfUFJFTE9BRCA9PT0gJ2ZhbHNlJykge1xuICAgIHN0YXJ0UHJlbG9hZGVyKClcbiAgfVxufVxuXG4vKipcbiAqIFRoZSBwcmVsb2FkZXIgc2VhcmNoZXMgZm9yIGFsbCBhbmNob3IgZWxlbWVudHMgb24gdGhlIHBhZ2UgZXZlcnkgcG9sbFxuICogaW50ZXJ2YWwsIGFuZCwgdW5sZXNzIHNwZWNpZmllZCBieSBkYXRhLXByZWZldGNoLCBzdGFydCBhIHZpc2liaWxpdHkgb2JzZXJ2ZXJcbiAqIGZvciB0aGF0IGVsZW1lbnQuXG4gKlxuICogVGhlIGhyZWYgb2YgdGhlIGFuY2hvciBp