react-static
Version:
A progressive static site generator for React
819 lines (662 loc) • 62.2 kB
JavaScript
"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