kepler.gl
Version:
kepler.gl is a webgl based application to visualize large scale location data in the browser
421 lines (412 loc) • 56.2 kB
JavaScript
"use strict";
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports["default"] = void 0;
var _typeof2 = _interopRequireDefault(require("@babel/runtime/helpers/typeof"));
var _window = _interopRequireDefault(require("global/window"));
var _document = _interopRequireDefault(require("global/document"));
var _console = _interopRequireDefault(require("global/console"));
var _miniSvgDataUri = _interopRequireDefault(require("mini-svg-data-uri"));
var _constants = require("@kepler.gl/constants");
var _domUtils = require("./dom-utils");
// SPDX-License-Identifier: MIT
// Copyright contributors to the kepler.gl project
/**
* This file is copied from https://github.com/tsayen/dom-to-image
* Modified by heshan0131 to allow loading external stylesheets and inline webfonts
*/
var inliner = newInliner();
var fontFaces = newFontFaces();
var images = newImages();
// Default impl options
var defaultOptions = {
// Default is to fail on error, no placeholder
imagePlaceholder: undefined,
// Default cache bust is false, it will use the cache
cacheBust: false
};
var domtoimage = {
toSvg: toSvg,
toPng: toPng,
toJpeg: toJpeg,
toBlob: toBlob,
toPixelData: toPixelData,
impl: {
fontFaces: fontFaces,
images: images,
inliner: inliner,
options: {}
}
};
/**
* @param {Node} node - The DOM Node object to render
* @param {Object} options - Rendering options
* @param {Function} [options.filter] - Should return true if passed node should be included in the output
* (excluding node means excluding it's children as well). Not called on the root node.
* @param {String} [options.bgcolor] - color for the background, any valid CSS color value.
* @param {Number} [options.width] - width to be applied to node before rendering.
* @param {Number} [options.height] - height to be applied to node before rendering.
* @param {Object} [options.style] - an object whose properties to be copied to node's style before rendering.
* @param {Number} [options.quality] - a Number between 0 and 1 indicating image quality (applicable to JPEG only), defaults to 1.0.
* @param {boolean} [options.escapeXhtmlForWebpack] - whether to apply fix for uglify error in dom-to-image (should be true for webpack builds), defaults to true.
* @param {String} [options.imagePlaceholder] - dataURL to use as a placeholder for failed images, default behaviour is to fail fast on images we can't fetch
* @param {Boolean} [options.cacheBust] - set to true to cache bust by appending the time to the request url
* @return {Promise} - A promise that is fulfilled with a SVG image data URL
* */
function toSvg(node, options) {
options = options || {};
copyOptions(options);
return Promise.resolve(node).then(function (nd) {
return cloneNode(nd, options.filter, true);
}).then(embedFonts).then(inlineImages).then(applyOptions).then(function (clone) {
return makeSvgDataUri(clone, options.width || (0, _domUtils.getWidth)(node), options.height || (0, _domUtils.getHeight)(node), options.escapeXhtmlForWebpack);
});
function applyOptions(clone) {
if (options.bgcolor) clone.style.backgroundColor = options.bgcolor;
if (options.width) clone.style.width = "".concat(options.width, "px");
if (options.height) clone.style.height = "".concat(options.height, "px");
if (options.style) Object.keys(options.style).forEach(function (property) {
clone.style[property] = options.style[property];
});
return clone;
}
}
/**
* @param {Node} node - The DOM Node object to render
* @param {Object} options - Rendering options
* @return {Promise} - A promise that is fulfilled with a Uint8Array containing RGBA pixel data.
* */
function toPixelData(node, options) {
return draw(node, options || {}).then(function (canvas) {
return canvas.getContext('2d').getImageData(0, 0, (0, _domUtils.getWidth)(node), (0, _domUtils.getHeight)(node)).data;
});
}
/**
* @param {Node} node - The DOM Node object to render
* @param {Object} options - Rendering options
* @return {Promise} - A promise that is fulfilled with a PNG image data URL
* */
function toPng(node, options) {
return draw(node, options || {}).then(function (canvas) {
return canvas.toDataURL();
});
}
/**
* @param {Node} node - The DOM Node object to render
* @param {Object} options - Rendering options
* @return {Promise} - A promise that is fulfilled with a JPEG image data URL
* */
function toJpeg(node, options) {
options = options || {};
return draw(node, options).then(function (canvas) {
return canvas.toDataURL('image/jpeg', options.quality || 1.0);
});
}
/**
* @param {Node} node - The DOM Node object to render
* @param {Object} options - Rendering options
* @return {Promise} - A promise that is fulfilled with a PNG image blob
* */
function toBlob(node, options) {
return draw(node, options || {}).then(_domUtils.canvasToBlob);
}
function copyOptions(options) {
// Copy options to impl options for use in impl
if (typeof options.imagePlaceholder === 'undefined') {
domtoimage.impl.options.imagePlaceholder = defaultOptions.imagePlaceholder;
} else {
domtoimage.impl.options.imagePlaceholder = options.imagePlaceholder;
}
if (typeof options.cacheBust === 'undefined') {
domtoimage.impl.options.cacheBust = defaultOptions.cacheBust;
} else {
domtoimage.impl.options.cacheBust = options.cacheBust;
}
}
function draw(domNode, options) {
return toSvg(domNode, options).then(_domUtils.makeImage).then((0, _domUtils.delay)(100)).then(function (image) {
var canvas = newCanvas(domNode);
canvas.getContext('2d').drawImage(image, 0, 0);
return canvas;
});
function newCanvas(dNode) {
var canvas = _document["default"].createElement('canvas');
canvas.width = options.width || (0, _domUtils.getWidth)(dNode);
canvas.height = options.height || (0, _domUtils.getHeight)(dNode);
if (options.bgcolor) {
var ctx = canvas.getContext('2d');
ctx.fillStyle = options.bgcolor;
ctx.fillRect(0, 0, canvas.width, canvas.height);
}
return canvas;
}
}
function cloneNode(node, filter, root) {
if (!root && filter && !filter(node)) {
return Promise.resolve();
}
return Promise.resolve(node).then(makeNodeCopy).then(function (clone) {
return cloneChildren(node, clone, filter);
}).then(function (clone) {
return (0, _domUtils.processClone)(node, clone);
});
function makeNodeCopy(nd) {
if (nd instanceof _window["default"].HTMLCanvasElement) {
return (0, _domUtils.makeImage)(nd.toDataURL());
}
return nd.cloneNode(false);
}
function cloneChildrenInOrder(parent, arrChildren, flt) {
var done = Promise.resolve();
arrChildren.forEach(function (child) {
done = done.then(function () {
return cloneNode(child, flt, null);
}).then(function (childClone) {
if (childClone) {
parent.appendChild(childClone);
}
});
});
return done;
}
function cloneChildren(original, clone, flt) {
var children = original.childNodes;
if (children.length === 0) {
return Promise.resolve(clone);
}
return cloneChildrenInOrder(clone, (0, _domUtils.asArray)(children), flt).then(function () {
return clone;
});
}
}
function embedFonts(node) {
return fontFaces.resolveAll().then(function (cssText) {
var styleNode = _document["default"].createElement('style');
node.appendChild(styleNode);
styleNode.appendChild(_document["default"].createTextNode(cssText));
return node;
});
}
function inlineImages(node) {
return images.inlineAll(node).then(function () {
return node;
});
}
function makeSvgDataUri(node, width, height) {
var escapeXhtmlForWebpack = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
return Promise.resolve(node).then(function (nd) {
nd.setAttribute('xmlns', 'http://www.w3.org/1999/xhtml');
var serializedString = new _window["default"].XMLSerializer().serializeToString(nd);
var xhtml = escapeXhtmlForWebpack ? (0, _domUtils.escapeXhtml)(serializedString) : serializedString;
var foreignObject = "<foreignObject x=\"0\" y=\"0\" width=\"100%\" height=\"100%\">".concat(xhtml, "</foreignObject>");
var svgStr = "<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"".concat(width, "\" height=\"").concat(height, "\">").concat(foreignObject, "</svg>");
// Optimizing SVGs in data URIs
// see https://codepen.io/tigt/post/optimizing-svgs-in-data-uris
// the best way of encoding SVG in a data: URI is data:image/svg+xml,[actual data].
// We don’t need the ;charset=utf-8 parameter because the given SVG is ASCII.
return (0, _miniSvgDataUri["default"])(svgStr);
});
}
function newInliner() {
var URL_REGEX = /url\(['"]?([^'"]+?)['"]?\)/g;
return {
inlineAll: inlineAll,
shouldProcess: shouldProcess,
impl: {
readUrls: readUrls,
inline: inline
}
};
function shouldProcess(string) {
return string.search(URL_REGEX) !== -1;
}
function readUrls(string) {
var result = [];
var match;
while ((match = URL_REGEX.exec(string)) !== null) {
result.push(match[1]);
}
return result.filter(function (url) {
return !(0, _domUtils.isDataUrl)(url);
});
}
function urlAsRegex(url0) {
return new RegExp("(url\\(['\"]?)(".concat((0, _domUtils.escape)(url0), ")(['\"]?\\))"), 'g');
}
function inline(string, url, baseUrl, get) {
return Promise.resolve(url).then(function (ul) {
return baseUrl ? (0, _domUtils.resolveUrl)(ul, baseUrl) : ul;
}).then(function (ul) {
return typeof get === 'function' ? get(ul) : (0, _domUtils.getAndEncode)(ul, domtoimage.impl.options);
}).then(function (data) {
return (0, _domUtils.dataAsUrl)(data, (0, _domUtils.mimeType)(url));
}).then(function (dataUrl) {
return string.replace(urlAsRegex(url), "$1".concat(dataUrl, "$3"));
});
}
function inlineAll(string, baseUrl, get) {
if (!shouldProcess(string) || (0, _domUtils.isSrcAsDataUrl)(string)) {
return Promise.resolve(string);
}
return Promise.resolve(string).then(readUrls).then(function (urls) {
var done = Promise.resolve(string);
urls.forEach(function (url) {
done = done.then(function (str) {
return inline(str, url, baseUrl, get);
});
});
return done;
});
}
}
function newFontFaces() {
return {
resolveAll: resolveAll,
impl: {
readAll: readAll
}
};
function resolveAll() {
return readAll().then(function (webFonts) {
return Promise.all(webFonts.map(function (webFont) {
return webFont.resolve();
}));
}).then(function (cssStrings) {
return cssStrings.join('\n');
});
}
function readAll() {
return Promise.resolve((0, _domUtils.asArray)(_document["default"].styleSheets)).then(loadExternalStyleSheets).then(getCssRules).then(selectWebFontRules).then(function (rules) {
return rules.map(newWebFont);
});
function selectWebFontRules(cssRules) {
return cssRules.filter(function (rule) {
return rule.type === _window["default"].CSSRule.FONT_FACE_RULE;
}).filter(function (rule) {
return inliner.shouldProcess(rule.style.getPropertyValue('src'));
});
}
function loadExternalStyleSheets(styleSheets) {
return Promise.all(styleSheets.map(function (sheet) {
if (sheet.href) {
// cloudfont doesn't have allow origin header properly set
// error response will remain in cache
var cache = sheet.href.includes('uber-fonts') ? 'no-cache' : 'default';
return _window["default"].fetch(sheet.href, {
credentials: 'omit',
cache: cache
}).then(function (response) {
return response.text();
}).then(function (text) {
var result = (0, _domUtils.setStyleSheetBaseHref)(text, sheet.href);
return (0, _domUtils.toStyleSheet)(result);
})["catch"](function (err) {
// Handle any error that occurred in any of the previous
// promises in the chain. stylesheet failed to load should not stop
// the process, hence result in only a warning, instead of reject
_console["default"].warn(_constants.IMAGE_EXPORT_ERRORS.styleSheet, sheet.href);
_console["default"].log(err);
return;
});
}
return Promise.resolve(sheet);
}));
}
function getCssRules(styleSheets) {
var cssRules = [];
styleSheets.forEach(function (sheet) {
// try...catch because browser may not able to enumerate rules for cross-domain sheets
if (!sheet) {
return;
}
var rules;
try {
rules = sheet.rules || sheet.cssRules;
} catch (e) {
_console["default"].log("'Can't read the css rules of: ".concat(sheet.href), e);
return;
}
if (rules && (0, _typeof2["default"])(rules) === 'object') {
try {
(0, _domUtils.asArray)(rules || []).forEach(cssRules.push.bind(cssRules));
} catch (e) {
_console["default"].log("Error while reading CSS rules from ".concat(sheet.href), e);
return;
}
} else {
_console["default"].log('getCssRules can not find cssRules');
return;
}
});
return cssRules;
}
function newWebFont(webFontRule) {
return {
resolve: function resolve() {
var baseUrl = (webFontRule.parentStyleSheet || {}).href;
return inliner.inlineAll(webFontRule.cssText, baseUrl, null);
},
src: function src() {
return webFontRule.style.getPropertyValue('src');
}
};
}
}
}
function newImages() {
return {
inlineAll: inlineAll,
impl: {
newImage: newImage
}
};
function newImage(element) {
function inline(get) {
if ((0, _domUtils.isDataUrl)(element.src)) {
return Promise.resolve();
}
return Promise.resolve(element.src).then(function (ul) {
return typeof get === 'function' ? get(ul) : (0, _domUtils.getAndEncode)(ul, domtoimage.impl.options);
}).then(function (data) {
return (0, _domUtils.dataAsUrl)(data, (0, _domUtils.mimeType)(element.src));
}).then(function (dataUrl) {
return new Promise(function (resolve, reject) {
element.onload = resolve;
element.onerror = reject;
element.src = dataUrl;
});
});
}
return {
inline: inline
};
}
function inlineAll(node) {
if (!(node instanceof Element)) {
return Promise.resolve(node);
}
return inlineBackground(node).then(function () {
if (node instanceof HTMLImageElement) {
return newImage(node).inline(null);
}
return Promise.all((0, _domUtils.asArray)(node.childNodes).map(function (child) {
return inlineAll(child);
}));
});
function inlineBackground(nd) {
var background = nd.style.getPropertyValue('background');
if (!background) {
return Promise.resolve(nd);
}
return inliner.inlineAll(background, null, null).then(function (inlined) {
nd.style.setProperty('background', inlined, nd.style.getPropertyPriority('background'));
}).then(function () {
return nd;
});
}
}
}
var _default = exports["default"] = domtoimage;
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfd2luZG93IiwiX2ludGVyb3BSZXF1aXJlRGVmYXVsdCIsInJlcXVpcmUiLCJfZG9jdW1lbnQiLCJfY29uc29sZSIsIl9taW5pU3ZnRGF0YVVyaSIsIl9jb25zdGFudHMiLCJfZG9tVXRpbHMiLCJpbmxpbmVyIiwibmV3SW5saW5lciIsImZvbnRGYWNlcyIsIm5ld0ZvbnRGYWNlcyIsImltYWdlcyIsIm5ld0ltYWdlcyIsImRlZmF1bHRPcHRpb25zIiwiaW1hZ2VQbGFjZWhvbGRlciIsInVuZGVmaW5lZCIsImNhY2hlQnVzdCIsImRvbXRvaW1hZ2UiLCJ0b1N2ZyIsInRvUG5nIiwidG9KcGVnIiwidG9CbG9iIiwidG9QaXhlbERhdGEiLCJpbXBsIiwib3B0aW9ucyIsIm5vZGUiLCJjb3B5T3B0aW9ucyIsIlByb21pc2UiLCJyZXNvbHZlIiwidGhlbiIsIm5kIiwiY2xvbmVOb2RlIiwiZmlsdGVyIiwiZW1iZWRGb250cyIsImlubGluZUltYWdlcyIsImFwcGx5T3B0aW9ucyIsImNsb25lIiwibWFrZVN2Z0RhdGFVcmkiLCJ3aWR0aCIsImdldFdpZHRoIiwiaGVpZ2h0IiwiZ2V0SGVpZ2h0IiwiZXNjYXBlWGh0bWxGb3JXZWJwYWNrIiwiYmdjb2xvciIsInN0eWxlIiwiYmFja2dyb3VuZENvbG9yIiwiY29uY2F0IiwiT2JqZWN0Iiwia2V5cyIsImZvckVhY2giLCJwcm9wZXJ0eSIsImRyYXciLCJjYW52YXMiLCJnZXRDb250ZXh0IiwiZ2V0SW1hZ2VEYXRhIiwiZGF0YSIsInRvRGF0YVVSTCIsInF1YWxpdHkiLCJjYW52YXNUb0Jsb2IiLCJkb21Ob2RlIiwibWFrZUltYWdlIiwiZGVsYXkiLCJpbWFnZSIsIm5ld0NhbnZhcyIsImRyYXdJbWFnZSIsImROb2RlIiwiZG9jdW1lbnQiLCJjcmVhdGVFbGVtZW50IiwiY3R4IiwiZmlsbFN0eWxlIiwiZmlsbFJlY3QiLCJyb290IiwibWFrZU5vZGVDb3B5IiwiY2xvbmVDaGlsZHJlbiIsInByb2Nlc3NDbG9uZSIsIldpbmRvdyIsIkhUTUxDYW52YXNFbGVtZW50IiwiY2xvbmVDaGlsZHJlbkluT3JkZXIiLCJwYXJlbnQiLCJhcnJDaGlsZHJlbiIsImZsdCIsImRvbmUiLCJjaGlsZCIsImNoaWxkQ2xvbmUiLCJhcHBlbmRDaGlsZCIsIm9yaWdpbmFsIiwiY2hpbGRyZW4iLCJjaGlsZE5vZGVzIiwibGVuZ3RoIiwiYXNBcnJheSIsInJlc29sdmVBbGwiLCJjc3NUZXh0Iiwic3R5bGVOb2RlIiwiY3JlYXRlVGV4dE5vZGUiLCJpbmxpbmVBbGwiLCJhcmd1bWVudHMiLCJzZXRBdHRyaWJ1dGUiLCJzZXJpYWxpemVkU3RyaW5nIiwiWE1MU2VyaWFsaXplciIsInNlcmlhbGl6ZVRvU3RyaW5nIiwieGh0bWwiLCJlc2NhcGVYaHRtbCIsImZvcmVpZ25PYmplY3QiLCJzdmdTdHIiLCJzdmdUb01pbmlEYXRhVVJJIiwiVVJMX1JFR0VYIiwic2hvdWxkUHJvY2VzcyIsInJlYWRVcmxzIiwiaW5saW5lIiwic3RyaW5nIiwic2VhcmNoIiwicmVzdWx0IiwibWF0Y2giLCJleGVjIiwicHVzaCIsInVybCIsImlzRGF0YVVybCIsInVybEFzUmVnZXgiLCJ1cmwwIiwiUmVnRXhwIiwiZXNjYXBlIiwiYmFzZVVybCIsImdldCIsInVsIiwicmVzb2x2ZVVybCIsImdldEFuZEVuY29kZSIsImRhdGFBc1VybCIsIm1pbWVUeXBlIiwiZGF0YVVybCIsInJlcGxhY2UiLCJpc1NyY0FzRGF0YVVybCIsInVybHMiLCJzdHIiLCJyZWFkQWxsIiwid2ViRm9udHMiLCJhbGwiLCJtYXAiLCJ3ZWJGb250IiwiY3NzU3RyaW5ncyIsImpvaW4iLCJzdHlsZVNoZWV0cyIsImxvYWRFeHRlcm5hbFN0eWxlU2hlZXRzIiwiZ2V0Q3NzUnVsZXMiLCJzZWxlY3RXZWJGb250UnVsZXMiLCJydWxlcyIsIm5ld1dlYkZvbnQiLCJjc3NSdWxlcyIsInJ1bGUiLCJ0eXBlIiwiQ1NTUnVsZSIsIkZPTlRfRkFDRV9SVUxFIiwiZ2V0UHJvcGVydHlWYWx1ZSIsInNoZWV0IiwiaHJlZiIsImNhY2hlIiwiaW5jbHVkZXMiLCJmZXRjaCIsImNyZWRlbnRpYWxzIiwicmVzcG9uc2UiLCJ0ZXh0Iiwic2V0U3R5bGVTaGVldEJhc2VIcmVmIiwidG9TdHlsZVNoZWV0IiwiZXJyIiwiQ29uc29sZSIsIndhcm4iLCJJTUFHRV9FWFBPUlRfRVJST1JTIiwic3R5bGVTaGVldCIsImxvZyIsImUiLCJfdHlwZW9mMiIsImJpbmQiLCJ3ZWJGb250UnVsZSIsInBhcmVudFN0eWxlU2hlZXQiLCJzcmMiLCJuZXdJbWFnZSIsImVsZW1lbnQiLCJyZWplY3QiLCJvbmxvYWQiLCJvbmVycm9yIiwiRWxlbWVudCIsImlubGluZUJhY2tncm91bmQiLCJIVE1MSW1hZ2VFbGVtZW50IiwiYmFja2dyb3VuZCIsImlubGluZWQiLCJzZXRQcm9wZXJ0eSIsImdldFByb3BlcnR5UHJpb3JpdHkiLCJfZGVmYXVsdCIsImV4cG9ydHMiXSwic291cmNlcyI6WyIuLi9zcmMvZG9tLXRvLWltYWdlLnRzIl0sInNvdXJjZXNDb250ZW50IjpbIi8vIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbi8vIENvcHlyaWdodCBjb250cmlidXRvcnMgdG8gdGhlIGtlcGxlci5nbCBwcm9qZWN0XG5cbi8qKlxuICogVGhpcyBmaWxlIGlzIGNvcGllZCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS90c2F5ZW4vZG9tLXRvLWltYWdlXG4gKiBNb2RpZmllZCBieSBoZXNoYW4wMTMxIHRvIGFsbG93IGxvYWRpbmcgZXh0ZXJuYWwgc3R5bGVzaGVldHMgYW5kIGlubGluZSB3ZWJmb250c1xuICovXG5cbmltcG9ydCBXaW5kb3cgZnJvbSAnZ2xvYmFsL3dpbmRvdyc7XG5pbXBvcnQgZG9jdW1lbnQgZnJvbSAnZ2xvYmFsL2RvY3VtZW50JztcbmltcG9ydCBDb25zb2xlIGZyb20gJ2dsb2JhbC9jb25zb2xlJztcbmltcG9ydCBzdmdUb01pbmlEYXRhVVJJIGZyb20gJ21pbmktc3ZnLWRhdGEtdXJpJztcbmltcG9ydCB7SU1BR0VfRVhQT1JUX0VSUk9SU30gZnJvbSAnQGtlcGxlci5nbC9jb25zdGFudHMnO1xuXG5pbXBvcnQge1xuICBjYW52YXNUb0Jsb2IsXG4gIGVzY2FwZSxcbiAgZXNjYXBlWGh0bWwsXG4gIGRlbGF5LFxuICBwcm9jZXNzQ2xvbmUsXG4gIGFzQXJyYXksXG4gIG1ha2VJbWFnZSxcbiAgbWltZVR5cGUsXG4gIGRhdGFBc1VybCxcbiAgaXNEYXRhVXJsLFxuICBpc1NyY0FzRGF0YVVybCxcbiAgcmVzb2x2ZVVybCxcbiAgZ2V0V2lkdGgsXG4gIGdldEhlaWdodCxcbiAgZ2V0QW5kRW5jb2RlLFxuICBzZXRTdHlsZVNoZWV0QmFzZUhyZWYsXG4gIHRvU3R5bGVTaGVldFxufSBmcm9tICcuL2RvbS11dGlscyc7XG5cbmNvbnN0IGlubGluZXIgPSBuZXdJbmxpbmVyKCk7XG5jb25zdCBmb250RmFjZXMgPSBuZXdGb250RmFjZXMoKTtcbmNvbnN0IGltYWdlcyA9IG5ld0ltYWdlcygpO1xuLy8gRGVmYXVsdCBpbXBsIG9wdGlvbnNcbmNvbnN0IGRlZmF1bHRPcHRpb25zID0ge1xuICAvLyBEZWZhdWx0IGlzIHRvIGZhaWwgb24gZXJyb3IsIG5vIHBsYWNlaG9sZGVyXG4gIGltYWdlUGxhY2Vob2xkZXI6IHVuZGVmaW5lZCxcbiAgLy8gRGVmYXVsdCBjYWNoZSBidXN0IGlzIGZhbHNlLCBpdCB3aWxsIHVzZSB0aGUgY2FjaGVcbiAgY2FjaGVCdXN0OiBmYWxzZVxufTtcblxuY29uc3QgZG9tdG9pbWFnZSA9IHtcbiAgdG9TdmcsXG4gIHRvUG5nLFxuICB0b0pwZWcsXG4gIHRvQmxvYixcbiAgdG9QaXhlbERhdGEsXG4gIGltcGw6IHtcbiAgICBmb250RmFjZXMsXG4gICAgaW1hZ2VzLFxuICAgIGlubGluZXIsXG4gICAgb3B0aW9uczoge30gYXMgYW55XG4gIH1cbn07XG5cbi8qKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIC0gVGhlIERPTSBOb2RlIG9iamVjdCB0byByZW5kZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gUmVuZGVyaW5nIG9wdGlvbnNcbiAqIEBwYXJhbSB7RnVuY3Rpb259IFtvcHRpb25zLmZpbHRlcl0gLSBTaG91bGQgcmV0dXJuIHRydWUgaWYgcGFzc2VkIG5vZGUgc2hvdWxkIGJlIGluY2x1ZGVkIGluIHRoZSBvdXRwdXRcbiAqICAgICAgICAgIChleGNsdWRpbmcgbm9kZSBtZWFucyBleGNsdWRpbmcgaXQncyBjaGlsZHJlbiBhcyB3ZWxsKS4gTm90IGNhbGxlZCBvbiB0aGUgcm9vdCBub2RlLlxuICogQHBhcmFtIHtTdHJpbmd9IFtvcHRpb25zLmJnY29sb3JdIC0gY29sb3IgZm9yIHRoZSBiYWNrZ3JvdW5kLCBhbnkgdmFsaWQgQ1NTIGNvbG9yIHZhbHVlLlxuICogQHBhcmFtIHtOdW1iZXJ9IFtvcHRpb25zLndpZHRoXSAtIHdpZHRoIHRvIGJlIGFwcGxpZWQgdG8gbm9kZSBiZWZvcmUgcmVuZGVyaW5nLlxuICogQHBhcmFtIHtOdW1iZXJ9IFtvcHRpb25zLmhlaWdodF0gLSBoZWlnaHQgdG8gYmUgYXBwbGllZCB0byBub2RlIGJlZm9yZSByZW5kZXJpbmcuXG4gKiBAcGFyYW0ge09iamVjdH0gW29wdGlvbnMuc3R5bGVdIC0gYW4gb2JqZWN0IHdob3NlIHByb3BlcnRpZXMgdG8gYmUgY29waWVkIHRvIG5vZGUncyBzdHlsZSBiZWZvcmUgcmVuZGVyaW5nLlxuICogQHBhcmFtIHtOdW1iZXJ9IFtvcHRpb25zLnF1YWxpdHldIC0gYSBOdW1iZXIgYmV0d2VlbiAwIGFuZCAxIGluZGljYXRpbmcgaW1hZ2UgcXVhbGl0eSAoYXBwbGljYWJsZSB0byBKUEVHIG9ubHkpLCBkZWZhdWx0cyB0byAxLjAuXG4gKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmVzY2FwZVhodG1sRm9yV2VicGFja10gLSB3aGV0aGVyIHRvIGFwcGx5IGZpeCBmb3IgdWdsaWZ5IGVycm9yIGluIGRvbS10by1pbWFnZSAoc2hvdWxkIGJlIHRydWUgZm9yIHdlYnBhY2sgYnVpbGRzKSwgZGVmYXVsdHMgdG8gdHJ1ZS5cbiAqIEBwYXJhbSB7U3RyaW5nfSBbb3B0aW9ucy5pbWFnZVBsYWNlaG9sZGVyXSAtIGRhdGFVUkwgdG8gdXNlIGFzIGEgcGxhY2Vob2xkZXIgZm9yIGZhaWxlZCBpbWFnZXMsIGRlZmF1bHQgYmVoYXZpb3VyIGlzIHRvIGZhaWwgZmFzdCBvbiBpbWFnZXMgd2UgY2FuJ3QgZmV0Y2hcbiAqIEBwYXJhbSB7Qm9vbGVhbn0gW29wdGlvbnMuY2FjaGVCdXN0XSAtIHNldCB0byB0cnVlIHRvIGNhY2hlIGJ1c3QgYnkgYXBwZW5kaW5nIHRoZSB0aW1lIHRvIHRoZSByZXF1ZXN0IHVybFxuICogQHJldHVybiB7UHJvbWlzZX0gLSBBIHByb21pc2UgdGhhdCBpcyBmdWxmaWxsZWQgd2l0aCBhIFNWRyBpbWFnZSBkYXRhIFVSTFxuICogKi9cbmZ1bmN0aW9uIHRvU3ZnKG5vZGUsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIGNvcHlPcHRpb25zKG9wdGlvbnMpO1xuICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5vZGUpXG4gICAgLnRoZW4obmQgPT4gY2xvbmVOb2RlKG5kLCBvcHRpb25zLmZpbHRlciwgdHJ1ZSkpXG4gICAgLnRoZW4oZW1iZWRGb250cylcbiAgICAudGhlbihpbmxpbmVJbWFnZXMpXG4gICAgLnRoZW4oYXBwbHlPcHRpb25zKVxuICAgIC50aGVuKGNsb25lID0+XG4gICAgICBtYWtlU3ZnRGF0YVVyaShcbiAgICAgICAgY2xvbmUsXG4gICAgICAgIG9wdGlvbnMud2lkdGggfHwgZ2V0V2lkdGgobm9kZSksXG4gICAgICAgIG9wdGlvbnMuaGVpZ2h0IHx8IGdldEhlaWdodChub2RlKSxcbiAgICAgICAgb3B0aW9ucy5lc2NhcGVYaHRtbEZvcldlYnBhY2tcbiAgICAgIClcbiAgICApO1xuXG4gIGZ1bmN0aW9uIGFwcGx5T3B0aW9ucyhjbG9uZSkge1xuICAgIGlmIChvcHRpb25zLmJnY29sb3IpIGNsb25lLnN0eWxlLmJhY2tncm91bmRDb2xvciA9IG9wdGlvbnMuYmdjb2xvcjtcblxuICAgIGlmIChvcHRpb25zLndpZHRoKSBjbG9uZS5zdHlsZS53aWR0aCA9IGAke29wdGlvbnMud2lkdGh9cHhgO1xuICAgIGlmIChvcHRpb25zLmhlaWdodCkgY2xvbmUuc3R5bGUuaGVpZ2h0ID0gYCR7b3B0aW9ucy5oZWlnaHR9cHhgO1xuXG4gICAgaWYgKG9wdGlvbnMuc3R5bGUpXG4gICAgICBPYmplY3Qua2V5cyhvcHRpb25zLnN0eWxlKS5mb3JFYWNoKHByb3BlcnR5ID0+IHtcbiAgICAgICAgY2xvbmUuc3R5bGVbcHJvcGVydHldID0gb3B0aW9ucy5zdHlsZVtwcm9wZXJ0eV07XG4gICAgICB9KTtcblxuICAgIHJldHVybiBjbG9uZTtcbiAgfVxufVxuXG4vKipcbiAqIEBwYXJhbSB7Tm9kZX0gbm9kZSAtIFRoZSBET00gTm9kZSBvYmplY3QgdG8gcmVuZGVyXG4gKiBAcGFyYW0ge09iamVjdH0gb3B0aW9ucyAtIFJlbmRlcmluZyBvcHRpb25zXG4gKiBAcmV0dXJuIHtQcm9taXNlfSAtIEEgcHJvbWlzZSB0aGF0IGlzIGZ1bGZpbGxlZCB3aXRoIGEgVWludDhBcnJheSBjb250YWluaW5nIFJHQkEgcGl4ZWwgZGF0YS5cbiAqICovXG5mdW5jdGlvbiB0b1BpeGVsRGF0YShub2RlLCBvcHRpb25zKSB7XG4gIHJldHVybiBkcmF3KG5vZGUsIG9wdGlvbnMgfHwge30pLnRoZW4oXG4gICAgY2FudmFzID0+IGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpLmdldEltYWdlRGF0YSgwLCAwLCBnZXRXaWR0aChub2RlKSwgZ2V0SGVpZ2h0KG5vZGUpKS5kYXRhXG4gICk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIC0gVGhlIERPTSBOb2RlIG9iamVjdCB0byByZW5kZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gUmVuZGVyaW5nIG9wdGlvbnNcbiAqIEByZXR1cm4ge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgaXMgZnVsZmlsbGVkIHdpdGggYSBQTkcgaW1hZ2UgZGF0YSBVUkxcbiAqICovXG5mdW5jdGlvbiB0b1BuZyhub2RlLCBvcHRpb25zKSB7XG4gIHJldHVybiBkcmF3KG5vZGUsIG9wdGlvbnMgfHwge30pLnRoZW4oY2FudmFzID0+IGNhbnZhcy50b0RhdGFVUkwoKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIC0gVGhlIERPTSBOb2RlIG9iamVjdCB0byByZW5kZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gUmVuZGVyaW5nIG9wdGlvbnNcbiAqIEByZXR1cm4ge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgaXMgZnVsZmlsbGVkIHdpdGggYSBKUEVHIGltYWdlIGRhdGEgVVJMXG4gKiAqL1xuZnVuY3Rpb24gdG9KcGVnKG5vZGUsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIHJldHVybiBkcmF3KG5vZGUsIG9wdGlvbnMpLnRoZW4oY2FudmFzID0+IGNhbnZhcy50b0RhdGFVUkwoJ2ltYWdlL2pwZWcnLCBvcHRpb25zLnF1YWxpdHkgfHwgMS4wKSk7XG59XG5cbi8qKlxuICogQHBhcmFtIHtOb2RlfSBub2RlIC0gVGhlIERPTSBOb2RlIG9iamVjdCB0byByZW5kZXJcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gUmVuZGVyaW5nIG9wdGlvbnNcbiAqIEByZXR1cm4ge1Byb21pc2V9IC0gQSBwcm9taXNlIHRoYXQgaXMgZnVsZmlsbGVkIHdpdGggYSBQTkcgaW1hZ2UgYmxvYlxuICogKi9cbmZ1bmN0aW9uIHRvQmxvYihub2RlLCBvcHRpb25zKSB7XG4gIHJldHVybiBkcmF3KG5vZGUsIG9wdGlvbnMgfHwge30pLnRoZW4oY2FudmFzVG9CbG9iKTtcbn1cblxuZnVuY3Rpb24gY29weU9wdGlvbnMob3B0aW9ucykge1xuICAvLyBDb3B5IG9wdGlvbnMgdG8gaW1wbCBvcHRpb25zIGZvciB1c2UgaW4gaW1wbFxuICBpZiAodHlwZW9mIG9wdGlvbnMuaW1hZ2VQbGFjZWhvbGRlciA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBkb210b2ltYWdlLmltcGwub3B0aW9ucy5pbWFnZVBsYWNlaG9sZGVyID0gZGVmYXVsdE9wdGlvbnMuaW1hZ2VQbGFjZWhvbGRlcjtcbiAgfSBlbHNlIHtcbiAgICBkb210b2ltYWdlLmltcGwub3B0aW9ucy5pbWFnZVBsYWNlaG9sZGVyID0gb3B0aW9ucy5pbWFnZVBsYWNlaG9sZGVyO1xuICB9XG5cbiAgaWYgKHR5cGVvZiBvcHRpb25zLmNhY2hlQnVzdCA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBkb210b2ltYWdlLmltcGwub3B0aW9ucy5jYWNoZUJ1c3QgPSBkZWZhdWx0T3B0aW9ucy5jYWNoZUJ1c3Q7XG4gIH0gZWxzZSB7XG4gICAgZG9tdG9pbWFnZS5pbXBsLm9wdGlvbnMuY2FjaGVCdXN0ID0gb3B0aW9ucy5jYWNoZUJ1c3Q7XG4gIH1cbn1cblxuZnVuY3Rpb24gZHJhdyhkb21Ob2RlLCBvcHRpb25zKSB7XG4gIHJldHVybiB0b1N2Zyhkb21Ob2RlLCBvcHRpb25zKVxuICAgIC50aGVuKG1ha2VJbWFnZSlcbiAgICAudGhlbihkZWxheSgxMDApKVxuICAgIC50aGVuKGltYWdlID0+IHtcbiAgICAgIGNvbnN0IGNhbnZhcyA9IG5ld0NhbnZhcyhkb21Ob2RlKTtcbiAgICAgIGNhbnZhcy5nZXRDb250ZXh0KCcyZCcpLmRyYXdJbWFnZShpbWFnZSwgMCwgMCk7XG4gICAgICByZXR1cm4gY2FudmFzO1xuICAgIH0pO1xuXG4gIGZ1bmN0aW9uIG5ld0NhbnZhcyhkTm9kZSkge1xuICAgIGNvbnN0IGNhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgIGNhbnZhcy53aWR0aCA9IG9wdGlvbnMud2lkdGggfHwgZ2V0V2lkdGgoZE5vZGUpO1xuICAgIGNhbnZhcy5oZWlnaHQgPSBvcHRpb25zLmhlaWdodCB8fCBnZXRIZWlnaHQoZE5vZGUpO1xuXG4gICAgaWYgKG9wdGlvbnMuYmdjb2xvcikge1xuICAgICAgY29uc3QgY3R4ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICBjdHguZmlsbFN0eWxlID0gb3B0aW9ucy5iZ2NvbG9yO1xuICAgICAgY3R4LmZpbGxSZWN0KDAsIDAsIGNhbnZhcy53aWR0aCwgY2FudmFzLmhlaWdodCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNhbnZhcztcbiAgfVxufVxuXG5mdW5jdGlvbiBjbG9uZU5vZGUobm9kZSwgZmlsdGVyLCByb290KSB7XG4gIGlmICghcm9vdCAmJiBmaWx0ZXIgJiYgIWZpbHRlcihub2RlKSkge1xuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUoKTtcbiAgfVxuXG4gIHJldHVybiBQcm9taXNlLnJlc29sdmUobm9kZSlcbiAgICAudGhlbihtYWtlTm9kZUNvcHkpXG4gICAgLnRoZW4oY2xvbmUgPT4gY2xvbmVDaGlsZHJlbihub2RlLCBjbG9uZSwgZmlsdGVyKSlcbiAgICAudGhlbihjbG9uZSA9PiBwcm9jZXNzQ2xvbmUobm9kZSwgY2xvbmUpKTtcblxuICBmdW5jdGlvbiBtYWtlTm9kZUNvcHkobmQpIHtcbiAgICBpZiAobmQgaW5zdGFuY2VvZiBXaW5kb3cuSFRNTENhbnZhc0VsZW1lbnQpIHtcbiAgICAgIHJldHVybiBtYWtlSW1hZ2UobmQudG9EYXRhVVJMKCkpO1xuICAgIH1cbiAgICByZXR1cm4gbmQuY2xvbmVOb2RlKGZhbHNlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lQ2hpbGRyZW5Jbk9yZGVyKHBhcmVudCwgYXJyQ2hpbGRyZW4sIGZsdCkge1xuICAgIGxldCBkb25lID0gUHJvbWlzZS5yZXNvbHZlKCk7XG4gICAgYXJyQ2hpbGRyZW4uZm9yRWFjaChjaGlsZCA9PiB7XG4gICAgICBkb25lID0gZG9uZVxuICAgICAgICAudGhlbigoKSA9PiBjbG9uZU5vZGUoY2hpbGQsIGZsdCwgbnVsbCkpXG4gICAgICAgIC50aGVuKGNoaWxkQ2xvbmUgPT4ge1xuICAgICAgICAgIGlmIChjaGlsZENsb25lKSB7XG4gICAgICAgICAgICBwYXJlbnQuYXBwZW5kQ2hpbGQoY2hpbGRDbG9uZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gZG9uZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsb25lQ2hpbGRyZW4ob3JpZ2luYWwsIGNsb25lLCBmbHQpIHtcbiAgICBjb25zdCBjaGlsZHJlbiA9IG9yaWdpbmFsLmNoaWxkTm9kZXM7XG4gICAgaWYgKGNoaWxkcmVuLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShjbG9uZSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGNsb25lQ2hpbGRyZW5Jbk9yZGVyKGNsb25lLCBhc0FycmF5KGNoaWxkcmVuKSwgZmx0KS50aGVuKCgpID0+IGNsb25lKTtcbiAgfVxufVxuXG5mdW5jdGlvbiBlbWJlZEZvbnRzKG5vZGUpIHtcbiAgcmV0dXJuIGZvbnRGYWNlcy5yZXNvbHZlQWxsKCkudGhlbihjc3NUZXh0ID0+IHtcbiAgICBjb25zdCBzdHlsZU5vZGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzdHlsZScpO1xuICAgIG5vZGUuYXBwZW5kQ2hpbGQoc3R5bGVOb2RlKTtcbiAgICBzdHlsZU5vZGUuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoY3NzVGV4dCkpO1xuICAgIHJldHVybiBub2RlO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gaW5saW5lSW1hZ2VzKG5vZGUpIHtcbiAgcmV0dXJuIGltYWdlcy5pbmxpbmVBbGwobm9kZSkudGhlbigoKSA9PiBub2RlKTtcbn1cblxuZnVuY3Rpb24gbWFrZVN2Z0RhdGFVcmkobm9kZSwgd2lkdGgsIGhlaWdodCwgZXNjYXBlWGh0bWxGb3JXZWJwYWNrID0gdHJ1ZSkge1xuICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5vZGUpLnRoZW4obmQgPT4ge1xuICAgIG5kLnNldEF0dHJpYnV0ZSgneG1sbnMnLCAnaHR0cDovL3d3dy53My5vcmcvMTk5OS94aHRtbCcpO1xuICAgIGNvbnN0IHNlcmlhbGl6ZWRTdHJpbmcgPSBuZXcgV2luZG93LlhNTFNlcmlhbGl6ZXIoKS5zZXJpYWxpemVUb1N0cmluZyhuZCk7XG5cbiAgICBjb25zdCB4aHRtbCA9IGVzY2FwZVhodG1sRm9yV2VicGFjayA/IGVzY2FwZVhodG1sKHNlcmlhbGl6ZWRTdHJpbmcpIDogc2VyaWFsaXplZFN0cmluZztcbiAgICBjb25zdCBmb3JlaWduT2JqZWN0ID0gYDxmb3JlaWduT2JqZWN0IHg9XCIwXCIgeT1cIjBcIiB3aWR0aD1cIjEwMCVcIiBoZWlnaHQ9XCIxMDAlXCI+JHt4aHRtbH08L2ZvcmVpZ25PYmplY3Q+YDtcbiAgICBjb25zdCBzdmdTdHIgPSBgPHN2ZyB4bWxucz1cImh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnXCIgd2lkdGg9XCIke3dpZHRofVwiIGhlaWdodD1cIiR7aGVpZ2h0fVwiPiR7Zm9yZWlnbk9iamVjdH08L3N2Zz5gO1xuXG4gICAgLy8gT3B0aW1pemluZyBTVkdzIGluIGRhdGEgVVJJc1xuICAgIC8vIHNlZSBodHRwczovL2NvZGVwZW4uaW8vdGlndC9wb3N0L29wdGltaXppbmctc3Zncy1pbi1kYXRhLXVyaXNcbiAgICAvLyB0aGUgYmVzdCB3YXkgb2YgZW5jb2RpbmcgU1ZHIGluIGEgZGF0YTogVVJJIGlzIGRhdGE6aW1hZ2Uvc3ZnK3htbCxbYWN0dWFsIGRhdGFdLlxuICAgIC8vIFdlIGRvbuKAmXQgbmVlZCB0aGUgO2NoYXJzZXQ9dXRmLTggcGFyYW1ldGVyIGJlY2F1c2UgdGhlIGdpdmVuIFNWRyBpcyBBU0NJSS5cbiAgICByZXR1cm4gc3ZnVG9NaW5pRGF0YVVSSShzdmdTdHIpO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gbmV3SW5saW5lcigpIHtcbiAgY29uc3QgVVJMX1JFR0VYID0gL3VybFxcKFsnXCJdPyhbXidcIl0rPylbJ1wiXT9cXCkvZztcblxuICByZXR1cm4ge1xuICAgIGlubGluZUFsbCxcbiAgICBzaG91bGRQcm9jZXNzLFxuICAgIGltcGw6IHtcbiAgICAgIHJlYWRVcmxzLFxuICAgICAgaW5saW5lXG4gICAgfVxuICB9O1xuXG4gIGZ1bmN0aW9uIHNob3VsZFByb2Nlc3Moc3RyaW5nKSB7XG4gICAgcmV0dXJuIHN0cmluZy5zZWFyY2goVVJMX1JFR0VYKSAhPT0gLTE7XG4gIH1cblxuICBmdW5jdGlvbiByZWFkVXJscyhzdHJpbmcpIHtcbiAgICBjb25zdCByZXN1bHQ6IHN0cmluZ1tdID0gW107XG4gICAgbGV0IG1hdGNoOiBudWxsIHwgUmVnRXhwRXhlY0FycmF5O1xuICAgIHdoaWxlICgobWF0Y2ggPSBVUkxfUkVHRVguZXhlYyhzdHJpbmcpKSAhPT0gbnVsbCkge1xuICAgICAgcmVzdWx0LnB1c2gobWF0Y2hbMV0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0LmZpbHRlcih1cmwgPT4ge1xuICAgICAgcmV0dXJuICFpc0RhdGFVcmwodXJsKTtcbiAgICB9KTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVybEFzUmVnZXgodXJsMCkge1xuICAgIHJldHVybiBuZXcgUmVnRXhwKGAodXJsXFxcXChbJ1wiXT8pKCR7ZXNjYXBlKHVybDApfSkoWydcIl0/XFxcXCkpYCwgJ2cnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGlubGluZShzdHJpbmcsIHVybCwgYmFzZVVybCwgZ2V0KSB7XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSh1cmwpXG4gICAgICAudGhlbih1bCA9PiAoYmFzZVVybCA/IHJlc29sdmVVcmwodWwsIGJhc2VVcmwpIDogdWwpKVxuICAgICAgLnRoZW4odWwgPT4gKHR5cGVvZiBnZXQgPT09ICdmdW5jdGlvbicgPyBnZXQodWwpIDogZ2V0QW5kRW5jb2RlKHVsLCBkb210b2ltYWdlLmltcGwub3B0aW9ucykpKVxuICAgICAgLnRoZW4oZGF0YSA9PiBkYXRhQXNVcmwoZGF0YSwgbWltZVR5cGUodXJsKSkpXG4gICAgICAudGhlbihkYXRhVXJsID0+IHN0cmluZy5yZXBsYWNlKHVybEFzUmVnZXgodXJsKSwgYCQxJHtkYXRhVXJsfSQzYCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gaW5saW5lQWxsKHN0cmluZywgYmFzZVVybCwgZ2V0KSB7XG4gICAgaWYgKCFzaG91bGRQcm9jZXNzKHN0cmluZykgfHwgaXNTcmNBc0RhdGFVcmwoc3RyaW5nKSkge1xuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShzdHJpbmcpO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHN0cmluZylcbiAgICAgIC50aGVuKHJlYWRVcmxzKVxuICAgICAgLnRoZW4odXJscyA9PiB7XG4gICAgICAgIGxldCBkb25lID0gUHJvbWlzZS5yZXNvbHZlKHN0cmluZyk7XG4gICAgICAgIHVybHMuZm9yRWFjaCh1cmwgPT4ge1xuICAgICAgICAgIGRvbmUgPSBkb25lLnRoZW4oc3RyID0+IGlubGluZShzdHIsIHVybCwgYmFzZVVybCwgZ2V0KSk7XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gZG9uZTtcbiAgICAgIH0pO1xuICB9XG59XG5cbmZ1bmN0aW9uIG5ld0ZvbnRGYWNlcygpIHtcbiAgcmV0dXJuIHtcbiAgICByZXNvbHZlQWxsLFxuICAgIGltcGw6IHtyZWFkQWxsfVxuICB9O1xuXG4gIGZ1bmN0aW9uIHJlc29sdmVBbGwoKSB7XG4gICAgcmV0dXJuIHJlYWRBbGwoKVxuICAgICAgLnRoZW4od2ViRm9udHMgPT4ge1xuICAgICAgICByZXR1cm4gUHJvbWlzZS5hbGwod2ViRm9udHMubWFwKHdlYkZvbnQgPT4gd2ViRm9udC5yZXNvbHZlKCkpKTtcbiAgICAgIH0pXG4gICAgICAudGhlbihjc3NTdHJpbmdzID0+IGNzc1N0cmluZ3Muam9pbignXFxuJykpO1xuICB9XG5cbiAgZnVuY3Rpb24gcmVhZEFsbCgpIHtcbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKGFzQXJyYXkoZG9jdW1lbnQuc3R5bGVTaGVldHMpKVxuICAgICAgLnRoZW4obG9hZEV4dGVybmFsU3R5bGVTaGVldHMpXG4gICAgICAudGhlbihnZXRDc3NSdWxlcylcbiAgICAgIC50aGVuKHNlbGVjdFdlYkZvbnRSdWxlcylcbiAgICAgIC50aGVuKHJ1bGVzID0+IHJ1bGVzLm1hcChuZXdXZWJGb250KSk7XG5cbiAgICBmdW5jdGlvbiBzZWxlY3RXZWJGb250UnVsZXMoY3NzUnVsZXMpIHtcbiAgICAgIHJldHVybiBjc3NSdWxlc1xuICAgICAgICAuZmlsdGVyKHJ1bGUgPT4gcnVsZS50eXBlID09PSBXaW5kb3cuQ1NTUnVsZS5GT05UX0ZBQ0VfUlVMRSlcbiAgICAgICAgLmZpbHRlcihydWxlID0+IGlubGluZXIuc2hvdWxkUHJvY2VzcyhydWxlLnN0eWxlLmdldFByb3BlcnR5VmFsdWUoJ3NyYycpKSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9hZEV4dGVybmFsU3R5bGVTaGVldHMoc3R5bGVTaGVldHMpIHtcbiAgICAgIHJldHVybiBQcm9taXNlLmFsbChcbiAgICAgICAgc3R5bGVTaGVldHMubWFwKHNoZWV0ID0+IHtcbiAgICAgICAgICBpZiAoc2hlZXQuaHJlZikge1xuICAgICAgICAgICAgLy8gY2xvdWRmb250IGRvZXNuJ3QgaGF2ZSBhbGxvdyBvcmlnaW4gaGVhZGVyIHByb3Blcmx5IHNldFxuICAgICAgICAgICAgLy8gZXJyb3IgcmVzcG9uc2Ugd2lsbCByZW1haW4gaW4gY2FjaGVcbiAgICAgICAgICAgIGNvbnN0IGNhY2hlID0gc2hlZXQuaHJlZi5pbmNsdWRlcygndWJlci1mb250cycpID8gJ25vLWNhY2hlJyA6ICdkZWZhdWx0JztcbiAgICAgICAgICAgIHJldHVybiBXaW5kb3cuZmV0Y2goc2hlZXQuaHJlZiwge2NyZWRlbnRpYWxzOiAnb21pdCcsIGNhY2hlfSlcbiAgICAgICAgICAgICAgLnRoZW4ocmVzcG9uc2UgPT4gcmVzcG9uc2UudGV4dCgpKVxuICAgICAgICAgICAgICAudGhlbih0ZXh0ID0+IHtcbiAgICAgICAgICAgICAgICBjb25zdCByZXN1bHQgPSBzZXRTdHlsZVNoZWV0QmFzZUhyZWYodGV4dCwgc2hlZXQuaHJlZik7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRvU3R5bGVTaGVldChyZXN1bHQpO1xuICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAuY2F0Y2goZXJyID0+IHtcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgYW55IGVycm9yIHRoYXQgb2NjdXJyZWQgaW4gYW55IG9mIHRoZSBwcmV2aW91c1xuICAgICAgICAgICAgICAgIC8vIHByb21pc2VzIGluIHRoZSBjaGFpbi4gc3R5bGVzaGVldCBmYWlsZWQgdG8gbG9hZCBzaG91bGQgbm90IHN0b3BcbiAgICAgICAgICAgICAgICAvLyB0aGUgcHJvY2VzcywgaGVuY2UgcmVzdWx0IGluIG9ubHkgYSB3YXJuaW5nLCBpbnN0ZWFkIG9mIHJlamVjdFxuICAgICAgICAgICAgICAgIENvbnNvbGUud2FybihJTUFHRV9FWFBPUlRfRVJST1JTLnN0eWxlU2hlZXQsIHNoZWV0LmhyZWYpO1xuICAgICAgICAgICAgICAgIENvbnNvbGUubG9nKGVycik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShzaGVldCk7XG4gICAgICAgIH0pXG4gICAgICApO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdldENzc1J1bGVzKHN0eWxlU2hlZXRzKSB7XG4gICAgICBjb25zdCBjc3NSdWxlczogYW55W10gPSBbXTtcbiAgICAgIHN0eWxlU2hlZXRzLmZvckVhY2goc2hlZXQgPT4ge1xuICAgICAgICAvLyB0cnkuLi5jYXRjaCBiZWNhdXNlIGJyb3dzZXIgbWF5IG5vdCBhYmxlIHRvIGVudW1lcmF0ZSBydWxlcyBmb3IgY3Jvc3MtZG9tYWluIHNoZWV0c1xuICAgICAgICBpZiAoIXNoZWV0KSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIGxldCBydWxlcztcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBydWxlcyA9IHNoZWV0LnJ1bGVzIHx8IHNoZWV0LmNzc1J1bGVzO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgQ29uc29sZS5sb2coYCdDYW4ndCByZWFkIHRoZSBjc3MgcnVsZXMgb2Y6ICR7c2hlZXQuaHJlZn1gLCBlKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocnVsZXMgJiYgdHlwZW9mIHJ1bGVzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBhc0FycmF5KHJ1bGVzIHx8IFtdKS5mb3JFYWNoKGNzc1J1bGVzLnB1c2guYmluZChjc3NSdWxlcykpO1xuICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIENvbnNvbGUubG9nKGBFcnJvciB3aGlsZSByZWFkaW5nIENTUyBydWxlcyBmcm9tICR7c2hlZXQuaHJlZn1gLCBlKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgQ29uc29sZS5sb2coJ2dldENzc1J1bGVzIGNhbiBub3QgZmluZCBjc3NSdWxlcycpO1xuICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgfSk7XG5cbiAgICAgIHJldHVybiBjc3NSdWxlcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBuZXdXZWJGb250KHdlYkZvbnRSdWxlKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZXNvbHZlOiAoKSA9PiB7XG4gICAgICAgICAgY29uc3QgYmFzZVVybCA9ICh3ZWJGb250UnVsZS5wYXJlbnRTdHlsZVNoZWV0IHx8IHt9KS5ocmVmO1xuICAgICAgICAgIHJldHVybiBpbmxpbmVyLmlubGluZUFsbCh3ZWJGb250UnVsZS5jc3NUZXh0LCBiYXNlVXJsLCBudWxsKTtcbiAgICAgICAgfSxcbiAgICAgICAgc3JjOiAoKSA9PiB3ZWJGb250UnVsZS5zdHlsZS5nZXRQcm9wZXJ0eVZhbHVlKCdzcmMnKVxuICAgICAgfTtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gbmV3SW1hZ2VzKCkge1xuICByZXR1cm4ge1xuICAgIGlubGluZUFsbCxcbiAgICBpbXBsOiB7XG4gICAgICBuZXdJbWFnZVxuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBuZXdJbWFnZShlbGVtZW50KSB7XG4gICAgZnVuY3Rpb24gaW5saW5lKGdldCkge1xuICAgICAgaWYgKGlzRGF0YVVybChlbGVtZW50LnNyYykpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShlbGVtZW50LnNyYylcbiAgICAgICAgLnRoZW4odWwgPT5cbiAgICAgICAgICB0eXBlb2YgZ2V0ID09PSAnZnVuY3Rpb24nID8gZ2V0KHVsKSA6IGdldEFuZEVuY29kZSh1bCwgZG9tdG9pbWFnZS5pbXBsLm9wdGlvbnMpXG4gICAgICAgIClcbiAgICAgICAgLnRoZW4oZGF0YSA9PiBkYXRhQXNVcmwoZGF0YSwgbWltZVR5cGUoZWxlbWVudC5zcmMpKSlcbiAgICAgICAgLnRoZW4oXG4gICAgICAgICAgZGF0YVVybCA9PlxuICAgICAgICAgICAgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgICAgICAgICBlbGVtZW50Lm9ubG9hZCA9IHJlc29sdmU7XG4gICAgICAgICAgICAgIGVsZW1lbnQub25lcnJvciA9IHJlamVjdDtcbiAgICAgICAgICAgICAgZWxlbWVudC5zcmMgPSBkYXRhVXJsO1xuICAgICAgICAgICAgfSlcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgaW5saW5lXG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGlubGluZUFsbChub2RlKSB7XG4gICAgaWYgKCEobm9kZSBpbnN0YW5jZW9mIEVsZW1lbnQpKSB7XG4gICAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKG5vZGUpO1xuICAgIH1cblxuICAgIHJldHVybiBpbmxpbmVCYWNrZ3JvdW5kKG5vZGUpLnRoZW4oKCkgPT4ge1xuICAgICAgaWYgKG5vZGUgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50KSB7XG4gICAgICAgIHJldHVybiBuZXdJbWFnZShub2RlKS5pbmxpbmUobnVsbCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gUHJvbWlzZS5hbGwoYXNBcnJheShub2RlLmNoaWxkTm9kZXMpLm1hcChjaGlsZCA9PiBpbmxpbmVBbGwoY2hpbGQpKSk7XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBpbmxpbmVCYWNrZ3JvdW5kKG5kKSB7XG4gICAgICBjb25zdCBiYWNrZ3JvdW5kID0gbmQuc3R5bGUuZ2V0UHJvcGVydHlWYWx1ZSgnYmFja2dyb3VuZCcpO1xuXG4gICAgICBpZiAoIWJhY2tncm91bmQpIHtcbiAgICAgICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShuZCk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBpbmxpbmVyXG4gICAgICAgIC5pbmxpbmVBbGwoYmFja2dyb3VuZCwgbnVsbCwgbnVsbClcbiAgICAgICAgLnRoZW4oaW5saW5lZCA9PiB7XG4gICAgICAgICAgbmQuc3R5bGUuc2V0UHJvcGVydHkoJ2JhY2tncm91bmQnLCBpbmxpbmVkLCBuZC5zdHlsZS5nZXRQcm9wZXJ0eVByaW9yaXR5KCdiYWNrZ3JvdW5kJykpO1xuICAgICAgICB9KVxuICAgICAgICAudGhlbigoKSA9PiBuZCk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCBkZWZhdWx0IGRvbXRvaW1hZ2U7XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBUUEsSUFBQUEsT0FBQSxHQUFBQyxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUMsU0FBQSxHQUFBRixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUUsUUFBQSxHQUFBSCxzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUcsZUFBQSxHQUFBSixzQkFBQSxDQUFBQyxPQUFBO0FBQ0EsSUFBQUksVUFBQSxHQUFBSixPQUFBO0FBRUEsSUFBQUssU0FBQSxHQUFBTCxP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