react-static
Version:
A progressive static site generator for React
349 lines (276 loc) • 37.6 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.getEmbeddedRouteInfoScript = getEmbeddedRouteInfoScript;
exports["default"] = void 0;
var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
var _crypto = _interopRequireDefault(require("crypto"));
var _react = _interopRequireDefault(require("react"));
var _server = require("react-dom/server");
var _reactHelmet = _interopRequireDefault(require("react-helmet"));
var _reactUniversalComponent = require("react-universal-component");
var _webpackFlushChunks = _interopRequireDefault(require("webpack-flush-chunks"));
var _path = _interopRequireDefault(require("path"));
var _fsExtra = _interopRequireDefault(require("fs-extra"));
var _jsesc = _interopRequireDefault(require("jsesc"));
var _Redirect = _interopRequireDefault(require("./components/Redirect"));
var _plugins = _interopRequireDefault(require("./plugins"));
var _utils = require("../utils");
var _chunkBuilder = require("../utils/chunkBuilder");
var _HtmlWithMeta = _interopRequireDefault(require("./components/HtmlWithMeta"));
var _HeadWithMeta = _interopRequireDefault(require("./components/HeadWithMeta"));
var _BodyWithMeta = _interopRequireDefault(require("./components/BodyWithMeta"));
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var cachedBasePath;
var cachedHrefReplace;
var cachedSrcReplace;
function getSHA256(str) {
var hash = _crypto["default"].createHash('sha256');
hash.update(str);
return hash.digest('base64');
}
function getSubresourceHash(str) {
var sha256 = getSHA256(str);
return "sha256-".concat(sha256);
}
function getEmbeddedRouteInfoScript(embeddedRouteInfo) {
var routeInfoJSON = (0, _jsesc["default"])(JSON.stringify(embeddedRouteInfo), {
isScriptContext: true,
wrap: true,
json: true
});
var script = "window.__routeInfo = JSON.parse(".concat(routeInfoJSON, ");");
var hash = getSubresourceHash(script);
return {
hash: hash,
script: script
};
}
var _default = /*#__PURE__*/function () {
var _exportRoute = (0, _asyncToGenerator2["default"])( /*#__PURE__*/_regenerator["default"].mark(function _callee(state) {
var _state, config, DocumentTemplate, route, siteData, clientStats, incremental, _state2, Comp, sharedHashesByProp, template, data, sharedData, routePath, remove, removeLocation, basePath, hrefReplace, srcReplace, routeInfo, embeddedRouteInfo, inlineScripts, meta, chunkNames, head, clientScripts, clientStyleSheets, clientCss, FinalComp, renderToStringAndExtract, appHtml, RenderedComp, DocumentHtml, html, publicPath, htmlFilename, routeInfoFilename, res;
return _regenerator["default"].wrap(function _callee$(_context) {
while (1) {
switch (_context.prev = _context.next) {
case 0:
_state = state, config = _state.config, DocumentTemplate = _state.DocumentTemplate, route = _state.route, siteData = _state.siteData, clientStats = _state.clientStats, incremental = _state.incremental;
_state2 = state, Comp = _state2.Comp;
sharedHashesByProp = route.sharedHashesByProp, template = route.template, data = route.data, sharedData = route.sharedData, routePath = route.path, remove = route.remove;
if (!(incremental && remove)) {
_context.next = 8;
break;
}
if (!((0, _utils.is404Path)(route.path) || route.path === '/')) {
_context.next = 6;
break;
}
throw new Error("You are attempting to incrementally remove the ".concat((0, _utils.is404Path)(route.path) ? '404' : 'index', " route from your export. This is currently not supported (or recommended) by React Static."));
case 6:
removeLocation = _path["default"].join(config.paths.DIST, route.path);
return _context.abrupt("return", _fsExtra["default"].remove(removeLocation));
case 8:
basePath = cachedBasePath || (cachedBasePath = config.basePath);
hrefReplace = cachedHrefReplace || (cachedHrefReplace = new RegExp("(href=[\"'])\\/(".concat(basePath ? "".concat(basePath, "\\/") : '', ")?([^\\/])"), 'gm'));
srcReplace = cachedSrcReplace || (cachedSrcReplace = new RegExp("(src=[\"'])\\/(".concat(basePath ? "".concat(basePath, "\\/") : '', ")?([^\\/])"), 'gm')); // This routeInfo will be saved to disk. It should only include the
// data and hashes to construct all of the props later.
_context.next = 13;
return _plugins["default"].routeInfo({
template: template,
sharedHashesByProp: sharedHashesByProp,
data: data,
path: routePath
}, state);
case 13:
routeInfo = _context.sent;
// This embeddedRouteInfo will be inlined into the HTML for this route.
// It should include all of the data, including shared data
embeddedRouteInfo = _objectSpread(_objectSpread({}, routeInfo), {}, {
sharedData: sharedData,
siteData: siteData
});
inlineScripts = {
routeInfo: getEmbeddedRouteInfoScript(embeddedRouteInfo)
};
state = _objectSpread(_objectSpread({}, state), {}, {
routeInfo: routeInfo,
embeddedRouteInfo: embeddedRouteInfo,
inlineScripts: inlineScripts
}); // Make a place to collect chunks, meta info and head tags
meta = {};
chunkNames = [];
head = {};
clientScripts = [];
clientStyleSheets = [];
clientCss = {};
// Get the react component from the Comp and pass it the export context. This
// uses reactContext under the hood to pass down the exportContext, since
// react's new context api doesn't survive across bundling.
Comp = config.disableRuntime ? Comp : Comp(embeddedRouteInfo);
if (route.redirect) {
FinalComp = function FinalComp() {
return /*#__PURE__*/_react["default"].createElement(_Redirect["default"], {
fromPath: route.path,
to: route.redirect
});
};
} else {
FinalComp = function FinalComp(props) {
return /*#__PURE__*/_react["default"].createElement(_reactUniversalComponent.ReportChunks, {
report: function report(chunkName) {
// if we are building to a absolute path we must make the detected
// chunkName relative and matching to the one we set in
// generateTemplates
if (!config.paths.DIST.startsWith(config.paths.ROOT)) {
chunkName = (0, _chunkBuilder.absoluteToRelativeChunkName)(config.paths.ROOT, chunkName);
}
chunkNames.push(chunkName);
}
}, /*#__PURE__*/_react["default"].createElement(Comp, props));
};
}
renderToStringAndExtract = function renderToStringAndExtract(comp) {
// Rend the app to string!
var appHtml = (0, _server.renderToString)(comp);
var _flushChunks = (0, _webpackFlushChunks["default"])(clientStats, {
chunkNames: chunkNames,
outputPath: config.paths.DIST
}),
scripts = _flushChunks.scripts,
stylesheets = _flushChunks.stylesheets,
css = _flushChunks.css;
clientScripts = scripts;
clientStyleSheets = stylesheets;
clientCss = css; // Extract head calls using Helmet synchronously right after renderToString
// to not introduce any race conditions in the meta data rendering
var helmet = _reactHelmet["default"].renderStatic();
head = {
htmlProps: helmet.htmlAttributes.toComponent(),
bodyProps: helmet.bodyAttributes.toComponent(),
base: helmet.base.toComponent(),
link: helmet.link.toComponent(),
meta: helmet.meta.toComponent(),
noscript: helmet.noscript.toComponent(),
script: helmet.script.toComponent(),
style: helmet.style.toComponent(),
title: helmet.title.toComponent()
};
return appHtml;
};
state = _objectSpread(_objectSpread({}, state), {}, {
meta: meta
});
_context.prev = 27;
_context.next = 30;
return _plugins["default"].beforeRenderToElement(FinalComp, state);
case 30:
FinalComp = _context.sent;
if (!config.renderToElement) {
_context.next = 33;
break;
}
throw new Error("config.renderToElement has been deprecated in favor of the " + "'beforeRenderToElement' or 'beforeRenderToHtml' hooks instead.");
case 33:
RenderedComp = /*#__PURE__*/_react["default"].createElement(FinalComp, null); // Run the beforeRenderToHtml hook
// Rum the Html hook
_context.next = 36;
return _plugins["default"].beforeRenderToHtml(RenderedComp, state);
case 36:
RenderedComp = _context.sent;
if (!config.renderToHtml) {
_context.next = 39;
break;
}
throw new Error("config.renderToHtml has been deprecated in favor of the " + "'beforeRenderToHtml' or 'beforeHtmlToDocument' hooks instead.");
case 39:
appHtml = renderToStringAndExtract(RenderedComp);
_context.next = 42;
return _plugins["default"].beforeHtmlToDocument(appHtml, state);
case 42:
appHtml = _context.sent;
_context.next = 50;
break;
case 45:
_context.prev = 45;
_context.t0 = _context["catch"](27);
if (_context.t0.then) {
_context.t0.message = 'Components are not allowed to suspend during static export. Please ' + 'make its data available synchronously and try again!';
}
_context.t0.message = "Failed exporting HTML for URL ".concat(route.path, " (").concat(route.template, "): ").concat(_context.t0.message);
throw _context.t0;
case 50:
state = _objectSpread(_objectSpread({}, state), {}, {
head: head,
clientScripts: clientScripts,
clientStyleSheets: clientStyleSheets,
clientCss: clientCss
});
_context.t1 = _server.renderToStaticMarkup;
_context.t2 = _react["default"];
_context.t3 = DocumentTemplate;
_context.next = 56;
return (0, _HtmlWithMeta["default"])(state);
case 56:
_context.t4 = _context.sent;
_context.next = 59;
return (0, _HeadWithMeta["default"])(state);
case 59:
_context.t5 = _context.sent;
_context.next = 62;
return (0, _BodyWithMeta["default"])(state);
case 62:
_context.t6 = _context.sent;
_context.t7 = state;
_context.t8 = {
Html: _context.t4,
Head: _context.t5,
Body: _context.t6,
state: _context.t7
};
_context.t9 = /*#__PURE__*/_react["default"].createElement("div", {
id: "root",
dangerouslySetInnerHTML: {
__html: appHtml
}
});
_context.t10 = _context.t2.createElement.call(_context.t2, _context.t3, _context.t8, _context.t9);
DocumentHtml = (0, _context.t1)(_context.t10);
// Render the html for the page inside of the base document.
html = "<!DOCTYPE html>".concat(DocumentHtml);
_context.next = 71;
return _plugins["default"].beforeDocumentToFile(html, state);
case 71:
html = _context.sent;
// If the siteRoot is set and we're not in staging, prefix all absolute URLs
// with the siteRoot
publicPath = (0, _utils.makePathAbsolute)(process.env.REACT_STATIC_PUBLIC_PATH);
if (process.env.REACT_STATIC_DISABLE_ROUTE_PREFIXING !== 'true') {
html = html.replace(hrefReplace, "$1".concat(publicPath, "$3"));
}
html = html.replace(srcReplace, "$1".concat(publicPath, "$3")); // If the route is a 404 page, write it directly to 404.html, instead of
// inside a directory.
htmlFilename = (0, _utils.is404Path)(route.path) ? _path["default"].join(config.paths.DIST, '404.html') : _path["default"].join(config.paths.DIST, route.path, 'index.html'); // Make the routeInfo sit right next to its companion html file
routeInfoFilename = _path["default"].join(config.paths.DIST, route.path, 'routeInfo.json');
_context.next = 79;
return Promise.all([_fsExtra["default"].outputFile(htmlFilename, html), !route.redirect ? _fsExtra["default"].outputJson(routeInfoFilename, routeInfo) : Promise.resolve()]);
case 79:
res = _context.sent;
return _context.abrupt("return", res);
case 81:
case "end":
return _context.stop();
}
}
}, _callee, null, [[27, 45]]);
}));
function exportRoute(_x) {
return _exportRoute.apply(this, arguments);
}
return exportRoute;
}();
exports["default"] = _default;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9zdGF0aWMvZXhwb3J0Um91dGUuanMiXSwibmFtZXMiOlsiY2FjaGVkQmFzZVBhdGgiLCJjYWNoZWRIcmVmUmVwbGFjZSIsImNhY2hlZFNyY1JlcGxhY2UiLCJnZXRTSEEyNTYiLCJzdHIiLCJoYXNoIiwiY3J5cHRvIiwiY3JlYXRlSGFzaCIsInVwZGF0ZSIsImRpZ2VzdCIsImdldFN1YnJlc291cmNlSGFzaCIsInNoYTI1NiIsImdldEVtYmVkZGVkUm91dGVJbmZvU2NyaXB0IiwiZW1iZWRkZWRSb3V0ZUluZm8iLCJyb3V0ZUluZm9KU09OIiwiSlNPTiIsInN0cmluZ2lmeSIsImlzU2NyaXB0Q29udGV4dCIsIndyYXAiLCJqc29uIiwic2NyaXB0Iiwic3RhdGUiLCJjb25maWciLCJEb2N1bWVudFRlbXBsYXRlIiwicm91dGUiLCJzaXRlRGF0YSIsImNsaWVudFN0YXRzIiwiaW5jcmVtZW50YWwiLCJDb21wIiwic2hhcmVkSGFzaGVzQnlQcm9wIiwidGVtcGxhdGUiLCJkYXRhIiwic2hhcmVkRGF0YSIsInJvdXRlUGF0aCIsInBhdGgiLCJyZW1vdmUiLCJFcnJvciIsInJlbW92ZUxvY2F0aW9uIiwibm9kZVBhdGgiLCJqb2luIiwicGF0aHMiLCJESVNUIiwiZnMiLCJiYXNlUGF0aCIsImhyZWZSZXBsYWNlIiwiUmVnRXhwIiwic3JjUmVwbGFjZSIsInBsdWdpbnMiLCJyb3V0ZUluZm8iLCJpbmxpbmVTY3JpcHRzIiwibWV0YSIsImNodW5rTmFtZXMiLCJoZWFkIiwiY2xpZW50U2NyaXB0cyIsImNsaWVudFN0eWxlU2hlZXRzIiwiY2xpZW50Q3NzIiwiZGlzYWJsZVJ1bnRpbWUiLCJyZWRpcmVjdCIsIkZpbmFsQ29tcCIsInByb3BzIiwiY2h1bmtOYW1lIiwic3RhcnRzV2l0aCIsIlJPT1QiLCJwdXNoIiwicmVuZGVyVG9TdHJpbmdBbmRFeHRyYWN0IiwiY29tcCIsImFwcEh0bWwiLCJvdXRwdXRQYXRoIiwic2NyaXB0cyIsInN0eWxlc2hlZXRzIiwiY3NzIiwiaGVsbWV0IiwiSGVsbWV0IiwicmVuZGVyU3RhdGljIiwiaHRtbFByb3BzIiwiaHRtbEF0dHJpYnV0ZXMiLCJ0b0NvbXBvbmVudCIsImJvZHlQcm9wcyIsImJvZHlBdHRyaWJ1dGVzIiwiYmFzZSIsImxpbmsiLCJub3NjcmlwdCIsInN0eWxlIiwidGl0bGUiLCJiZWZvcmVSZW5kZXJUb0VsZW1lbnQiLCJyZW5kZXJUb0VsZW1lbnQiLCJSZW5kZXJlZENvbXAiLCJiZWZvcmVSZW5kZXJUb0h0bWwiLCJyZW5kZXJUb0h0bWwiLCJiZWZvcmVIdG1sVG9Eb2N1bWVudCIsInRoZW4iLCJtZXNzYWdlIiwicmVuZGVyVG9TdGF0aWNNYXJrdXAiLCJfX2h0bWwiLCJEb2N1bWVudEh0bWwiLCJodG1sIiwiYmVmb3JlRG9jdW1lbnRUb0ZpbGUiLCJwdWJsaWNQYXRoIiwicHJvY2VzcyIsImVudiIsIlJFQUNUX1NUQVRJQ19QVUJMSUNfUEFUSCIsIlJFQUNUX1NUQVRJQ19ESVNBQkxFX1JPVVRFX1BSRUZJWElORyIsInJlcGxhY2UiLCJodG1sRmlsZW5hbWUiLCJyb3V0ZUluZm9GaWxlbmFtZSIsIlByb21pc2UiLCJhbGwiLCJvdXRwdXRGaWxlIiwib3V0cHV0SnNvbiIsInJlc29sdmUiLCJyZXMiLCJleHBvcnRSb3V0ZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUVBOztBQUNBOztBQUNBOztBQUNBOztBQUVBOztBQUNBOztBQUNBOzs7Ozs7QUFFQSxJQUFJQSxjQUFKO0FBQ0EsSUFBSUMsaUJBQUo7QUFDQSxJQUFJQyxnQkFBSjs7QUFFQSxTQUFTQyxTQUFULENBQW1CQyxHQUFuQixFQUF3QjtBQUN0QixNQUFNQyxJQUFJLEdBQUdDLG1CQUFPQyxVQUFQLENBQWtCLFFBQWxCLENBQWI7O0FBQ0FGLEVBQUFBLElBQUksQ0FBQ0csTUFBTCxDQUFZSixHQUFaO0FBQ0EsU0FBT0MsSUFB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YUMsSUFEVyxFQUV4QmpCLEtBQUssQ0FBQ1UsSUFGa0IsRUFHeEIsZ0JBSHdCLENBdk9aO0FBQUE7QUFBQSxtQkE2T0l1RSxPQUFPLENBQUNDLEdBQVIsQ0FBWSxDQUM1QmhFLG9CQUFHaUUsVUFBSCxDQUFjSixZQUFkLEVBQTRCUixJQUE1QixDQUQ0QixFQUU1QixDQUFDdkUsS0FBSyxDQUFDaUMsUUFBUCxHQUNJZixvQkFBR2tFLFVBQUgsQ0FBY0osaUJBQWQsRUFBaUN4RCxTQUFqQyxDQURKLEdBRUl5RCxPQUFPLENBQUNJLE9BQVIsRUFKd0IsQ0FBWixDQTdPSjs7QUFBQTtBQTZPUkMsWUFBQUEsR0E3T1E7QUFBQSw2Q0FtUFBBLEdBblBPOztBQUFBO0FBQUE7QUFBQTtBQUFBO0FBQUE7QUFBQTtBQUFBLEc7O1dBQWVDLFc7Ozs7U0FBQUEsVyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBjcnlwdG8gZnJvbSAnY3J5cHRvJ1xuaW1wb3J0IFJlYWN0IGZyb20gJ3JlYWN0J1xuaW1wb3J0IHsgcmVuZGVyVG9TdHJpbmcsIHJlbmRlclRvU3RhdGljTWFya3VwIH0gZnJvbSAncmVhY3QtZG9tL3NlcnZlcidcbmltcG9ydCBIZWxtZXQgZnJvbSAncmVhY3QtaGVsbWV0J1xuaW1wb3J0IHsgUmVwb3J0Q2h1bmtzIH0gZnJvbSAncmVhY3QtdW5pdmVyc2FsLWNvbXBvbmVudCdcbmltcG9ydCBmbHVzaENodW5rcyBmcm9tICd3ZWJwYWNrLWZsdXNoLWNodW5rcydcbmltcG9ydCBub2RlUGF0aCBmcm9tICdwYXRoJ1xuaW1wb3J0IGZzIGZyb20gJ2ZzLWV4dHJhJ1xuaW1wb3J0IGpzZXNjIGZyb20gJ2pzZXNjJ1xuXG5pbXBvcnQgUmVkaXJlY3QgZnJvbSAnLi9jb21wb25lbnRzL1JlZGlyZWN0J1xuaW1wb3J0IHBsdWdpbnMgZnJvbSAnLi9wbHVnaW5zJ1xuaW1wb3J0IHsgbWFrZVBhdGhBYnNvbHV0ZSwgaXM0MDRQYXRoIH0gZnJvbSAnLi4vdXRpbHMnXG5pbXBvcnQgeyBhYnNvbHV0ZVRvUmVsYXRpdmVDaHVua05hbWUgfSBmcm9tICcuLi91dGlscy9jaHVua0J1aWxkZXInXG5cbmltcG9ydCBtYWtlSHRtbFdpdGhNZXRhIGZyb20gJy4vY29tcG9uZW50cy9IdG1sV2l0aE1ldGEnXG5pbXBvcnQgbWFrZUhlYWRXaXRoTWV0YSBmcm9tICcuL2NvbXBvbmVudHMvSGVhZFdpdGhNZXRhJ1xuaW1wb3J0IG1ha2VCb2R5V2l0aE1ldGEgZnJvbSAnLi9jb21wb25lbnRzL0JvZHlXaXRoTWV0YSdcblxubGV0IGNhY2hlZEJhc2VQYXRoXG5sZXQgY2FjaGVkSHJlZlJlcGxhY2VcbmxldCBjYWNoZWRTcmNSZXBsYWNlXG5cbmZ1bmN0aW9uIGdldFNIQTI1NihzdHIpIHtcbiAgY29uc3QgaGFzaCA9IGNyeXB0by5jcmVhdGVIYXNoKCdzaGEyNTYnKVxuICBoYXNoLnVwZGF0ZShzdHIpXG4gIHJldHVybiBoYXNoLmRpZ2VzdCgnYmFzZTY0Jylcbn1cblxuZnVuY3Rpb24gZ2V0U3VicmVzb3VyY2VIYXNoKHN0cikge1xuICBjb25zdCBzaGEyNTYgPSBnZXRTSEEyNTYoc3RyKVxuICByZXR1cm4gYHNoYTI1Ni0ke3NoYTI1Nn1gXG59XG5cbmV4cG9ydCBmdW5jdGlvbiBnZXRFbWJlZGRlZFJvdXRlSW5mb1NjcmlwdChlbWJlZGRlZFJvdXRlSW5mbykge1xuICBjb25zdCByb3V0ZUluZm9KU09OID0ganNlc2MoSlNPTi5zdHJpbmdpZnkoZW1iZWRkZWRSb3V0ZUluZm8pLCB7XG4gICAgaXNTY3JpcHRDb250ZXh0OiB0cnVlLFxuICAgIHdyYXA6IHRydWUsXG4gICAganNvbjogdHJ1ZSxcbiAgfSlcbiAgY29uc3Qgc2NyaXB0ID0gYHdpbmRvdy5fX3JvdXRlSW5mbyA9IEpTT04ucGFyc2UoJHtyb3V0ZUluZm9KU09OfSk7YFxuICBjb25zdCBoYXNoID0gZ2V0U3VicmVzb3VyY2VIYXNoKHNjcmlwdClcblxuICByZXR1cm4ge1xuICAgIGhhc2gsXG4gICAgc2NyaXB0LFxuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IChhc3luYyBmdW5jdGlvbiBleHBvcnRSb3V0ZShzdGF0ZSkge1xuICBjb25zdCB7XG4gICAgY29uZmlnLFxuICAgIERvY3VtZW50VGVtcGxhdGUsXG4gICAgcm91dGUsXG4gICAgc2l0ZURhdGEsXG4gICAgY2xpZW50U3RhdHMsXG4gICAgaW5jcmVtZW50YWwsXG4gIH0gPSBzdGF0ZVxuXG4gIGxldCB7IENvbXAgfSA9IHN0YXRlXG5cbiAgY29uc3Qge1xuICAgIHNoYXJlZEhhc2hlc0J5UHJvcCxcbiAgICB0ZW1wbGF0ZSxcbiAgICBkYXRhLFxuICAgIHNoYXJlZERhdGEsXG4gICAgcGF0aDogcm91dGVQYXRoLFxuICAgIHJlbW92ZSxcbiAgfSA9IHJvdXRlXG5cbiAgaWYgKGluY3JlbWVudGFsICYmIHJlbW92ZSkge1xuICAgIGlmIChpczQwNFBhdGgocm91dGUucGF0aCkgfHwgcm91dGUucGF0aCA9PT0gJy8nKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBZb3UgYXJlIGF0dGVtcHRpbmcgdG8gaW5jcmVtZW50YWxseSByZW1vdmUgdGhlICR7XG4gICAgICAgICAgaXM0MDRQYXRoKHJvdXRlLnBhdGgpID8gJzQwNCcgOiAnaW5kZXgnXG4gICAgICAgIH0gcm91dGUgZnJvbSB5b3VyIGV4cG9ydC4gVGhpcyBpcyBjdXJyZW50bHkgbm90IHN1cHBvcnRlZCAob3IgcmVjb21tZW5kZWQpIGJ5IFJlYWN0IFN0YXRpYy5gXG4gICAgICApXG4gICAgfVxuICAgIGNvbnN0IHJlbW92ZUxvY2F0aW9uID0gbm9kZVBhdGguam9pbihjb25maWcucGF0aHMuRElTVCwgcm91dGUucGF0aClcbiAgICByZXR1cm4gZnMucmVtb3ZlKHJlbW92ZUxvY2F0aW9uKVxuICB9XG5cbiAgY29uc3QgYmFzZVBhdGggPSBjYWNoZWRCYXNlUGF0aCB8fCAoY2FjaGVkQmFzZVBhdGggPSBjb25maWcuYmFzZVBhdGgpXG5cbiAgY29uc3QgaHJlZlJlcGxhY2UgPVxuICAgIGNhY2hlZEhyZWZSZXBsYWNlIHx8XG4gICAgKGNhY2hlZEhyZWZSZXBsYWNlID0gbmV3IFJlZ0V4cChcbiAgICAgIGAoaHJlZj1bXCInXSlcXFxcLygke2Jhc2VQYXRoID8gYCR7YmFzZVBhdGh9XFxcXC9gIDogJyd9KT8oW15cXFxcL10pYCxcbiAgICAgICdnbSdcbiAgICApKVxuXG4gIGNvbnN0IHNyY1JlcGxhY2UgPVxuICAgIGNhY2hlZFNyY1JlcGxhY2UgfHxcbiAgICAoY2FjaGVkU3JjUmVwbGFjZSA9IG5ldyBSZWdFeHAoXG4gICAgICBgKHNyYz1bXCInXSlcXFxcLygke2Jhc2VQYXRoID8gYCR7YmFzZVBhdGh9XFxcXC9gIDogJyd9KT8oW15cXFxcL10pYCxcbiAgICAgICdnbSdcbiAgICApKVxuXG4gIC8vIFRoaXMgcm91dGVJbmZvIHdpbGwgYmUgc2F2ZWQgdG8gZGlzay4gSXQgc2hvdWxkIG9ubHkgaW5jbHVkZSB0aGVcbiAgLy8gZGF0YSBhbmQgaGFzaGVzIHRvIGNvbnN0cnVjdCBhbGwgb2YgdGhlIHByb3BzIGxhdGVyLlxuICBjb25zdCByb3V0ZUluZm8gPSBhd2FpdCBwbHVnaW5zLnJvdXRlSW5mbyhcbiAgICB7XG4gICAgICB0ZW1wbGF0ZSxcbiAgICAgIHNoYXJlZEhhc2hlc0J5UHJvcCxcbiAgICAgIGRhdGEsXG4gICAgICBwYXRoOiByb3V0ZVBhdGgsXG4gICAgfSxcbiAgICBzdGF0ZVxuICApXG5cbiAgLy8gVGhpcyBlbWJlZGRlZFJvdXRlSW5mbyB3aWxsIGJlIGlubGluZWQgaW50byB0aGUgSFRNTCBmb3IgdGhpcyByb3V0ZS5cbiAgLy8gSXQgc2hvdWxkIGluY2x1ZGUgYWxsIG9mIHRoZSBkYXRhLCBpbmNsdWRpbmcgc2hhcmVkIGRhdGFcbiAgY29uc3QgZW1iZWRkZWRSb3V0ZUluZm8gPSB7XG4gICAgLi4ucm91dGVJbmZvLFxuICAgIHNoYXJlZERhdGEsXG4gICAgc2l0ZURhdGEsXG4gIH1cblxuICBjb25zdCBpbmxpbmVTY3JpcHRzID0ge1xuICAgIHJvdXRlSW5mbzogZ2V0RW1iZWRkZWRSb3V0ZUluZm9TY3JpcHQoZW1iZWRkZWRSb3V0ZUluZm8pLFxuICB9XG5cbiAgc3RhdGUgPSB7XG4gICAgLi4uc3RhdGUsXG4gICAgcm91dGVJbmZvLFxuICAgIGVtYmVkZGVkUm91dGVJbmZvLFxuICAgIGlubGluZVNjcmlwdHMsXG4gIH1cblxuICAvLyBNYWtlIGEgcGxhY2UgdG8gY29sbGVjdCBjaHVua3MsIG1ldGEgaW5mbyBhbmQgaGVhZCB0YWdzXG4gIGNvbnN0IG1ldGEgPSB7fVxuICBjb25zdCBjaHVua05hbWVzID0gW11cbiAgbGV0IGhlYWQgPSB7fVxuICBsZXQgY2xpZW50U2NyaXB0cyA9IFtdXG4gIGxldCBjbGllbnRTdHlsZVNoZWV0cyA9IFtdXG4gIGxldCBjbGllbnRDc3MgPSB7fVxuXG4gIGxldCBGaW5hbENvbXBcblxuICAvLyBHZXQgdGhlIHJlYWN0IGNvbXBvbmVudCBmcm9tIHRoZSBDb21wIGFuZCBwYXNzIGl0IHRoZSBleHBvcnQgY29udGV4dC4gVGhpc1xuICAvLyB1c2VzIHJlYWN0Q29udGV4dCB1bmRlciB0aGUgaG9vZCB0byBwYXNzIGRvd24gdGhlIGV4cG9ydENvbnRleHQsIHNpbmNlXG4gIC8vIHJlYWN0J3MgbmV3IGNvbnRleHQgYXBpIGRvZXNuJ3Qgc3Vydml2ZSBhY3Jvc3MgYnVuZGxpbmcuXG4gIENvbXAgPSBjb25maWcuZGlzYWJsZVJ1bnRpbWUgPyBDb21wIDogQ29tcChlbWJlZGRlZFJvdXRlSW5mbylcblxuICBpZiAocm91dGUucmVkaXJlY3QpIHtcbiAgICBGaW5hbENvbXAgPSAoKSA9PiA8UmVkaXJlY3QgZnJvbVBhdGg9e3JvdXRlLnBhdGh9IHRvPXtyb3V0ZS5yZWRpcmVjdH0gLz5cbiAgfSBlbHNlIHtcbiAgICBGaW5hbENvbXAgPSBwcm9wcyA9PiAoXG4gICAgICA8UmVwb3J0Q2h1bmtzXG4gICAgICAgIHJlcG9ydD17Y2h1bmtOYW1lID0+IHtcbiAgICAgICAgICAvLyBpZiB3ZSBhcmUgYnVpbGRpbmcgdG8gYSBhYnNvbHV0ZSBwYXRoIHdlIG11c3QgbWFrZSB0aGUgZGV0ZWN0ZWRcbiAgICAgICAgICAvLyBjaHVua05hbWUgcmVsYXRpdmUgYW5kIG1hdGNoaW5nIHRvIHRoZSBvbmUgd2Ugc2V0IGluXG4gICAgICAgICAgLy8gZ2VuZXJhdGVUZW1wbGF0ZXNcbiAgICAgICAgICBpZiAoIWNvbmZpZy5wYXRocy5ESVNULnN0YXJ0c1dpdGgoY29uZmlnLnBhdGhzLlJPT1QpKSB7XG4gICAgICAgICAgICBjaHVua05hbWUgPSBhYnNvbHV0ZVRvUmVsYXRpdmVDaHVua05hbWUoXG4gICAgICAgICAgICAgIGNvbmZpZy5wYXRocy5ST09ULFxuICAgICAgICAgICAgICBjaHVua05hbWVcbiAgICAgICAgICAgIClcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBjaHVua05hbWVzLnB1c2goY2h1bmtOYW1lKVxuICAgICAgICB9fVxuICAgICAgPlxuICAgICAgICA8Q29tcCB7Li4ucHJvcHN9IC8+XG4gICAgICA8L1JlcG9ydENodW5rcz5cbiAgICApXG4gIH1cblxuICBjb25zdCByZW5kZXJUb1N0cmluZ0FuZEV4dHJhY3QgPSBjb21wID0+IHtcbiAgICAvLyBSZW5kIHRoZSBhcHAgdG8gc3RyaW5nIVxuICAgIGNvbnN0IGFwcEh0bWwgPSByZW5kZXJUb1N0cmluZyhjb21wKVxuICAgIGNvbnN0IHsgc2NyaXB0cywgc3R5bGVzaGVldHMsIGNzcyB9ID0gZmx1c2hDaHVua3MoY2xpZW50U3RhdHMsIHtcbiAgICAgIGNodW5rTmFtZXMsXG4gICAgICBvdXRwdXRQYXRoOiBjb25maWcucGF0aHMuRElTVCxcbiAgICB9KVxuXG4gICAgY2xpZW50U2NyaXB0cyA9IHNjcmlwdHNcbiAgICBjbGllbnRTdHlsZVNoZWV0cyA9IHN0eWxlc2hlZXRzXG4gICAgY2xpZW50Q3NzID0gY3NzXG4gICAgLy8gRXh0cmFjdCBoZWFkIGNhbGxzIHVzaW5nIEhlbG1ldCBzeW5jaHJvbm91c2x5IHJpZ2h0IGFmdGVyIHJlbmRlclRvU3RyaW5nXG4gICAgLy8gdG8gbm90IGludHJvZHVjZSBhbnkgcmFjZSBjb25kaXRpb25zIGluIHRoZSBtZXRhIGRhdGEgcmVuZGVyaW5nXG4gICAgY29uc3QgaGVsbWV0ID0gSGVsbWV0LnJlbmRlclN0YXRpYygpXG4gICAgaGVhZCA9IHtcbiAgICAgIGh0bWxQcm9wczogaGVsbWV0Lmh0bWxBdHRyaWJ1dGVzLnRvQ29tcG9uZW50KCksXG4gICAgICBib2R5UHJvcHM6IGhlbG1ldC5ib2R5QXR0cmlidXRlcy50b0NvbXBvbmVudCgpLFxuICAgICAgYmFzZTogaGVsbWV0LmJhc2UudG9Db21wb25lbnQoKSxcbiAgICAgIGxpbms6IGhlbG1ldC5saW5rLnRvQ29tcG9uZW50KCksXG4gICAgICBtZXRhOiBoZWxtZXQubWV0YS50b0NvbXBvbmVudCgpLFxuICAgICAgbm9zY3JpcHQ6IGhlbG1ldC5ub3NjcmlwdC50b0NvbXBvbmVudCgpLFxuICAgICAgc2NyaXB0OiBoZWxtZXQuc2NyaXB0LnRvQ29tcG9uZW50KCksXG4gICAgICBzdHlsZTogaGVsbWV0LnN0eWxlLnRvQ29tcG9uZW50KCksXG4gICAgICB0aXRsZTogaGVsbWV0LnRpdGxlLnRvQ29tcG9uZW50KCksXG4gICAgfVxuXG4gICAgcmV0dXJuIGFwcEh0bWxcbiAgfVxuXG4gIGxldCBhcHBIdG1sXG5cbiAgc3RhdGUgPSB7XG4gICAgLi4uc3RhdGUsXG4gICAgbWV0YSxcbiAgfVxuXG4gIHRyeSB7XG4gICAgRmluYWxDb21wID0gYXdhaXQgcGx1Z2lucy5iZWZvcmVSZW5kZXJUb0VsZW1lbnQoRmluYWxDb21wLCBzdGF0ZSlcblxuICAgIGlmIChjb25maWcucmVuZGVyVG9FbGVtZW50KSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBjb25maWcucmVuZGVyVG9FbGVtZW50IGhhcyBiZWVuIGRlcHJlY2F0ZWQgaW4gZmF2b3Igb2YgdGhlIGAgK1xuICAgICAgICAgIGAnYmVmb3JlUmVuZGVyVG9FbGVtZW50JyBvciAnYmVmb3JlUmVuZGVyVG9IdG1sJyBob29rcyBpbnN0ZWFkLmBcbiAgICAgIClcbiAgICB9XG5cbiAgICBsZXQgUmVuZGVyZWRDb21wID0gPEZpbmFsQ29tcCAvPlxuXG4gICAgLy8gUnVuIHRoZSBiZWZvcmVSZW5kZXJUb0h0bWwgaG9va1xuICAgIC8vIFJ1bSB0aGUgSHRtbCBob29rXG4gICAgUmVuZGVyZWRDb21wID0gYXdhaXQgcGx1Z2lucy5iZWZvcmVSZW5kZXJUb0h0bWwoUmVuZGVyZWRDb21wLCBzdGF0ZSlcblxuICAgIGlmIChjb25maWcucmVuZGVyVG9IdG1sKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgIGBjb25maWcucmVuZGVyVG9IdG1sIGhhcyBiZWVuIGRlcHJlY2F0ZWQgaW4gZmF2b3Igb2YgdGhlIGAgK1xuICAgICAgICAgIGAnYmVmb3JlUmVuZGVyVG9IdG1sJyBvciAnYmVmb3JlSHRtbFRvRG9jdW1lbnQnIGhvb2tzIGluc3RlYWQuYFxuICAgICAgKVxuICAgIH1cblxuICAgIGFwcEh0bWwgPSByZW5kZXJUb1N0cmluZ0FuZEV4dHJhY3QoUmVuZGVyZWRDb21wKVxuXG4gICAgYXBwSHRtbCA9IGF3YWl0IHBsdWdpbnMuYmVmb3JlSHRtbFRvRG9jdW1lbnQoYXBwSHRtbCwgc3RhdGUpXG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgaWYgKGVycm9yLnRoZW4pIHtcbiAgICAgIGVycm9yLm1lc3NhZ2UgPVxuICAgICAgICAnQ29tcG9uZW50cyBhcmUgbm90IGFsbG93ZWQgdG8gc3VzcGVuZCBkdXJpbmcgc3RhdGljIGV4cG9ydC4gUGxlYXNlICcgK1xuICAgICAgICAnbWFrZSBpdHMgZGF0YSBhdmFpbGFibGUgc3luY2hyb25vdXNseSBhbmQgdHJ5IGFnYWluISdcbiAgICB9XG4gICAgZXJyb3IubWVzc2FnZSA9IGBGYWlsZWQgZXhwb3J0aW5nIEhUTUwgZm9yIFVSTCAke3JvdXRlLnBhdGh9ICgke3JvdXRlLnRlbXBsYXRlfSk6ICR7ZXJyb3IubWVzc2FnZX1gXG4gICAgdGhyb3cgZXJyb3JcbiAgfVxuXG4gIHN0YXRlID0ge1xuICAgIC4uLnN0YXRlLFxuICAgIGhlYWQsXG4gICAgY2xpZW50U2NyaXB0cyxcbiAgICBjbGllbnRTdHlsZVNoZWV0cyxcbiAgICBjbGllbnRDc3MsXG4gIH1cblxuICBjb25zdCBEb2N1bWVudEh0bWwgPSByZW5kZXJUb1N0YXRpY01hcmt1cChcbiAgICA8RG9jdW1lbnRUZW1wbGF0ZVxuICAgICAgSHRtbD17YXdhaXQgbWFrZUh0bWxXaXRoTWV0YShzdGF0ZSl9XG4gICAgICBIZWFkPXthd2FpdCBtYWtlSGVhZFdpdGhNZXRhKHN0YXRlKX1cbiAgICAgIEJvZHk9e2F3YWl0IG1ha2VCb2R5V2l0aE1ldGEoc3RhdGUpfVxuICAgICAgc3RhdGU9e3N0YXRlfVxuICAgID5cbiAgICAgIDxkaXYgaWQ9XCJyb290XCIgZGFuZ2Vyb3VzbHlTZXRJbm5lckhUTUw9e3sgX19odG1sOiBhcHBIdG1sIH19IC8+XG4gICAgPC9Eb2N1bWVudFRlbXBsYXRlPlxuICApXG5cbiAgLy8gUmVuZGVyIHRoZSBodG1sIGZvciB0aGUgcGFnZSBpbnNpZGUgb2YgdGhlIGJhc2UgZG9jdW1lbnQuXG4gIGxldCBodG1sID0gYDwhRE9DVFlQRSBodG1sPiR7RG9jdW1lbnRIdG1sfWBcblxuICBodG1sID0gYXdhaXQgcGx1Z2lucy5iZWZvcmVEb2N1bWVudFRvRmlsZShodG1sLCBzdGF0ZSlcblxuICAvLyBJZiB0aGUgc2l0ZVJvb3QgaXMgc2V0IGFuZCB3ZSdyZSBub3QgaW4gc3RhZ2luZywgcHJlZml4IGFsbCBhYnNvbHV0ZSBVUkxzXG4gIC8vIHdpdGggdGhlIHNpdGVSb290XG4gIGNvbnN0IHB1YmxpY1BhdGggPSBtYWtlUGF0aEFic29sdXRlKHByb2Nlc3MuZW52LlJFQUNUX1NUQVRJQ19QVUJMSUNfUEFUSClcbiAgaWYgKHByb2Nlc3MuZW52LlJFQUNUX1NUQVRJQ19ESVNBQkxFX1JPVVRFX1BSRUZJWElORyAhPT0gJ3RydWUnKSB7XG4gICAgaHRtbCA9IGh0bWwucmVwbGFjZShocmVmUmVwbGFjZSwgYCQxJHtwdWJsaWNQYXRofSQzYClcbiAgfVxuXG4gIGh0bWwgPSBodG1sLnJlcGxhY2Uoc3JjUmVwbGFjZSwgYCQxJHtwdWJsaWNQYXRofSQzYClcblxuICAvLyBJZiB0aGUgcm91dGUgaXMgYSA0MDQgcGFnZSwgd3JpdGUgaXQgZGlyZWN0bHkgdG8gNDA0Lmh0bWwsIGluc3RlYWQgb2ZcbiAgLy8gaW5zaWRlIGEgZGlyZWN0b3J5LlxuICBjb25zdCBodG1sRmlsZW5hbWUgPSBpczQwNFBhdGgocm91dGUucGF0aClcbiAgICA/IG5vZGVQYXRoLmpvaW4oY29uZmlnLnBhdGhzLkRJU1QsICc0MDQuaHRtbCcpXG4gICAgOiBub2RlUGF0aC5qb2luKGNvbmZpZy5wYXRocy5ESVNULCByb3V0ZS5wYXRoLCAnaW5kZXguaHRtbCcpXG5cbiAgLy8gTWFrZSB0aGUgcm91dGVJbmZvIHNpdCByaWdodCBuZXh0IHRvIGl0cyBjb21wYW5pb24gaHRtbCBmaWxlXG4gIGNvbnN0IHJvdXRlSW5mb0ZpbGVuYW1lID0gbm9kZVBhdGguam9pbihcbiAgICBjb25maWcucGF0aHMuRElTVCxcbiAgICByb3V0ZS5wYXRoLFxuICAgICdyb3V0ZUluZm8uanNvbidcbiAgKVxuXG4gIGNvbnN0IHJlcyA9IGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICBmcy5vdXRwdXRGaWxlKGh0bWxGaWxlbmFtZSwgaHRtbCksXG4gICAgIXJvdXRlLnJlZGlyZWN0XG4gICAgICA/IGZzLm91dHB1dEpzb24ocm91dGVJbmZvRmlsZW5hbWUsIHJvdXRlSW5mbylcbiAgICAgIDogUHJvbWlzZS5yZXNvbHZlKCksXG4gIF0pXG4gIHJldHVybiByZXNcbn0pXG4iXX0=