Skip to content

Instantly share code, notes, and snippets.

@dreki
Last active May 6, 2017 02:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dreki/3c751d9a026b6d2f6d1ee1ce86e317a2 to your computer and use it in GitHub Desktop.
Save dreki/3c751d9a026b6d2f6d1ee1ce86e317a2 to your computer and use it in GitHub Desktop.
requirebin sketch
/* global document */
// Welcome! require() some modules from npm (like you were using browserify)
// and then hit Run Code to run your code on the right side.
// Modules get downloaded from browserify-cdn and bundled in your browser.
const diff = require('diffhtml');
const container = document.querySelector('.js-container');
document.querySelector('.js-add').addEventListener('click', () => {
/*
let div = document.createElement('div');
div.classList.add('box');
div.classList.add('js-box');
div.innerText = new Date().getSeconds();
container.appendChild(div);
*/
diff.innerHTML(
container,
container.innerHTML + `<div class="box js-box">${new Date().getSeconds()}</div>`
);
});
setTimeout(function(){
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({"diffhtml":[function(require,module,exports){
(function (global){
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.diff = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createAttribute = exports.createElement = exports.release = exports.html = undefined;
var _taggedTemplate = _dereq_('./util/tagged-template');
Object.defineProperty(exports, 'html', {
enumerable: true,
get: function get() {
return _taggedTemplate.html;
}
});
var _release = _dereq_('./node/release');
Object.defineProperty(exports, 'release', {
enumerable: true,
get: function get() {
return _interopRequireDefault(_release).default;
}
});
var _helpers = _dereq_('./tree/helpers');
Object.defineProperty(exports, 'createElement', {
enumerable: true,
get: function get() {
return _helpers.createElement;
}
});
Object.defineProperty(exports, 'createAttribute', {
enumerable: true,
get: function get() {
return _helpers.createAttribute;
}
});
exports.outerHTML = outerHTML;
exports.innerHTML = innerHTML;
exports.element = element;
exports.addTransitionState = addTransitionState;
exports.removeTransitionState = removeTransitionState;
exports.use = use;
var _transaction = _dereq_('./node/transaction');
var _transaction2 = _interopRequireDefault(_transaction);
var _transitions = _dereq_('./util/transitions');
var _cache = _dereq_('./util/cache');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Used to diff the outerHTML contents of the passed element with the markup
* contents. Very useful for applying a global diff on the
* `document.documentElement`.
*
* @example
*
* import { outerHTML } from 'diffhtml'
*
* // Remove all attributes and set the children to be a single text node
* // containing the text 'Hello world',
* outerHTML(document.body, '<body>Hello world</body>')
*
*
* @param {Object} element - A DOM Node to render into
* @param {String|Object} markup='' - A string of markup or virtual tree
* @param {Object =} options={} - An object containing configuration options
*/
function outerHTML(element) {
var markup = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
options.inner = false;
(0, _transaction2.default)(element, markup, options);
}
/**
* Used to diff the innerHTML contents of the passed element with the markup
* contents. This is useful with libraries like Backbone that render Views
* into element container.
*
* @example
*
* import { innerHTML } from 'diffhtml'
*
* // Sets the body children to be a single text node containing the text
* // 'Hello world'.
* innerHTML(document.body, 'Hello world')
*
*
* @param {Object} element - A DOM Node to render into
* @param {String|Object} markup='' - A string of markup or virtual tree
* @param {Object =} options={} - An object containing configuration options
*/
function innerHTML(element) {
var markup = arguments.length <= 1 || arguments[1] === undefined ? '' : arguments[1];
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
options.inner = true;
(0, _transaction2.default)(element, markup, options);
}
/**
* Used to diff two elements. The `inner` Boolean property can be specified in
* the options to set innerHTML\outerHTML behavior. By default it is
* outerHTML.
*
* @example
*
* // It is usually better to rename this method to something descriptive.
* import { element as diffElement } from 'diffhtml'
*
* // Create a new body tag.
* const newBody = $(`<body>
* <strong>Hello world!</strong>
* </body>`).get();
*
*
* diffElement(document.body, newBody);
*
*
* @param {Object} element - A DOM Node to render into
* @param {Object} newElement - A string of markup or virtual tree
* @param {Object =} options={} - An object containing configuration options
*/
function element(element, newElement) {
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
(0, _transaction2.default)(element, newElement, options);
}
/**
* Adds a global transition listener. With many elements this could be an
* expensive operation, so try to limit the amount of listeners added if you're
* concerned about performance.
*
* Since the callback triggers with various elements, most of which you
* probably don't care about, you'll want to filter. A good way of filtering
* is to use the DOM `matches` method. It's fairly well supported
* (http://caniuse.com/#feat=matchesselector) and may suit many projects. If
* you need backwards compatibility, consider using jQuery's `is`.
*
* @example
*
* import { addTransitionState } from 'diffhtml'
*
* // Fade in all elements as they are added to the DOM.
* addTransitionState('attached', el => $(el).fadeIn().promise())
*
* // Fade out all elements as they leave the DOM.
* addTransitionState('detached', el => $(el).fadeOut().promise())
*
*
* @param state - String name that matches what's available in the
* documentation above.
* @param callback - Function to receive the matching elements.
*/
function addTransitionState(state, callback) {
if (!state) {
throw new Error('Missing transition state name');
}
if (!callback) {
throw new Error('Missing transition state callback');
}
// Not a valid state name.
if (Object.keys(_transitions.states).indexOf(state) === -1) {
throw new Error('Invalid state name: ' + state);
}
_transitions.states[state].push(callback);
}
/**
* Removes a global transition listener.
*
* When invoked with no arguments, this method will remove all transition
* callbacks. When invoked with the name argument it will remove all transition
* state callbacks matching the name, and so on for the callback.
*
* @example
*
* import { removeTransitionState } from 'diffhtml'
*
* // Remove all transition state handlers.
* removeTransitionState()
*
* // Remove all `attached` state handlers.
* removeTransitionState('attached')
*
* @param {String =} state - Name that matches what's available in the
* documentation above
* @param {Function =} callback - Callback to receive the matching elements
*/
function removeTransitionState(state, callback) {
if (!callback && state) {
_transitions.states[state].length = 0;
} else if (state && callback) {
// Not a valid state name.
if (Object.keys(_transitions.states).indexOf(state) === -1) {
throw new Error('Invalid state name ' + state);
}
var index = _transitions.states[state].indexOf(callback);
_transitions.states[state].splice(index, 1);
} else {
for (var _state in _transitions.states) {
_transitions.states[_state].length = 0;
}
}
}
/**
* Registers middleware functions which are called during the render
* transaction flow. These should be very fast and ideally asynchronous to
* avoid blocking the render.
*
* @example
*
* import { use } from 'diffhtml'
* import logger from 'diffhtml-logger'
*
* // Add the diffHTML logger middleware, to console out render information.
* use(logger)
*
*
* @param {Function} middleware - A function that gets passed internals
* @return {Function} - When invoked removes and deactivates the middleware
*/
function use(middleware) {
if (typeof middleware !== 'function') {
throw new Error('Middleware must be a function');
}
// Add the function to the set of middlewares.
_cache.MiddlewareCache.add(middleware);
// The unsubscribe method for the middleware.
return function () {
// Remove this middleware from the internal cache. This will prevent it
// from being invoked in the future.
_cache.MiddlewareCache.delete(middleware);
// Call the unsubscribe method if defined in the middleware (allows them
// to cleanup).
middleware.unsubscribe && middleware.unsubscribe();
};
}
},{"./node/release":5,"./node/transaction":6,"./tree/helpers":7,"./util/cache":10,"./util/tagged-template":17,"./util/transitions":18}],2:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = getFinalizeCallback;
var _transaction = _dereq_('../node/transaction');
var _transaction2 = _interopRequireDefault(_transaction);
var _cache = _dereq_('../util/cache');
var _memory = _dereq_('../util/memory');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* Pulls the next render object (containing the respective arguments to
* patchNode) and invokes the next transaction.
*
* @param state
*/
var renderNext = function renderNext(state) {
var nextRender = state.nextRender;
state.nextRender = undefined;
(0, _transaction2.default)(nextRender.node, nextRender.newHTML, nextRender.options);
};
/**
* Returns a callback that finalizes the transaction, setting the isRendering
* flag to false. This allows us to pick off and invoke the next available
* transaction to render. This code recyles the unprotected allocated pool
* objects and triggers a `renderComplete` event.
*
* @param {Object} node - A DOM Node that has just had patches applied
* @param {Object} state - The current state object associated with the Node
* @return {Function} - Closure that when called completes the transaction
*/
function getFinalizeCallback(node, state) {
/**
* When the render completes, clean up memory, and schedule the next render
* if necessary.
*
* @param {Array} remainingMiddleware - Array of middleware to invoke
*/
return function finalizeTransaction() {
var remainingMiddleware = arguments.length <= 0 || arguments[0] === undefined ? [] : arguments[0];
var isInner = state.options.inner;
state.previousMarkup = isInner ? node.innerHTML : node.outerHTML;
state.previousText = node.textContent;
state.isRendering = false;
// This is designed to handle use cases where renders are being hammered
// or when transitions are used with Promises. If this element has a next
// render state, trigger it first as priority.
if (state.nextRender) {
renderNext(state);
}
// Otherwise dig into the other states and pick off the first one
// available.
else {
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = _cache.StateCache.entries()[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var _state = _step.value;
if (_state.nextRender) {
renderNext(_state);
break;
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
}
// Clean out all the existing allocations.
(0, _memory.cleanMemory)();
// Call the remaining middleware signaling the render is complete.
for (var i = 0; i < remainingMiddleware.length; i++) {
remainingMiddleware[i]();
}
};
}
},{"../node/transaction":6,"../util/cache":10,"../util/memory":13}],3:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.default = make;
var _cache = _dereq_('../util/cache');
var _svg = _dereq_('../util/svg');
var svg = _interopRequireWildcard(_svg);
var _entities = _dereq_('../util/entities');
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
/**
* Gets a specific type of DOM Node depending on the passed in nodeName.
*
* @param nodeName {String} - The nodeName to disambiguate the type
* @param nodeValue {String} - The nodeValue to set if a Text Node
* @return {Object} - A DOM Node matching the nodeName
*/
var createNodeFromName = function createNodeFromName(_ref) {
var nodeName = _ref.nodeName;
var nodeValue = _ref.nodeValue;
// If we're dealing with a Text Node, we need to use the special DOM method,
// since createElement does not understand the nodeName '#text'.
// All other nodes can be created through createElement.
if (nodeName === '#text') {
return document.createTextNode(nodeValue);
}
// If the nodeName matches any of the known SVG element names, mark it as
// SVG. The reason for doing this over detecting if nested in an <svg>
// element, is that we do not currently have circular dependencies in the
// VTree, by avoiding parentNode, so there is no way to crawl up the parents.
else if (svg.elements.indexOf(nodeName) > -1) {
return document.createElementNS(svg.namespace, nodeName);
}
// If not a Text or SVG Node, then create with the standard method.
else {
return document.createElement(nodeName);
}
};
/**
* Takes in a Virtual Tree Element (VTree) and creates a DOM Node from it.
* Sets the node into the Node cache. If this VTree already has an
* associated node, it will reuse that.
*
* @param {Object} - A Virtual Tree Element or VTree-like element
* @return {Object} - A DOM Node matching the vTree
*/
function make(vTree) {
// If no Virtual Tree Element was specified, return null.
if (!vTree) {
return null;
}
// If the DOM Node was already created, reuse the existing node.
if (_cache.NodeCache.has(vTree)) {
return _cache.NodeCache.get(vTree);
}
var node = createNodeFromName(vTree);
// Copy all the attributes from the vTree into the newly created DOM
// Node.
for (var i = 0; i < (vTree.attributes || []).length; i++) {
var attr = vTree.attributes[i];
var isObject = _typeof(attr.value) === 'object';
var isFunction = typeof attr.value === 'function';
// If not a dynamic type, set as an attribute, since it's a valid
// attribute value.
if (attr.name && !isObject && !isFunction) {
node.setAttribute(attr.name, (0, _entities.decodeEntities)(attr.value));
} else if (attr.name && typeof attr.value !== 'string') {
// Necessary to track the attribute/prop existence.
node.setAttribute(attr.name, '');
// Since this is a dynamic value it gets set as a property.
node[attr.name] = attr.value;
}
}
// Append all the children into the node, making sure to run them
// through this `make` function as well.
for (var _i = 0; _i < (vTree.childNodes || []).length; _i++) {
node.appendChild(make(vTree.childNodes[_i]));
}
// Add to the nodes cache.
_cache.NodeCache.set(vTree, node);
return node;
}
},{"../util/cache":10,"../util/entities":11,"../util/svg":16}],4:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.default = patchNode;
var _make = _dereq_('./make');
var _make2 = _interopRequireDefault(_make);
var _transitions = _dereq_('../util/transitions');
var _parser = _dereq_('../util/parser');
var _cache = _dereq_('../util/cache');
var _pools = _dereq_('../util/pools');
var _memory = _dereq_('../util/memory');
var _entities = _dereq_('../util/entities');
var _sync = _dereq_('../tree/sync');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isElementNode = function isElementNode(node) {
return node.nodeType === 1;
};
var filter = Array.prototype.filter;
/**
* Looks to see if an element can be replaced. It must have a parentNode to do
* so. This will trigger an error when the element does not have a parentNode.
* This typically happens when trying to replace a disconnected DOM Node or the
* documentElement.
*
* @param {String} verb - Verb to replace in the template string
* @param {Object} oldNode - Old DOM Node to check if able to be replaced
* @param {Object} patch - Used to clean up vTree references
*/
var checkForMissingParent = function checkForMissingParent(verb, oldNode, patch) {
if (!oldNode.parentNode) {
// Clean up these elements to keep memory consistent.
(0, _memory.unprotectElement)(patch.old);
(0, _memory.unprotectElement)(patch.new);
// Throw an error to stop rendering/inform the developer.
throw new Error(('\n Can\'t ' + verb + ' without parent, is this the document root?\n ').trim());
}
};
// Trigger the attached transition state for this element and all childNodes.
var attach = function attach(_ref) {
var vTree = _ref.vTree;
var fragment = _ref.fragment;
var parentNode = _ref.parentNode;
var triggerTransition = _ref.triggerTransition;
var state = _ref.state;
// This element has been attached, so it should definitely be marked as
// protected.
(0, _memory.protectElement)(vTree);
// Create a DOM Node for this Virtual Tree element.
var node = (0, _make2.default)(vTree);
// If the element added was a DOM text node or SVG text element, trigger
// the textChanged transition.
if (vTree.nodeName === '#text') {
var promises = (0, _transitions.makePromises)('textChanged', [node], null, vTree.nodeValue);
node.nodeValue = (0, _entities.decodeEntities)(vTree.nodeValue);
if (parentNode) {
var nodeName = parentNode.nodeName.toLowerCase();
if (_parser.blockText.has(nodeName)) {
parentNode.nodeValue = (0, _entities.decodeEntities)(vTree.nodeValue);
}
}
triggerTransition('textChanged', promises);
}
vTree.attributes.forEach(function (attr) {
triggerTransition('attributeChanged', (0, _transitions.makePromises)('attributeChanged', [node], attr.name, null, attr.value));
});
// Call all `childNodes` attached callbacks as well.
vTree.childNodes.forEach(function (vTree) {
return attach({
vTree: vTree, parentNode: node, triggerTransition: triggerTransition, state: state
});
});
// If a Document Fragment was specified, append the DOM Node into it.
if (fragment) {
fragment.appendChild(node);
}
return node;
};
/**
* Processes a set of patches onto a tracked DOM Node.
*
* @param {Object} node - DOM Node to process patchs on
* @param {Array} patches - Contains patch objects
*/
function patchNode(node, patches) {
var state = _cache.StateCache.get(node);
var promises = [];
var triggerTransition = (0, _transitions.buildTrigger)(promises);
// Loop through all the patches and apply them.
var _loop = function _loop(i) {
var patch = patches[i];
var el = (0, _make2.default)(patch.element);
var oldEl = (0, _make2.default)(patch.old);
var newEl = (0, _make2.default)(patch.new);
// Empty the Node's contents. This is an optimization, since `innerHTML`
// will be faster than iterating over every element and manually removing.
if (patch.__do__ === _sync.REMOVE_ELEMENT_CHILDREN) {
var childNodes = filter.call(el.childNodes, isElementNode);
var detachPromises = (0, _transitions.makePromises)('detached', childNodes);
triggerTransition('detached', detachPromises, function (promises) {
var callback = function callback() {
(0, _memory.unprotectElement)(patch.toRemove);
el.innerHTML = '';
};
if (promises && promises.length) {
Promise.all(promises).then(callback);
} else {
callback();
}
});
}
// Remove the entire Node. Only does something if the Node has a parent
// element.
else if (patch.__do__ === _sync.REMOVE_ENTIRE_ELEMENT) {
var _childNodes = [el].filter(isElementNode);
var _detachPromises = (0, _transitions.makePromises)('detached', _childNodes);
if (el.parentNode) {
triggerTransition('detached', _detachPromises, function (promises) {
var callback = function callback() {
el.parentNode.removeChild(el);
(0, _memory.unprotectElement)(patch.toRemove);
};
if (promises && promises.length) {
Promise.all(promises).then(callback);
} else {
callback();
}
});
} else {
(0, _memory.unprotectElement)(patch.toRemove);
}
}
// Replace the entire Node.
else if (patch.__do__ === _sync.REPLACE_ENTIRE_ELEMENT) {
(function () {
var allPromises = [];
var attachedPromises = (0, _transitions.makePromises)('attached', [newEl].filter(isElementNode));
var detachedPromises = (0, _transitions.makePromises)('detached', [oldEl].filter(isElementNode));
var replacedPromises = (0, _transitions.makePromises)('replaced', [oldEl], newEl);
// Add all the transition state promises into the main array, we'll use
// them all to decide when to alter the DOM.
triggerTransition('detached', detachedPromises, function (promises) {
allPromises.push.apply(allPromises, promises);
});
triggerTransition('attached', attachedPromises, function (promises) {
allPromises.push.apply(allPromises, promises);
attach({ vTree: patch.new, triggerTransition: triggerTransition, state: state });
});
triggerTransition('replaced', replacedPromises, function (promises) {
allPromises.push.apply(allPromises, promises);
});
(0, _memory.unprotectElement)(patch.old);
// Reset the tree cache. TODO Look into this...
_cache.StateCache.set(newEl, {
oldTree: patch.new,
element: newEl
});
// Once all the promises have completed, invoke the action, if no
// promises were added, this will be a synchronous operation.
if (allPromises.length) {
Promise.all(allPromises).then(function replaceEntireElement() {
checkForMissingParent(oldEl, patch);
oldEl.parentNode.replaceChild(newEl, oldEl);
}, function (ex) {
return console.log(ex);
});
} else {
if (!oldEl.parentNode) {
(0, _memory.unprotectElement)(patch.new);
if (_cache.StateCache.has(newEl)) {
_cache.StateCache.delete(newEl);
}
throw new Error(replaceFailMsg);
}
oldEl.parentNode.replaceChild(newEl, oldEl);
}
})();
}
// Node manip.
else if (patch.__do__ === _sync.MODIFY_ELEMENT) {
// Add.
if (el && patch.fragment && !oldEl) {
(function () {
var fragment = document.createDocumentFragment();
// Loop over every element to be added and process the Virtual Tree
// element into the DOM Node and append into the DOM fragment.
var toAttach = patch.fragment.map(function (vTree) {
return attach({
vTree: vTree, fragment: fragment, triggerTransition: triggerTransition, state: state
});
}).filter(isElementNode);
// Turn elements into childNodes of the patch element.
el.appendChild(fragment);
// Trigger transitions.
var makeAttached = (0, _transitions.makePromises)('attached', toAttach);
triggerTransition('attached', makeAttached);
})();
}
// Remove.
else if (oldEl && !newEl) {
// Ensure we can remove the old DOM Node.
checkForMissingParent('remove', oldEl, patch);
var makeDetached = (0, _transitions.makePromises)('detached', [oldEl]);
triggerTransition('detached', makeDetached, function (promises) {
var callback = function callback() {
if (oldEl.parentNode) {
oldEl.parentNode.removeChild(oldEl);
}
// And then empty out the entire contents.
oldEl.innerHTML = '';
(0, _memory.unprotectElement)(patch.old);
};
if (promises && promises.length) {
Promise.all(promises).then(callback);
} else {
callback();
}
});
}
// Replace.
else if (oldEl && newEl) {
(function () {
// Ensure we can replace the old DOM Node.
checkForMissingParent('replace', oldEl, patch);
// Append the element first, before doing the replacement.
if (oldEl.nextSibling) {
oldEl.parentNode.insertBefore(newEl, oldEl.nextSibling);
} else {
oldEl.parentNode.appendChild(newEl);
}
// Removed state for transitions API.
var allPromises = [];
var attachPromises = (0, _transitions.makePromises)('attached', [newEl].filter(isElementNode));
var detachPromises = (0, _transitions.makePromises)('detached', [oldEl].filter(isElementNode));
var replacePromises = (0, _transitions.makePromises)('replaced', [oldEl], newEl);
triggerTransition('replaced', replacePromises, function (promises) {
if (promises && promises.length) {
allPromises.push.apply(allPromises, promises);
}
});
triggerTransition('detached', detachPromises, function (promises) {
if (promises && promises.length) {
allPromises.push.apply(allPromises, promises);
}
});
triggerTransition('attached', attachPromises, function (promises) {
if (promises && promises.filter(Boolean).length) {
allPromises.push.apply(allPromises, promises);
}
attach({ vTree: patch.new, triggerTransition: triggerTransition, state: state });
});
// Once all the promises have completed, invoke the action, if no
// promises were added, this will be a synchronous operation.
if (allPromises.length) {
Promise.all(allPromises).then(function replaceElement() {
if (oldEl.parentNode) {
oldEl.parentNode.replaceChild(newEl, oldEl);
}
(0, _memory.unprotectElement)(patch.old);
(0, _memory.protectElement)(patch.new);
}, function (ex) {
return console.log(ex);
});
} else {
checkForMissingParent('replace', oldEl, patch);
oldEl.parentNode.replaceChild(newEl, oldEl);
(0, _memory.unprotectElement)(patch.old);
(0, _memory.protectElement)(patch.new);
}
})();
}
}
// Attribute manipulation.
else if (patch.__do__ === _sync.MODIFY_ATTRIBUTE) {
var attributes = patch.attributes;
attributes.forEach(function (_ref2) {
var oldAttr = _ref2.oldAttr;
var newAttr = _ref2.newAttr;
var name = newAttr ? newAttr.name : oldAttr.name;
var value = (oldAttr ? oldAttr.value : undefined) || null;
var attrChangePromises = (0, _transitions.makePromises)('attributeChanged', [el], name, value, newAttr ? newAttr.value : null);
triggerTransition('attributeChanged', attrChangePromises, function (promises) {
var callback = function callback() {
// Always remove the old attribute, we never re-use it.
if (oldAttr) {
_pools.pools.attributeObject.unprotect(oldAttr);
// Remove the Virtual Tree Attribute from the element and memory.
if (!newAttr) {
el.removeAttribute(oldAttr.name);
if (oldAttr.name in el) {
el[oldAttr.name] = undefined;
}
}
}
// Add/Change the attribute or property.
if (newAttr) {
var isObject = _typeof(newAttr.value) === 'object';
var isFunction = typeof newAttr.value === 'function';
// Protect the Virtual Attribute object.
_pools.pools.attributeObject.protect(newAttr);
// If not a dynamic type, set as an attribute, since it's a valid
// attribute value.
if (!isObject && !isFunction) {
if (newAttr.name) {
el.setAttribute(newAttr.name, (0, _entities.decodeEntities)(newAttr.value));
}
} else if (typeof newAttr.value !== 'string') {
// Necessary to track the attribute/prop existence.
el.setAttribute(newAttr.name, '');
// Since this is a dynamic value it gets set as a property.
el[newAttr.name] = newAttr.value;
}
// Support live updating of the value attribute.
if (newAttr.name === 'value' || newAttr.name === 'checked') {
el[newAttr.name] = newAttr.value;
}
}
};
if (promises && promises.length) {
Promise.all(promises).then(callback, function unhandledException() {});
} else {
callback();
}
});
});
}
// Text node manipulation.
else if (patch.__do__ === _sync.CHANGE_TEXT) {
var textChangePromises = (0, _transitions.makePromises)('textChanged', [el], el.nodeValue, patch.value);
triggerTransition('textChanged', textChangePromises, function (promises) {
var callback = function callback() {
patch.element.nodeValue = (0, _entities.decodeEntities)(patch.value);
el.nodeValue = patch.element.nodeValue;
if (el.parentNode) {
var nodeName = el.parentNode.nodeName.toLowerCase();
if (_parser.blockText.has(nodeName)) {
el.parentNode.nodeValue = (0, _entities.decodeEntities)(patch.element.nodeValue);
}
}
};
if (promises && promises.length) {
Promise.all(promises).then(callback);
} else {
callback();
}
});
}
};
for (var i = 0; i < patches.length; i++) {
_loop(i);
}
// Return the Promises that were allocated so that rendering can be blocked
// until they resolve.
return promises.filter(Boolean);
}
},{"../tree/sync":9,"../util/cache":10,"../util/entities":11,"../util/memory":13,"../util/parser":14,"../util/pools":15,"../util/transitions":18,"./make":3}],5:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = releaseNode;
var _cache = _dereq_('../util/cache');
var _memory = _dereq_('../util/memory');
/**
* Releases state and recycles internal memory.
*
* @param node {Object} - A DOM Node to lookup state from
*/
function releaseNode(node) {
// Try and find a state object for this DOM Node.
var state = _cache.StateCache.get(node);
// If there is a Virtual Tree element, recycle all objects allocated for it.
if (state && state.oldTree) {
(0, _memory.unprotectElement)(state.oldTree);
}
// Remove the Node's state object from the cache.
_cache.StateCache.delete(node);
// Recycle all unprotected objects.
(0, _memory.cleanMemory)();
}
},{"../util/cache":10,"../util/memory":13}],6:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.default = createTransaction;
var _patch = _dereq_('./patch');
var _patch2 = _interopRequireDefault(_patch);
var _finalize = _dereq_('./finalize');
var _finalize2 = _interopRequireDefault(_finalize);
var _make = _dereq_('../tree/make');
var _make2 = _interopRequireDefault(_make);
var _sync = _dereq_('../tree/sync');
var _sync2 = _interopRequireDefault(_sync);
var _helpers = _dereq_('../tree/helpers');
var _memory = _dereq_('../util/memory');
var _parser = _dereq_('../util/parser');
var _pools = _dereq_('../util/pools');
var _cache = _dereq_('../util/cache');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* If diffHTML is rendering anywhere asynchronously, we need to wait until it
* completes before this render can be executed. This sets up the next buffer,
* if necessary, which serves as a Boolean determination later to `bufferSet`.
*
* @param {Object} state - The current DOM Node state within diffHTML
* @param {Object} nextRender - The respective arguments to set buffer
* @return {Boolean} - Whether or not diffHTML is currently rendering
*/
var setBufferState = function setBufferState(state, nextRender) {
// Look up all existing states for any rendering, and set the next render
// buffer if blocked.
_cache.StateCache.forEach(function (_state) {
// If we attach a nextRender, then the buffer has been set.
if (_state.isRendering) {
state.nextRender = nextRender;
}
});
// Let outside code know if we were blocked.
return Boolean(state.nextRender);
};
/**
* Gets a Virtual Tree Element from the newHTML passed to a diff method.
*
* @param {String|Object} newHTML - HTML/DOM Node/Virtual Tree Element
* @return {Object} - Virtual Tree Element
*/
var getTreeFromNewHTML = function getTreeFromNewHTML(newHTML, options, callback) {
// This is HTML Markup, so we need to parse it.
if (typeof newHTML === 'string') {
var silenceWarnings = options.silenceWarnings;
var childNodes = (0, _parser.parse)(newHTML, null, { silenceWarnings: silenceWarnings }).childNodes;
// If we are dealing with innerHTML, use all the Nodes. If we're dealing
// with outerHTML, we can only support diffing against a single element,
// so pick the first one.
return callback(childNodes);
}
// This is a DOM Node, so we need to convert to a vTree.
else if (newHTML.ownerDocument) {
var newTree = (0, _make2.default)(newHTML);
if (newTree.nodeType === 11) {
_pools.pools.elementObject.unprotect(newTree);
return callback(newTree.childNodes);
}
return callback(newTree);
}
// This is a Virtual Tree Element, or something like it, so we can just pass
// it along.
return callback(newHTML);
};
/**
* Creates a sequential render transaction on a DOM Node. This requires
* checking for a previous render first. Since diffHTML is globally connected
* (hopefully only running one copy...), this will prevent transitions from
* interferring.
*
* @param node
* @param newHTML
* @param options
*/
function createTransaction(node, newHTML, options) {
if ((typeof node === 'undefined' ? 'undefined' : _typeof(node)) !== 'object') {
throw new Error('Missing DOM Node object');
}
// Used to associate state with the currently rendering node. This
// prevents attaching properties to the instance itself.
var state = _cache.StateCache.get(node) || {};
var isInner = options.inner;
var previousMarkup = state.previousMarkup;
var previousText = state.previousText;
var bufferSet = setBufferState(state, { node: node, newHTML: newHTML, options: options });
// Associate the current render options with the DOM Node state.
state.options = options;
// Always ensure the most up-to-date state object is stored.
_cache.StateCache.set(node, state);
// Short circuit the rest of this render if we ended up having to set a
// buffer. This happens when some other code using diffHTML is rendering
// asynchronously (using transitions w/ Promise).
if (bufferSet) {
return;
}
// This looks for changes in the DOM from what we'd expect. This means we
// need to rebuild the old Virtual Tree. This allows for keeping our tree in
// sync with unexpected DOM changes. It's not very performant, so ideally you
// should never change markup that diffHTML affects from outside of diffHTML
// if performance is a concern.
var sameInnerHTML = isInner ? previousMarkup === node.innerHTML : true;
var sameOuterHTML = !isInner ? previousMarkup === node.outerHTML : true;
var sameTextContent = previousText === node.textContent;
// If the contents haven't changed, abort, since there is no point in
// continuing. Only support this if the new markup is a string, otherwise
// it's possible for our object recycling to match twice.
if (typeof newHTML === 'string' && state.newHTML === newHTML) {
return;
}
// Associate the last markup rendered with this node.
else if (typeof newHTML === 'string') {
state.newHTML = newHTML;
}
// We rebuild the tree whenever the DOM Node changes, including the first
// time we patch a DOM Node.
var rebuildTree = function rebuildTree() {
var oldTree = state.oldTree;
if (oldTree) {
(0, _memory.unprotectElement)(oldTree);
}
state.oldTree = (0, _memory.protectElement)((0, _make2.default)(node));
};
if (!sameInnerHTML || !sameOuterHTML || !sameTextContent) {
rebuildTree();
}
// We're rendering in the UI thread.
state.isRendering = true;
// Store all transaction starting middleware functions being executed here.
var startTransactionMiddlewares = [];
// Start off the middleware execution.
_cache.MiddlewareCache.forEach(function (executeMiddleware) {
// Pass the start transaction call with the input arguments.
var result = executeMiddleware({ node: node, newHTML: newHTML, options: options });
if (result) {
startTransactionMiddlewares.push(result);
}
});
// Alias the `oldTree` off of state for parity.
var oldTree = state.oldTree;
// We need to ensure that our target to diff is a Virtual Tree Element. This
// function takes in whatever `newHTML` is and normalizes to a tree object.
// The callback function runs on every normalized Node to wrap childNodes
// in the case of setting innerHTML.
var newTree = getTreeFromNewHTML(newHTML, options, function (newTree) {
if (isInner) {
_pools.pools.elementObject.unprotect(newTree);
var nodeName = state.oldTree.nodeName;
var attributes = state.oldTree.attributes;
return (0, _helpers.createElement)(nodeName, attributes, newTree);
}
return Array.isArray(newTree) ? newTree[0] : newTree;
});
// Trigger any middleware with the DOM Node, old Virtual Tree Element, and
// new Virtual Tree Element. This allows the middleware to mutate and inspect
// the trees before they get consumed by diffHTML.
var prePatchMiddlewares = [];
// By exposing the internal tree synchronization and DOM Node patch methods,
// a middleware could implement sync/patch on a separate thread.
var transactionMethods = {
syncTree: _sync2.default,
patchNode: _patch2.default,
protectElement: _memory.protectElement,
unprotectElement: _memory.unprotectElement
};
// Save the current transaction tree state and allow the mdidleware to
// override the trees.
var transactionState = {
oldTree: oldTree,
newTree: newTree,
transactionMethods: transactionMethods
};
// Run each middleware and pass the transaction state which contains internal
// functions otherwise not available by the public API.
for (var i = 0; i < startTransactionMiddlewares.length; i++) {
// Pass the the existing Virtual Tree Element, and the new Virtual Tree
// Element. This is triggered before the synchronization and patching has
// occured.
var result = startTransactionMiddlewares[i](transactionState);
if (result) {
prePatchMiddlewares.push(result);
}
}
// Synchronize the trees, use any middleware replacements, if supplied.
var patches = (0, _sync2.default)(transactionState.oldTree, transactionState.newTree);
// Apply the set of patches to the Node.
var promises = (0, _patch2.default)(node, patches);
// Trigger any middleware after syncing and patching the element. This is
// mainly useful to get the Promises for something like devtools and patches
// for something like logging.
var postPatchMiddlewares = [];
for (var _i = 0; _i < prePatchMiddlewares.length; _i++) {
// The DOM Node patching has finished and now we're sending the patchset
// and the promises which can also be pushed into to do some asynchronous
// behavior in a middleware.
var _result = prePatchMiddlewares[_i]({
patches: patches,
promises: promises
});
if (_result) {
postPatchMiddlewares.push(_result);
}
}
// Clean up and finalize this transaction. If there is another transaction,
// get a callback to run once this completes to run it.
var finalizeTransaction = (0, _finalize2.default)(node, state);
// Operate synchronously unless opted into a Promise-chain. Doesn't matter if
// they are actually Promises or not, since they will all resolve eventually
// with `Promise.all`.
if (promises.length) {
Promise.all(promises).then(function () {
finalizeTransaction(postPatchMiddlewares);
}, function (ex) {
return console.log(ex);
});
} else {
// Pass off the remaining middleware to allow users to dive into the
// transaction completed lifecycle event.
finalizeTransaction(postPatchMiddlewares);
}
}
},{"../tree/helpers":7,"../tree/make":8,"../tree/sync":9,"../util/cache":10,"../util/memory":13,"../util/parser":14,"../util/pools":15,"./finalize":2,"./patch":4}],7:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.createElement = createElement;
exports.createAttribute = createAttribute;
var _pools = _dereq_('../util/pools');
var _escape = _dereq_('../util/escape');
var _escape2 = _interopRequireDefault(_escape);
var _make = _dereq_('../tree/make');
var _make2 = _interopRequireDefault(_make);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* TODO Phase this out if possible, super slow iterations...
*
* @param childNodes
* @return
*/
var normalizeChildNodes = function normalizeChildNodes(_childNodes) {
var newChildNodes = [];
var childNodes = Array.isArray(_childNodes) ? _childNodes : [_childNodes];
childNodes.forEach(function (childNode) {
if ((typeof childNode === 'undefined' ? 'undefined' : _typeof(childNode)) !== 'object') {
newChildNodes.push(createElement('#text', null, String(childNode)));
} else if ('length' in childNode) {
for (var i = 0; i < childNode.length; i++) {
var newChild = childNode[i];
var newNode = newChild.ownerDocument ? (0, _make2.default)(newChild) : newChild;
newChildNodes.push(newNode);
}
} else {
var node = childNode.ownerDocument ? (0, _make2.default)(childNode) : childNode;
newChildNodes.push(node);
}
});
return newChildNodes;
};
/**
* Creates a virtual element used in or as a virtual tree.
*
* @param nodeName
* @param attributes
* @param childNodes
* @return {Object} element
*/
function createElement(nodeName, attributes, childNodes) {
if (nodeName === '') {
return normalizeChildNodes(childNodes);
}
if (typeof nodeName === 'function') {
var props = attributes;
props.children = childNodes;
return new nodeName(props).render(props);
} else if ((typeof nodeName === 'undefined' ? 'undefined' : _typeof(nodeName)) === 'object') {
var _props = attributes;
_props.children = childNodes;
return nodeName.render(_props);
}
var entry = _pools.pools.elementObject.get();
var isTextNode = nodeName === 'text' || nodeName === '#text';
entry.key = '';
entry.nodeName = nodeName.toLowerCase();
entry.rawNodeName = nodeName;
if (!isTextNode) {
entry.nodeType = 1;
entry.nodeValue = '';
entry.attributes = attributes || [];
entry.childNodes = normalizeChildNodes(childNodes);
// Set the key prop if passed as an attr.
entry.attributes.some(function (attr) {
if (attr.name === 'key') {
entry.key = attr.value;
return true;
}
});
} else {
var value = Array.isArray(childNodes) ? childNodes.join('') : childNodes;
entry.nodeType = nodeName === '#document-fragment' ? 11 : 3;
entry.nodeValue = (0, _escape2.default)(String(value));
entry.attributes.length = 0;
entry.childNodes.length = 0;
}
return entry;
}
/**
* Creates a virtual attribute used in a virtual element.
*
* @param name
* @param value
* @return {Object} attribute
*/
function createAttribute(name, value) {
var entry = _pools.pools.attributeObject.get();
entry.name = name;
entry.value = value;
return entry;
}
},{"../tree/make":8,"../util/escape":12,"../util/pools":15}],8:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = makeNode;
var _helpers = _dereq_('./helpers');
var _pools = _dereq_('../util/pools');
var _cache = _dereq_('../util/cache');
/**
* Converts a DOM Node into a Virtual Tree Element.
*
* @param {Object} node - A DOM Node
* @return {Object} - A Virtual Tree Element
*/
function makeNode(node) {
// These are the only DOM Node properties we care about.
var nodeName = node.nodeName.toLowerCase();
var nodeType = node.nodeType;
var nodeValue = node.nodeValue;
var attributes = node.attributes || [];
var childNodes = node.childNodes || [];
// We ignore any DOM Node that isn't an: Element, Text, Document Fragment, or
// Shadow Root.
if (nodeType !== 1 && nodeType !== 3 && nodeType !== 11) {
return false;
}
// We can consider either of these DOM Nodes as Text Nodes.
var isTextNode = nodeName === '#text' || nodeName === 'text';
// In the case of Text Node's we can have the createElement function set
// the nodeValue for us.
var initialValue = isTextNode ? nodeValue : [];
// Creates a Virtual Tree Element based off this nodeName. We aren't going
// to set the attributes right away since we want to set the key on the vTree
// and push directly into the pre-existing array.
var vTree = (0, _helpers.createElement)(node.nodeName, [], initialValue);
// Creates Virtual Tree Attributes for each attribute in the DOM Node.
for (var i = 0; i < attributes.length; i++) {
var attr = (0, _helpers.createAttribute)(attributes[i].name, attributes[i].value);
// If the `key` attribute is found, set the respective value on the vTree.
if (attr.name === 'key') {
vTree.key = attr.value;
}
vTree.attributes.push(attr);
}
// Associate this newly allocated vTree with this DOM Node.
_cache.NodeCache.set(vTree, node);
// If the element has child nodes, convert them all to virtual nodes.
for (var _i = 0; _i < childNodes.length; _i++) {
var newNode = makeNode(childNodes[_i]);
// We may get a falsy value back if we pass in a Comment Node or other
// DOM Nodes that we intentionally ignore.
if (newNode) {
vTree.childNodes.push(newNode);
}
}
// Prune out whitespace/everything from between tags nested under the HTML
// tag, since this behavior can be observed in browsers and specification.
if (vTree.nodeName === 'html') {
vTree.childNodes = vTree.childNodes.filter(function (childNode) {
return childNode.nodeName === 'head' || childNode.nodeName === 'body';
});
}
return vTree;
}
},{"../util/cache":10,"../util/pools":15,"./helpers":7}],9:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = sync;
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } }
var slice = Array.prototype.slice;
var filter = Array.prototype.filter;
// Patch actions.
var REMOVE_ELEMENT_CHILDREN = exports.REMOVE_ELEMENT_CHILDREN = -2;
var REMOVE_ENTIRE_ELEMENT = exports.REMOVE_ENTIRE_ELEMENT = -1;
var REPLACE_ENTIRE_ELEMENT = exports.REPLACE_ENTIRE_ELEMENT = 0;
var MODIFY_ELEMENT = exports.MODIFY_ELEMENT = 1;
var MODIFY_ATTRIBUTE = exports.MODIFY_ATTRIBUTE = 2;
var CHANGE_TEXT = exports.CHANGE_TEXT = 3;
/**
* Synchronizes changes from the newTree into the oldTree.
*
* @param oldTree
* @param newTree
* @param patches - optional
*/
function sync(oldTree, newTree, patches) {
patches = patches || [];
if (!Array.isArray(patches)) {
throw new Error('Missing Array to sync patches into');
}
if (!oldTree) {
throw new Error('Missing existing tree to sync');
}
var oldNodeValue = oldTree.nodeValue;
var oldChildNodes = oldTree.childNodes;
var oldIsTextNode = oldTree.nodeName === '#text';
// TODO Make this static...
var oldChildNodesLength = oldChildNodes ? oldChildNodes.length : 0;
if (!newTree) {
var removed = [oldTree].concat(oldChildNodes.splice(0, oldChildNodesLength));
patches.push({
__do__: REMOVE_ENTIRE_ELEMENT,
element: oldTree,
toRemove: removed
});
return patches;
}
var nodeValue = newTree.nodeValue;
var childNodes = newTree.childNodes;
var childNodesLength = childNodes ? childNodes.length : 0;
var nodeName = newTree.nodeName;
var attributes = newTree.attributes;
var newIsTextNode = nodeName === '#text';
var newIsFragment = newTree.nodeName === '#document-fragment';
// Replace the key attributes.
oldTree.key = newTree.key;
// If the element we're replacing is totally different from the previous
// replace the entire element, don't bother investigating children.
if (oldTree.nodeName !== newTree.nodeName) {
patches.push({
__do__: REPLACE_ENTIRE_ELEMENT,
old: oldTree,
new: newTree
});
return patches;
}
// This element never changes.
else if (oldTree === newTree) {
return patches;
}
var areTextNodes = oldIsTextNode && newIsTextNode;
// If the top level nodeValue has changed we should reflect it.
if (areTextNodes && oldNodeValue !== nodeValue) {
patches.push({
__do__: CHANGE_TEXT,
element: oldTree,
value: newTree.nodeValue
});
oldTree.nodeValue = newTree.nodeValue;
return patches;
}
// Ensure keys exist for all the old & new elements.
var noOldKeys = !oldChildNodes.some(function (oldChildNode) {
return oldChildNode.key;
});
var newKeys = null;
var oldKeys = null;
if (!noOldKeys) {
newKeys = new Set(childNodes.map(function (childNode) {
return String(childNode.key);
}).filter(Boolean));
oldKeys = new Set(oldChildNodes.map(function (childNode) {
return String(childNode.key);
}).filter(Boolean));
}
// Most common additive elements.
if (childNodesLength > oldChildNodesLength) {
// Store elements in a DocumentFragment to increase performance and be
// generally simplier to work with.
var fragment = [];
for (var i = oldChildNodesLength; i < childNodesLength; i++) {
// Internally add to the tree.
oldChildNodes.push(childNodes[i]);
// Add to the document fragment.
fragment.push(childNodes[i]);
}
oldChildNodesLength = oldChildNodes.length;
// Assign the fragment to the patches to be injected.
patches.push({
__do__: MODIFY_ELEMENT,
element: oldTree,
fragment: fragment
});
}
// Remove these elements.
if (oldChildNodesLength > childNodesLength) {
(function () {
// For now just splice out the end items.
var diff = oldChildNodesLength - childNodesLength;
var toRemove = [];
var shallowClone = [].concat(_toConsumableArray(oldChildNodes));
// There needs to be keys to diff, if not, there's no point in checking.
if (noOldKeys) {
toRemove = oldChildNodes.splice(oldChildNodesLength - diff, diff);
}
// This is an expensive operation so we do the above check to ensure that a
// key was specified.
else {
(function () {
var keysToRemove = new Set();
// Find the keys in the sets to remove.
oldKeys.forEach(function (key) {
if (!newKeys.has(key)) {
keysToRemove.add(key);
}
});
// If the original childNodes contain a key attribute, use this to
// compare over the naive method below.
shallowClone.forEach(function (oldChildNode, i) {
if (toRemove.length >= diff) {
return;
} else if (keysToRemove.has(oldChildNode.key)) {
var nextChild = oldChildNodes[i + 1];
var nextIsTextNode = nextChild && nextChild.nodeType === 3;
var count = 1;
// Always remove whitespace in between the elements.
if (nextIsTextNode && toRemove.length + 2 <= diff) {
count = 2;
}
// All siblings must contain a key attribute if they exist.
else if (nextChild && nextChild.nodeType === 1 && !nextChild.key) {
throw new Error('\n All element siblings must consistently contain key attributes.\n '.trim());
}
// Find the index position from the original array.
var indexPos = oldChildNodes.indexOf(oldChildNode);
// Find all the items to remove.
toRemove.push.apply(toRemove, oldChildNodes.splice(indexPos, count));
}
});
})();
}
// Ensure we don't remove too many elements by accident;
toRemove.length = diff;
// Ensure our internal length check is matched.
oldChildNodesLength = oldChildNodes.length;
if (childNodesLength === 0) {
patches.push({
__do__: REMOVE_ELEMENT_CHILDREN,
element: oldTree,
toRemove: toRemove
});
} else {
// Remove the element, this happens before the splice so that we still
// have access to the element.
toRemove.forEach(function (old) {
return patches.push({
__do__: MODIFY_ELEMENT,
old: old
});
});
}
})();
}
// Replace elements if they are different.
if (oldChildNodesLength >= childNodesLength) {
for (var _i = 0; _i < childNodesLength; _i++) {
if (oldChildNodes[_i].nodeName !== childNodes[_i].nodeName) {
// Add to the patches.
patches.push({
__do__: MODIFY_ELEMENT,
old: oldChildNodes[_i],
new: childNodes[_i]
});
// Replace the internal tree's point of view of this element.
oldChildNodes[_i] = childNodes[_i];
} else {
sync(oldChildNodes[_i], childNodes[_i], patches);
}
}
}
// Attributes are significantly easier than elements and we ignore checking
// them on fragments. The algorithm is the same as elements, check for
// additions/removals based off length, and then iterate once to make
// adjustments.
if (!newIsFragment && attributes) {
// Cache the lengths for performance and readability.
var oldLength = oldTree.attributes.length;
var newLength = attributes.length;
// Construct a single patch for the entire changeset.
var patch = {
__do__: MODIFY_ATTRIBUTE,
element: oldTree,
attributes: []
};
// Find additions.
if (newLength > oldLength) {
for (var _i2 = oldLength; _i2 < newLength; _i2++) {
var oldAttr = oldTree.attributes[_i2];
var newAttr = attributes[_i2];
patch.attributes.push({ oldAttr: oldAttr, newAttr: newAttr });
oldTree.attributes.push(newAttr);
}
}
// Find removals.
if (oldLength > newLength) {
for (var _i3 = newLength; _i3 < oldLength; _i3++) {
var _oldAttr = oldTree.attributes[_i3];
var _newAttr = attributes[_i3];
patch.attributes.push({ oldAttr: _oldAttr, newAttr: _newAttr });
}
// Reset the internal attributes to be less.
oldTree.attributes = oldTree.attributes.slice(0, newLength);
}
// Find changes.
for (var _i4 = 0; _i4 < attributes.length; _i4++) {
var _oldAttr2 = oldTree.attributes[_i4];
var _newAttr2 = attributes[_i4];
var oldAttrName = _oldAttr2 ? _oldAttr2.name : undefined;
var oldAttrValue = _oldAttr2 ? _oldAttr2.value : undefined;
var newAttrName = _newAttr2 ? _newAttr2.name : undefined;
var newAttrValue = _newAttr2 ? _newAttr2.value : undefined;
// Only push in a change if the attribute or value changes.
if (oldAttrValue !== newAttrValue) {
// Add the attribute items to add and remove.
patch.attributes.push({
oldAttr: _oldAttr2,
newAttr: _newAttr2
});
oldTree.attributes[_i4] = _newAttr2;
}
}
// Add the attribute changes patch to the series of patches, unless there
// are no attributes to change.
if (patch.attributes.length) {
patches.push(patch);
}
}
return patches;
}
},{}],10:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
// Associates DOM Nodes with state objects.
var StateCache = exports.StateCache = new Map();
// Associates Virtual Tree Elements with DOM Nodes.
var NodeCache = exports.NodeCache = new Map();
// Caches all middleware. You cannot unset a middleware once it has been added.
var MiddlewareCache = exports.MiddlewareCache = new Set();
},{}],11:[function(_dereq_,module,exports){
(function (global){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.decodeEntities = decodeEntities;
// Support loading diffHTML in non-browser environments.
var element = global.document ? document.createElement('div') : null;
/**
* Decodes HTML strings.
*
* @see http://stackoverflow.com/a/5796718
* @param string
* @return unescaped HTML
*/
function decodeEntities(string) {
// If there are no HTML entities, we can safely pass the string through.
if (!element || !string || !string.indexOf || string.indexOf('&') === -1) {
return string;
}
element.innerHTML = string;
return element.textContent;
}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],12:[function(_dereq_,module,exports){
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = escape;
/**
* Tiny HTML escaping function, useful to prevent things like XSS and
* unintentionally breaking attributes with quotes.
*
* @param {String} unescaped - An HTML value, unescaped
* @return {String} - An HTML-safe string
*/
function escape(unescaped) {
return unescaped.replace(/["&'<>`]/g, function (match) {
return "&#" + match.charCodeAt(0) + ";";
});
}
},{}],13:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.protectElement = protectElement;
exports.unprotectElement = unprotectElement;
exports.cleanMemory = cleanMemory;
var _pools = _dereq_('../util/pools');
var _cache = _dereq_('./cache');
/**
* Ensures that an element is not recycled during a render cycle.
*
* @param element
* @return element
*/
function protectElement(element) {
if (Array.isArray(element)) {
return element.forEach(protectElement);
}
var elementObject = _pools.pools.elementObject;
var attributeObject = _pools.pools.attributeObject;
elementObject.protect(element);
element.attributes.forEach(attributeObject.protect, attributeObject);
element.childNodes.forEach(protectElement);
return element;
}
/**
* Allows an element to be recycled during a render cycle.
*
* @param element
* @return
*/
function unprotectElement(element) {
if (Array.isArray(element)) {
return element.forEach(unprotectElement);
}
var elementObject = _pools.pools.elementObject;
var attributeObject = _pools.pools.attributeObject;
elementObject.unprotect(element);
element.attributes.forEach(attributeObject.unprotect, attributeObject);
element.childNodes.forEach(unprotectElement);
_cache.NodeCache.delete(element);
return element;
}
/**
* Recycles all unprotected allocations.
*/
function cleanMemory() {
var elementCache = _pools.pools.elementObject.cache;
var attributeCache = _pools.pools.attributeObject.cache;
// Empty all element allocations.
elementCache.allocated.forEach(function (v) {
if (elementCache.free.length < _pools.count) {
elementCache.free.push(v);
}
});
elementCache.allocated.clear();
// Clean out unused elements.
_cache.NodeCache.forEach(function (node, descriptor) {
if (!elementCache.protected.has(descriptor)) {
_cache.NodeCache.delete(descriptor);
}
});
// Empty all attribute allocations.
attributeCache.allocated.forEach(function (v) {
if (attributeCache.free.length < _pools.count) {
attributeCache.free.push(v);
}
});
attributeCache.allocated.clear();
}
},{"../util/pools":15,"./cache":10}],14:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.blockText = undefined;
exports.parse = parse;
var _pools = _dereq_('./pools');
var _make = _dereq_('../tree/make');
var _make2 = _interopRequireDefault(_make);
var _helpers = _dereq_('../tree/helpers');
var _escape = _dereq_('./escape');
var _escape2 = _interopRequireDefault(_escape);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// Code based off of:
// https://github.com/ashi009/node-fast-html-parser
var TOKEN = '__DIFFHTML__';
var doctypeEx = /<!.*>/ig;
var attrEx = /\b([_a-z][_a-z0-9\-]*)\s*(=\s*("([^"]+)"|'([^']+)'|(\S+)))?/ig;
var tagEx = /<!--[^]*?(?=-->)-->|<(\/?)([a-z\-][a-z0-9\-]*)\s*([^>]*?)(\/?)>/ig;
var spaceEx = /[^ ]/;
// We use this Set in the node/patch module so marking it exported.
var blockText = exports.blockText = new Set(['script', 'noscript', 'style', 'code', 'template']);
var selfClosing = new Set(['meta', 'img', 'link', 'input', 'area', 'br', 'hr']);
var kElementsClosedByOpening = {
li: { li: true },
p: { p: true, div: true },
td: { td: true, th: true },
th: { td: true, th: true }
};
var kElementsClosedByClosing = {
li: { ul: true, ol: true },
a: { div: true },
b: { div: true },
i: { div: true },
p: { div: true },
td: { tr: true, table: true },
th: { tr: true, table: true }
};
/**
* Interpolate dynamic supplemental values from the tagged template into the
* tree.
*
* @param currentParent
* @param string
* @param supplemental
*/
var interpolateDynamicBits = function interpolateDynamicBits(currentParent, string, supplemental) {
if (string && string.indexOf(TOKEN) > -1) {
(function () {
var toAdd = [];
// Break up the incoming string into dynamic parts that are then pushed
// into a new set of child nodes.
string.split(TOKEN).forEach(function (value, index) {
if (index === 0) {
// We trim here to allow for newlines before and after markup starts.
if (value && value.trim()) {
toAdd.push(TextNode(value));
}
// The first item does not mean there was dynamic content.
return;
}
// If we are in the second iteration, this
var dynamicBit = supplemental.children.shift();
if (typeof dynamicBit === 'string') {
toAdd.push(TextNode(dynamicBit));
} else if (Array.isArray(dynamicBit)) {
toAdd.push.apply(toAdd, dynamicBit);
} else if (dynamicBit.ownerDocument) {
toAdd.push((0, _make2.default)(dynamicBit));
} else {
toAdd.push(dynamicBit);
}
// This is a useful Text Node.
if (value && value.trim()) {
toAdd.push(TextNode(value));
}
});
currentParent.childNodes.push.apply(currentParent.childNodes, toAdd);
})();
} else if (string && string.length && !doctypeEx.exec(string)) {
currentParent.childNodes.push(TextNode(string));
}
};
/**
* TextNode to contain a text element in DOM tree.
*
* @param {String} nodeValue - A value to set in the text,, set unescaped
* @return {Object} - A Virtual Tree element representing the Text Node
*/
var TextNode = function TextNode(value) {
var vTree = (0, _helpers.createElement)('#text', [], []);
vTree.nodeValue = value;
return vTree;
};
/**
* HTMLElement, which contains a set of children.
*
* Note: this is a minimalist implementation, no complete tree structure
* provided (no parentNode, nextSibling, previousSibling etc).
*
* @param {String} nodeName - DOM Node name
* @param {Object} rawAttrs - DOM Node Attributes
* @param {Object} supplemental - Interpolated data from a tagged template
* @return {Object} vTree
*/
var HTMLElement = function HTMLElement(nodeName, rawAttrs, supplemental) {
var vTree = (0, _helpers.createElement)(nodeName, [], []);
for (var match; match = attrEx.exec(rawAttrs || '');) {
var name = match[1];
var value = match[6] || match[5] || match[4] || match[1];
var attr = (0, _helpers.createAttribute)(name, value);
if (attr.value === TOKEN) {
attr.value = supplemental.props.shift();
}
// If a key attribute is found attach directly to the vTree.
if (attr.name === 'key') {
vTree.key = attr.value;
}
// Look for empty attributes.
if (match[6] === '""') {
attr.value = '';
}
vTree.attributes.push(attr);
}
return vTree;
};
/**
* Parses HTML and returns a root element
*
* @param {String} html - String of HTML markup to parse into a Virtual Tree
* @param {Object} supplemental - Dynamic interpolated data values
* @param {Object} options - Contains options like silencing warnings
* @return {Object} - Parsed Virtual Tree Element
*/
function parse(html, supplemental) {
var options = arguments.length <= 2 || arguments[2] === undefined ? {} : arguments[2];
var root = HTMLElement('#document-fragment');
var stack = [root];
var currentParent = root;
var lastTextPos = -1;
// If there are no HTML elements, treat the passed in html as a single
// text node.
if (html.indexOf('<') === -1 && html) {
interpolateDynamicBits(currentParent, html, supplemental);
return root;
}
// Look through the HTML markup for valid tags.
for (var match, text; match = tagEx.exec(html);) {
if (lastTextPos > -1) {
if (lastTextPos + match[0].length < tagEx.lastIndex) {
// if has content
text = html.slice(lastTextPos, tagEx.lastIndex - match[0].length);
interpolateDynamicBits(currentParent, text, supplemental);
}
}
var matchOffset = tagEx.lastIndex - match[0].length;
if (lastTextPos === -1 && matchOffset > 0) {
var string = html.slice(0, matchOffset);
if (string && string.trim() && !doctypeEx.exec(string)) {
interpolateDynamicBits(currentParent, string, supplemental);
}
}
lastTextPos = tagEx.lastIndex;
// This is a comment.
if (match[0][1] === '!') {
continue;
}
if (!match[1]) {
// not </ tags
var attrs = {};
if (!match[4] && kElementsClosedByOpening[currentParent.rawNodeName]) {
if (kElementsClosedByOpening[currentParent.rawNodeName][match[2]]) {
stack.pop();
currentParent = stack[stack.length - 1];
}
}
currentParent = currentParent.childNodes[currentParent.childNodes.push(HTMLElement(match[2], match[3], supplemental)) - 1];
stack.push(currentParent);
if (blockText.has(match[2])) {
// A little test to find next </script> or </style> ...
var closeMarkup = '</' + match[2] + '>';
var index = html.indexOf(closeMarkup, tagEx.lastIndex);
var length = match[2].length;
if (index === -1) {
lastTextPos = tagEx.lastIndex = html.length + 1;
} else {
lastTextPos = index + closeMarkup.length;
tagEx.lastIndex = lastTextPos;
match[1] = true;
}
var newText = html.slice(match.index + match[0].length, index);
interpolateDynamicBits(currentParent, newText.trim(), supplemental);
}
}
if (match[1] || match[4] || selfClosing.has(match[2])) {
if (match[2] !== currentParent.rawNodeName && options.strict) {
var nodeName = currentParent.rawNodeName;
// Find a subset of the markup passed in to validate.
var markup = html.slice(tagEx.lastIndex - match[0].length).split('\n').slice(0, 3);
// Position the caret next to the first non-whitespace character.
var caret = Array(spaceEx.exec(markup[0]).index).join(' ') + '^';
// Craft the warning message and inject it into the markup.
markup.splice(1, 0, caret + '\nPossibly invalid markup. Saw ' + match[2] + ', expected ' + nodeName + '...\n ');
// Throw an error message if the markup isn't what we expected.
throw new Error('' + markup.join('\n'));
}
// </ or /> or <br> etc.
while (currentParent) {
if (currentParent.rawNodeName == match[2]) {
stack.pop();
currentParent = stack[stack.length - 1];
break;
} else {
var tag = kElementsClosedByClosing[currentParent.rawNodeName];
// Trying to close current tag, and move on
if (tag) {
if (tag[match[2]]) {
stack.pop();
currentParent = stack[stack.length - 1];
continue;
}
}
// Use aggressive strategy to handle unmatching markups.
break;
}
}
}
}
// Find any last remaining text after the parsing completes over tags.
var remainingText = html.slice(lastTextPos === -1 ? 0 : lastTextPos).trim();
// If the text exists and isn't just whitespace, push into a new TextNode.
interpolateDynamicBits(currentParent, remainingText, supplemental);
// This is an entire document, so only allow the HTML children to be
// body or head.
if (root.childNodes.length && root.childNodes[0].nodeName === 'html') {
(function () {
// Store elements from before body end and after body end.
var head = { before: [], after: [] };
var body = { after: [] };
var beforeHead = true;
var beforeBody = true;
var HTML = root.childNodes[0];
// Iterate the children and store elements in the proper array for
// later concat, replace the current childNodes with this new array.
HTML.childNodes = HTML.childNodes.filter(function (el) {
// If either body or head, allow as a valid element.
if (el.nodeName === 'body' || el.nodeName === 'head') {
if (el.nodeName === 'head') {
beforeHead = false;
}
if (el.nodeName === 'body') {
beforeBody = false;
}
return true;
}
// Not a valid nested HTML tag element, move to respective container.
else if (el.nodeType === 1) {
if (beforeHead && beforeBody) {
head.before.push(el);
} else if (!beforeHead && beforeBody) {
head.after.push(el);
} else if (!beforeBody) {
body.after.push(el);
}
}
});
// Ensure the first element is the HEAD tag.
if (!HTML.childNodes[0] || HTML.childNodes[0].nodeName !== 'head') {
var headInstance = _pools.pools.elementObject.get();
headInstance.nodeName = 'head';
headInstance.childNodes.length = 0;
headInstance.attributes.length = 0;
var existing = headInstance.childNodes;
existing.unshift.apply(existing, head.before);
existing.push.apply(existing, head.after);
HTML.childNodes.unshift(headInstance);
} else {
var _existing = HTML.childNodes[0].childNodes;
_existing.unshift.apply(_existing, head.before);
_existing.push.apply(_existing, head.after);
}
// Ensure the second element is the body tag.
if (!HTML.childNodes[1] || HTML.childNodes[1].nodeName !== 'body') {
var bodyInstance = _pools.pools.elementObject.get();
bodyInstance.nodeName = 'body';
bodyInstance.childNodes.length = 0;
bodyInstance.attributes.length = 0;
var _existing2 = bodyInstance.childNodes;
_existing2.push.apply(_existing2, body.after);
HTML.childNodes.push(bodyInstance);
} else {
var _existing3 = HTML.childNodes[1].childNodes;
_existing3.push.apply(_existing3, body.after);
}
})();
}
return root;
}
},{"../tree/helpers":7,"../tree/make":8,"./escape":12,"./pools":15}],15:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.createPool = createPool;
exports.initializePools = initializePools;
var pools = exports.pools = {};
var count = exports.count = 10000;
/**
* Creates a pool to query new or reused values from.
*
* @param name
* @param opts
* @return {Object} pool
*/
function createPool(name, opts) {
var size = opts.size;
var fill = opts.fill;
var cache = {
free: [],
allocated: new Set(),
protected: new Set()
};
// Prime the cache with n objects.
for (var i = 0; i < size; i++) {
cache.free.push(fill());
}
return {
cache: cache,
get: function get() {
var value = cache.free.pop() || fill();
cache.allocated.add(value);
return value;
},
protect: function protect(value) {
cache.allocated.delete(value);
cache.protected.add(value);
},
unprotect: function unprotect(value) {
if (cache.protected.has(value)) {
cache.protected.delete(value);
cache.free.push(value);
}
}
};
}
function initializePools(COUNT) {
pools.attributeObject = createPool('attributeObject', {
size: COUNT,
fill: function fill() {
return { name: '', value: '' };
}
});
pools.elementObject = createPool('elementObject', {
size: COUNT,
fill: function fill() {
return {
rawNodeName: '',
nodeName: '',
nodeValue: '',
nodeType: 1,
key: '',
childNodes: [],
attributes: []
};
}
});
}
// Create ${COUNT} items of each type.
initializePools(count);
},{}],16:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
// List of SVG elements.
var elements = exports.elements = ['altGlyph', 'altGlyphDef', 'altGlyphItem', 'animate', 'animateColor', 'animateMotion', 'animateTransform', 'circle', 'clipPath', 'color-profile', 'cursor', 'defs', 'desc', 'ellipse', 'feBlend', 'feColorMatrix', 'feComponentTransfer', 'feComposite', 'feConvolveMatrix', 'feDiffuseLighting', 'feDisplacementMap', 'feDistantLight', 'feFlood', 'feFuncA', 'feFuncB', 'feFuncG', 'feFuncR', 'feGaussianBlur', 'feImage', 'feMerge', 'feMergeNode', 'feMorphology', 'feOffset', 'fePointLight', 'feSpecularLighting', 'feSpotLight', 'feTile', 'feTurbulence', 'filter', 'font', 'font-face', 'font-face-format', 'font-face-name', 'font-face-src', 'font-face-uri', 'foreignObject', 'g', 'glyph', 'glyphRef', 'hkern', 'image', 'line', 'linearGradient', 'marker', 'mask', 'metadata', 'missing-glyph', 'mpath', 'path', 'pattern', 'polygon', 'polyline', 'radialGradient', 'rect', 'set', 'stop', 'svg', 'switch', 'symbol', 'text', 'textPath', 'tref', 'tspan', 'use', 'view', 'vkern'];
// Namespace.
var namespace = exports.namespace = 'http://www.w3.org/2000/svg';
},{}],17:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol ? "symbol" : typeof obj; };
exports.html = html;
var _parser = _dereq_('./parser');
var _escape = _dereq_('./escape');
var _escape2 = _interopRequireDefault(_escape);
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
var isPropEx = /(=|'|")/;
var TOKEN = '__DIFFHTML__';
/**
* Get the next value from the list. If the next value is a string, make sure
* it is escaped.
*
* @param {Array} values - Values extracted from tagged template literal
* @return {String|*} - Escaped string, otherwise any value passed
*/
var nextValue = function nextValue(values) {
var value = values.shift();
return typeof value === 'string' ? (0, _escape2.default)(value) : value;
};
/**
* Parses tagged template contents into a Virtual Tree. These tagged templates
* separate static strings from values, so we need to do some special token
* work
*
* @param {Array} strings - A list of static strings, split by value
* @param {Array} ...values - A list of interpolated values
* @return {Object|Array} - A Virtual Tree Element or array of elements
*/
function html(strings) {
for (var _len = arguments.length, values = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
values[_key - 1] = arguments[_key];
}
// Automatically coerce a string literal to array.
if (typeof strings === 'string') {
strings = [strings];
}
// Do not attempt to parse empty strings.
if (!strings[0].length && !values.length) {
return null;
}
// Parse only the text, no dynamic bits.
if (strings.length === 1 && !values.length) {
var _childNodes = (0, _parser.parse)(strings[0]).childNodes;
return _childNodes.length > 1 ? _childNodes : _childNodes[0];
}
// Used to store markup and tokens.
var retVal = [];
// We filter the supplemental values by where they are used. Values are
// either props or children.
var supplemental = {
props: [],
children: []
};
// Loop over the static strings, each break correlates to an interpolated
// value. Since these values can be dynamic, we cannot pass them to the
// diffHTML HTML parser inline. They are passed as an additional argument
// called supplemental. The following loop instruments the markup with tokens
// that the parser then uses to assemble the correct tree.
strings.forEach(function (string) {
// Always add the string, we need it to parse the markup later.
retVal.push(string);
if (values.length) {
var value = nextValue(values);
var lastSegment = string.split(' ').pop();
var lastCharacter = lastSegment.trim().slice(-1);
var isProp = Boolean(lastCharacter.match(isPropEx));
if (isProp) {
supplemental.props.push(value);
retVal.push(TOKEN);
} else if (Array.isArray(value) || (typeof value === 'undefined' ? 'undefined' : _typeof(value)) === 'object') {
supplemental.children.push(value);
retVal.push(TOKEN);
} else {
retVal.push(value);
}
}
});
// Parse the instrumented markup to get the Virtual Tree.
var childNodes = (0, _parser.parse)(retVal.join(''), supplemental).childNodes;
// This makes it easier to work with a single element as a root, instead of
// always return an array.
return childNodes.length > 1 ? childNodes : childNodes[0];
}
},{"./escape":12,"./parser":14}],18:[function(_dereq_,module,exports){
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.buildTrigger = buildTrigger;
exports.makePromises = makePromises;
var forEach = Array.prototype.forEach;
/**
* Contains arrays to store transition callbacks.
*
* attached
* --------
*
* For when elements come into the DOM. The callback triggers immediately after
* the element enters the DOM. It is called with the element as the only
* argument.
*
* detached
* --------
*
* For when elements are removed from the DOM. The callback triggers just
* before the element leaves the DOM. It is called with the element as the only
* argument.
*
* replaced
* --------
*
* For when elements are replaced in the DOM. The callback triggers after the
* new element enters the DOM, and before the old element leaves. It is called
* with old and new elements as arguments, in that order.
*
* attributeChanged
* ----------------
*
* Triggered when an element's attribute has changed. The callback triggers
* after the attribute has changed in the DOM. It is called with the element,
* the attribute name, old value, and current value.
*
* textChanged
* -----------
*
* Triggered when an element's `textContent` chnages. The callback triggers
* after the textContent has changed in the DOM. It is called with the element,
* the old value, and current value.
*/
var states = exports.states = {
attached: [],
detached: [],
replaced: [],
attributeChanged: [],
textChanged: []
};
// Define the custom signatures necessary for the loop to fill in the "magic"
// methods that process the transitions consistently.
var fnSignatures = {
attached: function attached(el) {
return function (cb) {
return cb(el);
};
},
detached: function detached(el) {
return function (cb) {
return cb(el);
};
},
replaced: function replaced(oldEl, newEl) {
return function (cb) {
return cb(oldEl, newEl);
};
},
textChanged: function textChanged(el, oldVal, newVal) {
return function (cb) {
return cb(el, oldVal, newVal);
};
},
attributeChanged: function attributeChanged(el, name, oldVal, newVal) {
return function (cb) {
return cb(el, name, oldVal, newVal);
};
}
};
var make = {};
// Dynamically fill in the custom methods instead of manually constructing
// them.
Object.keys(states).forEach(function (stateName) {
var mapFn = fnSignatures[stateName];
/**
* Make's the transition promises.
*
* @param elements
* @param args
* @param promises
*/
make[stateName] = function makeTransitionPromises(elements, args, promises) {
// Sometimes an array-like is passed so using forEach in this manner yields
// more consistent results.
forEach.call(elements, function (element) {
// Never pass text nodes to a state callback unless it is textChanged.
if (stateName !== 'textChanged' && element.nodeType !== 1) {
return;
}
// Call the map function with each element.
var newPromises = states[stateName].map(mapFn.apply(null, [element].concat(args)));
// Merge these Promises into the main cache.
promises.push.apply(promises, newPromises);
// Recursively call into the children if attached or detached.
if (stateName === 'attached' || stateName === 'detached') {
make[stateName](element.childNodes, args, promises);
}
});
return promises.filter(function (promise) {
return Boolean(promise && promise.then);
});
};
});
/**
* Builds a reusable trigger mechanism for the element transitions.
*
* @param allPromises
*/
function buildTrigger(allPromises) {
var addPromises = allPromises.push.apply.bind(allPromises.push, allPromises);
// This becomes `triggerTransition` in process.js.
return function (stateName, makePromisesCallback, callback) {
if (states[stateName] && states[stateName].length) {
// Calls into each custom hook to bind Promises into the local array,
// these will then get merged into the main `allPromises` array.
var promises = makePromisesCallback([]);
// Add these promises into the global cache.
addPromises(promises);
if (callback) {
callback(promises.length ? promises : undefined);
}
} else if (callback) {
callback();
}
};
}
/**
* Make a reusable function for easy transition calling.
*
* @param stateName
*/
function makePromises(stateName) {
for (var _len = arguments.length, args = Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) {
args[_key - 1] = arguments[_key];
}
// Ensure elements is always an array.
var elements = [].concat(args[0]);
// Accepts the local Array of promises to use.
return function (promises) {
return make[stateName](elements, args.slice(1), promises);
};
}
},{}]},{},[1])(1)
});
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImRpc3QvZGlmZmh0bWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIoZnVuY3Rpb24oZil7aWYodHlwZW9mIGV4cG9ydHM9PT1cIm9iamVjdFwiJiZ0eXBlb2YgbW9kdWxlIT09XCJ1bmRlZmluZWRcIil7bW9kdWxlLmV4cG9ydHM9ZigpfWVsc2UgaWYodHlwZW9mIGRlZmluZT09PVwiZnVuY3Rpb25cIiYmZGVmaW5lLmFtZCl7ZGVmaW5lKFtdLGYpfWVsc2V7dmFyIGc7aWYodHlwZW9mIHdpbmRvdyE9PVwidW5kZWZpbmVkXCIpe2c9d2luZG93fWVsc2UgaWYodHlwZW9mIGdsb2JhbCE9PVwidW5kZWZpbmVkXCIpe2c9Z2xvYmFsfWVsc2UgaWYodHlwZW9mIHNlbGYhPT1cInVuZGVmaW5lZFwiKXtnPXNlbGZ9ZWxzZXtnPXRoaXN9Zy5kaWZmID0gZigpfX0pKGZ1bmN0aW9uKCl7dmFyIGRlZmluZSxtb2R1bGUsZXhwb3J0cztyZXR1cm4gKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkoezE6W2Z1bmN0aW9uKF9kZXJlcV8sbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuZXhwb3J0cy5jcmVhdGVBdHRyaWJ1dGUgPSBleHBvcnRzLmNyZWF0ZUVsZW1lbnQgPSBleHBvcnRzLnJlbGVhc2UgPSBleHBvcnRzLmh0bWwgPSB1bmRlZmluZWQ7XG5cbnZhciBfdGFnZ2VkVGVtcGxhdGUgPSBfZGVyZXFfKCcuL3V0aWwvdGFnZ2VkLXRlbXBsYXRlJyk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnaHRtbCcsIHtcbiAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgcmV0dXJuIF90YWdnZWRUZW1wbGF0ZS5odG1sO1xuICB9XG59KTtcblxudmFyIF9yZWxlYXNlID0gX2RlcmVxXygnLi9ub2RlL3JlbGVhc2UnKTtcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdyZWxlYXNlJywge1xuICBlbnVtZXJhYmxlOiB0cnVlLFxuICBnZXQ6IGZ1bmN0aW9uIGdldCgpIHtcbiAgICByZXR1cm4gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfcmVsZWFzZSkuZGVmYXVsdDtcbiAgfVxufSk7XG5cbnZhciBfaGVscGVycyA9IF9kZXJlcV8oJy4vdHJlZS9oZWxwZXJzJyk7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnY3JlYXRlRWxlbWVudCcsIHtcbiAgZW51bWVyYWJsZTogdHJ1ZSxcbiAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgcmV0dXJuIF9oZWxwZXJzLmNyZWF0ZUVsZW1lbnQ7XG4gIH1cbn0pO1xuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsICdjcmVhdGVBdHRyaWJ1dGUnLCB7XG4gIGVudW1lcmFibGU6IHRydWUsXG4gIGdldDogZnVuY3Rpb24gZ2V0KCkge1xuICAgIHJldHVybiBfaGVscGVycy5jcmVhdGVBdHRyaWJ1dGU7XG4gIH1cbn0pO1xuZXhwb3J0cy5vdXRlckhUTUwgPSBvdXRlckhUTUw7XG5leHBvcnRzLmlubmVySFRNTCA9IGlubmVySFRNTDtcbmV4cG9ydHMuZWxlbWVudCA9IGVsZW1lbnQ7XG5leHBvcnRzLmFkZFRyYW5zaXRpb25TdGF0ZSA9IGFkZFRyYW5zaXRpb25TdGF0ZTtcbmV4cG9ydHMucmVtb3ZlVHJhbnNpdGlvblN0YXRlID0gcmVtb3ZlVHJhbnNpdGlvblN0YXRlO1xuZXhwb3J0cy51c2UgPSB1c2U7XG5cbnZhciBfdHJhbnNhY3Rpb24gPSBfZGVyZXFfKCcuL25vZGUvdHJhbnNhY3Rpb24nKTtcblxudmFyIF90cmFuc2FjdGlvbjIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF90cmFuc2FjdGlvbik7XG5cbnZhciBfdHJhbnNpdGlvbnMgPSBfZGVyZXFfKCcuL3V0aWwvdHJhbnNpdGlvbnMnKTtcblxudmFyIF9jYWNoZSA9IF9kZXJlcV8oJy4vdXRpbC9jYWNoZScpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBkZWZhdWx0OiBvYmogfTsgfVxuXG4vKipcbiAqIFVzZWQgdG8gZGlmZiB0aGUgb3V0ZXJIVE1MIGNvbnRlbnRzIG9mIHRoZSBwYXNzZWQgZWxlbWVudCB3aXRoIHRoZSBtYXJrdXBcbiAqIGNvbnRlbnRzLiBWZXJ5IHVzZWZ1bCBmb3IgYXBwbHlpbmcgYSBnbG9iYWwgZGlmZiBvbiB0aGVcbiAqIGBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnRgLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogICAgaW1wb3J0IHsgb3V0ZXJIVE1MIH0gZnJvbSAnZGlmZmh0bWwnXG4gKlxuICogICAgLy8gUmVtb3ZlIGFsbCBhdHRyaWJ1dGVzIGFuZCBzZXQgdGhlIGNoaWxkcmVuIHRvIGJlIGEgc2luZ2xlIHRleHQgbm9kZVxuICogICAgLy8gY29udGFpbmluZyB0aGUgdGV4dCAnSGVsbG8gd29ybGQnLFxuICogICAgb3V0ZXJIVE1MKGRvY3VtZW50LmJvZHksICc8Ym9keT5IZWxsbyB3b3JsZDwvYm9keT4nKVxuICpcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gZWxlbWVudCAtIEEgRE9NIE5vZGUgdG8gcmVuZGVyIGludG9cbiAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gbWFya3VwPScnIC0gQSBzdHJpbmcgb2YgbWFya3VwIG9yIHZpcnR1YWwgdHJlZVxuICogQHBhcmFtIHtPYmplY3QgPX0gb3B0aW9ucz17fSAtIEFuIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICovXG5mdW5jdGlvbiBvdXRlckhUTUwoZWxlbWVudCkge1xuICB2YXIgbWFya3VwID0gYXJndW1lbnRzLmxlbmd0aCA8PSAxIHx8IGFyZ3VtZW50c1sxXSA9PT0gdW5kZWZpbmVkID8gJycgOiBhcmd1bWVudHNbMV07XG4gIHZhciBvcHRpb25zID0gYXJndW1lbnRzLmxlbmd0aCA8PSAyIHx8IGFyZ3VtZW50c1syXSA9PT0gdW5kZWZpbmVkID8ge30gOiBhcmd1bWVudHNbMl07XG5cbiAgb3B0aW9ucy5pbm5lciA9IGZhbHNlO1xuICAoMCwgX3RyYW5zYWN0aW9uMi5kZWZhdWx0KShlbGVtZW50LCBtYXJrdXAsIG9wdGlvbnMpO1xufVxuXG4vKipcbiAqIFVzZWQgdG8gZGlmZiB0aGUgaW5uZXJIVE1MIGNvbnRlbnRzIG9mIHRoZSBwYXNzZWQgZWxlbWVudCB3aXRoIHRoZSBtYXJrdXBcbiAqIGNvbnRlbnRzLiBUaGlzIGlzIHVzZWZ1bCB3aXRoIGxpYnJhcmllcyBsaWtlIEJhY2tib25lIHRoYXQgcmVuZGVyIFZpZXdzXG4gKiBpbnRvIGVsZW1lbnQgY29udGFpbmVyLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogICAgaW1wb3J0IHsgaW5uZXJIVE1MIH0gZnJvbSAnZGlmZmh0bWwnXG4gKlxuICogICAgLy8gU2V0cyB0aGUgYm9keSBjaGlsZHJlbiB0byBiZSBhIHNpbmdsZSB0ZXh0IG5vZGUgY29udGFpbmluZyB0aGUgdGV4dFxuICogICAgLy8gJ0hlbGxvIHdvcmxkJy5cbiAqICAgIGlubmVySFRNTChkb2N1bWVudC5ib2R5LCAnSGVsbG8gd29ybGQnKVxuICpcbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gZWxlbWVudCAtIEEgRE9NIE5vZGUgdG8gcmVuZGVyIGludG9cbiAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gbWFya3VwPScnIC0gQSBzdHJpbmcgb2YgbWFya3VwIG9yIHZpcnR1YWwgdHJlZVxuICogQHBhcmFtIHtPYmplY3QgPX0gb3B0aW9ucz17fSAtIEFuIG9iamVjdCBjb250YWluaW5nIGNvbmZpZ3VyYXRpb24gb3B0aW9uc1xuICovXG5mdW5jdGlvbiBpbm5lckhUTUwoZWxlbWVudCkge1xuICB2YXIgbWFya3VwID0gYXJndW1lbnRzLmxlbmd0aCA8PSAxIHx8IGFyZ3VtZW50c1sxXSA9PT0gdW5kZWZpbmVkID8gJycgOiBhcmd1bWVudHNbMV07XG4gIHZhciBvcHRpb25zID0gYXJndW1lbnRzLmxlbmd0aCA8PSAyIHx8IGFyZ3VtZW50c1syXSA9PT0gdW5kZWZpbmVkID8ge30gOiBhcmd1bWVudHNbMl07XG5cbiAgb3B0aW9ucy5pbm5lciA9IHRydWU7XG4gICgwLCBfdHJhbnNhY3Rpb24yLmRlZmF1bHQpKGVsZW1lbnQsIG1hcmt1cCwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogVXNlZCB0byBkaWZmIHR3byBlbGVtZW50cy4gVGhlIGBpbm5lcmAgQm9vbGVhbiBwcm9wZXJ0eSBjYW4gYmUgc3BlY2lmaWVkIGluXG4gKiB0aGUgb3B0aW9ucyB0byBzZXQgaW5uZXJIVE1MXFxvdXRlckhUTUwgYmVoYXZpb3IuIEJ5IGRlZmF1bHQgaXQgaXNcbiAqIG91dGVySFRNTC5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqICAgIC8vIEl0IGlzIHVzdWFsbHkgYmV0dGVyIHRvIHJlbmFtZSB0aGlzIG1ldGhvZCB0byBzb21ldGhpbmcgZGVzY3JpcHRpdmUuXG4gKiAgICBpbXBvcnQgeyBlbGVtZW50IGFzIGRpZmZFbGVtZW50IH0gZnJvbSAnZGlmZmh0bWwnXG4gKlxuICogICAgLy8gQ3JlYXRlIGEgbmV3IGJvZHkgdGFnLlxuICogICAgY29uc3QgbmV3Qm9keSA9ICQoYDxib2R5PlxuICogICAgICA8c3Ryb25nPkhlbGxvIHdvcmxkITwvc3Ryb25nPlxuICogICAgPC9ib2R5PmApLmdldCgpO1xuICpcbiAqXG4gKiAgICBkaWZmRWxlbWVudChkb2N1bWVudC5ib2R5LCBuZXdCb2R5KTtcbiAqXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IGVsZW1lbnQgLSBBIERPTSBOb2RlIHRvIHJlbmRlciBpbnRvXG4gKiBAcGFyYW0ge09iamVjdH0gbmV3RWxlbWVudCAtIEEgc3RyaW5nIG9mIG1hcmt1cCBvciB2aXJ0dWFsIHRyZWVcbiAqIEBwYXJhbSB7T2JqZWN0ID19IG9wdGlvbnM9e30gLSBBbiBvYmplY3QgY29udGFpbmluZyBjb25maWd1cmF0aW9uIG9wdGlvbnNcbiAqL1xuZnVuY3Rpb24gZWxlbWVudChlbGVtZW50LCBuZXdFbGVtZW50KSB7XG4gIHZhciBvcHRpb25zID0gYXJndW1lbnRzLmxlbmd0aCA8PSAyIHx8IGFyZ3VtZW50c1syXSA9PT0gdW5kZWZpbmVkID8ge30gOiBhcmd1bWVudHNbMl07XG5cbiAgKDAsIF90cmFuc2FjdGlvbjIuZGVmYXVsdCkoZWxlbWVudCwgbmV3RWxlbWVudCwgb3B0aW9ucyk7XG59XG5cbi8qKlxuICogQWRkcyBhIGdsb2JhbCB0cmFuc2l0aW9uIGxpc3RlbmVyLiBXaXRoIG1hbnkgZWxlbWVudHMgdGhpcyBjb3VsZCBiZSBhblxuICogZXhwZW5zaXZlIG9wZXJhdGlvbiwgc28gdHJ5IHRvIGxpbWl0IHRoZSBhbW91bnQgb2YgbGlzdGVuZXJzIGFkZGVkIGlmIHlvdSdyZVxuICogY29uY2VybmVkIGFib3V0IHBlcmZvcm1hbmNlLlxuICpcbiAqIFNpbmNlIHRoZSBjYWxsYmFjayB0cmlnZ2VycyB3aXRoIHZhcmlvdXMgZWxlbWVudHMsIG1vc3Qgb2Ygd2hpY2ggeW91XG4gKiBwcm9iYWJseSBkb24ndCBjYXJlIGFib3V0LCB5b3UnbGwgd2FudCB0byBmaWx0ZXIuIEEgZ29vZCB3YXkgb2YgZmlsdGVyaW5nXG4gKiBpcyB0byB1c2UgdGhlIERPTSBgbWF0Y2hlc2AgbWV0aG9kLiBJdCdzIGZhaXJseSB3ZWxsIHN1cHBvcnRlZFxuICogKGh0dHA6Ly9jYW5pdXNlLmNvbS8jZmVhdD1tYXRjaGVzc2VsZWN0b3IpIGFuZCBtYXkgc3VpdCBtYW55IHByb2plY3RzLiBJZlxuICogeW91IG5lZWQgYmFja3dhcmRzIGNvbXBhdGliaWxpdHksIGNvbnNpZGVyIHVzaW5nIGpRdWVyeSdzIGBpc2AuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAgICBpbXBvcnQgeyBhZGRUcmFuc2l0aW9uU3RhdGUgfSBmcm9tICdkaWZmaHRtbCdcbiAqXG4gKiAgICAvLyBGYWRlIGluIGFsbCBlbGVtZW50cyBhcyB0aGV5IGFyZSBhZGRlZCB0byB0aGUgRE9NLlxuICogICAgYWRkVHJhbnNpdGlvblN0YXRlKCdhdHRhY2hlZCcsIGVsID0+ICQoZWwpLmZhZGVJbigpLnByb21pc2UoKSlcbiAqXG4gKiAgICAvLyBGYWRlIG91dCBhbGwgZWxlbWVudHMgYXMgdGhleSBsZWF2ZSB0aGUgRE9NLlxuICogICAgYWRkVHJhbnNpdGlvblN0YXRlKCdkZXRhY2hlZCcsIGVsID0+ICQoZWwpLmZhZGVPdXQoKS5wcm9taXNlKCkpXG4gKlxuICpcbiAqIEBwYXJhbSBzdGF0ZSAtIFN0cmluZyBuYW1lIHRoYXQgbWF0Y2hlcyB3aGF0J3MgYXZhaWxhYmxlIGluIHRoZVxuICogZG9jdW1lbnRhdGlvbiBhYm92ZS5cbiAqIEBwYXJhbSBjYWxsYmFjayAtIEZ1bmN0aW9uIHRvIHJlY2VpdmUgdGhlIG1hdGNoaW5nIGVsZW1lbnRzLlxuICovXG5mdW5jdGlvbiBhZGRUcmFuc2l0aW9uU3RhdGUoc3RhdGUsIGNhbGxiYWNrKSB7XG4gIGlmICghc3RhdGUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ01pc3NpbmcgdHJhbnNpdGlvbiBzdGF0ZSBuYW1lJyk7XG4gIH1cblxuICBpZiAoIWNhbGxiYWNrKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIHRyYW5zaXRpb24gc3RhdGUgY2FsbGJhY2snKTtcbiAgfVxuXG4gIC8vIE5vdCBhIHZhbGlkIHN0YXRlIG5hbWUuXG4gIGlmIChPYmplY3Qua2V5cyhfdHJhbnNpdGlvbnMuc3RhdGVzKS5pbmRleE9mKHN0YXRlKSA9PT0gLTEpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgc3RhdGUgbmFtZTogJyArIHN0YXRlKTtcbiAgfVxuXG4gIF90cmFuc2l0aW9ucy5zdGF0ZXNbc3RhdGVdLnB1c2goY2FsbGJhY2spO1xufVxuXG4vKipcbiAqIFJlbW92ZXMgYSBnbG9iYWwgdHJhbnNpdGlvbiBsaXN0ZW5lci5cbiAqXG4gKiBXaGVuIGludm9rZWQgd2l0aCBubyBhcmd1bWVudHMsIHRoaXMgbWV0aG9kIHdpbGwgcmVtb3ZlIGFsbCB0cmFuc2l0aW9uXG4gKiBjYWxsYmFja3MuIFdoZW4gaW52b2tlZCB3aXRoIHRoZSBuYW1lIGFyZ3VtZW50IGl0IHdpbGwgcmVtb3ZlIGFsbCB0cmFuc2l0aW9uXG4gKiBzdGF0ZSBjYWxsYmFja3MgbWF0Y2hpbmcgdGhlIG5hbWUsIGFuZCBzbyBvbiBmb3IgdGhlIGNhbGxiYWNrLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogICAgaW1wb3J0IHsgcmVtb3ZlVHJhbnNpdGlvblN0YXRlIH0gZnJvbSAnZGlmZmh0bWwnXG4gKlxuICogICAgLy8gUmVtb3ZlIGFsbCB0cmFuc2l0aW9uIHN0YXRlIGhhbmRsZXJzLlxuICogICAgcmVtb3ZlVHJhbnNpdGlvblN0YXRlKClcbiAqXG4gKiAgICAvLyBSZW1vdmUgYWxsIGBhdHRhY2hlZGAgc3RhdGUgaGFuZGxlcnMuXG4gKiAgICByZW1vdmVUcmFuc2l0aW9uU3RhdGUoJ2F0dGFjaGVkJylcbiAqXG4gKiBAcGFyYW0ge1N0cmluZyA9fSBzdGF0ZSAtIE5hbWUgdGhhdCBtYXRjaGVzIHdoYXQncyBhdmFpbGFibGUgaW4gdGhlXG4gKiBkb2N1bWVudGF0aW9uIGFib3ZlXG4gKiBAcGFyYW0ge0Z1bmN0aW9uID19IGNhbGxiYWNrIC0gQ2FsbGJhY2sgdG8gcmVjZWl2ZSB0aGUgbWF0Y2hpbmcgZWxlbWVudHNcbiAqL1xuZnVuY3Rpb24gcmVtb3ZlVHJhbnNpdGlvblN0YXRlKHN0YXRlLCBjYWxsYmFjaykge1xuICBpZiAoIWNhbGxiYWNrICYmIHN0YXRlKSB7XG4gICAgX3RyYW5zaXRpb25zLnN0YXRlc1tzdGF0ZV0ubGVuZ3RoID0gMDtcbiAgfSBlbHNlIGlmIChzdGF0ZSAmJiBjYWxsYmFjaykge1xuICAgIC8vIE5vdCBhIHZhbGlkIHN0YXRlIG5hbWUuXG4gICAgaWYgKE9iamVjdC5rZXlzKF90cmFuc2l0aW9ucy5zdGF0ZXMpLmluZGV4T2Yoc3RhdGUpID09PSAtMSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHN0YXRlIG5hbWUgJyArIHN0YXRlKTtcbiAgICB9XG5cbiAgICB2YXIgaW5kZXggPSBfdHJhbnNpdGlvbnMuc3RhdGVzW3N0YXRlXS5pbmRleE9mKGNhbGxiYWNrKTtcbiAgICBfdHJhbnNpdGlvbnMuc3RhdGVzW3N0YXRlXS5zcGxpY2UoaW5kZXgsIDEpO1xuICB9IGVsc2Uge1xuICAgIGZvciAodmFyIF9zdGF0ZSBpbiBfdHJhbnNpdGlvbnMuc3RhdGVzKSB7XG4gICAgICBfdHJhbnNpdGlvbnMuc3RhdGVzW19zdGF0ZV0ubGVuZ3RoID0gMDtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBSZWdpc3RlcnMgbWlkZGxld2FyZSBmdW5jdGlvbnMgd2hpY2ggYXJlIGNhbGxlZCBkdXJpbmcgdGhlIHJlbmRlclxuICogdHJhbnNhY3Rpb24gZmxvdy4gVGhlc2Ugc2hvdWxkIGJlIHZlcnkgZmFzdCBhbmQgaWRlYWxseSBhc3luY2hyb25vdXMgdG9cbiAqIGF2b2lkIGJsb2NraW5nIHRoZSByZW5kZXIuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiAgICBpbXBvcnQgeyB1c2UgfSBmcm9tICdkaWZmaHRtbCdcbiAqICAgIGltcG9ydCBsb2dnZXIgZnJvbSAnZGlmZmh0bWwtbG9nZ2VyJ1xuICpcbiAqICAgIC8vIEFkZCB0aGUgZGlmZkhUTUwgbG9nZ2VyIG1pZGRsZXdhcmUsIHRvIGNvbnNvbGUgb3V0IHJlbmRlciBpbmZvcm1hdGlvbi5cbiAqICAgIHVzZShsb2dnZXIpXG4gKlxuICpcbiAqIEBwYXJhbSB7RnVuY3Rpb259IG1pZGRsZXdhcmUgLSBBIGZ1bmN0aW9uIHRoYXQgZ2V0cyBwYXNzZWQgaW50ZXJuYWxzXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gLSBXaGVuIGludm9rZWQgcmVtb3ZlcyBhbmQgZGVhY3RpdmF0ZXMgdGhlIG1pZGRsZXdhcmVcbiAqL1xuZnVuY3Rpb24gdXNlKG1pZGRsZXdhcmUpIHtcbiAgaWYgKHR5cGVvZiBtaWRkbGV3YXJlICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaWRkbGV3YXJlIG11c3QgYmUgYSBmdW5jdGlvbicpO1xuICB9XG5cbiAgLy8gQWRkIHRoZSBmdW5jdGlvbiB0byB0aGUgc2V0IG9mIG1pZGRsZXdhcmVzLlxuICBfY2FjaGUuTWlkZGxld2FyZUNhY2hlLmFkZChtaWRkbGV3YXJlKTtcblxuICAvLyBUaGUgdW5zdWJzY3JpYmUgbWV0aG9kIGZvciB0aGUgbWlkZGxld2FyZS5cbiAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAvLyBSZW1vdmUgdGhpcyBtaWRkbGV3YXJlIGZyb20gdGhlIGludGVybmFsIGNhY2hlLiBUaGlzIHdpbGwgcHJldmVudCBpdFxuICAgIC8vIGZyb20gYmVpbmcgaW52b2tlZCBpbiB0aGUgZnV0dXJlLlxuICAgIF9jYWNoZS5NaWRkbGV3YXJlQ2FjaGUuZGVsZXRlKG1pZGRsZXdhcmUpO1xuXG4gICAgLy8gQ2FsbCB0aGUgdW5zdWJzY3JpYmUgbWV0aG9kIGlmIGRlZmluZWQgaW4gdGhlIG1pZGRsZXdhcmUgKGFsbG93cyB0aGVtXG4gICAgLy8gdG8gY2xlYW51cCkuXG4gICAgbWlkZGxld2FyZS51bnN1YnNjcmliZSAmJiBtaWRkbGV3YXJlLnVuc3Vic2NyaWJlKCk7XG4gIH07XG59XG5cbn0se1wiLi9ub2RlL3JlbGVhc2VcIjo1LFwiLi9ub2RlL3RyYW5zYWN0aW9uXCI6NixcIi4vdHJlZS9oZWxwZXJzXCI6NyxcIi4vdXRpbC9jYWNoZVwiOjEwLFwiLi91dGlsL3RhZ2dlZC10ZW1wbGF0ZVwiOjE3LFwiLi91dGlsL3RyYW5zaXRpb25zXCI6MTh9XSwyOltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcbmV4cG9ydHMuZGVmYXVsdCA9IGdldEZpbmFsaXplQ2FsbGJhY2s7XG5cbnZhciBfdHJhbnNhY3Rpb24gPSBfZGVyZXFfKCcuLi9ub2RlL3RyYW5zYWN0aW9uJyk7XG5cbnZhciBfdHJhbnNhY3Rpb24yID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfdHJhbnNhY3Rpb24pO1xuXG52YXIgX2NhY2hlID0gX2RlcmVxXygnLi4vdXRpbC9jYWNoZScpO1xuXG52YXIgX21lbW9yeSA9IF9kZXJlcV8oJy4uL3V0aWwvbWVtb3J5Jyk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZURlZmF1bHQob2JqKSB7IHJldHVybiBvYmogJiYgb2JqLl9fZXNNb2R1bGUgPyBvYmogOiB7IGRlZmF1bHQ6IG9iaiB9OyB9XG5cbi8qKlxuICogUHVsbHMgdGhlIG5leHQgcmVuZGVyIG9iamVjdCAoY29udGFpbmluZyB0aGUgcmVzcGVjdGl2ZSBhcmd1bWVudHMgdG9cbiAqIHBhdGNoTm9kZSkgYW5kIGludm9rZXMgdGhlIG5leHQgdHJhbnNhY3Rpb24uXG4gKlxuICogQHBhcmFtIHN0YXRlXG4gKi9cbnZhciByZW5kZXJOZXh0ID0gZnVuY3Rpb24gcmVuZGVyTmV4dChzdGF0ZSkge1xuICB2YXIgbmV4dFJlbmRlciA9IHN0YXRlLm5leHRSZW5kZXI7XG4gIHN0YXRlLm5leHRSZW5kZXIgPSB1bmRlZmluZWQ7XG5cbiAgKDAsIF90cmFuc2FjdGlvbjIuZGVmYXVsdCkobmV4dFJlbmRlci5ub2RlLCBuZXh0UmVuZGVyLm5ld0hUTUwsIG5leHRSZW5kZXIub3B0aW9ucyk7XG59O1xuXG4vKipcbiAqIFJldHVybnMgYSBjYWxsYmFjayB0aGF0IGZpbmFsaXplcyB0aGUgdHJhbnNhY3Rpb24sIHNldHRpbmcgdGhlIGlzUmVuZGVyaW5nXG4gKiBmbGFnIHRvIGZhbHNlLiBUaGlzIGFsbG93cyB1cyB0byBwaWNrIG9mZiBhbmQgaW52b2tlIHRoZSBuZXh0IGF2YWlsYWJsZVxuICogdHJhbnNhY3Rpb24gdG8gcmVuZGVyLiBUaGlzIGNvZGUgcmVjeWxlcyB0aGUgdW5wcm90ZWN0ZWQgYWxsb2NhdGVkIHBvb2xcbiAqIG9iamVjdHMgYW5kIHRyaWdnZXJzIGEgYHJlbmRlckNvbXBsZXRlYCBldmVudC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbm9kZSAtIEEgRE9NIE5vZGUgdGhhdCBoYXMganVzdCBoYWQgcGF0Y2hlcyBhcHBsaWVkXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgLSBUaGUgY3VycmVudCBzdGF0ZSBvYmplY3QgYXNzb2NpYXRlZCB3aXRoIHRoZSBOb2RlXG4gKiBAcmV0dXJuIHtGdW5jdGlvbn0gLSBDbG9zdXJlIHRoYXQgd2hlbiBjYWxsZWQgY29tcGxldGVzIHRoZSB0cmFuc2FjdGlvblxuICovXG5mdW5jdGlvbiBnZXRGaW5hbGl6ZUNhbGxiYWNrKG5vZGUsIHN0YXRlKSB7XG4gIC8qKlxuICAgKiBXaGVuIHRoZSByZW5kZXIgY29tcGxldGVzLCBjbGVhbiB1cCBtZW1vcnksIGFuZCBzY2hlZHVsZSB0aGUgbmV4dCByZW5kZXJcbiAgICogaWYgbmVjZXNzYXJ5LlxuICAgKlxuICAgKiBAcGFyYW0ge0FycmF5fSByZW1haW5pbmdNaWRkbGV3YXJlIC0gQXJyYXkgb2YgbWlkZGxld2FyZSB0byBpbnZva2VcbiAgICovXG4gIHJldHVybiBmdW5jdGlvbiBmaW5hbGl6ZVRyYW5zYWN0aW9uKCkge1xuICAgIHZhciByZW1haW5pbmdNaWRkbGV3YXJlID0gYXJndW1lbnRzLmxlbmd0aCA8PSAwIHx8IGFyZ3VtZW50c1swXSA9PT0gdW5kZWZpbmVkID8gW10gOiBhcmd1bWVudHNbMF07XG5cbiAgICB2YXIgaXNJbm5lciA9IHN0YXRlLm9wdGlvbnMuaW5uZXI7XG5cbiAgICBzdGF0ZS5wcmV2aW91c01hcmt1cCA9IGlzSW5uZXIgPyBub2RlLmlubmVySFRNTCA6IG5vZGUub3V0ZXJIVE1MO1xuICAgIHN0YXRlLnByZXZpb3VzVGV4dCA9IG5vZGUudGV4dENvbnRlbnQ7XG5cbiAgICBzdGF0ZS5pc1JlbmRlcmluZyA9IGZhbHNlO1xuXG4gICAgLy8gVGhpcyBpcyBkZXNpZ25lZCB0byBoYW5kbGUgdXNlIGNhc2VzIHdoZXJlIHJlbmRlcnMgYXJlIGJlaW5nIGhhbW1lcmVkXG4gICAgLy8gb3Igd2hlbiB0cmFuc2l0aW9ucyBhcmUgdXNlZCB3aXRoIFByb21pc2VzLiBJZiB0aGlzIGVsZW1lbnQgaGFzIGEgbmV4dFxuICAgIC8vIHJlbmRlciBzdGF0ZSwgdHJpZ2dlciBpdCBmaXJzdCBhcyBwcmlvcml0eS5cbiAgICBpZiAoc3RhdGUubmV4dFJlbmRlcikge1xuICAgICAgcmVuZGVyTmV4dChzdGF0ZSk7XG4gICAgfVxuICAgIC8vIE90aGVyd2lzZSBkaWcgaW50byB0aGUgb3RoZXIgc3RhdGVzIGFuZCBwaWNrIG9mZiB0aGUgZmlyc3Qgb25lXG4gICAgLy8gYXZhaWxhYmxlLlxuICAgIGVsc2Uge1xuICAgICAgICB2YXIgX2l0ZXJhdG9yTm9ybWFsQ29tcGxldGlvbiA9IHRydWU7XG4gICAgICAgIHZhciBfZGlkSXRlcmF0b3JFcnJvciA9IGZhbHNlO1xuICAgICAgICB2YXIgX2l0ZXJhdG9yRXJyb3IgPSB1bmRlZmluZWQ7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBmb3IgKHZhciBfaXRlcmF0b3IgPSBfY2FjaGUuU3RhdGVDYWNoZS5lbnRyaWVzKClbU3ltYm9sLml0ZXJhdG9yXSgpLCBfc3RlcDsgIShfaXRlcmF0b3JOb3JtYWxDb21wbGV0aW9uID0gKF9zdGVwID0gX2l0ZXJhdG9yLm5leHQoKSkuZG9uZSk7IF9pdGVyYXRvck5vcm1hbENvbXBsZXRpb24gPSB0cnVlKSB7XG4gICAgICAgICAgICB2YXIgX3N0YXRlID0gX3N0ZXAudmFsdWU7XG5cbiAgICAgICAgICAgIGlmIChfc3RhdGUubmV4dFJlbmRlcikge1xuICAgICAgICAgICAgICByZW5kZXJOZXh0KF9zdGF0ZSk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAgICAgX2RpZEl0ZXJhdG9yRXJyb3IgPSB0cnVlO1xuICAgICAgICAgIF9pdGVyYXRvckVycm9yID0gZXJyO1xuICAgICAgICB9IGZpbmFsbHkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICBpZiAoIV9pdGVyYXRvck5vcm1hbENvbXBsZXRpb24gJiYgX2l0ZXJhdG9yLnJldHVybikge1xuICAgICAgICAgICAgICBfaXRlcmF0b3IucmV0dXJuKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIGlmIChfZGlkSXRlcmF0b3JFcnJvcikge1xuICAgICAgICAgICAgICB0aHJvdyBfaXRlcmF0b3JFcnJvcjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgIC8vIENsZWFuIG91dCBhbGwgdGhlIGV4aXN0aW5nIGFsbG9jYXRpb25zLlxuICAgICgwLCBfbWVtb3J5LmNsZWFuTWVtb3J5KSgpO1xuXG4gICAgLy8gQ2FsbCB0aGUgcmVtYWluaW5nIG1pZGRsZXdhcmUgc2lnbmFsaW5nIHRoZSByZW5kZXIgaXMgY29tcGxldGUuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZW1haW5pbmdNaWRkbGV3YXJlLmxlbmd0aDsgaSsrKSB7XG4gICAgICByZW1haW5pbmdNaWRkbGV3YXJlW2ldKCk7XG4gICAgfVxuICB9O1xufVxuXG59LHtcIi4uL25vZGUvdHJhbnNhY3Rpb25cIjo2LFwiLi4vdXRpbC9jYWNoZVwiOjEwLFwiLi4vdXRpbC9tZW1vcnlcIjoxM31dLDM6W2Z1bmN0aW9uKF9kZXJlcV8sbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuXG52YXIgX3R5cGVvZiA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgU3ltYm9sLml0ZXJhdG9yID09PSBcInN5bWJvbFwiID8gZnVuY3Rpb24gKG9iaikgeyByZXR1cm4gdHlwZW9mIG9iajsgfSA6IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIG9iaiAmJiB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb2JqLmNvbnN0cnVjdG9yID09PSBTeW1ib2wgPyBcInN5bWJvbFwiIDogdHlwZW9mIG9iajsgfTtcblxuZXhwb3J0cy5kZWZhdWx0ID0gbWFrZTtcblxudmFyIF9jYWNoZSA9IF9kZXJlcV8oJy4uL3V0aWwvY2FjaGUnKTtcblxudmFyIF9zdmcgPSBfZGVyZXFfKCcuLi91dGlsL3N2ZycpO1xuXG52YXIgc3ZnID0gX2ludGVyb3BSZXF1aXJlV2lsZGNhcmQoX3N2Zyk7XG5cbnZhciBfZW50aXRpZXMgPSBfZGVyZXFfKCcuLi91dGlsL2VudGl0aWVzJyk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZVdpbGRjYXJkKG9iaikgeyBpZiAob2JqICYmIG9iai5fX2VzTW9kdWxlKSB7IHJldHVybiBvYmo7IH0gZWxzZSB7IHZhciBuZXdPYmogPSB7fTsgaWYgKG9iaiAhPSBudWxsKSB7IGZvciAodmFyIGtleSBpbiBvYmopIHsgaWYgKE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbChvYmosIGtleSkpIG5ld09ialtrZXldID0gb2JqW2tleV07IH0gfSBuZXdPYmouZGVmYXVsdCA9IG9iajsgcmV0dXJuIG5ld09iajsgfSB9XG5cbi8qKlxuICogR2V0cyBhIHNwZWNpZmljIHR5cGUgb2YgRE9NIE5vZGUgZGVwZW5kaW5nIG9uIHRoZSBwYXNzZWQgaW4gbm9kZU5hbWUuXG4gKlxuICogQHBhcmFtIG5vZGVOYW1lIHtTdHJpbmd9IC0gVGhlIG5vZGVOYW1lIHRvIGRpc2FtYmlndWF0ZSB0aGUgdHlwZVxuICogQHBhcmFtIG5vZGVWYWx1ZSB7U3RyaW5nfSAtIFRoZSBub2RlVmFsdWUgdG8gc2V0IGlmIGEgVGV4dCBOb2RlXG4gKiBAcmV0dXJuIHtPYmplY3R9IC0gQSBET00gTm9kZSBtYXRjaGluZyB0aGUgbm9kZU5hbWVcbiAqL1xudmFyIGNyZWF0ZU5vZGVGcm9tTmFtZSA9IGZ1bmN0aW9uIGNyZWF0ZU5vZGVGcm9tTmFtZShfcmVmKSB7XG4gIHZhciBub2RlTmFtZSA9IF9yZWYubm9kZU5hbWU7XG4gIHZhciBub2RlVmFsdWUgPSBfcmVmLm5vZGVWYWx1ZTtcblxuICAvLyBJZiB3ZSdyZSBkZWFsaW5nIHdpdGggYSBUZXh0IE5vZGUsIHdlIG5lZWQgdG8gdXNlIHRoZSBzcGVjaWFsIERPTSBtZXRob2QsXG4gIC8vIHNpbmNlIGNyZWF0ZUVsZW1lbnQgZG9lcyBub3QgdW5kZXJzdGFuZCB0aGUgbm9kZU5hbWUgJyN0ZXh0Jy5cbiAgLy8gQWxsIG90aGVyIG5vZGVzIGNhbiBiZSBjcmVhdGVkIHRocm91Z2ggY3JlYXRlRWxlbWVudC5cbiAgaWYgKG5vZGVOYW1lID09PSAnI3RleHQnKSB7XG4gICAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKG5vZGVWYWx1ZSk7XG4gIH1cbiAgLy8gSWYgdGhlIG5vZGVOYW1lIG1hdGNoZXMgYW55IG9mIHRoZSBrbm93biBTVkcgZWxlbWVudCBuYW1lcywgbWFyayBpdCBhc1xuICAvLyBTVkcuIFRoZSByZWFzb24gZm9yIGRvaW5nIHRoaXMgb3ZlciBkZXRlY3RpbmcgaWYgbmVzdGVkIGluIGFuIDxzdmc+XG4gIC8vIGVsZW1lbnQsIGlzIHRoYXQgd2UgZG8gbm90IGN1cnJlbnRseSBoYXZlIGNpcmN1bGFyIGRlcGVuZGVuY2llcyBpbiB0aGVcbiAgLy8gVlRyZWUsIGJ5IGF2b2lkaW5nIHBhcmVudE5vZGUsIHNvIHRoZXJlIGlzIG5vIHdheSB0byBjcmF3bCB1cCB0aGUgcGFyZW50cy5cbiAgZWxzZSBpZiAoc3ZnLmVsZW1lbnRzLmluZGV4T2Yobm9kZU5hbWUpID4gLTEpIHtcbiAgICAgIHJldHVybiBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoc3ZnLm5hbWVzcGFjZSwgbm9kZU5hbWUpO1xuICAgIH1cbiAgICAvLyBJZiBub3QgYSBUZXh0IG9yIFNWRyBOb2RlLCB0aGVuIGNyZWF0ZSB3aXRoIHRoZSBzdGFuZGFyZCBtZXRob2QuXG4gICAgZWxzZSB7XG4gICAgICAgIHJldHVybiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KG5vZGVOYW1lKTtcbiAgICAgIH1cbn07XG5cbi8qKlxuICogVGFrZXMgaW4gYSBWaXJ0dWFsIFRyZWUgRWxlbWVudCAoVlRyZWUpIGFuZCBjcmVhdGVzIGEgRE9NIE5vZGUgZnJvbSBpdC5cbiAqIFNldHMgdGhlIG5vZGUgaW50byB0aGUgTm9kZSBjYWNoZS4gSWYgdGhpcyBWVHJlZSBhbHJlYWR5IGhhcyBhblxuICogYXNzb2NpYXRlZCBub2RlLCBpdCB3aWxsIHJldXNlIHRoYXQuXG4gKlxuICogQHBhcmFtIHtPYmplY3R9IC0gQSBWaXJ0dWFsIFRyZWUgRWxlbWVudCBvciBWVHJlZS1saWtlIGVsZW1lbnRcbiAqIEByZXR1cm4ge09iamVjdH0gLSBBIERPTSBOb2RlIG1hdGNoaW5nIHRoZSB2VHJlZVxuICovXG5mdW5jdGlvbiBtYWtlKHZUcmVlKSB7XG4gIC8vIElmIG5vIFZpcnR1YWwgVHJlZSBFbGVtZW50IHdhcyBzcGVjaWZpZWQsIHJldHVybiBudWxsLlxuICBpZiAoIXZUcmVlKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH1cblxuICAvLyBJZiB0aGUgRE9NIE5vZGUgd2FzIGFscmVhZHkgY3JlYXRlZCwgcmV1c2UgdGhlIGV4aXN0aW5nIG5vZGUuXG4gIGlmIChfY2FjaGUuTm9kZUNhY2hlLmhhcyh2VHJlZSkpIHtcbiAgICByZXR1cm4gX2NhY2hlLk5vZGVDYWNoZS5nZXQodlRyZWUpO1xuICB9XG5cbiAgdmFyIG5vZGUgPSBjcmVhdGVOb2RlRnJvbU5hbWUodlRyZWUpO1xuXG4gIC8vIENvcHkgYWxsIHRoZSBhdHRyaWJ1dGVzIGZyb20gdGhlIHZUcmVlIGludG8gdGhlIG5ld2x5IGNyZWF0ZWQgRE9NXG4gIC8vIE5vZGUuXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgKHZUcmVlLmF0dHJpYnV0ZXMgfHwgW10pLmxlbmd0aDsgaSsrKSB7XG4gICAgdmFyIGF0dHIgPSB2VHJlZS5hdHRyaWJ1dGVzW2ldO1xuICAgIHZhciBpc09iamVjdCA9IF90eXBlb2YoYXR0ci52YWx1ZSkgPT09ICdvYmplY3QnO1xuICAgIHZhciBpc0Z1bmN0aW9uID0gdHlwZW9mIGF0dHIudmFsdWUgPT09ICdmdW5jdGlvbic7XG5cbiAgICAvLyBJZiBub3QgYSBkeW5hbWljIHR5cGUsIHNldCBhcyBhbiBhdHRyaWJ1dGUsIHNpbmNlIGl0J3MgYSB2YWxpZFxuICAgIC8vIGF0dHJpYnV0ZSB2YWx1ZS5cbiAgICBpZiAoYXR0ci5uYW1lICYmICFpc09iamVjdCAmJiAhaXNGdW5jdGlvbikge1xuICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUoYXR0ci5uYW1lLCAoMCwgX2VudGl0aWVzLmRlY29kZUVudGl0aWVzKShhdHRyLnZhbHVlKSk7XG4gICAgfSBlbHNlIGlmIChhdHRyLm5hbWUgJiYgdHlwZW9mIGF0dHIudmFsdWUgIT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBOZWNlc3NhcnkgdG8gdHJhY2sgdGhlIGF0dHJpYnV0ZS9wcm9wIGV4aXN0ZW5jZS5cbiAgICAgIG5vZGUuc2V0QXR0cmlidXRlKGF0dHIubmFtZSwgJycpO1xuXG4gICAgICAvLyBTaW5jZSB0aGlzIGlzIGEgZHluYW1pYyB2YWx1ZSBpdCBnZXRzIHNldCBhcyBhIHByb3BlcnR5LlxuICAgICAgbm9kZVthdHRyLm5hbWVdID0gYXR0ci52YWx1ZTtcbiAgICB9XG4gIH1cblxuICAvLyBBcHBlbmQgYWxsIHRoZSBjaGlsZHJlbiBpbnRvIHRoZSBub2RlLCBtYWtpbmcgc3VyZSB0byBydW4gdGhlbVxuICAvLyB0aHJvdWdoIHRoaXMgYG1ha2VgIGZ1bmN0aW9uIGFzIHdlbGwuXG4gIGZvciAodmFyIF9pID0gMDsgX2kgPCAodlRyZWUuY2hpbGROb2RlcyB8fCBbXSkubGVuZ3RoOyBfaSsrKSB7XG4gICAgbm9kZS5hcHBlbmRDaGlsZChtYWtlKHZUcmVlLmNoaWxkTm9kZXNbX2ldKSk7XG4gIH1cblxuICAvLyBBZGQgdG8gdGhlIG5vZGVzIGNhY2hlLlxuICBfY2FjaGUuTm9kZUNhY2hlLnNldCh2VHJlZSwgbm9kZSk7XG5cbiAgcmV0dXJuIG5vZGU7XG59XG5cbn0se1wiLi4vdXRpbC9jYWNoZVwiOjEwLFwiLi4vdXRpbC9lbnRpdGllc1wiOjExLFwiLi4vdXRpbC9zdmdcIjoxNn1dLDQ6W2Z1bmN0aW9uKF9kZXJlcV8sbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuXG52YXIgX3R5cGVvZiA9IHR5cGVvZiBTeW1ib2wgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgU3ltYm9sLml0ZXJhdG9yID09PSBcInN5bWJvbFwiID8gZnVuY3Rpb24gKG9iaikgeyByZXR1cm4gdHlwZW9mIG9iajsgfSA6IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIG9iaiAmJiB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgb2JqLmNvbnN0cnVjdG9yID09PSBTeW1ib2wgPyBcInN5bWJvbFwiIDogdHlwZW9mIG9iajsgfTtcblxuZXhwb3J0cy5kZWZhdWx0ID0gcGF0Y2hOb2RlO1xuXG52YXIgX21ha2UgPSBfZGVyZXFfKCcuL21ha2UnKTtcblxudmFyIF9tYWtlMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX21ha2UpO1xuXG52YXIgX3RyYW5zaXRpb25zID0gX2RlcmVxXygnLi4vdXRpbC90cmFuc2l0aW9ucycpO1xuXG52YXIgX3BhcnNlciA9IF9kZXJlcV8oJy4uL3V0aWwvcGFyc2VyJyk7XG5cbnZhciBfY2FjaGUgPSBfZGVyZXFfKCcuLi91dGlsL2NhY2hlJyk7XG5cbnZhciBfcG9vbHMgPSBfZGVyZXFfKCcuLi91dGlsL3Bvb2xzJyk7XG5cbnZhciBfbWVtb3J5ID0gX2RlcmVxXygnLi4vdXRpbC9tZW1vcnknKTtcblxudmFyIF9lbnRpdGllcyA9IF9kZXJlcV8oJy4uL3V0aWwvZW50aXRpZXMnKTtcblxudmFyIF9zeW5jID0gX2RlcmVxXygnLi4vdHJlZS9zeW5jJyk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wUmVxdWlyZURlZmF1bHQob2JqKSB7IHJldHVybiBvYmogJiYgb2JqLl9fZXNNb2R1bGUgPyBvYmogOiB7IGRlZmF1bHQ6IG9iaiB9OyB9XG5cbnZhciBpc0VsZW1lbnROb2RlID0gZnVuY3Rpb24gaXNFbGVtZW50Tm9kZShub2RlKSB7XG4gIHJldHVybiBub2RlLm5vZGVUeXBlID09PSAxO1xufTtcbnZhciBmaWx0ZXIgPSBBcnJheS5wcm90b3R5cGUuZmlsdGVyO1xuXG4vKipcbiAqIExvb2tzIHRvIHNlZSBpZiBhbiBlbGVtZW50IGNhbiBiZSByZXBsYWNlZC4gSXQgbXVzdCBoYXZlIGEgcGFyZW50Tm9kZSB0byBkb1xuICogc28uIFRoaXMgd2lsbCB0cmlnZ2VyIGFuIGVycm9yIHdoZW4gdGhlIGVsZW1lbnQgZG9lcyBub3QgaGF2ZSBhIHBhcmVudE5vZGUuXG4gKiBUaGlzIHR5cGljYWxseSBoYXBwZW5zIHdoZW4gdHJ5aW5nIHRvIHJlcGxhY2UgYSBkaXNjb25uZWN0ZWQgRE9NIE5vZGUgb3IgdGhlXG4gKiBkb2N1bWVudEVsZW1lbnQuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IHZlcmIgLSBWZXJiIHRvIHJlcGxhY2UgaW4gdGhlIHRlbXBsYXRlIHN0cmluZ1xuICogQHBhcmFtIHtPYmplY3R9IG9sZE5vZGUgLSBPbGQgRE9NIE5vZGUgdG8gY2hlY2sgaWYgYWJsZSB0byBiZSByZXBsYWNlZFxuICogQHBhcmFtIHtPYmplY3R9IHBhdGNoIC0gVXNlZCB0byBjbGVhbiB1cCB2VHJlZSByZWZlcmVuY2VzXG4gKi9cbnZhciBjaGVja0Zvck1pc3NpbmdQYXJlbnQgPSBmdW5jdGlvbiBjaGVja0Zvck1pc3NpbmdQYXJlbnQodmVyYiwgb2xkTm9kZSwgcGF0Y2gpIHtcbiAgaWYgKCFvbGROb2RlLnBhcmVudE5vZGUpIHtcbiAgICAvLyBDbGVhbiB1cCB0aGVzZSBlbGVtZW50cyB0byBrZWVwIG1lbW9yeSBjb25zaXN0ZW50LlxuICAgICgwLCBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm9sZCk7XG4gICAgKDAsIF9tZW1vcnkudW5wcm90ZWN0RWxlbWVudCkocGF0Y2gubmV3KTtcblxuICAgIC8vIFRocm93IGFuIGVycm9yIHRvIHN0b3AgcmVuZGVyaW5nL2luZm9ybSB0aGUgZGV2ZWxvcGVyLlxuICAgIHRocm93IG5ldyBFcnJvcigoJ1xcbiAgICAgIENhblxcJ3QgJyArIHZlcmIgKyAnIHdpdGhvdXQgcGFyZW50LCBpcyB0aGlzIHRoZSBkb2N1bWVudCByb290P1xcbiAgICAnKS50cmltKCkpO1xuICB9XG59O1xuXG4vLyBUcmlnZ2VyIHRoZSBhdHRhY2hlZCB0cmFuc2l0aW9uIHN0YXRlIGZvciB0aGlzIGVsZW1lbnQgYW5kIGFsbCBjaGlsZE5vZGVzLlxudmFyIGF0dGFjaCA9IGZ1bmN0aW9uIGF0dGFjaChfcmVmKSB7XG4gIHZhciB2VHJlZSA9IF9yZWYudlRyZWU7XG4gIHZhciBmcmFnbWVudCA9IF9yZWYuZnJhZ21lbnQ7XG4gIHZhciBwYXJlbnROb2RlID0gX3JlZi5wYXJlbnROb2RlO1xuICB2YXIgdHJpZ2dlclRyYW5zaXRpb24gPSBfcmVmLnRyaWdnZXJUcmFuc2l0aW9uO1xuICB2YXIgc3RhdGUgPSBfcmVmLnN0YXRlO1xuXG4gIC8vIFRoaXMgZWxlbWVudCBoYXMgYmVlbiBhdHRhY2hlZCwgc28gaXQgc2hvdWxkIGRlZmluaXRlbHkgYmUgbWFya2VkIGFzXG4gIC8vIHByb3RlY3RlZC5cbiAgKDAsIF9tZW1vcnkucHJvdGVjdEVsZW1lbnQpKHZUcmVlKTtcblxuICAvLyBDcmVhdGUgYSBET00gTm9kZSBmb3IgdGhpcyBWaXJ0dWFsIFRyZWUgZWxlbWVudC5cbiAgdmFyIG5vZGUgPSAoMCwgX21ha2UyLmRlZmF1bHQpKHZUcmVlKTtcblxuICAvLyBJZiB0aGUgZWxlbWVudCBhZGRlZCB3YXMgYSBET00gdGV4dCBub2RlIG9yIFNWRyB0ZXh0IGVsZW1lbnQsIHRyaWdnZXJcbiAgLy8gdGhlIHRleHRDaGFuZ2VkIHRyYW5zaXRpb24uXG4gIGlmICh2VHJlZS5ub2RlTmFtZSA9PT0gJyN0ZXh0Jykge1xuICAgIHZhciBwcm9taXNlcyA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgndGV4dENoYW5nZWQnLCBbbm9kZV0sIG51bGwsIHZUcmVlLm5vZGVWYWx1ZSk7XG5cbiAgICBub2RlLm5vZGVWYWx1ZSA9ICgwLCBfZW50aXRpZXMuZGVjb2RlRW50aXRpZXMpKHZUcmVlLm5vZGVWYWx1ZSk7XG5cbiAgICBpZiAocGFyZW50Tm9kZSkge1xuICAgICAgdmFyIG5vZGVOYW1lID0gcGFyZW50Tm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXG4gICAgICBpZiAoX3BhcnNlci5ibG9ja1RleHQuaGFzKG5vZGVOYW1lKSkge1xuICAgICAgICBwYXJlbnROb2RlLm5vZGVWYWx1ZSA9ICgwLCBfZW50aXRpZXMuZGVjb2RlRW50aXRpZXMpKHZUcmVlLm5vZGVWYWx1ZSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgdHJpZ2dlclRyYW5zaXRpb24oJ3RleHRDaGFuZ2VkJywgcHJvbWlzZXMpO1xuICB9XG5cbiAgdlRyZWUuYXR0cmlidXRlcy5mb3JFYWNoKGZ1bmN0aW9uIChhdHRyKSB7XG4gICAgdHJpZ2dlclRyYW5zaXRpb24oJ2F0dHJpYnV0ZUNoYW5nZWQnLCAoMCwgX3RyYW5zaXRpb25zLm1ha2VQcm9taXNlcykoJ2F0dHJpYnV0ZUNoYW5nZWQnLCBbbm9kZV0sIGF0dHIubmFtZSwgbnVsbCwgYXR0ci52YWx1ZSkpO1xuICB9KTtcblxuICAvLyBDYWxsIGFsbCBgY2hpbGROb2Rlc2AgYXR0YWNoZWQgY2FsbGJhY2tzIGFzIHdlbGwuXG4gIHZUcmVlLmNoaWxkTm9kZXMuZm9yRWFjaChmdW5jdGlvbiAodlRyZWUpIHtcbiAgICByZXR1cm4gYXR0YWNoKHtcbiAgICAgIHZUcmVlOiB2VHJlZSwgcGFyZW50Tm9kZTogbm9kZSwgdHJpZ2dlclRyYW5zaXRpb246IHRyaWdnZXJUcmFuc2l0aW9uLCBzdGF0ZTogc3RhdGVcbiAgICB9KTtcbiAgfSk7XG5cbiAgLy8gSWYgYSBEb2N1bWVudCBGcmFnbWVudCB3YXMgc3BlY2lmaWVkLCBhcHBlbmQgdGhlIERPTSBOb2RlIGludG8gaXQuXG4gIGlmIChmcmFnbWVudCkge1xuICAgIGZyYWdtZW50LmFwcGVuZENoaWxkKG5vZGUpO1xuICB9XG5cbiAgcmV0dXJuIG5vZGU7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyBhIHNldCBvZiBwYXRjaGVzIG9udG8gYSB0cmFja2VkIERPTSBOb2RlLlxuICpcbiAqIEBwYXJhbSB7T2JqZWN0fSBub2RlIC0gRE9NIE5vZGUgdG8gcHJvY2VzcyBwYXRjaHMgb25cbiAqIEBwYXJhbSB7QXJyYXl9IHBhdGNoZXMgLSBDb250YWlucyBwYXRjaCBvYmplY3RzXG4gKi9cbmZ1bmN0aW9uIHBhdGNoTm9kZShub2RlLCBwYXRjaGVzKSB7XG4gIHZhciBzdGF0ZSA9IF9jYWNoZS5TdGF0ZUNhY2hlLmdldChub2RlKTtcbiAgdmFyIHByb21pc2VzID0gW107XG4gIHZhciB0cmlnZ2VyVHJhbnNpdGlvbiA9ICgwLCBfdHJhbnNpdGlvbnMuYnVpbGRUcmlnZ2VyKShwcm9taXNlcyk7XG5cbiAgLy8gTG9vcCB0aHJvdWdoIGFsbCB0aGUgcGF0Y2hlcyBhbmQgYXBwbHkgdGhlbS5cblxuICB2YXIgX2xvb3AgPSBmdW5jdGlvbiBfbG9vcChpKSB7XG4gICAgdmFyIHBhdGNoID0gcGF0Y2hlc1tpXTtcbiAgICB2YXIgZWwgPSAoMCwgX21ha2UyLmRlZmF1bHQpKHBhdGNoLmVsZW1lbnQpO1xuICAgIHZhciBvbGRFbCA9ICgwLCBfbWFrZTIuZGVmYXVsdCkocGF0Y2gub2xkKTtcbiAgICB2YXIgbmV3RWwgPSAoMCwgX21ha2UyLmRlZmF1bHQpKHBhdGNoLm5ldyk7XG5cbiAgICAvLyBFbXB0eSB0aGUgTm9kZSdzIGNvbnRlbnRzLiBUaGlzIGlzIGFuIG9wdGltaXphdGlvbiwgc2luY2UgYGlubmVySFRNTGBcbiAgICAvLyB3aWxsIGJlIGZhc3RlciB0aGFuIGl0ZXJhdGluZyBvdmVyIGV2ZXJ5IGVsZW1lbnQgYW5kIG1hbnVhbGx5IHJlbW92aW5nLlxuICAgIGlmIChwYXRjaC5fX2RvX18gPT09IF9zeW5jLlJFTU9WRV9FTEVNRU5UX0NISUxEUkVOKSB7XG4gICAgICB2YXIgY2hpbGROb2RlcyA9IGZpbHRlci5jYWxsKGVsLmNoaWxkTm9kZXMsIGlzRWxlbWVudE5vZGUpO1xuICAgICAgdmFyIGRldGFjaFByb21pc2VzID0gKDAsIF90cmFuc2l0aW9ucy5tYWtlUHJvbWlzZXMpKCdkZXRhY2hlZCcsIGNoaWxkTm9kZXMpO1xuXG4gICAgICB0cmlnZ2VyVHJhbnNpdGlvbignZGV0YWNoZWQnLCBkZXRhY2hQcm9taXNlcywgZnVuY3Rpb24gKHByb21pc2VzKSB7XG4gICAgICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uIGNhbGxiYWNrKCkge1xuICAgICAgICAgICgwLCBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnQpKHBhdGNoLnRvUmVtb3ZlKTtcbiAgICAgICAgICBlbC5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgfTtcblxuICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgUHJvbWlzZS5hbGwocHJvbWlzZXMpLnRoZW4oY2FsbGJhY2spO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIFJlbW92ZSB0aGUgZW50aXJlIE5vZGUuIE9ubHkgZG9lcyBzb21ldGhpbmcgaWYgdGhlIE5vZGUgaGFzIGEgcGFyZW50XG4gICAgLy8gZWxlbWVudC5cbiAgICBlbHNlIGlmIChwYXRjaC5fX2RvX18gPT09IF9zeW5jLlJFTU9WRV9FTlRJUkVfRUxFTUVOVCkge1xuICAgICAgICB2YXIgX2NoaWxkTm9kZXMgPSBbZWxdLmZpbHRlcihpc0VsZW1lbnROb2RlKTtcbiAgICAgICAgdmFyIF9kZXRhY2hQcm9taXNlcyA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgnZGV0YWNoZWQnLCBfY2hpbGROb2Rlcyk7XG5cbiAgICAgICAgaWYgKGVsLnBhcmVudE5vZGUpIHtcbiAgICAgICAgICB0cmlnZ2VyVHJhbnNpdGlvbignZGV0YWNoZWQnLCBfZGV0YWNoUHJvbWlzZXMsIGZ1bmN0aW9uIChwcm9taXNlcykge1xuICAgICAgICAgICAgdmFyIGNhbGxiYWNrID0gZnVuY3Rpb24gY2FsbGJhY2soKSB7XG4gICAgICAgICAgICAgIGVsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZWwpO1xuICAgICAgICAgICAgICAoMCwgX21lbW9yeS51bnByb3RlY3RFbGVtZW50KShwYXRjaC50b1JlbW92ZSk7XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgKDAsIF9tZW1vcnkudW5wcm90ZWN0RWxlbWVudCkocGF0Y2gudG9SZW1vdmUpO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFJlcGxhY2UgdGhlIGVudGlyZSBOb2RlLlxuICAgICAgZWxzZSBpZiAocGF0Y2guX19kb19fID09PSBfc3luYy5SRVBMQUNFX0VOVElSRV9FTEVNRU5UKSB7XG4gICAgICAgICAgKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhbGxQcm9taXNlcyA9IFtdO1xuXG4gICAgICAgICAgICB2YXIgYXR0YWNoZWRQcm9taXNlcyA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgnYXR0YWNoZWQnLCBbbmV3RWxdLmZpbHRlcihpc0VsZW1lbnROb2RlKSk7XG5cbiAgICAgICAgICAgIHZhciBkZXRhY2hlZFByb21pc2VzID0gKDAsIF90cmFuc2l0aW9ucy5tYWtlUHJvbWlzZXMpKCdkZXRhY2hlZCcsIFtvbGRFbF0uZmlsdGVyKGlzRWxlbWVudE5vZGUpKTtcblxuICAgICAgICAgICAgdmFyIHJlcGxhY2VkUHJvbWlzZXMgPSAoMCwgX3RyYW5zaXRpb25zLm1ha2VQcm9taXNlcykoJ3JlcGxhY2VkJywgW29sZEVsXSwgbmV3RWwpO1xuXG4gICAgICAgICAgICAvLyBBZGQgYWxsIHRoZSB0cmFuc2l0aW9uIHN0YXRlIHByb21pc2VzIGludG8gdGhlIG1haW4gYXJyYXksIHdlJ2xsIHVzZVxuICAgICAgICAgICAgLy8gdGhlbSBhbGwgdG8gZGVjaWRlIHdoZW4gdG8gYWx0ZXIgdGhlIERPTS5cbiAgICAgICAgICAgIHRyaWdnZXJUcmFuc2l0aW9uKCdkZXRhY2hlZCcsIGRldGFjaGVkUHJvbWlzZXMsIGZ1bmN0aW9uIChwcm9taXNlcykge1xuICAgICAgICAgICAgICBhbGxQcm9taXNlcy5wdXNoLmFwcGx5KGFsbFByb21pc2VzLCBwcm9taXNlcyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ2F0dGFjaGVkJywgYXR0YWNoZWRQcm9taXNlcywgZnVuY3Rpb24gKHByb21pc2VzKSB7XG4gICAgICAgICAgICAgIGFsbFByb21pc2VzLnB1c2guYXBwbHkoYWxsUHJvbWlzZXMsIHByb21pc2VzKTtcbiAgICAgICAgICAgICAgYXR0YWNoKHsgdlRyZWU6IHBhdGNoLm5ldywgdHJpZ2dlclRyYW5zaXRpb246IHRyaWdnZXJUcmFuc2l0aW9uLCBzdGF0ZTogc3RhdGUgfSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ3JlcGxhY2VkJywgcmVwbGFjZWRQcm9taXNlcywgZnVuY3Rpb24gKHByb21pc2VzKSB7XG4gICAgICAgICAgICAgIGFsbFByb21pc2VzLnB1c2guYXBwbHkoYWxsUHJvbWlzZXMsIHByb21pc2VzKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAoMCwgX21lbW9yeS51bnByb3RlY3RFbGVtZW50KShwYXRjaC5vbGQpO1xuXG4gICAgICAgICAgICAvLyBSZXNldCB0aGUgdHJlZSBjYWNoZS4gVE9ETyBMb29rIGludG8gdGhpcy4uLlxuICAgICAgICAgICAgX2NhY2hlLlN0YXRlQ2FjaGUuc2V0KG5ld0VsLCB7XG4gICAgICAgICAgICAgIG9sZFRyZWU6IHBhdGNoLm5ldyxcbiAgICAgICAgICAgICAgZWxlbWVudDogbmV3RWxcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAvLyBPbmNlIGFsbCB0aGUgcHJvbWlzZXMgaGF2ZSBjb21wbGV0ZWQsIGludm9rZSB0aGUgYWN0aW9uLCBpZiBub1xuICAgICAgICAgICAgLy8gcHJvbWlzZXMgd2VyZSBhZGRlZCwgdGhpcyB3aWxsIGJlIGEgc3luY2hyb25vdXMgb3BlcmF0aW9uLlxuICAgICAgICAgICAgaWYgKGFsbFByb21pc2VzLmxlbmd0aCkge1xuICAgICAgICAgICAgICBQcm9taXNlLmFsbChhbGxQcm9taXNlcykudGhlbihmdW5jdGlvbiByZXBsYWNlRW50aXJlRWxlbWVudCgpIHtcbiAgICAgICAgICAgICAgICBjaGVja0Zvck1pc3NpbmdQYXJlbnQob2xkRWwsIHBhdGNoKTtcbiAgICAgICAgICAgICAgICBvbGRFbC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChuZXdFbCwgb2xkRWwpO1xuICAgICAgICAgICAgICB9LCBmdW5jdGlvbiAoZXgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY29uc29sZS5sb2coZXgpO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGlmICghb2xkRWwucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgICAgICgwLCBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm5ldyk7XG5cbiAgICAgICAgICAgICAgICBpZiAoX2NhY2hlLlN0YXRlQ2FjaGUuaGFzKG5ld0VsKSkge1xuICAgICAgICAgICAgICAgICAgX2NhY2hlLlN0YXRlQ2FjaGUuZGVsZXRlKG5ld0VsKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IocmVwbGFjZUZhaWxNc2cpO1xuICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgb2xkRWwucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobmV3RWwsIG9sZEVsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gTm9kZSBtYW5pcC5cbiAgICAgICAgZWxzZSBpZiAocGF0Y2guX19kb19fID09PSBfc3luYy5NT0RJRllfRUxFTUVOVCkge1xuICAgICAgICAgICAgLy8gQWRkLlxuICAgICAgICAgICAgaWYgKGVsICYmIHBhdGNoLmZyYWdtZW50ICYmICFvbGRFbCkge1xuICAgICAgICAgICAgICAoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcblxuICAgICAgICAgICAgICAgIC8vIExvb3Agb3ZlciBldmVyeSBlbGVtZW50IHRvIGJlIGFkZGVkIGFuZCBwcm9jZXNzIHRoZSBWaXJ0dWFsIFRyZWVcbiAgICAgICAgICAgICAgICAvLyBlbGVtZW50IGludG8gdGhlIERPTSBOb2RlIGFuZCBhcHBlbmQgaW50byB0aGUgRE9NIGZyYWdtZW50LlxuICAgICAgICAgICAgICAgIHZhciB0b0F0dGFjaCA9IHBhdGNoLmZyYWdtZW50Lm1hcChmdW5jdGlvbiAodlRyZWUpIHtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBhdHRhY2goe1xuICAgICAgICAgICAgICAgICAgICB2VHJlZTogdlRyZWUsIGZyYWdtZW50OiBmcmFnbWVudCwgdHJpZ2dlclRyYW5zaXRpb246IHRyaWdnZXJUcmFuc2l0aW9uLCBzdGF0ZTogc3RhdGVcbiAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pLmZpbHRlcihpc0VsZW1lbnROb2RlKTtcblxuICAgICAgICAgICAgICAgIC8vIFR1cm4gZWxlbWVudHMgaW50byBjaGlsZE5vZGVzIG9mIHRoZSBwYXRjaCBlbGVtZW50LlxuICAgICAgICAgICAgICAgIGVsLmFwcGVuZENoaWxkKGZyYWdtZW50KTtcblxuICAgICAgICAgICAgICAgIC8vIFRyaWdnZXIgdHJhbnNpdGlvbnMuXG4gICAgICAgICAgICAgICAgdmFyIG1ha2VBdHRhY2hlZCA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgnYXR0YWNoZWQnLCB0b0F0dGFjaCk7XG4gICAgICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ2F0dGFjaGVkJywgbWFrZUF0dGFjaGVkKTtcbiAgICAgICAgICAgICAgfSkoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUmVtb3ZlLlxuICAgICAgICAgICAgZWxzZSBpZiAob2xkRWwgJiYgIW5ld0VsKSB7XG4gICAgICAgICAgICAgICAgLy8gRW5zdXJlIHdlIGNhbiByZW1vdmUgdGhlIG9sZCBET00gTm9kZS5cbiAgICAgICAgICAgICAgICBjaGVja0Zvck1pc3NpbmdQYXJlbnQoJ3JlbW92ZScsIG9sZEVsLCBwYXRjaCk7XG5cbiAgICAgICAgICAgICAgICB2YXIgbWFrZURldGFjaGVkID0gKDAsIF90cmFuc2l0aW9ucy5tYWtlUHJvbWlzZXMpKCdkZXRhY2hlZCcsIFtvbGRFbF0pO1xuXG4gICAgICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ2RldGFjaGVkJywgbWFrZURldGFjaGVkLCBmdW5jdGlvbiAocHJvbWlzZXMpIHtcbiAgICAgICAgICAgICAgICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uIGNhbGxiYWNrKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAob2xkRWwucGFyZW50Tm9kZSkge1xuICAgICAgICAgICAgICAgICAgICAgIG9sZEVsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQob2xkRWwpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQW5kIHRoZW4gZW1wdHkgb3V0IHRoZSBlbnRpcmUgY29udGVudHMuXG4gICAgICAgICAgICAgICAgICAgIG9sZEVsLmlubmVySFRNTCA9ICcnO1xuXG4gICAgICAgICAgICAgICAgICAgICgwLCBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm9sZCk7XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAvLyBSZXBsYWNlLlxuICAgICAgICAgICAgICBlbHNlIGlmIChvbGRFbCAmJiBuZXdFbCkge1xuICAgICAgICAgICAgICAgICAgKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRW5zdXJlIHdlIGNhbiByZXBsYWNlIHRoZSBvbGQgRE9NIE5vZGUuXG4gICAgICAgICAgICAgICAgICAgIGNoZWNrRm9yTWlzc2luZ1BhcmVudCgncmVwbGFjZScsIG9sZEVsLCBwYXRjaCk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQXBwZW5kIHRoZSBlbGVtZW50IGZpcnN0LCBiZWZvcmUgZG9pbmcgdGhlIHJlcGxhY2VtZW50LlxuICAgICAgICAgICAgICAgICAgICBpZiAob2xkRWwubmV4dFNpYmxpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICBvbGRFbC5wYXJlbnROb2RlLmluc2VydEJlZm9yZShuZXdFbCwgb2xkRWwubmV4dFNpYmxpbmcpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIG9sZEVsLnBhcmVudE5vZGUuYXBwZW5kQ2hpbGQobmV3RWwpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVtb3ZlZCBzdGF0ZSBmb3IgdHJhbnNpdGlvbnMgQVBJLlxuICAgICAgICAgICAgICAgICAgICB2YXIgYWxsUHJvbWlzZXMgPSBbXTtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgYXR0YWNoUHJvbWlzZXMgPSAoMCwgX3RyYW5zaXRpb25zLm1ha2VQcm9taXNlcykoJ2F0dGFjaGVkJywgW25ld0VsXS5maWx0ZXIoaXNFbGVtZW50Tm9kZSkpO1xuXG4gICAgICAgICAgICAgICAgICAgIHZhciBkZXRhY2hQcm9taXNlcyA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgnZGV0YWNoZWQnLCBbb2xkRWxdLmZpbHRlcihpc0VsZW1lbnROb2RlKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHJlcGxhY2VQcm9taXNlcyA9ICgwLCBfdHJhbnNpdGlvbnMubWFrZVByb21pc2VzKSgncmVwbGFjZWQnLCBbb2xkRWxdLCBuZXdFbCk7XG5cbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ3JlcGxhY2VkJywgcmVwbGFjZVByb21pc2VzLCBmdW5jdGlvbiAocHJvbWlzZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbGxQcm9taXNlcy5wdXNoLmFwcGx5KGFsbFByb21pc2VzLCBwcm9taXNlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICB0cmlnZ2VyVHJhbnNpdGlvbignZGV0YWNoZWQnLCBkZXRhY2hQcm9taXNlcywgZnVuY3Rpb24gKHByb21pc2VzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgaWYgKHByb21pc2VzICYmIHByb21pc2VzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWxsUHJvbWlzZXMucHVzaC5hcHBseShhbGxQcm9taXNlcywgcHJvbWlzZXMpO1xuICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ2F0dGFjaGVkJywgYXR0YWNoUHJvbWlzZXMsIGZ1bmN0aW9uIChwcm9taXNlcykge1xuICAgICAgICAgICAgICAgICAgICAgIGlmIChwcm9taXNlcyAmJiBwcm9taXNlcy5maWx0ZXIoQm9vbGVhbikubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbGxQcm9taXNlcy5wdXNoLmFwcGx5KGFsbFByb21pc2VzLCBwcm9taXNlcyk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgYXR0YWNoKHsgdlRyZWU6IHBhdGNoLm5ldywgdHJpZ2dlclRyYW5zaXRpb246IHRyaWdnZXJUcmFuc2l0aW9uLCBzdGF0ZTogc3RhdGUgfSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIE9uY2UgYWxsIHRoZSBwcm9taXNlcyBoYXZlIGNvbXBsZXRlZCwgaW52b2tlIHRoZSBhY3Rpb24sIGlmIG5vXG4gICAgICAgICAgICAgICAgICAgIC8vIHByb21pc2VzIHdlcmUgYWRkZWQsIHRoaXMgd2lsbCBiZSBhIHN5bmNocm9ub3VzIG9wZXJhdGlvbi5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGFsbFByb21pc2VzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgIFByb21pc2UuYWxsKGFsbFByb21pc2VzKS50aGVuKGZ1bmN0aW9uIHJlcGxhY2VFbGVtZW50KCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9sZEVsLnBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgb2xkRWwucGFyZW50Tm9kZS5yZXBsYWNlQ2hpbGQobmV3RWwsIG9sZEVsKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIF9tZW1vcnkudW5wcm90ZWN0RWxlbWVudCkocGF0Y2gub2xkKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgKDAsIF9tZW1vcnkucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm5ldyk7XG4gICAgICAgICAgICAgICAgICAgICAgfSwgZnVuY3Rpb24gKGV4KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY29uc29sZS5sb2coZXgpO1xuICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgIGNoZWNrRm9yTWlzc2luZ1BhcmVudCgncmVwbGFjZScsIG9sZEVsLCBwYXRjaCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICBvbGRFbC5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChuZXdFbCwgb2xkRWwpO1xuICAgICAgICAgICAgICAgICAgICAgICgwLCBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm9sZCk7XG4gICAgICAgICAgICAgICAgICAgICAgKDAsIF9tZW1vcnkucHJvdGVjdEVsZW1lbnQpKHBhdGNoLm5ldyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgIH0pKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIEF0dHJpYnV0ZSBtYW5pcHVsYXRpb24uXG4gICAgICAgICAgZWxzZSBpZiAocGF0Y2guX19kb19fID09PSBfc3luYy5NT0RJRllfQVRUUklCVVRFKSB7XG4gICAgICAgICAgICAgIHZhciBhdHRyaWJ1dGVzID0gcGF0Y2guYXR0cmlidXRlcztcblxuICAgICAgICAgICAgICBhdHRyaWJ1dGVzLmZvckVhY2goZnVuY3Rpb24gKF9yZWYyKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9sZEF0dHIgPSBfcmVmMi5vbGRBdHRyO1xuICAgICAgICAgICAgICAgIHZhciBuZXdBdHRyID0gX3JlZjIubmV3QXR0cjtcblxuICAgICAgICAgICAgICAgIHZhciBuYW1lID0gbmV3QXR0ciA/IG5ld0F0dHIubmFtZSA6IG9sZEF0dHIubmFtZTtcbiAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSAob2xkQXR0ciA/IG9sZEF0dHIudmFsdWUgOiB1bmRlZmluZWQpIHx8IG51bGw7XG5cbiAgICAgICAgICAgICAgICB2YXIgYXR0ckNoYW5nZVByb21pc2VzID0gKDAsIF90cmFuc2l0aW9ucy5tYWtlUHJvbWlzZXMpKCdhdHRyaWJ1dGVDaGFuZ2VkJywgW2VsXSwgbmFtZSwgdmFsdWUsIG5ld0F0dHIgPyBuZXdBdHRyLnZhbHVlIDogbnVsbCk7XG5cbiAgICAgICAgICAgICAgICB0cmlnZ2VyVHJhbnNpdGlvbignYXR0cmlidXRlQ2hhbmdlZCcsIGF0dHJDaGFuZ2VQcm9taXNlcywgZnVuY3Rpb24gKHByb21pc2VzKSB7XG4gICAgICAgICAgICAgICAgICB2YXIgY2FsbGJhY2sgPSBmdW5jdGlvbiBjYWxsYmFjaygpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gQWx3YXlzIHJlbW92ZSB0aGUgb2xkIGF0dHJpYnV0ZSwgd2UgbmV2ZXIgcmUtdXNlIGl0LlxuICAgICAgICAgICAgICAgICAgICBpZiAob2xkQXR0cikge1xuICAgICAgICAgICAgICAgICAgICAgIF9wb29scy5wb29scy5hdHRyaWJ1dGVPYmplY3QudW5wcm90ZWN0KG9sZEF0dHIpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gUmVtb3ZlIHRoZSBWaXJ0dWFsIFRyZWUgQXR0cmlidXRlIGZyb20gdGhlIGVsZW1lbnQgYW5kIG1lbW9yeS5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoIW5ld0F0dHIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsLnJlbW92ZUF0dHJpYnV0ZShvbGRBdHRyLm5hbWUpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob2xkQXR0ci5uYW1lIGluIGVsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgIGVsW29sZEF0dHIubmFtZV0gPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQWRkL0NoYW5nZSB0aGUgYXR0cmlidXRlIG9yIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgICAgICBpZiAobmV3QXR0cikge1xuICAgICAgICAgICAgICAgICAgICAgIHZhciBpc09iamVjdCA9IF90eXBlb2YobmV3QXR0ci52YWx1ZSkgPT09ICdvYmplY3QnO1xuICAgICAgICAgICAgICAgICAgICAgIHZhciBpc0Z1bmN0aW9uID0gdHlwZW9mIG5ld0F0dHIudmFsdWUgPT09ICdmdW5jdGlvbic7XG5cbiAgICAgICAgICAgICAgICAgICAgICAvLyBQcm90ZWN0IHRoZSBWaXJ0dWFsIEF0dHJpYnV0ZSBvYmplY3QuXG4gICAgICAgICAgICAgICAgICAgICAgX3Bvb2xzLnBvb2xzLmF0dHJpYnV0ZU9iamVjdC5wcm90ZWN0KG5ld0F0dHIpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gSWYgbm90IGEgZHluYW1pYyB0eXBlLCBzZXQgYXMgYW4gYXR0cmlidXRlLCBzaW5jZSBpdCdzIGEgdmFsaWRcbiAgICAgICAgICAgICAgICAgICAgICAvLyBhdHRyaWJ1dGUgdmFsdWUuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc09iamVjdCAmJiAhaXNGdW5jdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG5ld0F0dHIubmFtZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICBlbC5zZXRBdHRyaWJ1dGUobmV3QXR0ci5uYW1lLCAoMCwgX2VudGl0aWVzLmRlY29kZUVudGl0aWVzKShuZXdBdHRyLnZhbHVlKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgbmV3QXR0ci52YWx1ZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIE5lY2Vzc2FyeSB0byB0cmFjayB0aGUgYXR0cmlidXRlL3Byb3AgZXhpc3RlbmNlLlxuICAgICAgICAgICAgICAgICAgICAgICAgZWwuc2V0QXR0cmlidXRlKG5ld0F0dHIubmFtZSwgJycpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBTaW5jZSB0aGlzIGlzIGEgZHluYW1pYyB2YWx1ZSBpdCBnZXRzIHNldCBhcyBhIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgICAgICAgICAgZWxbbmV3QXR0ci5uYW1lXSA9IG5ld0F0dHIudmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgLy8gU3VwcG9ydCBsaXZlIHVwZGF0aW5nIG9mIHRoZSB2YWx1ZSBhdHRyaWJ1dGUuXG4gICAgICAgICAgICAgICAgICAgICAgaWYgKG5ld0F0dHIubmFtZSA9PT0gJ3ZhbHVlJyB8fCBuZXdBdHRyLm5hbWUgPT09ICdjaGVja2VkJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxbbmV3QXR0ci5uYW1lXSA9IG5ld0F0dHIudmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGNhbGxiYWNrLCBmdW5jdGlvbiB1bmhhbmRsZWRFeGNlcHRpb24oKSB7fSk7XG4gICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVGV4dCBub2RlIG1hbmlwdWxhdGlvbi5cbiAgICAgICAgICAgIGVsc2UgaWYgKHBhdGNoLl9fZG9fXyA9PT0gX3N5bmMuQ0hBTkdFX1RFWFQpIHtcbiAgICAgICAgICAgICAgICB2YXIgdGV4dENoYW5nZVByb21pc2VzID0gKDAsIF90cmFuc2l0aW9ucy5tYWtlUHJvbWlzZXMpKCd0ZXh0Q2hhbmdlZCcsIFtlbF0sIGVsLm5vZGVWYWx1ZSwgcGF0Y2gudmFsdWUpO1xuXG4gICAgICAgICAgICAgICAgdHJpZ2dlclRyYW5zaXRpb24oJ3RleHRDaGFuZ2VkJywgdGV4dENoYW5nZVByb21pc2VzLCBmdW5jdGlvbiAocHJvbWlzZXMpIHtcbiAgICAgICAgICAgICAgICAgIHZhciBjYWxsYmFjayA9IGZ1bmN0aW9uIGNhbGxiYWNrKCkge1xuICAgICAgICAgICAgICAgICAgICBwYXRjaC5lbGVtZW50Lm5vZGVWYWx1ZSA9ICgwLCBfZW50aXRpZXMuZGVjb2RlRW50aXRpZXMpKHBhdGNoLnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgZWwubm9kZVZhbHVlID0gcGF0Y2guZWxlbWVudC5ub2RlVmFsdWU7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGVsLnBhcmVudE5vZGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICB2YXIgbm9kZU5hbWUgPSBlbC5wYXJlbnROb2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICBpZiAoX3BhcnNlci5ibG9ja1RleHQuaGFzKG5vZGVOYW1lKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZWwucGFyZW50Tm9kZS5ub2RlVmFsdWUgPSAoMCwgX2VudGl0aWVzLmRlY29kZUVudGl0aWVzKShwYXRjaC5lbGVtZW50Lm5vZGVWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgICBpZiAocHJvbWlzZXMgJiYgcHJvbWlzZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgIH1cbiAgfTtcblxuICBmb3IgKHZhciBpID0gMDsgaSA8IHBhdGNoZXMubGVuZ3RoOyBpKyspIHtcbiAgICBfbG9vcChpKTtcbiAgfVxuXG4gIC8vIFJldHVybiB0aGUgUHJvbWlzZXMgdGhhdCB3ZXJlIGFsbG9jYXRlZCBzbyB0aGF0IHJlbmRlcmluZyBjYW4gYmUgYmxvY2tlZFxuICAvLyB1bnRpbCB0aGV5IHJlc29sdmUuXG4gIHJldHVybiBwcm9taXNlcy5maWx0ZXIoQm9vbGVhbik7XG59XG5cbn0se1wiLi4vdHJlZS9zeW5jXCI6OSxcIi4uL3V0aWwvY2FjaGVcIjoxMCxcIi4uL3V0aWwvZW50aXRpZXNcIjoxMSxcIi4uL3V0aWwvbWVtb3J5XCI6MTMsXCIuLi91dGlsL3BhcnNlclwiOjE0LFwiLi4vdXRpbC9wb29sc1wiOjE1LFwiLi4vdXRpbC90cmFuc2l0aW9uc1wiOjE4LFwiLi9tYWtlXCI6M31dLDU6W2Z1bmN0aW9uKF9kZXJlcV8sbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuZXhwb3J0cy5kZWZhdWx0ID0gcmVsZWFzZU5vZGU7XG5cbnZhciBfY2FjaGUgPSBfZGVyZXFfKCcuLi91dGlsL2NhY2hlJyk7XG5cbnZhciBfbWVtb3J5ID0gX2RlcmVxXygnLi4vdXRpbC9tZW1vcnknKTtcblxuLyoqXG4gKiBSZWxlYXNlcyBzdGF0ZSBhbmQgcmVjeWNsZXMgaW50ZXJuYWwgbWVtb3J5LlxuICpcbiAqIEBwYXJhbSBub2RlIHtPYmplY3R9IC0gQSBET00gTm9kZSB0byBsb29rdXAgc3RhdGUgZnJvbVxuICovXG5mdW5jdGlvbiByZWxlYXNlTm9kZShub2RlKSB7XG4gIC8vIFRyeSBhbmQgZmluZCBhIHN0YXRlIG9iamVjdCBmb3IgdGhpcyBET00gTm9kZS5cbiAgdmFyIHN0YXRlID0gX2NhY2hlLlN0YXRlQ2FjaGUuZ2V0KG5vZGUpO1xuXG4gIC8vIElmIHRoZXJlIGlzIGEgVmlydHVhbCBUcmVlIGVsZW1lbnQsIHJlY3ljbGUgYWxsIG9iamVjdHMgYWxsb2NhdGVkIGZvciBpdC5cbiAgaWYgKHN0YXRlICYmIHN0YXRlLm9sZFRyZWUpIHtcbiAgICAoMCwgX21lbW9yeS51bnByb3RlY3RFbGVtZW50KShzdGF0ZS5vbGRUcmVlKTtcbiAgfVxuXG4gIC8vIFJlbW92ZSB0aGUgTm9kZSdzIHN0YXRlIG9iamVjdCBmcm9tIHRoZSBjYWNoZS5cbiAgX2NhY2hlLlN0YXRlQ2FjaGUuZGVsZXRlKG5vZGUpO1xuXG4gIC8vIFJlY3ljbGUgYWxsIHVucHJvdGVjdGVkIG9iamVjdHMuXG4gICgwLCBfbWVtb3J5LmNsZWFuTWVtb3J5KSgpO1xufVxuXG59LHtcIi4uL3V0aWwvY2FjaGVcIjoxMCxcIi4uL3V0aWwvbWVtb3J5XCI6MTN9XSw2OltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF90eXBlb2YgPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gXCJzeW1ib2xcIiA/IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIHR5cGVvZiBvYmo7IH0gOiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmogJiYgdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sID8gXCJzeW1ib2xcIiA6IHR5cGVvZiBvYmo7IH07XG5cbmV4cG9ydHMuZGVmYXVsdCA9IGNyZWF0ZVRyYW5zYWN0aW9uO1xuXG52YXIgX3BhdGNoID0gX2RlcmVxXygnLi9wYXRjaCcpO1xuXG52YXIgX3BhdGNoMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX3BhdGNoKTtcblxudmFyIF9maW5hbGl6ZSA9IF9kZXJlcV8oJy4vZmluYWxpemUnKTtcblxudmFyIF9maW5hbGl6ZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9maW5hbGl6ZSk7XG5cbnZhciBfbWFrZSA9IF9kZXJlcV8oJy4uL3RyZWUvbWFrZScpO1xuXG52YXIgX21ha2UyID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfbWFrZSk7XG5cbnZhciBfc3luYyA9IF9kZXJlcV8oJy4uL3RyZWUvc3luYycpO1xuXG52YXIgX3N5bmMyID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfc3luYyk7XG5cbnZhciBfaGVscGVycyA9IF9kZXJlcV8oJy4uL3RyZWUvaGVscGVycycpO1xuXG52YXIgX21lbW9yeSA9IF9kZXJlcV8oJy4uL3V0aWwvbWVtb3J5Jyk7XG5cbnZhciBfcGFyc2VyID0gX2RlcmVxXygnLi4vdXRpbC9wYXJzZXInKTtcblxudmFyIF9wb29scyA9IF9kZXJlcV8oJy4uL3V0aWwvcG9vbHMnKTtcblxudmFyIF9jYWNoZSA9IF9kZXJlcV8oJy4uL3V0aWwvY2FjaGUnKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuLyoqXG4gKiBJZiBkaWZmSFRNTCBpcyByZW5kZXJpbmcgYW55d2hlcmUgYXN5bmNocm9ub3VzbHksIHdlIG5lZWQgdG8gd2FpdCB1bnRpbCBpdFxuICogY29tcGxldGVzIGJlZm9yZSB0aGlzIHJlbmRlciBjYW4gYmUgZXhlY3V0ZWQuIFRoaXMgc2V0cyB1cCB0aGUgbmV4dCBidWZmZXIsXG4gKiBpZiBuZWNlc3NhcnksIHdoaWNoIHNlcnZlcyBhcyBhIEJvb2xlYW4gZGV0ZXJtaW5hdGlvbiBsYXRlciB0byBgYnVmZmVyU2V0YC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gc3RhdGUgLSBUaGUgY3VycmVudCBET00gTm9kZSBzdGF0ZSB3aXRoaW4gZGlmZkhUTUxcbiAqIEBwYXJhbSB7T2JqZWN0fSBuZXh0UmVuZGVyIC0gVGhlIHJlc3BlY3RpdmUgYXJndW1lbnRzIHRvIHNldCBidWZmZXJcbiAqIEByZXR1cm4ge0Jvb2xlYW59IC0gV2hldGhlciBvciBub3QgZGlmZkhUTUwgaXMgY3VycmVudGx5IHJlbmRlcmluZ1xuICovXG52YXIgc2V0QnVmZmVyU3RhdGUgPSBmdW5jdGlvbiBzZXRCdWZmZXJTdGF0ZShzdGF0ZSwgbmV4dFJlbmRlcikge1xuICAvLyBMb29rIHVwIGFsbCBleGlzdGluZyBzdGF0ZXMgZm9yIGFueSByZW5kZXJpbmcsIGFuZCBzZXQgdGhlIG5leHQgcmVuZGVyXG4gIC8vIGJ1ZmZlciBpZiBibG9ja2VkLlxuICBfY2FjaGUuU3RhdGVDYWNoZS5mb3JFYWNoKGZ1bmN0aW9uIChfc3RhdGUpIHtcbiAgICAvLyBJZiB3ZSBhdHRhY2ggYSBuZXh0UmVuZGVyLCB0aGVuIHRoZSBidWZmZXIgaGFzIGJlZW4gc2V0LlxuICAgIGlmIChfc3RhdGUuaXNSZW5kZXJpbmcpIHtcbiAgICAgIHN0YXRlLm5leHRSZW5kZXIgPSBuZXh0UmVuZGVyO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gTGV0IG91dHNpZGUgY29kZSBrbm93IGlmIHdlIHdlcmUgYmxvY2tlZC5cbiAgcmV0dXJuIEJvb2xlYW4oc3RhdGUubmV4dFJlbmRlcik7XG59O1xuXG4vKipcbiAqIEdldHMgYSBWaXJ0dWFsIFRyZWUgRWxlbWVudCBmcm9tIHRoZSBuZXdIVE1MIHBhc3NlZCB0byBhIGRpZmYgbWV0aG9kLlxuICpcbiAqIEBwYXJhbSB7U3RyaW5nfE9iamVjdH0gbmV3SFRNTCAtIEhUTUwvRE9NIE5vZGUvVmlydHVhbCBUcmVlIEVsZW1lbnRcbiAqIEByZXR1cm4ge09iamVjdH0gLSBWaXJ0dWFsIFRyZWUgRWxlbWVudFxuICovXG52YXIgZ2V0VHJlZUZyb21OZXdIVE1MID0gZnVuY3Rpb24gZ2V0VHJlZUZyb21OZXdIVE1MKG5ld0hUTUwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gIC8vIFRoaXMgaXMgSFRNTCBNYXJrdXAsIHNvIHdlIG5lZWQgdG8gcGFyc2UgaXQuXG4gIGlmICh0eXBlb2YgbmV3SFRNTCA9PT0gJ3N0cmluZycpIHtcbiAgICB2YXIgc2lsZW5jZVdhcm5pbmdzID0gb3B0aW9ucy5zaWxlbmNlV2FybmluZ3M7XG4gICAgdmFyIGNoaWxkTm9kZXMgPSAoMCwgX3BhcnNlci5wYXJzZSkobmV3SFRNTCwgbnVsbCwgeyBzaWxlbmNlV2FybmluZ3M6IHNpbGVuY2VXYXJuaW5ncyB9KS5jaGlsZE5vZGVzO1xuXG4gICAgLy8gSWYgd2UgYXJlIGRlYWxpbmcgd2l0aCBpbm5lckhUTUwsIHVzZSBhbGwgdGhlIE5vZGVzLiBJZiB3ZSdyZSBkZWFsaW5nXG4gICAgLy8gd2l0aCBvdXRlckhUTUwsIHdlIGNhbiBvbmx5IHN1cHBvcnQgZGlmZmluZyBhZ2FpbnN0IGEgc2luZ2xlIGVsZW1lbnQsXG4gICAgLy8gc28gcGljayB0aGUgZmlyc3Qgb25lLlxuICAgIHJldHVybiBjYWxsYmFjayhjaGlsZE5vZGVzKTtcbiAgfVxuICAvLyBUaGlzIGlzIGEgRE9NIE5vZGUsIHNvIHdlIG5lZWQgdG8gY29udmVydCB0byBhIHZUcmVlLlxuICBlbHNlIGlmIChuZXdIVE1MLm93bmVyRG9jdW1lbnQpIHtcbiAgICAgIHZhciBuZXdUcmVlID0gKDAsIF9tYWtlMi5kZWZhdWx0KShuZXdIVE1MKTtcblxuICAgICAgaWYgKG5ld1RyZWUubm9kZVR5cGUgPT09IDExKSB7XG4gICAgICAgIF9wb29scy5wb29scy5lbGVtZW50T2JqZWN0LnVucHJvdGVjdChuZXdUcmVlKTtcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG5ld1RyZWUuY2hpbGROb2Rlcyk7XG4gICAgICB9XG5cbiAgICAgIHJldHVybiBjYWxsYmFjayhuZXdUcmVlKTtcbiAgICB9XG5cbiAgLy8gVGhpcyBpcyBhIFZpcnR1YWwgVHJlZSBFbGVtZW50LCBvciBzb21ldGhpbmcgbGlrZSBpdCwgc28gd2UgY2FuIGp1c3QgcGFzc1xuICAvLyBpdCBhbG9uZy5cbiAgcmV0dXJuIGNhbGxiYWNrKG5ld0hUTUwpO1xufTtcblxuLyoqXG4gKiBDcmVhdGVzIGEgc2VxdWVudGlhbCByZW5kZXIgdHJhbnNhY3Rpb24gb24gYSBET00gTm9kZS4gVGhpcyByZXF1aXJlc1xuICogY2hlY2tpbmcgZm9yIGEgcHJldmlvdXMgcmVuZGVyIGZpcnN0LiBTaW5jZSBkaWZmSFRNTCBpcyBnbG9iYWxseSBjb25uZWN0ZWRcbiAqIChob3BlZnVsbHkgb25seSBydW5uaW5nIG9uZSBjb3B5Li4uKSwgdGhpcyB3aWxsIHByZXZlbnQgdHJhbnNpdGlvbnMgZnJvbVxuICogaW50ZXJmZXJyaW5nLlxuICpcbiAqIEBwYXJhbSBub2RlXG4gKiBAcGFyYW0gbmV3SFRNTFxuICogQHBhcmFtIG9wdGlvbnNcbiAqL1xuZnVuY3Rpb24gY3JlYXRlVHJhbnNhY3Rpb24obm9kZSwgbmV3SFRNTCwgb3B0aW9ucykge1xuICBpZiAoKHR5cGVvZiBub2RlID09PSAndW5kZWZpbmVkJyA/ICd1bmRlZmluZWQnIDogX3R5cGVvZihub2RlKSkgIT09ICdvYmplY3QnKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIERPTSBOb2RlIG9iamVjdCcpO1xuICB9XG5cbiAgLy8gVXNlZCB0byBhc3NvY2lhdGUgc3RhdGUgd2l0aCB0aGUgY3VycmVudGx5IHJlbmRlcmluZyBub2RlLiBUaGlzXG4gIC8vIHByZXZlbnRzIGF0dGFjaGluZyBwcm9wZXJ0aWVzIHRvIHRoZSBpbnN0YW5jZSBpdHNlbGYuXG4gIHZhciBzdGF0ZSA9IF9jYWNoZS5TdGF0ZUNhY2hlLmdldChub2RlKSB8fCB7fTtcbiAgdmFyIGlzSW5uZXIgPSBvcHRpb25zLmlubmVyO1xuICB2YXIgcHJldmlvdXNNYXJrdXAgPSBzdGF0ZS5wcmV2aW91c01hcmt1cDtcbiAgdmFyIHByZXZpb3VzVGV4dCA9IHN0YXRlLnByZXZpb3VzVGV4dDtcbiAgdmFyIGJ1ZmZlclNldCA9IHNldEJ1ZmZlclN0YXRlKHN0YXRlLCB7IG5vZGU6IG5vZGUsIG5ld0hUTUw6IG5ld0hUTUwsIG9wdGlvbnM6IG9wdGlvbnMgfSk7XG5cbiAgLy8gQXNzb2NpYXRlIHRoZSBjdXJyZW50IHJlbmRlciBvcHRpb25zIHdpdGggdGhlIERPTSBOb2RlIHN0YXRlLlxuICBzdGF0ZS5vcHRpb25zID0gb3B0aW9ucztcblxuICAvLyBBbHdheXMgZW5zdXJlIHRoZSBtb3N0IHVwLXRvLWRhdGUgc3RhdGUgb2JqZWN0IGlzIHN0b3JlZC5cbiAgX2NhY2hlLlN0YXRlQ2FjaGUuc2V0KG5vZGUsIHN0YXRlKTtcblxuICAvLyBTaG9ydCBjaXJjdWl0IHRoZSByZXN0IG9mIHRoaXMgcmVuZGVyIGlmIHdlIGVuZGVkIHVwIGhhdmluZyB0byBzZXQgYVxuICAvLyBidWZmZXIuIFRoaXMgaGFwcGVucyB3aGVuIHNvbWUgb3RoZXIgY29kZSB1c2luZyBkaWZmSFRNTCBpcyByZW5kZXJpbmdcbiAgLy8gYXN5bmNocm9ub3VzbHkgKHVzaW5nIHRyYW5zaXRpb25zIHcvIFByb21pc2UpLlxuICBpZiAoYnVmZmVyU2V0KSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gVGhpcyBsb29rcyBmb3IgY2hhbmdlcyBpbiB0aGUgRE9NIGZyb20gd2hhdCB3ZSdkIGV4cGVjdC4gVGhpcyBtZWFucyB3ZVxuICAvLyBuZWVkIHRvIHJlYnVpbGQgdGhlIG9sZCBWaXJ0dWFsIFRyZWUuIFRoaXMgYWxsb3dzIGZvciBrZWVwaW5nIG91ciB0cmVlIGluXG4gIC8vIHN5bmMgd2l0aCB1bmV4cGVjdGVkIERPTSBjaGFuZ2VzLiBJdCdzIG5vdCB2ZXJ5IHBlcmZvcm1hbnQsIHNvIGlkZWFsbHkgeW91XG4gIC8vIHNob3VsZCBuZXZlciBjaGFuZ2UgbWFya3VwIHRoYXQgZGlmZkhUTUwgYWZmZWN0cyBmcm9tIG91dHNpZGUgb2YgZGlmZkhUTUxcbiAgLy8gaWYgcGVyZm9ybWFuY2UgaXMgYSBjb25jZXJuLlxuICB2YXIgc2FtZUlubmVySFRNTCA9IGlzSW5uZXIgPyBwcmV2aW91c01hcmt1cCA9PT0gbm9kZS5pbm5lckhUTUwgOiB0cnVlO1xuICB2YXIgc2FtZU91dGVySFRNTCA9ICFpc0lubmVyID8gcHJldmlvdXNNYXJrdXAgPT09IG5vZGUub3V0ZXJIVE1MIDogdHJ1ZTtcbiAgdmFyIHNhbWVUZXh0Q29udGVudCA9IHByZXZpb3VzVGV4dCA9PT0gbm9kZS50ZXh0Q29udGVudDtcblxuICAvLyBJZiB0aGUgY29udGVudHMgaGF2ZW4ndCBjaGFuZ2VkLCBhYm9ydCwgc2luY2UgdGhlcmUgaXMgbm8gcG9pbnQgaW5cbiAgLy8gY29udGludWluZy4gT25seSBzdXBwb3J0IHRoaXMgaWYgdGhlIG5ldyBtYXJrdXAgaXMgYSBzdHJpbmcsIG90aGVyd2lzZVxuICAvLyBpdCdzIHBvc3NpYmxlIGZvciBvdXIgb2JqZWN0IHJlY3ljbGluZyB0byBtYXRjaCB0d2ljZS5cbiAgaWYgKHR5cGVvZiBuZXdIVE1MID09PSAnc3RyaW5nJyAmJiBzdGF0ZS5uZXdIVE1MID09PSBuZXdIVE1MKSB7XG4gICAgcmV0dXJuO1xuICB9XG4gIC8vIEFzc29jaWF0ZSB0aGUgbGFzdCBtYXJrdXAgcmVuZGVyZWQgd2l0aCB0aGlzIG5vZGUuXG4gIGVsc2UgaWYgKHR5cGVvZiBuZXdIVE1MID09PSAnc3RyaW5nJykge1xuICAgICAgc3RhdGUubmV3SFRNTCA9IG5ld0hUTUw7XG4gICAgfVxuXG4gIC8vIFdlIHJlYnVpbGQgdGhlIHRyZWUgd2hlbmV2ZXIgdGhlIERPTSBOb2RlIGNoYW5nZXMsIGluY2x1ZGluZyB0aGUgZmlyc3RcbiAgLy8gdGltZSB3ZSBwYXRjaCBhIERPTSBOb2RlLlxuICB2YXIgcmVidWlsZFRyZWUgPSBmdW5jdGlvbiByZWJ1aWxkVHJlZSgpIHtcbiAgICB2YXIgb2xkVHJlZSA9IHN0YXRlLm9sZFRyZWU7XG5cbiAgICBpZiAob2xkVHJlZSkge1xuICAgICAgKDAsIF9tZW1vcnkudW5wcm90ZWN0RWxlbWVudCkob2xkVHJlZSk7XG4gICAgfVxuXG4gICAgc3RhdGUub2xkVHJlZSA9ICgwLCBfbWVtb3J5LnByb3RlY3RFbGVtZW50KSgoMCwgX21ha2UyLmRlZmF1bHQpKG5vZGUpKTtcbiAgfTtcblxuICBpZiAoIXNhbWVJbm5lckhUTUwgfHwgIXNhbWVPdXRlckhUTUwgfHwgIXNhbWVUZXh0Q29udGVudCkge1xuICAgIHJlYnVpbGRUcmVlKCk7XG4gIH1cblxuICAvLyBXZSdyZSByZW5kZXJpbmcgaW4gdGhlIFVJIHRocmVhZC5cbiAgc3RhdGUuaXNSZW5kZXJpbmcgPSB0cnVlO1xuXG4gIC8vIFN0b3JlIGFsbCB0cmFuc2FjdGlvbiBzdGFydGluZyBtaWRkbGV3YXJlIGZ1bmN0aW9ucyBiZWluZyBleGVjdXRlZCBoZXJlLlxuICB2YXIgc3RhcnRUcmFuc2FjdGlvbk1pZGRsZXdhcmVzID0gW107XG5cbiAgLy8gU3RhcnQgb2ZmIHRoZSBtaWRkbGV3YXJlIGV4ZWN1dGlvbi5cbiAgX2NhY2hlLk1pZGRsZXdhcmVDYWNoZS5mb3JFYWNoKGZ1bmN0aW9uIChleGVjdXRlTWlkZGxld2FyZSkge1xuICAgIC8vIFBhc3MgdGhlIHN0YXJ0IHRyYW5zYWN0aW9uIGNhbGwgd2l0aCB0aGUgaW5wdXQgYXJndW1lbnRzLlxuICAgIHZhciByZXN1bHQgPSBleGVjdXRlTWlkZGxld2FyZSh7IG5vZGU6IG5vZGUsIG5ld0hUTUw6IG5ld0hUTUwsIG9wdGlvbnM6IG9wdGlvbnMgfSk7XG5cbiAgICBpZiAocmVzdWx0KSB7XG4gICAgICBzdGFydFRyYW5zYWN0aW9uTWlkZGxld2FyZXMucHVzaChyZXN1bHQpO1xuICAgIH1cbiAgfSk7XG5cbiAgLy8gQWxpYXMgdGhlIGBvbGRUcmVlYCBvZmYgb2Ygc3RhdGUgZm9yIHBhcml0eS5cbiAgdmFyIG9sZFRyZWUgPSBzdGF0ZS5vbGRUcmVlO1xuXG4gIC8vIFdlIG5lZWQgdG8gZW5zdXJlIHRoYXQgb3VyIHRhcmdldCB0byBkaWZmIGlzIGEgVmlydHVhbCBUcmVlIEVsZW1lbnQuIFRoaXNcbiAgLy8gZnVuY3Rpb24gdGFrZXMgaW4gd2hhdGV2ZXIgYG5ld0hUTUxgIGlzIGFuZCBub3JtYWxpemVzIHRvIGEgdHJlZSBvYmplY3QuXG4gIC8vIFRoZSBjYWxsYmFjayBmdW5jdGlvbiBydW5zIG9uIGV2ZXJ5IG5vcm1hbGl6ZWQgTm9kZSB0byB3cmFwIGNoaWxkTm9kZXNcbiAgLy8gaW4gdGhlIGNhc2Ugb2Ygc2V0dGluZyBpbm5lckhUTUwuXG4gIHZhciBuZXdUcmVlID0gZ2V0VHJlZUZyb21OZXdIVE1MKG5ld0hUTUwsIG9wdGlvbnMsIGZ1bmN0aW9uIChuZXdUcmVlKSB7XG4gICAgaWYgKGlzSW5uZXIpIHtcbiAgICAgIF9wb29scy5wb29scy5lbGVtZW50T2JqZWN0LnVucHJvdGVjdChuZXdUcmVlKTtcblxuICAgICAgdmFyIG5vZGVOYW1lID0gc3RhdGUub2xkVHJlZS5ub2RlTmFtZTtcbiAgICAgIHZhciBhdHRyaWJ1dGVzID0gc3RhdGUub2xkVHJlZS5hdHRyaWJ1dGVzO1xuXG4gICAgICByZXR1cm4gKDAsIF9oZWxwZXJzLmNyZWF0ZUVsZW1lbnQpKG5vZGVOYW1lLCBhdHRyaWJ1dGVzLCBuZXdUcmVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4gQXJyYXkuaXNBcnJheShuZXdUcmVlKSA/IG5ld1RyZWVbMF0gOiBuZXdUcmVlO1xuICB9KTtcblxuICAvLyBUcmlnZ2VyIGFueSBtaWRkbGV3YXJlIHdpdGggdGhlIERPTSBOb2RlLCBvbGQgVmlydHVhbCBUcmVlIEVsZW1lbnQsIGFuZFxuICAvLyBuZXcgVmlydHVhbCBUcmVlIEVsZW1lbnQuIFRoaXMgYWxsb3dzIHRoZSBtaWRkbGV3YXJlIHRvIG11dGF0ZSBhbmQgaW5zcGVjdFxuICAvLyB0aGUgdHJlZXMgYmVmb3JlIHRoZXkgZ2V0IGNvbnN1bWVkIGJ5IGRpZmZIVE1MLlxuICB2YXIgcHJlUGF0Y2hNaWRkbGV3YXJlcyA9IFtdO1xuXG4gIC8vIEJ5IGV4cG9zaW5nIHRoZSBpbnRlcm5hbCB0cmVlIHN5bmNocm9uaXphdGlvbiBhbmQgRE9NIE5vZGUgcGF0Y2ggbWV0aG9kcyxcbiAgLy8gYSBtaWRkbGV3YXJlIGNvdWxkIGltcGxlbWVudCBzeW5jL3BhdGNoIG9uIGEgc2VwYXJhdGUgdGhyZWFkLlxuICB2YXIgdHJhbnNhY3Rpb25NZXRob2RzID0ge1xuICAgIHN5bmNUcmVlOiBfc3luYzIuZGVmYXVsdCxcbiAgICBwYXRjaE5vZGU6IF9wYXRjaDIuZGVmYXVsdCxcbiAgICBwcm90ZWN0RWxlbWVudDogX21lbW9yeS5wcm90ZWN0RWxlbWVudCxcbiAgICB1bnByb3RlY3RFbGVtZW50OiBfbWVtb3J5LnVucHJvdGVjdEVsZW1lbnRcbiAgfTtcblxuICAvLyBTYXZlIHRoZSBjdXJyZW50IHRyYW5zYWN0aW9uIHRyZWUgc3RhdGUgYW5kIGFsbG93IHRoZSBtZGlkbGV3YXJlIHRvXG4gIC8vIG92ZXJyaWRlIHRoZSB0cmVlcy5cbiAgdmFyIHRyYW5zYWN0aW9uU3RhdGUgPSB7XG4gICAgb2xkVHJlZTogb2xkVHJlZSxcbiAgICBuZXdUcmVlOiBuZXdUcmVlLFxuICAgIHRyYW5zYWN0aW9uTWV0aG9kczogdHJhbnNhY3Rpb25NZXRob2RzXG4gIH07XG5cbiAgLy8gUnVuIGVhY2ggbWlkZGxld2FyZSBhbmQgcGFzcyB0aGUgdHJhbnNhY3Rpb24gc3RhdGUgd2hpY2ggY29udGFpbnMgaW50ZXJuYWxcbiAgLy8gZnVuY3Rpb25zIG90aGVyd2lzZSBub3QgYXZhaWxhYmxlIGJ5IHRoZSBwdWJsaWMgQVBJLlxuICBmb3IgKHZhciBpID0gMDsgaSA8IHN0YXJ0VHJhbnNhY3Rpb25NaWRkbGV3YXJlcy5sZW5ndGg7IGkrKykge1xuICAgIC8vIFBhc3MgdGhlIHRoZSBleGlzdGluZyBWaXJ0dWFsIFRyZWUgRWxlbWVudCwgYW5kIHRoZSBuZXcgVmlydHVhbCBUcmVlXG4gICAgLy8gRWxlbWVudC4gVGhpcyBpcyB0cmlnZ2VyZWQgYmVmb3JlIHRoZSBzeW5jaHJvbml6YXRpb24gYW5kIHBhdGNoaW5nIGhhc1xuICAgIC8vIG9jY3VyZWQuXG4gICAgdmFyIHJlc3VsdCA9IHN0YXJ0VHJhbnNhY3Rpb25NaWRkbGV3YXJlc1tpXSh0cmFuc2FjdGlvblN0YXRlKTtcblxuICAgIGlmIChyZXN1bHQpIHtcbiAgICAgIHByZVBhdGNoTWlkZGxld2FyZXMucHVzaChyZXN1bHQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFN5bmNocm9uaXplIHRoZSB0cmVlcywgdXNlIGFueSBtaWRkbGV3YXJlIHJlcGxhY2VtZW50cywgaWYgc3VwcGxpZWQuXG4gIHZhciBwYXRjaGVzID0gKDAsIF9zeW5jMi5kZWZhdWx0KSh0cmFuc2FjdGlvblN0YXRlLm9sZFRyZWUsIHRyYW5zYWN0aW9uU3RhdGUubmV3VHJlZSk7XG5cbiAgLy8gQXBwbHkgdGhlIHNldCBvZiBwYXRjaGVzIHRvIHRoZSBOb2RlLlxuICB2YXIgcHJvbWlzZXMgPSAoMCwgX3BhdGNoMi5kZWZhdWx0KShub2RlLCBwYXRjaGVzKTtcblxuICAvLyBUcmlnZ2VyIGFueSBtaWRkbGV3YXJlIGFmdGVyIHN5bmNpbmcgYW5kIHBhdGNoaW5nIHRoZSBlbGVtZW50LiBUaGlzIGlzXG4gIC8vIG1haW5seSB1c2VmdWwgdG8gZ2V0IHRoZSBQcm9taXNlcyBmb3Igc29tZXRoaW5nIGxpa2UgZGV2dG9vbHMgYW5kIHBhdGNoZXNcbiAgLy8gZm9yIHNvbWV0aGluZyBsaWtlIGxvZ2dpbmcuXG4gIHZhciBwb3N0UGF0Y2hNaWRkbGV3YXJlcyA9IFtdO1xuXG4gIGZvciAodmFyIF9pID0gMDsgX2kgPCBwcmVQYXRjaE1pZGRsZXdhcmVzLmxlbmd0aDsgX2krKykge1xuICAgIC8vIFRoZSBET00gTm9kZSBwYXRjaGluZyBoYXMgZmluaXNoZWQgYW5kIG5vdyB3ZSdyZSBzZW5kaW5nIHRoZSBwYXRjaHNldFxuICAgIC8vIGFuZCB0aGUgcHJvbWlzZXMgd2hpY2ggY2FuIGFsc28gYmUgcHVzaGVkIGludG8gdG8gZG8gc29tZSBhc3luY2hyb25vdXNcbiAgICAvLyBiZWhhdmlvciBpbiBhIG1pZGRsZXdhcmUuXG4gICAgdmFyIF9yZXN1bHQgPSBwcmVQYXRjaE1pZGRsZXdhcmVzW19pXSh7XG4gICAgICBwYXRjaGVzOiBwYXRjaGVzLFxuICAgICAgcHJvbWlzZXM6IHByb21pc2VzXG4gICAgfSk7XG5cbiAgICBpZiAoX3Jlc3VsdCkge1xuICAgICAgcG9zdFBhdGNoTWlkZGxld2FyZXMucHVzaChfcmVzdWx0KTtcbiAgICB9XG4gIH1cblxuICAvLyBDbGVhbiB1cCBhbmQgZmluYWxpemUgdGhpcyB0cmFuc2FjdGlvbi4gSWYgdGhlcmUgaXMgYW5vdGhlciB0cmFuc2FjdGlvbixcbiAgLy8gZ2V0IGEgY2FsbGJhY2sgdG8gcnVuIG9uY2UgdGhpcyBjb21wbGV0ZXMgdG8gcnVuIGl0LlxuICB2YXIgZmluYWxpemVUcmFuc2FjdGlvbiA9ICgwLCBfZmluYWxpemUyLmRlZmF1bHQpKG5vZGUsIHN0YXRlKTtcblxuICAvLyBPcGVyYXRlIHN5bmNocm9ub3VzbHkgdW5sZXNzIG9wdGVkIGludG8gYSBQcm9taXNlLWNoYWluLiBEb2Vzbid0IG1hdHRlciBpZlxuICAvLyB0aGV5IGFyZSBhY3R1YWxseSBQcm9taXNlcyBvciBub3QsIHNpbmNlIHRoZXkgd2lsbCBhbGwgcmVzb2x2ZSBldmVudHVhbGx5XG4gIC8vIHdpdGggYFByb21pc2UuYWxsYC5cbiAgaWYgKHByb21pc2VzLmxlbmd0aCkge1xuICAgIFByb21pc2UuYWxsKHByb21pc2VzKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgIGZpbmFsaXplVHJhbnNhY3Rpb24ocG9zdFBhdGNoTWlkZGxld2FyZXMpO1xuICAgIH0sIGZ1bmN0aW9uIChleCkge1xuICAgICAgcmV0dXJuIGNvbnNvbGUubG9nKGV4KTtcbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICAvLyBQYXNzIG9mZiB0aGUgcmVtYWluaW5nIG1pZGRsZXdhcmUgdG8gYWxsb3cgdXNlcnMgdG8gZGl2ZSBpbnRvIHRoZVxuICAgIC8vIHRyYW5zYWN0aW9uIGNvbXBsZXRlZCBsaWZlY3ljbGUgZXZlbnQuXG4gICAgZmluYWxpemVUcmFuc2FjdGlvbihwb3N0UGF0Y2hNaWRkbGV3YXJlcyk7XG4gIH1cbn1cblxufSx7XCIuLi90cmVlL2hlbHBlcnNcIjo3LFwiLi4vdHJlZS9tYWtlXCI6OCxcIi4uL3RyZWUvc3luY1wiOjksXCIuLi91dGlsL2NhY2hlXCI6MTAsXCIuLi91dGlsL21lbW9yeVwiOjEzLFwiLi4vdXRpbC9wYXJzZXJcIjoxNCxcIi4uL3V0aWwvcG9vbHNcIjoxNSxcIi4vZmluYWxpemVcIjoyLFwiLi9wYXRjaFwiOjR9XSw3OltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF90eXBlb2YgPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gXCJzeW1ib2xcIiA/IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIHR5cGVvZiBvYmo7IH0gOiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmogJiYgdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sID8gXCJzeW1ib2xcIiA6IHR5cGVvZiBvYmo7IH07XG5cbmV4cG9ydHMuY3JlYXRlRWxlbWVudCA9IGNyZWF0ZUVsZW1lbnQ7XG5leHBvcnRzLmNyZWF0ZUF0dHJpYnV0ZSA9IGNyZWF0ZUF0dHJpYnV0ZTtcblxudmFyIF9wb29scyA9IF9kZXJlcV8oJy4uL3V0aWwvcG9vbHMnKTtcblxudmFyIF9lc2NhcGUgPSBfZGVyZXFfKCcuLi91dGlsL2VzY2FwZScpO1xuXG52YXIgX2VzY2FwZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9lc2NhcGUpO1xuXG52YXIgX21ha2UgPSBfZGVyZXFfKCcuLi90cmVlL21ha2UnKTtcblxudmFyIF9tYWtlMiA9IF9pbnRlcm9wUmVxdWlyZURlZmF1bHQoX21ha2UpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBkZWZhdWx0OiBvYmogfTsgfVxuXG4vKipcbiAqIFRPRE8gUGhhc2UgdGhpcyBvdXQgaWYgcG9zc2libGUsIHN1cGVyIHNsb3cgaXRlcmF0aW9ucy4uLlxuICpcbiAqIEBwYXJhbSBjaGlsZE5vZGVzXG4gKiBAcmV0dXJuXG4gKi9cbnZhciBub3JtYWxpemVDaGlsZE5vZGVzID0gZnVuY3Rpb24gbm9ybWFsaXplQ2hpbGROb2RlcyhfY2hpbGROb2Rlcykge1xuICB2YXIgbmV3Q2hpbGROb2RlcyA9IFtdO1xuICB2YXIgY2hpbGROb2RlcyA9IEFycmF5LmlzQXJyYXkoX2NoaWxkTm9kZXMpID8gX2NoaWxkTm9kZXMgOiBbX2NoaWxkTm9kZXNdO1xuXG4gIGNoaWxkTm9kZXMuZm9yRWFjaChmdW5jdGlvbiAoY2hpbGROb2RlKSB7XG4gICAgaWYgKCh0eXBlb2YgY2hpbGROb2RlID09PSAndW5kZWZpbmVkJyA/ICd1bmRlZmluZWQnIDogX3R5cGVvZihjaGlsZE5vZGUpKSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIG5ld0NoaWxkTm9kZXMucHVzaChjcmVhdGVFbGVtZW50KCcjdGV4dCcsIG51bGwsIFN0cmluZyhjaGlsZE5vZGUpKSk7XG4gICAgfSBlbHNlIGlmICgnbGVuZ3RoJyBpbiBjaGlsZE5vZGUpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGROb2RlLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBuZXdDaGlsZCA9IGNoaWxkTm9kZVtpXTtcbiAgICAgICAgdmFyIG5ld05vZGUgPSBuZXdDaGlsZC5vd25lckRvY3VtZW50ID8gKDAsIF9tYWtlMi5kZWZhdWx0KShuZXdDaGlsZCkgOiBuZXdDaGlsZDtcblxuICAgICAgICBuZXdDaGlsZE5vZGVzLnB1c2gobmV3Tm9kZSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBub2RlID0gY2hpbGROb2RlLm93bmVyRG9jdW1lbnQgPyAoMCwgX21ha2UyLmRlZmF1bHQpKGNoaWxkTm9kZSkgOiBjaGlsZE5vZGU7XG4gICAgICBuZXdDaGlsZE5vZGVzLnB1c2gobm9kZSk7XG4gICAgfVxuICB9KTtcblxuICByZXR1cm4gbmV3Q2hpbGROb2Rlcztcbn07XG5cbi8qKlxuICogQ3JlYXRlcyBhIHZpcnR1YWwgZWxlbWVudCB1c2VkIGluIG9yIGFzIGEgdmlydHVhbCB0cmVlLlxuICpcbiAqIEBwYXJhbSBub2RlTmFtZVxuICogQHBhcmFtIGF0dHJpYnV0ZXNcbiAqIEBwYXJhbSBjaGlsZE5vZGVzXG4gKiBAcmV0dXJuIHtPYmplY3R9IGVsZW1lbnRcbiAqL1xuZnVuY3Rpb24gY3JlYXRlRWxlbWVudChub2RlTmFtZSwgYXR0cmlidXRlcywgY2hpbGROb2Rlcykge1xuICBpZiAobm9kZU5hbWUgPT09ICcnKSB7XG4gICAgcmV0dXJuIG5vcm1hbGl6ZUNoaWxkTm9kZXMoY2hpbGROb2Rlcyk7XG4gIH1cblxuICBpZiAodHlwZW9mIG5vZGVOYW1lID09PSAnZnVuY3Rpb24nKSB7XG4gICAgdmFyIHByb3BzID0gYXR0cmlidXRlcztcbiAgICBwcm9wcy5jaGlsZHJlbiA9IGNoaWxkTm9kZXM7XG4gICAgcmV0dXJuIG5ldyBub2RlTmFtZShwcm9wcykucmVuZGVyKHByb3BzKTtcbiAgfSBlbHNlIGlmICgodHlwZW9mIG5vZGVOYW1lID09PSAndW5kZWZpbmVkJyA/ICd1bmRlZmluZWQnIDogX3R5cGVvZihub2RlTmFtZSkpID09PSAnb2JqZWN0Jykge1xuICAgIHZhciBfcHJvcHMgPSBhdHRyaWJ1dGVzO1xuICAgIF9wcm9wcy5jaGlsZHJlbiA9IGNoaWxkTm9kZXM7XG4gICAgcmV0dXJuIG5vZGVOYW1lLnJlbmRlcihfcHJvcHMpO1xuICB9XG5cbiAgdmFyIGVudHJ5ID0gX3Bvb2xzLnBvb2xzLmVsZW1lbnRPYmplY3QuZ2V0KCk7XG4gIHZhciBpc1RleHROb2RlID0gbm9kZU5hbWUgPT09ICd0ZXh0JyB8fCBub2RlTmFtZSA9PT0gJyN0ZXh0JztcblxuICBlbnRyeS5rZXkgPSAnJztcbiAgZW50cnkubm9kZU5hbWUgPSBub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuICBlbnRyeS5yYXdOb2RlTmFtZSA9IG5vZGVOYW1lO1xuXG4gIGlmICghaXNUZXh0Tm9kZSkge1xuICAgIGVudHJ5Lm5vZGVUeXBlID0gMTtcbiAgICBlbnRyeS5ub2RlVmFsdWUgPSAnJztcbiAgICBlbnRyeS5hdHRyaWJ1dGVzID0gYXR0cmlidXRlcyB8fCBbXTtcbiAgICBlbnRyeS5jaGlsZE5vZGVzID0gbm9ybWFsaXplQ2hpbGROb2RlcyhjaGlsZE5vZGVzKTtcblxuICAgIC8vIFNldCB0aGUga2V5IHByb3AgaWYgcGFzc2VkIGFzIGFuIGF0dHIuXG4gICAgZW50cnkuYXR0cmlidXRlcy5zb21lKGZ1bmN0aW9uIChhdHRyKSB7XG4gICAgICBpZiAoYXR0ci5uYW1lID09PSAna2V5Jykge1xuICAgICAgICBlbnRyeS5rZXkgPSBhdHRyLnZhbHVlO1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfSBlbHNlIHtcbiAgICB2YXIgdmFsdWUgPSBBcnJheS5pc0FycmF5KGNoaWxkTm9kZXMpID8gY2hpbGROb2Rlcy5qb2luKCcnKSA6IGNoaWxkTm9kZXM7XG5cbiAgICBlbnRyeS5ub2RlVHlwZSA9IG5vZGVOYW1lID09PSAnI2RvY3VtZW50LWZyYWdtZW50JyA/IDExIDogMztcbiAgICBlbnRyeS5ub2RlVmFsdWUgPSAoMCwgX2VzY2FwZTIuZGVmYXVsdCkoU3RyaW5nKHZhbHVlKSk7XG4gICAgZW50cnkuYXR0cmlidXRlcy5sZW5ndGggPSAwO1xuICAgIGVudHJ5LmNoaWxkTm9kZXMubGVuZ3RoID0gMDtcbiAgfVxuXG4gIHJldHVybiBlbnRyeTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIGEgdmlydHVhbCBhdHRyaWJ1dGUgdXNlZCBpbiBhIHZpcnR1YWwgZWxlbWVudC5cbiAqXG4gKiBAcGFyYW0gbmFtZVxuICogQHBhcmFtIHZhbHVlXG4gKiBAcmV0dXJuIHtPYmplY3R9IGF0dHJpYnV0ZVxuICovXG5mdW5jdGlvbiBjcmVhdGVBdHRyaWJ1dGUobmFtZSwgdmFsdWUpIHtcbiAgdmFyIGVudHJ5ID0gX3Bvb2xzLnBvb2xzLmF0dHJpYnV0ZU9iamVjdC5nZXQoKTtcblxuICBlbnRyeS5uYW1lID0gbmFtZTtcbiAgZW50cnkudmFsdWUgPSB2YWx1ZTtcblxuICByZXR1cm4gZW50cnk7XG59XG5cbn0se1wiLi4vdHJlZS9tYWtlXCI6OCxcIi4uL3V0aWwvZXNjYXBlXCI6MTIsXCIuLi91dGlsL3Bvb2xzXCI6MTV9XSw4OltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcbmV4cG9ydHMuZGVmYXVsdCA9IG1ha2VOb2RlO1xuXG52YXIgX2hlbHBlcnMgPSBfZGVyZXFfKCcuL2hlbHBlcnMnKTtcblxudmFyIF9wb29scyA9IF9kZXJlcV8oJy4uL3V0aWwvcG9vbHMnKTtcblxudmFyIF9jYWNoZSA9IF9kZXJlcV8oJy4uL3V0aWwvY2FjaGUnKTtcblxuLyoqXG4gKiBDb252ZXJ0cyBhIERPTSBOb2RlIGludG8gYSBWaXJ0dWFsIFRyZWUgRWxlbWVudC5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gbm9kZSAtIEEgRE9NIE5vZGVcbiAqIEByZXR1cm4ge09iamVjdH0gLSBBIFZpcnR1YWwgVHJlZSBFbGVtZW50XG4gKi9cbmZ1bmN0aW9uIG1ha2VOb2RlKG5vZGUpIHtcbiAgLy8gVGhlc2UgYXJlIHRoZSBvbmx5IERPTSBOb2RlIHByb3BlcnRpZXMgd2UgY2FyZSBhYm91dC5cbiAgdmFyIG5vZGVOYW1lID0gbm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuICB2YXIgbm9kZVR5cGUgPSBub2RlLm5vZGVUeXBlO1xuICB2YXIgbm9kZVZhbHVlID0gbm9kZS5ub2RlVmFsdWU7XG4gIHZhciBhdHRyaWJ1dGVzID0gbm9kZS5hdHRyaWJ1dGVzIHx8IFtdO1xuICB2YXIgY2hpbGROb2RlcyA9IG5vZGUuY2hpbGROb2RlcyB8fCBbXTtcblxuICAvLyBXZSBpZ25vcmUgYW55IERPTSBOb2RlIHRoYXQgaXNuJ3QgYW46IEVsZW1lbnQsIFRleHQsIERvY3VtZW50IEZyYWdtZW50LCBvclxuICAvLyBTaGFkb3cgUm9vdC5cbiAgaWYgKG5vZGVUeXBlICE9PSAxICYmIG5vZGVUeXBlICE9PSAzICYmIG5vZGVUeXBlICE9PSAxMSkge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIC8vIFdlIGNhbiBjb25zaWRlciBlaXRoZXIgb2YgdGhlc2UgRE9NIE5vZGVzIGFzIFRleHQgTm9kZXMuXG4gIHZhciBpc1RleHROb2RlID0gbm9kZU5hbWUgPT09ICcjdGV4dCcgfHwgbm9kZU5hbWUgPT09ICd0ZXh0JztcblxuICAvLyBJbiB0aGUgY2FzZSBvZiBUZXh0IE5vZGUncyB3ZSBjYW4gaGF2ZSB0aGUgY3JlYXRlRWxlbWVudCBmdW5jdGlvbiBzZXRcbiAgLy8gdGhlIG5vZGVWYWx1ZSBmb3IgdXMuXG4gIHZhciBpbml0aWFsVmFsdWUgPSBpc1RleHROb2RlID8gbm9kZVZhbHVlIDogW107XG5cbiAgLy8gQ3JlYXRlcyBhIFZpcnR1YWwgVHJlZSBFbGVtZW50IGJhc2VkIG9mZiB0aGlzIG5vZGVOYW1lLiBXZSBhcmVuJ3QgZ29pbmdcbiAgLy8gdG8gc2V0IHRoZSBhdHRyaWJ1dGVzIHJpZ2h0IGF3YXkgc2luY2Ugd2Ugd2FudCB0byBzZXQgdGhlIGtleSBvbiB0aGUgdlRyZWVcbiAgLy8gYW5kIHB1c2ggZGlyZWN0bHkgaW50byB0aGUgcHJlLWV4aXN0aW5nIGFycmF5LlxuICB2YXIgdlRyZWUgPSAoMCwgX2hlbHBlcnMuY3JlYXRlRWxlbWVudCkobm9kZS5ub2RlTmFtZSwgW10sIGluaXRpYWxWYWx1ZSk7XG5cbiAgLy8gQ3JlYXRlcyBWaXJ0dWFsIFRyZWUgQXR0cmlidXRlcyBmb3IgZWFjaCBhdHRyaWJ1dGUgaW4gdGhlIERPTSBOb2RlLlxuICBmb3IgKHZhciBpID0gMDsgaSA8IGF0dHJpYnV0ZXMubGVuZ3RoOyBpKyspIHtcbiAgICB2YXIgYXR0ciA9ICgwLCBfaGVscGVycy5jcmVhdGVBdHRyaWJ1dGUpKGF0dHJpYnV0ZXNbaV0ubmFtZSwgYXR0cmlidXRlc1tpXS52YWx1ZSk7XG5cbiAgICAvLyBJZiB0aGUgYGtleWAgYXR0cmlidXRlIGlzIGZvdW5kLCBzZXQgdGhlIHJlc3BlY3RpdmUgdmFsdWUgb24gdGhlIHZUcmVlLlxuICAgIGlmIChhdHRyLm5hbWUgPT09ICdrZXknKSB7XG4gICAgICB2VHJlZS5rZXkgPSBhdHRyLnZhbHVlO1xuICAgIH1cblxuICAgIHZUcmVlLmF0dHJpYnV0ZXMucHVzaChhdHRyKTtcbiAgfVxuXG4gIC8vIEFzc29jaWF0ZSB0aGlzIG5ld2x5IGFsbG9jYXRlZCB2VHJlZSB3aXRoIHRoaXMgRE9NIE5vZGUuXG4gIF9jYWNoZS5Ob2RlQ2FjaGUuc2V0KHZUcmVlLCBub2RlKTtcblxuICAvLyBJZiB0aGUgZWxlbWVudCBoYXMgY2hpbGQgbm9kZXMsIGNvbnZlcnQgdGhlbSBhbGwgdG8gdmlydHVhbCBub2Rlcy5cbiAgZm9yICh2YXIgX2kgPSAwOyBfaSA8IGNoaWxkTm9kZXMubGVuZ3RoOyBfaSsrKSB7XG4gICAgdmFyIG5ld05vZGUgPSBtYWtlTm9kZShjaGlsZE5vZGVzW19pXSk7XG5cbiAgICAvLyBXZSBtYXkgZ2V0IGEgZmFsc3kgdmFsdWUgYmFjayBpZiB3ZSBwYXNzIGluIGEgQ29tbWVudCBOb2RlIG9yIG90aGVyXG4gICAgLy8gRE9NIE5vZGVzIHRoYXQgd2UgaW50ZW50aW9uYWxseSBpZ25vcmUuXG4gICAgaWYgKG5ld05vZGUpIHtcbiAgICAgIHZUcmVlLmNoaWxkTm9kZXMucHVzaChuZXdOb2RlKTtcbiAgICB9XG4gIH1cblxuICAvLyBQcnVuZSBvdXQgd2hpdGVzcGFjZS9ldmVyeXRoaW5nIGZyb20gYmV0d2VlbiB0YWdzIG5lc3RlZCB1bmRlciB0aGUgSFRNTFxuICAvLyB0YWcsIHNpbmNlIHRoaXMgYmVoYXZpb3IgY2FuIGJlIG9ic2VydmVkIGluIGJyb3dzZXJzIGFuZCBzcGVjaWZpY2F0aW9uLlxuICBpZiAodlRyZWUubm9kZU5hbWUgPT09ICdodG1sJykge1xuICAgIHZUcmVlLmNoaWxkTm9kZXMgPSB2VHJlZS5jaGlsZE5vZGVzLmZpbHRlcihmdW5jdGlvbiAoY2hpbGROb2RlKSB7XG4gICAgICByZXR1cm4gY2hpbGROb2RlLm5vZGVOYW1lID09PSAnaGVhZCcgfHwgY2hpbGROb2RlLm5vZGVOYW1lID09PSAnYm9keSc7XG4gICAgfSk7XG4gIH1cblxuICByZXR1cm4gdlRyZWU7XG59XG5cbn0se1wiLi4vdXRpbC9jYWNoZVwiOjEwLFwiLi4vdXRpbC9wb29sc1wiOjE1LFwiLi9oZWxwZXJzXCI6N31dLDk6W2Z1bmN0aW9uKF9kZXJlcV8sbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgXCJfX2VzTW9kdWxlXCIsIHtcbiAgdmFsdWU6IHRydWVcbn0pO1xuZXhwb3J0cy5kZWZhdWx0ID0gc3luYztcblxuZnVuY3Rpb24gX3RvQ29uc3VtYWJsZUFycmF5KGFycikgeyBpZiAoQXJyYXkuaXNBcnJheShhcnIpKSB7IGZvciAodmFyIGkgPSAwLCBhcnIyID0gQXJyYXkoYXJyLmxlbmd0aCk7IGkgPCBhcnIubGVuZ3RoOyBpKyspIHsgYXJyMltpXSA9IGFycltpXTsgfSByZXR1cm4gYXJyMjsgfSBlbHNlIHsgcmV0dXJuIEFycmF5LmZyb20oYXJyKTsgfSB9XG5cbnZhciBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcbnZhciBmaWx0ZXIgPSBBcnJheS5wcm90b3R5cGUuZmlsdGVyO1xuXG4vLyBQYXRjaCBhY3Rpb25zLlxudmFyIFJFTU9WRV9FTEVNRU5UX0NISUxEUkVOID0gZXhwb3J0cy5SRU1PVkVfRUxFTUVOVF9DSElMRFJFTiA9IC0yO1xudmFyIFJFTU9WRV9FTlRJUkVfRUxFTUVOVCA9IGV4cG9ydHMuUkVNT1ZFX0VOVElSRV9FTEVNRU5UID0gLTE7XG52YXIgUkVQTEFDRV9FTlRJUkVfRUxFTUVOVCA9IGV4cG9ydHMuUkVQTEFDRV9FTlRJUkVfRUxFTUVOVCA9IDA7XG52YXIgTU9ESUZZX0VMRU1FTlQgPSBleHBvcnRzLk1PRElGWV9FTEVNRU5UID0gMTtcbnZhciBNT0RJRllfQVRUUklCVVRFID0gZXhwb3J0cy5NT0RJRllfQVRUUklCVVRFID0gMjtcbnZhciBDSEFOR0VfVEVYVCA9IGV4cG9ydHMuQ0hBTkdFX1RFWFQgPSAzO1xuXG4vKipcbiAqIFN5bmNocm9uaXplcyBjaGFuZ2VzIGZyb20gdGhlIG5ld1RyZWUgaW50byB0aGUgb2xkVHJlZS5cbiAqXG4gKiBAcGFyYW0gb2xkVHJlZVxuICogQHBhcmFtIG5ld1RyZWVcbiAqIEBwYXJhbSBwYXRjaGVzIC0gb3B0aW9uYWxcbiAqL1xuZnVuY3Rpb24gc3luYyhvbGRUcmVlLCBuZXdUcmVlLCBwYXRjaGVzKSB7XG4gIHBhdGNoZXMgPSBwYXRjaGVzIHx8IFtdO1xuXG4gIGlmICghQXJyYXkuaXNBcnJheShwYXRjaGVzKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignTWlzc2luZyBBcnJheSB0byBzeW5jIHBhdGNoZXMgaW50bycpO1xuICB9XG5cbiAgaWYgKCFvbGRUcmVlKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdNaXNzaW5nIGV4aXN0aW5nIHRyZWUgdG8gc3luYycpO1xuICB9XG5cbiAgdmFyIG9sZE5vZGVWYWx1ZSA9IG9sZFRyZWUubm9kZVZhbHVlO1xuICB2YXIgb2xkQ2hpbGROb2RlcyA9IG9sZFRyZWUuY2hpbGROb2RlcztcbiAgdmFyIG9sZElzVGV4dE5vZGUgPSBvbGRUcmVlLm5vZGVOYW1lID09PSAnI3RleHQnO1xuXG4gIC8vIFRPRE8gTWFrZSB0aGlzIHN0YXRpYy4uLlxuICB2YXIgb2xkQ2hpbGROb2Rlc0xlbmd0aCA9IG9sZENoaWxkTm9kZXMgPyBvbGRDaGlsZE5vZGVzLmxlbmd0aCA6IDA7XG5cbiAgaWYgKCFuZXdUcmVlKSB7XG4gICAgdmFyIHJlbW92ZWQgPSBbb2xkVHJlZV0uY29uY2F0KG9sZENoaWxkTm9kZXMuc3BsaWNlKDAsIG9sZENoaWxkTm9kZXNMZW5ndGgpKTtcblxuICAgIHBhdGNoZXMucHVzaCh7XG4gICAgICBfX2RvX186IFJFTU9WRV9FTlRJUkVfRUxFTUVOVCxcbiAgICAgIGVsZW1lbnQ6IG9sZFRyZWUsXG4gICAgICB0b1JlbW92ZTogcmVtb3ZlZFxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHBhdGNoZXM7XG4gIH1cblxuICB2YXIgbm9kZVZhbHVlID0gbmV3VHJlZS5ub2RlVmFsdWU7XG4gIHZhciBjaGlsZE5vZGVzID0gbmV3VHJlZS5jaGlsZE5vZGVzO1xuICB2YXIgY2hpbGROb2Rlc0xlbmd0aCA9IGNoaWxkTm9kZXMgPyBjaGlsZE5vZGVzLmxlbmd0aCA6IDA7XG4gIHZhciBub2RlTmFtZSA9IG5ld1RyZWUubm9kZU5hbWU7XG4gIHZhciBhdHRyaWJ1dGVzID0gbmV3VHJlZS5hdHRyaWJ1dGVzO1xuICB2YXIgbmV3SXNUZXh0Tm9kZSA9IG5vZGVOYW1lID09PSAnI3RleHQnO1xuICB2YXIgbmV3SXNGcmFnbWVudCA9IG5ld1RyZWUubm9kZU5hbWUgPT09ICcjZG9jdW1lbnQtZnJhZ21lbnQnO1xuXG4gIC8vIFJlcGxhY2UgdGhlIGtleSBhdHRyaWJ1dGVzLlxuICBvbGRUcmVlLmtleSA9IG5ld1RyZWUua2V5O1xuXG4gIC8vIElmIHRoZSBlbGVtZW50IHdlJ3JlIHJlcGxhY2luZyBpcyB0b3RhbGx5IGRpZmZlcmVudCBmcm9tIHRoZSBwcmV2aW91c1xuICAvLyByZXBsYWNlIHRoZSBlbnRpcmUgZWxlbWVudCwgZG9uJ3QgYm90aGVyIGludmVzdGlnYXRpbmcgY2hpbGRyZW4uXG4gIGlmIChvbGRUcmVlLm5vZGVOYW1lICE9PSBuZXdUcmVlLm5vZGVOYW1lKSB7XG4gICAgcGF0Y2hlcy5wdXNoKHtcbiAgICAgIF9fZG9fXzogUkVQTEFDRV9FTlRJUkVfRUxFTUVOVCxcbiAgICAgIG9sZDogb2xkVHJlZSxcbiAgICAgIG5ldzogbmV3VHJlZVxuICAgIH0pO1xuXG4gICAgcmV0dXJuIHBhdGNoZXM7XG4gIH1cbiAgLy8gVGhpcyBlbGVtZW50IG5ldmVyIGNoYW5nZXMuXG4gIGVsc2UgaWYgKG9sZFRyZWUgPT09IG5ld1RyZWUpIHtcbiAgICAgIHJldHVybiBwYXRjaGVzO1xuICAgIH1cblxuICB2YXIgYXJlVGV4dE5vZGVzID0gb2xkSXNUZXh0Tm9kZSAmJiBuZXdJc1RleHROb2RlO1xuXG4gIC8vIElmIHRoZSB0b3AgbGV2ZWwgbm9kZVZhbHVlIGhhcyBjaGFuZ2VkIHdlIHNob3VsZCByZWZsZWN0IGl0LlxuICBpZiAoYXJlVGV4dE5vZGVzICYmIG9sZE5vZGVWYWx1ZSAhPT0gbm9kZVZhbHVlKSB7XG4gICAgcGF0Y2hlcy5wdXNoKHtcbiAgICAgIF9fZG9fXzogQ0hBTkdFX1RFWFQsXG4gICAgICBlbGVtZW50OiBvbGRUcmVlLFxuICAgICAgdmFsdWU6IG5ld1RyZWUubm9kZVZhbHVlXG4gICAgfSk7XG5cbiAgICBvbGRUcmVlLm5vZGVWYWx1ZSA9IG5ld1RyZWUubm9kZVZhbHVlO1xuXG4gICAgcmV0dXJuIHBhdGNoZXM7XG4gIH1cblxuICAvLyBFbnN1cmUga2V5cyBleGlzdCBmb3IgYWxsIHRoZSBvbGQgJiBuZXcgZWxlbWVudHMuXG4gIHZhciBub09sZEtleXMgPSAhb2xkQ2hpbGROb2Rlcy5zb21lKGZ1bmN0aW9uIChvbGRDaGlsZE5vZGUpIHtcbiAgICByZXR1cm4gb2xkQ2hpbGROb2RlLmtleTtcbiAgfSk7XG4gIHZhciBuZXdLZXlzID0gbnVsbDtcbiAgdmFyIG9sZEtleXMgPSBudWxsO1xuXG4gIGlmICghbm9PbGRLZXlzKSB7XG4gICAgbmV3S2V5cyA9IG5ldyBTZXQoY2hpbGROb2Rlcy5tYXAoZnVuY3Rpb24gKGNoaWxkTm9kZSkge1xuICAgICAgcmV0dXJuIFN0cmluZyhjaGlsZE5vZGUua2V5KTtcbiAgICB9KS5maWx0ZXIoQm9vbGVhbikpO1xuXG4gICAgb2xkS2V5cyA9IG5ldyBTZXQob2xkQ2hpbGROb2Rlcy5tYXAoZnVuY3Rpb24gKGNoaWxkTm9kZSkge1xuICAgICAgcmV0dXJuIFN0cmluZyhjaGlsZE5vZGUua2V5KTtcbiAgICB9KS5maWx0ZXIoQm9vbGVhbikpO1xuICB9XG5cbiAgLy8gTW9zdCBjb21tb24gYWRkaXRpdmUgZWxlbWVudHMuXG4gIGlmIChjaGlsZE5vZGVzTGVuZ3RoID4gb2xkQ2hpbGROb2Rlc0xlbmd0aCkge1xuICAgIC8vIFN0b3JlIGVsZW1lbnRzIGluIGEgRG9jdW1lbnRGcmFnbWVudCB0byBpbmNyZWFzZSBwZXJmb3JtYW5jZSBhbmQgYmVcbiAgICAvLyBnZW5lcmFsbHkgc2ltcGxpZXIgdG8gd29yayB3aXRoLlxuICAgIHZhciBmcmFnbWVudCA9IFtdO1xuXG4gICAgZm9yICh2YXIgaSA9IG9sZENoaWxkTm9kZXNMZW5ndGg7IGkgPCBjaGlsZE5vZGVzTGVuZ3RoOyBpKyspIHtcbiAgICAgIC8vIEludGVybmFsbHkgYWRkIHRvIHRoZSB0cmVlLlxuICAgICAgb2xkQ2hpbGROb2Rlcy5wdXNoKGNoaWxkTm9kZXNbaV0pO1xuXG4gICAgICAvLyBBZGQgdG8gdGhlIGRvY3VtZW50IGZyYWdtZW50LlxuICAgICAgZnJhZ21lbnQucHVzaChjaGlsZE5vZGVzW2ldKTtcbiAgICB9XG5cbiAgICBvbGRDaGlsZE5vZGVzTGVuZ3RoID0gb2xkQ2hpbGROb2Rlcy5sZW5ndGg7XG5cbiAgICAvLyBBc3NpZ24gdGhlIGZyYWdtZW50IHRvIHRoZSBwYXRjaGVzIHRvIGJlIGluamVjdGVkLlxuICAgIHBhdGNoZXMucHVzaCh7XG4gICAgICBfX2RvX186IE1PRElGWV9FTEVNRU5ULFxuICAgICAgZWxlbWVudDogb2xkVHJlZSxcbiAgICAgIGZyYWdtZW50OiBmcmFnbWVudFxuICAgIH0pO1xuICB9XG5cbiAgLy8gUmVtb3ZlIHRoZXNlIGVsZW1lbnRzLlxuICBpZiAob2xkQ2hpbGROb2Rlc0xlbmd0aCA+IGNoaWxkTm9kZXNMZW5ndGgpIHtcbiAgICAoZnVuY3Rpb24gKCkge1xuICAgICAgLy8gRm9yIG5vdyBqdXN0IHNwbGljZSBvdXQgdGhlIGVuZCBpdGVtcy5cbiAgICAgIHZhciBkaWZmID0gb2xkQ2hpbGROb2Rlc0xlbmd0aCAtIGNoaWxkTm9kZXNMZW5ndGg7XG4gICAgICB2YXIgdG9SZW1vdmUgPSBbXTtcbiAgICAgIHZhciBzaGFsbG93Q2xvbmUgPSBbXS5jb25jYXQoX3RvQ29uc3VtYWJsZUFycmF5KG9sZENoaWxkTm9kZXMpKTtcblxuICAgICAgLy8gVGhlcmUgbmVlZHMgdG8gYmUga2V5cyB0byBkaWZmLCBpZiBub3QsIHRoZXJlJ3Mgbm8gcG9pbnQgaW4gY2hlY2tpbmcuXG4gICAgICBpZiAobm9PbGRLZXlzKSB7XG4gICAgICAgIHRvUmVtb3ZlID0gb2xkQ2hpbGROb2Rlcy5zcGxpY2Uob2xkQ2hpbGROb2Rlc0xlbmd0aCAtIGRpZmYsIGRpZmYpO1xuICAgICAgfVxuICAgICAgLy8gVGhpcyBpcyBhbiBleHBlbnNpdmUgb3BlcmF0aW9uIHNvIHdlIGRvIHRoZSBhYm92ZSBjaGVjayB0byBlbnN1cmUgdGhhdCBhXG4gICAgICAvLyBrZXkgd2FzIHNwZWNpZmllZC5cbiAgICAgIGVsc2Uge1xuICAgICAgICAgIChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIga2V5c1RvUmVtb3ZlID0gbmV3IFNldCgpO1xuXG4gICAgICAgICAgICAvLyBGaW5kIHRoZSBrZXlzIGluIHRoZSBzZXRzIHRvIHJlbW92ZS5cbiAgICAgICAgICAgIG9sZEtleXMuZm9yRWFjaChmdW5jdGlvbiAoa2V5KSB7XG4gICAgICAgICAgICAgIGlmICghbmV3S2V5cy5oYXMoa2V5KSkge1xuICAgICAgICAgICAgICAgIGtleXNUb1JlbW92ZS5hZGQoa2V5KTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIC8vIElmIHRoZSBvcmlnaW5hbCBjaGlsZE5vZGVzIGNvbnRhaW4gYSBrZXkgYXR0cmlidXRlLCB1c2UgdGhpcyB0b1xuICAgICAgICAgICAgLy8gY29tcGFyZSBvdmVyIHRoZSBuYWl2ZSBtZXRob2QgYmVsb3cuXG4gICAgICAgICAgICBzaGFsbG93Q2xvbmUuZm9yRWFjaChmdW5jdGlvbiAob2xkQ2hpbGROb2RlLCBpKSB7XG4gICAgICAgICAgICAgIGlmICh0b1JlbW92ZS5sZW5ndGggPj0gZGlmZikge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgfSBlbHNlIGlmIChrZXlzVG9SZW1vdmUuaGFzKG9sZENoaWxkTm9kZS5rZXkpKSB7XG4gICAgICAgICAgICAgICAgdmFyIG5leHRDaGlsZCA9IG9sZENoaWxkTm9kZXNbaSArIDFdO1xuICAgICAgICAgICAgICAgIHZhciBuZXh0SXNUZXh0Tm9kZSA9IG5leHRDaGlsZCAmJiBuZXh0Q2hpbGQubm9kZVR5cGUgPT09IDM7XG4gICAgICAgICAgICAgICAgdmFyIGNvdW50ID0gMTtcblxuICAgICAgICAgICAgICAgIC8vIEFsd2F5cyByZW1vdmUgd2hpdGVzcGFjZSBpbiBiZXR3ZWVuIHRoZSBlbGVtZW50cy5cbiAgICAgICAgICAgICAgICBpZiAobmV4dElzVGV4dE5vZGUgJiYgdG9SZW1vdmUubGVuZ3RoICsgMiA8PSBkaWZmKSB7XG4gICAgICAgICAgICAgICAgICBjb3VudCA9IDI7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIEFsbCBzaWJsaW5ncyBtdXN0IGNvbnRhaW4gYSBrZXkgYXR0cmlidXRlIGlmIHRoZXkgZXhpc3QuXG4gICAgICAgICAgICAgICAgZWxzZSBpZiAobmV4dENoaWxkICYmIG5leHRDaGlsZC5ub2RlVHlwZSA9PT0gMSAmJiAhbmV4dENoaWxkLmtleSkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1xcbiAgICAgICAgICAgICAgQWxsIGVsZW1lbnQgc2libGluZ3MgbXVzdCBjb25zaXN0ZW50bHkgY29udGFpbiBrZXkgYXR0cmlidXRlcy5cXG4gICAgICAgICAgICAnLnRyaW0oKSk7XG4gICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBGaW5kIHRoZSBpbmRleCBwb3NpdGlvbiBmcm9tIHRoZSBvcmlnaW5hbCBhcnJheS5cbiAgICAgICAgICAgICAgICB2YXIgaW5kZXhQb3MgPSBvbGRDaGlsZE5vZGVzLmluZGV4T2Yob2xkQ2hpbGROb2RlKTtcblxuICAgICAgICAgICAgICAgIC8vIEZpbmQgYWxsIHRoZSBpdGVtcyB0byByZW1vdmUuXG4gICAgICAgICAgICAgICAgdG9SZW1vdmUucHVzaC5hcHBseSh0b1JlbW92ZSwgb2xkQ2hpbGROb2Rlcy5zcGxpY2UoaW5kZXhQb3MsIGNvdW50KSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH0pKCk7XG4gICAgICAgIH1cblxuICAgICAgLy8gRW5zdXJlIHdlIGRvbid0IHJlbW92ZSB0b28gbWFueSBlbGVtZW50cyBieSBhY2NpZGVudDtcbiAgICAgIHRvUmVtb3ZlLmxlbmd0aCA9IGRpZmY7XG5cbiAgICAgIC8vIEVuc3VyZSBvdXIgaW50ZXJuYWwgbGVuZ3RoIGNoZWNrIGlzIG1hdGNoZWQuXG4gICAgICBvbGRDaGlsZE5vZGVzTGVuZ3RoID0gb2xkQ2hpbGROb2Rlcy5sZW5ndGg7XG5cbiAgICAgIGlmIChjaGlsZE5vZGVzTGVuZ3RoID09PSAwKSB7XG4gICAgICAgIHBhdGNoZXMucHVzaCh7XG4gICAgICAgICAgX19kb19fOiBSRU1PVkVfRUxFTUVOVF9DSElMRFJFTixcbiAgICAgICAgICBlbGVtZW50OiBvbGRUcmVlLFxuICAgICAgICAgIHRvUmVtb3ZlOiB0b1JlbW92ZVxuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIFJlbW92ZSB0aGUgZWxlbWVudCwgdGhpcyBoYXBwZW5zIGJlZm9yZSB0aGUgc3BsaWNlIHNvIHRoYXQgd2Ugc3RpbGxcbiAgICAgICAgLy8gaGF2ZSBhY2Nlc3MgdG8gdGhlIGVsZW1lbnQuXG4gICAgICAgIHRvUmVtb3ZlLmZvckVhY2goZnVuY3Rpb24gKG9sZCkge1xuICAgICAgICAgIHJldHVybiBwYXRjaGVzLnB1c2goe1xuICAgICAgICAgICAgX19kb19fOiBNT0RJRllfRUxFTUVOVCxcbiAgICAgICAgICAgIG9sZDogb2xkXG4gICAgICAgICAgfSk7XG4gICAgICAgIH0pO1xuICAgICAgfVxuICAgIH0pKCk7XG4gIH1cblxuICAvLyBSZXBsYWNlIGVsZW1lbnRzIGlmIHRoZXkgYXJlIGRpZmZlcmVudC5cbiAgaWYgKG9sZENoaWxkTm9kZXNMZW5ndGggPj0gY2hpbGROb2Rlc0xlbmd0aCkge1xuICAgIGZvciAodmFyIF9pID0gMDsgX2kgPCBjaGlsZE5vZGVzTGVuZ3RoOyBfaSsrKSB7XG4gICAgICBpZiAob2xkQ2hpbGROb2Rlc1tfaV0ubm9kZU5hbWUgIT09IGNoaWxkTm9kZXNbX2ldLm5vZGVOYW1lKSB7XG4gICAgICAgIC8vIEFkZCB0byB0aGUgcGF0Y2hlcy5cbiAgICAgICAgcGF0Y2hlcy5wdXNoKHtcbiAgICAgICAgICBfX2RvX186IE1PRElGWV9FTEVNRU5ULFxuICAgICAgICAgIG9sZDogb2xkQ2hpbGROb2Rlc1tfaV0sXG4gICAgICAgICAgbmV3OiBjaGlsZE5vZGVzW19pXVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBSZXBsYWNlIHRoZSBpbnRlcm5hbCB0cmVlJ3MgcG9pbnQgb2YgdmlldyBvZiB0aGlzIGVsZW1lbnQuXG4gICAgICAgIG9sZENoaWxkTm9kZXNbX2ldID0gY2hpbGROb2Rlc1tfaV07XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzeW5jKG9sZENoaWxkTm9kZXNbX2ldLCBjaGlsZE5vZGVzW19pXSwgcGF0Y2hlcyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gQXR0cmlidXRlcyBhcmUgc2lnbmlmaWNhbnRseSBlYXNpZXIgdGhhbiBlbGVtZW50cyBhbmQgd2UgaWdub3JlIGNoZWNraW5nXG4gIC8vIHRoZW0gb24gZnJhZ21lbnRzLiBUaGUgYWxnb3JpdGhtIGlzIHRoZSBzYW1lIGFzIGVsZW1lbnRzLCBjaGVjayBmb3JcbiAgLy8gYWRkaXRpb25zL3JlbW92YWxzIGJhc2VkIG9mZiBsZW5ndGgsIGFuZCB0aGVuIGl0ZXJhdGUgb25jZSB0byBtYWtlXG4gIC8vIGFkanVzdG1lbnRzLlxuICBpZiAoIW5ld0lzRnJhZ21lbnQgJiYgYXR0cmlidXRlcykge1xuICAgIC8vIENhY2hlIHRoZSBsZW5ndGhzIGZvciBwZXJmb3JtYW5jZSBhbmQgcmVhZGFiaWxpdHkuXG4gICAgdmFyIG9sZExlbmd0aCA9IG9sZFRyZWUuYXR0cmlidXRlcy5sZW5ndGg7XG4gICAgdmFyIG5ld0xlbmd0aCA9IGF0dHJpYnV0ZXMubGVuZ3RoO1xuXG4gICAgLy8gQ29uc3RydWN0IGEgc2luZ2xlIHBhdGNoIGZvciB0aGUgZW50aXJlIGNoYW5nZXNldC5cbiAgICB2YXIgcGF0Y2ggPSB7XG4gICAgICBfX2RvX186IE1PRElGWV9BVFRSSUJVVEUsXG4gICAgICBlbGVtZW50OiBvbGRUcmVlLFxuICAgICAgYXR0cmlidXRlczogW11cbiAgICB9O1xuXG4gICAgLy8gRmluZCBhZGRpdGlvbnMuXG4gICAgaWYgKG5ld0xlbmd0aCA+IG9sZExlbmd0aCkge1xuICAgICAgZm9yICh2YXIgX2kyID0gb2xkTGVuZ3RoOyBfaTIgPCBuZXdMZW5ndGg7IF9pMisrKSB7XG4gICAgICAgIHZhciBvbGRBdHRyID0gb2xkVHJlZS5hdHRyaWJ1dGVzW19pMl07XG4gICAgICAgIHZhciBuZXdBdHRyID0gYXR0cmlidXRlc1tfaTJdO1xuXG4gICAgICAgIHBhdGNoLmF0dHJpYnV0ZXMucHVzaCh7IG9sZEF0dHI6IG9sZEF0dHIsIG5ld0F0dHI6IG5ld0F0dHIgfSk7XG4gICAgICAgIG9sZFRyZWUuYXR0cmlidXRlcy5wdXNoKG5ld0F0dHIpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEZpbmQgcmVtb3ZhbHMuXG4gICAgaWYgKG9sZExlbmd0aCA+IG5ld0xlbmd0aCkge1xuICAgICAgZm9yICh2YXIgX2kzID0gbmV3TGVuZ3RoOyBfaTMgPCBvbGRMZW5ndGg7IF9pMysrKSB7XG4gICAgICAgIHZhciBfb2xkQXR0ciA9IG9sZFRyZWUuYXR0cmlidXRlc1tfaTNdO1xuICAgICAgICB2YXIgX25ld0F0dHIgPSBhdHRyaWJ1dGVzW19pM107XG5cbiAgICAgICAgcGF0Y2guYXR0cmlidXRlcy5wdXNoKHsgb2xkQXR0cjogX29sZEF0dHIsIG5ld0F0dHI6IF9uZXdBdHRyIH0pO1xuICAgICAgfVxuXG4gICAgICAvLyBSZXNldCB0aGUgaW50ZXJuYWwgYXR0cmlidXRlcyB0byBiZSBsZXNzLlxuICAgICAgb2xkVHJlZS5hdHRyaWJ1dGVzID0gb2xkVHJlZS5hdHRyaWJ1dGVzLnNsaWNlKDAsIG5ld0xlbmd0aCk7XG4gICAgfVxuXG4gICAgLy8gRmluZCBjaGFuZ2VzLlxuICAgIGZvciAodmFyIF9pNCA9IDA7IF9pNCA8IGF0dHJpYnV0ZXMubGVuZ3RoOyBfaTQrKykge1xuICAgICAgdmFyIF9vbGRBdHRyMiA9IG9sZFRyZWUuYXR0cmlidXRlc1tfaTRdO1xuICAgICAgdmFyIF9uZXdBdHRyMiA9IGF0dHJpYnV0ZXNbX2k0XTtcbiAgICAgIHZhciBvbGRBdHRyTmFtZSA9IF9vbGRBdHRyMiA/IF9vbGRBdHRyMi5uYW1lIDogdW5kZWZpbmVkO1xuICAgICAgdmFyIG9sZEF0dHJWYWx1ZSA9IF9vbGRBdHRyMiA/IF9vbGRBdHRyMi52YWx1ZSA6IHVuZGVmaW5lZDtcbiAgICAgIHZhciBuZXdBdHRyTmFtZSA9IF9uZXdBdHRyMiA/IF9uZXdBdHRyMi5uYW1lIDogdW5kZWZpbmVkO1xuICAgICAgdmFyIG5ld0F0dHJWYWx1ZSA9IF9uZXdBdHRyMiA/IF9uZXdBdHRyMi52YWx1ZSA6IHVuZGVmaW5lZDtcblxuICAgICAgLy8gT25seSBwdXNoIGluIGEgY2hhbmdlIGlmIHRoZSBhdHRyaWJ1dGUgb3IgdmFsdWUgY2hhbmdlcy5cbiAgICAgIGlmIChvbGRBdHRyVmFsdWUgIT09IG5ld0F0dHJWYWx1ZSkge1xuICAgICAgICAvLyBBZGQgdGhlIGF0dHJpYnV0ZSBpdGVtcyB0byBhZGQgYW5kIHJlbW92ZS5cbiAgICAgICAgcGF0Y2guYXR0cmlidXRlcy5wdXNoKHtcbiAgICAgICAgICBvbGRBdHRyOiBfb2xkQXR0cjIsXG4gICAgICAgICAgbmV3QXR0cjogX25ld0F0dHIyXG4gICAgICAgIH0pO1xuXG4gICAgICAgIG9sZFRyZWUuYXR0cmlidXRlc1tfaTRdID0gX25ld0F0dHIyO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEFkZCB0aGUgYXR0cmlidXRlIGNoYW5nZXMgcGF0Y2ggdG8gdGhlIHNlcmllcyBvZiBwYXRjaGVzLCB1bmxlc3MgdGhlcmVcbiAgICAvLyBhcmUgbm8gYXR0cmlidXRlcyB0byBjaGFuZ2UuXG4gICAgaWYgKHBhdGNoLmF0dHJpYnV0ZXMubGVuZ3RoKSB7XG4gICAgICBwYXRjaGVzLnB1c2gocGF0Y2gpO1xuICAgIH1cbiAgfVxuXG4gIHJldHVybiBwYXRjaGVzO1xufVxuXG59LHt9XSwxMDpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcbi8vIEFzc29jaWF0ZXMgRE9NIE5vZGVzIHdpdGggc3RhdGUgb2JqZWN0cy5cbnZhciBTdGF0ZUNhY2hlID0gZXhwb3J0cy5TdGF0ZUNhY2hlID0gbmV3IE1hcCgpO1xuXG4vLyBBc3NvY2lhdGVzIFZpcnR1YWwgVHJlZSBFbGVtZW50cyB3aXRoIERPTSBOb2Rlcy5cbnZhciBOb2RlQ2FjaGUgPSBleHBvcnRzLk5vZGVDYWNoZSA9IG5ldyBNYXAoKTtcblxuLy8gQ2FjaGVzIGFsbCBtaWRkbGV3YXJlLiBZb3UgY2Fubm90IHVuc2V0IGEgbWlkZGxld2FyZSBvbmNlIGl0IGhhcyBiZWVuIGFkZGVkLlxudmFyIE1pZGRsZXdhcmVDYWNoZSA9IGV4cG9ydHMuTWlkZGxld2FyZUNhY2hlID0gbmV3IFNldCgpO1xuXG59LHt9XSwxMTpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4oZnVuY3Rpb24gKGdsb2JhbCl7XG4ndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzLmRlY29kZUVudGl0aWVzID0gZGVjb2RlRW50aXRpZXM7XG4vLyBTdXBwb3J0IGxvYWRpbmcgZGlmZkhUTUwgaW4gbm9uLWJyb3dzZXIgZW52aXJvbm1lbnRzLlxudmFyIGVsZW1lbnQgPSBnbG9iYWwuZG9jdW1lbnQgPyBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKSA6IG51bGw7XG5cbi8qKlxuICogRGVjb2RlcyBIVE1MIHN0cmluZ3MuXG4gKlxuICogQHNlZSBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vYS81Nzk2NzE4XG4gKiBAcGFyYW0gc3RyaW5nXG4gKiBAcmV0dXJuIHVuZXNjYXBlZCBIVE1MXG4gKi9cbmZ1bmN0aW9uIGRlY29kZUVudGl0aWVzKHN0cmluZykge1xuICAvLyBJZiB0aGVyZSBhcmUgbm8gSFRNTCBlbnRpdGllcywgd2UgY2FuIHNhZmVseSBwYXNzIHRoZSBzdHJpbmcgdGhyb3VnaC5cbiAgaWYgKCFlbGVtZW50IHx8ICFzdHJpbmcgfHwgIXN0cmluZy5pbmRleE9mIHx8IHN0cmluZy5pbmRleE9mKCcmJykgPT09IC0xKSB7XG4gICAgcmV0dXJuIHN0cmluZztcbiAgfVxuXG4gIGVsZW1lbnQuaW5uZXJIVE1MID0gc3RyaW5nO1xuICByZXR1cm4gZWxlbWVudC50ZXh0Q29udGVudDtcbn1cblxufSkuY2FsbCh0aGlzLHR5cGVvZiBnbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgPyBnbG9iYWwgOiB0eXBlb2Ygc2VsZiAhPT0gXCJ1bmRlZmluZWRcIiA/IHNlbGYgOiB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93IDoge30pXG59LHt9XSwxMjpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG5cInVzZSBzdHJpY3RcIjtcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcbmV4cG9ydHMuZGVmYXVsdCA9IGVzY2FwZTtcbi8qKlxuICogVGlueSBIVE1MIGVzY2FwaW5nIGZ1bmN0aW9uLCB1c2VmdWwgdG8gcHJldmVudCB0aGluZ3MgbGlrZSBYU1MgYW5kXG4gKiB1bmludGVudGlvbmFsbHkgYnJlYWtpbmcgYXR0cmlidXRlcyB3aXRoIHF1b3Rlcy5cbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gdW5lc2NhcGVkIC0gQW4gSFRNTCB2YWx1ZSwgdW5lc2NhcGVkXG4gKiBAcmV0dXJuIHtTdHJpbmd9IC0gQW4gSFRNTC1zYWZlIHN0cmluZ1xuICovXG5mdW5jdGlvbiBlc2NhcGUodW5lc2NhcGVkKSB7XG4gIHJldHVybiB1bmVzY2FwZWQucmVwbGFjZSgvW1wiJic8PmBdL2csIGZ1bmN0aW9uIChtYXRjaCkge1xuICAgIHJldHVybiBcIiYjXCIgKyBtYXRjaC5jaGFyQ29kZUF0KDApICsgXCI7XCI7XG4gIH0pO1xufVxuXG59LHt9XSwxMzpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzLnByb3RlY3RFbGVtZW50ID0gcHJvdGVjdEVsZW1lbnQ7XG5leHBvcnRzLnVucHJvdGVjdEVsZW1lbnQgPSB1bnByb3RlY3RFbGVtZW50O1xuZXhwb3J0cy5jbGVhbk1lbW9yeSA9IGNsZWFuTWVtb3J5O1xuXG52YXIgX3Bvb2xzID0gX2RlcmVxXygnLi4vdXRpbC9wb29scycpO1xuXG52YXIgX2NhY2hlID0gX2RlcmVxXygnLi9jYWNoZScpO1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCBhbiBlbGVtZW50IGlzIG5vdCByZWN5Y2xlZCBkdXJpbmcgYSByZW5kZXIgY3ljbGUuXG4gKlxuICogQHBhcmFtIGVsZW1lbnRcbiAqIEByZXR1cm4gZWxlbWVudFxuICovXG5mdW5jdGlvbiBwcm90ZWN0RWxlbWVudChlbGVtZW50KSB7XG4gIGlmIChBcnJheS5pc0FycmF5KGVsZW1lbnQpKSB7XG4gICAgcmV0dXJuIGVsZW1lbnQuZm9yRWFjaChwcm90ZWN0RWxlbWVudCk7XG4gIH1cblxuICB2YXIgZWxlbWVudE9iamVjdCA9IF9wb29scy5wb29scy5lbGVtZW50T2JqZWN0O1xuICB2YXIgYXR0cmlidXRlT2JqZWN0ID0gX3Bvb2xzLnBvb2xzLmF0dHJpYnV0ZU9iamVjdDtcblxuICBlbGVtZW50T2JqZWN0LnByb3RlY3QoZWxlbWVudCk7XG5cbiAgZWxlbWVudC5hdHRyaWJ1dGVzLmZvckVhY2goYXR0cmlidXRlT2JqZWN0LnByb3RlY3QsIGF0dHJpYnV0ZU9iamVjdCk7XG4gIGVsZW1lbnQuY2hpbGROb2Rlcy5mb3JFYWNoKHByb3RlY3RFbGVtZW50KTtcblxuICByZXR1cm4gZWxlbWVudDtcbn1cblxuLyoqXG4gKiBBbGxvd3MgYW4gZWxlbWVudCB0byBiZSByZWN5Y2xlZCBkdXJpbmcgYSByZW5kZXIgY3ljbGUuXG4gKlxuICogQHBhcmFtIGVsZW1lbnRcbiAqIEByZXR1cm5cbiAqL1xuZnVuY3Rpb24gdW5wcm90ZWN0RWxlbWVudChlbGVtZW50KSB7XG4gIGlmIChBcnJheS5pc0FycmF5KGVsZW1lbnQpKSB7XG4gICAgcmV0dXJuIGVsZW1lbnQuZm9yRWFjaCh1bnByb3RlY3RFbGVtZW50KTtcbiAgfVxuXG4gIHZhciBlbGVtZW50T2JqZWN0ID0gX3Bvb2xzLnBvb2xzLmVsZW1lbnRPYmplY3Q7XG4gIHZhciBhdHRyaWJ1dGVPYmplY3QgPSBfcG9vbHMucG9vbHMuYXR0cmlidXRlT2JqZWN0O1xuXG4gIGVsZW1lbnRPYmplY3QudW5wcm90ZWN0KGVsZW1lbnQpO1xuXG4gIGVsZW1lbnQuYXR0cmlidXRlcy5mb3JFYWNoKGF0dHJpYnV0ZU9iamVjdC51bnByb3RlY3QsIGF0dHJpYnV0ZU9iamVjdCk7XG4gIGVsZW1lbnQuY2hpbGROb2Rlcy5mb3JFYWNoKHVucHJvdGVjdEVsZW1lbnQpO1xuXG4gIF9jYWNoZS5Ob2RlQ2FjaGUuZGVsZXRlKGVsZW1lbnQpO1xuXG4gIHJldHVybiBlbGVtZW50O1xufVxuXG4vKipcbiAqIFJlY3ljbGVzIGFsbCB1bnByb3RlY3RlZCBhbGxvY2F0aW9ucy5cbiAqL1xuZnVuY3Rpb24gY2xlYW5NZW1vcnkoKSB7XG4gIHZhciBlbGVtZW50Q2FjaGUgPSBfcG9vbHMucG9vbHMuZWxlbWVudE9iamVjdC5jYWNoZTtcbiAgdmFyIGF0dHJpYnV0ZUNhY2hlID0gX3Bvb2xzLnBvb2xzLmF0dHJpYnV0ZU9iamVjdC5jYWNoZTtcblxuICAvLyBFbXB0eSBhbGwgZWxlbWVudCBhbGxvY2F0aW9ucy5cbiAgZWxlbWVudENhY2hlLmFsbG9jYXRlZC5mb3JFYWNoKGZ1bmN0aW9uICh2KSB7XG4gICAgaWYgKGVsZW1lbnRDYWNoZS5mcmVlLmxlbmd0aCA8IF9wb29scy5jb3VudCkge1xuICAgICAgZWxlbWVudENhY2hlLmZyZWUucHVzaCh2KTtcbiAgICB9XG4gIH0pO1xuXG4gIGVsZW1lbnRDYWNoZS5hbGxvY2F0ZWQuY2xlYXIoKTtcblxuICAvLyBDbGVhbiBvdXQgdW51c2VkIGVsZW1lbnRzLlxuICBfY2FjaGUuTm9kZUNhY2hlLmZvckVhY2goZnVuY3Rpb24gKG5vZGUsIGRlc2NyaXB0b3IpIHtcbiAgICBpZiAoIWVsZW1lbnRDYWNoZS5wcm90ZWN0ZWQuaGFzKGRlc2NyaXB0b3IpKSB7XG4gICAgICBfY2FjaGUuTm9kZUNhY2hlLmRlbGV0ZShkZXNjcmlwdG9yKTtcbiAgICB9XG4gIH0pO1xuXG4gIC8vIEVtcHR5IGFsbCBhdHRyaWJ1dGUgYWxsb2NhdGlvbnMuXG4gIGF0dHJpYnV0ZUNhY2hlLmFsbG9jYXRlZC5mb3JFYWNoKGZ1bmN0aW9uICh2KSB7XG4gICAgaWYgKGF0dHJpYnV0ZUNhY2hlLmZyZWUubGVuZ3RoIDwgX3Bvb2xzLmNvdW50KSB7XG4gICAgICBhdHRyaWJ1dGVDYWNoZS5mcmVlLnB1c2godik7XG4gICAgfVxuICB9KTtcblxuICBhdHRyaWJ1dGVDYWNoZS5hbGxvY2F0ZWQuY2xlYXIoKTtcbn1cblxufSx7XCIuLi91dGlsL3Bvb2xzXCI6MTUsXCIuL2NhY2hlXCI6MTB9XSwxNDpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzLmJsb2NrVGV4dCA9IHVuZGVmaW5lZDtcbmV4cG9ydHMucGFyc2UgPSBwYXJzZTtcblxudmFyIF9wb29scyA9IF9kZXJlcV8oJy4vcG9vbHMnKTtcblxudmFyIF9tYWtlID0gX2RlcmVxXygnLi4vdHJlZS9tYWtlJyk7XG5cbnZhciBfbWFrZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9tYWtlKTtcblxudmFyIF9oZWxwZXJzID0gX2RlcmVxXygnLi4vdHJlZS9oZWxwZXJzJyk7XG5cbnZhciBfZXNjYXBlID0gX2RlcmVxXygnLi9lc2NhcGUnKTtcblxudmFyIF9lc2NhcGUyID0gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChfZXNjYXBlKTtcblxuZnVuY3Rpb24gX2ludGVyb3BSZXF1aXJlRGVmYXVsdChvYmopIHsgcmV0dXJuIG9iaiAmJiBvYmouX19lc01vZHVsZSA/IG9iaiA6IHsgZGVmYXVsdDogb2JqIH07IH1cblxuLy8gQ29kZSBiYXNlZCBvZmYgb2Y6XG4vLyBodHRwczovL2dpdGh1Yi5jb20vYXNoaTAwOS9ub2RlLWZhc3QtaHRtbC1wYXJzZXJcblxudmFyIFRPS0VOID0gJ19fRElGRkhUTUxfXyc7XG5cbnZhciBkb2N0eXBlRXggPSAvPCEuKj4vaWc7XG52YXIgYXR0ckV4ID0gL1xcYihbX2Etel1bX2EtejAtOVxcLV0qKVxccyooPVxccyooXCIoW15cIl0rKVwifCcoW14nXSspJ3woXFxTKykpKT8vaWc7XG52YXIgdGFnRXggPSAvPCEtLVteXSo/KD89LS0+KS0tPnw8KFxcLz8pKFthLXpcXC1dW2EtejAtOVxcLV0qKVxccyooW14+XSo/KShcXC8/KT4vaWc7XG52YXIgc3BhY2VFeCA9IC9bXiBdLztcblxuLy8gV2UgdXNlIHRoaXMgU2V0IGluIHRoZSBub2RlL3BhdGNoIG1vZHVsZSBzbyBtYXJraW5nIGl0IGV4cG9ydGVkLlxudmFyIGJsb2NrVGV4dCA9IGV4cG9ydHMuYmxvY2tUZXh0ID0gbmV3IFNldChbJ3NjcmlwdCcsICdub3NjcmlwdCcsICdzdHlsZScsICdjb2RlJywgJ3RlbXBsYXRlJ10pO1xuXG52YXIgc2VsZkNsb3NpbmcgPSBuZXcgU2V0KFsnbWV0YScsICdpbWcnLCAnbGluaycsICdpbnB1dCcsICdhcmVhJywgJ2JyJywgJ2hyJ10pO1xuXG52YXIga0VsZW1lbnRzQ2xvc2VkQnlPcGVuaW5nID0ge1xuICBsaTogeyBsaTogdHJ1ZSB9LFxuICBwOiB7IHA6IHRydWUsIGRpdjogdHJ1ZSB9LFxuICB0ZDogeyB0ZDogdHJ1ZSwgdGg6IHRydWUgfSxcbiAgdGg6IHsgdGQ6IHRydWUsIHRoOiB0cnVlIH1cbn07XG5cbnZhciBrRWxlbWVudHNDbG9zZWRCeUNsb3NpbmcgPSB7XG4gIGxpOiB7IHVsOiB0cnVlLCBvbDogdHJ1ZSB9LFxuICBhOiB7IGRpdjogdHJ1ZSB9LFxuICBiOiB7IGRpdjogdHJ1ZSB9LFxuICBpOiB7IGRpdjogdHJ1ZSB9LFxuICBwOiB7IGRpdjogdHJ1ZSB9LFxuICB0ZDogeyB0cjogdHJ1ZSwgdGFibGU6IHRydWUgfSxcbiAgdGg6IHsgdHI6IHRydWUsIHRhYmxlOiB0cnVlIH1cbn07XG5cbi8qKlxuICogSW50ZXJwb2xhdGUgZHluYW1pYyBzdXBwbGVtZW50YWwgdmFsdWVzIGZyb20gdGhlIHRhZ2dlZCB0ZW1wbGF0ZSBpbnRvIHRoZVxuICogdHJlZS5cbiAqXG4gKiBAcGFyYW0gY3VycmVudFBhcmVudFxuICogQHBhcmFtIHN0cmluZ1xuICogQHBhcmFtIHN1cHBsZW1lbnRhbFxuICovXG52YXIgaW50ZXJwb2xhdGVEeW5hbWljQml0cyA9IGZ1bmN0aW9uIGludGVycG9sYXRlRHluYW1pY0JpdHMoY3VycmVudFBhcmVudCwgc3RyaW5nLCBzdXBwbGVtZW50YWwpIHtcbiAgaWYgKHN0cmluZyAmJiBzdHJpbmcuaW5kZXhPZihUT0tFTikgPiAtMSkge1xuICAgIChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgdG9BZGQgPSBbXTtcblxuICAgICAgLy8gQnJlYWsgdXAgdGhlIGluY29taW5nIHN0cmluZyBpbnRvIGR5bmFtaWMgcGFydHMgdGhhdCBhcmUgdGhlbiBwdXNoZWRcbiAgICAgIC8vIGludG8gYSBuZXcgc2V0IG9mIGNoaWxkIG5vZGVzLlxuICAgICAgc3RyaW5nLnNwbGl0KFRPS0VOKS5mb3JFYWNoKGZ1bmN0aW9uICh2YWx1ZSwgaW5kZXgpIHtcbiAgICAgICAgaWYgKGluZGV4ID09PSAwKSB7XG4gICAgICAgICAgLy8gV2UgdHJpbSBoZXJlIHRvIGFsbG93IGZvciBuZXdsaW5lcyBiZWZvcmUgYW5kIGFmdGVyIG1hcmt1cCBzdGFydHMuXG4gICAgICAgICAgaWYgKHZhbHVlICYmIHZhbHVlLnRyaW0oKSkge1xuICAgICAgICAgICAgdG9BZGQucHVzaChUZXh0Tm9kZSh2YWx1ZSkpO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIC8vIFRoZSBmaXJzdCBpdGVtIGRvZXMgbm90IG1lYW4gdGhlcmUgd2FzIGR5bmFtaWMgY29udGVudC5cbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJZiB3ZSBhcmUgaW4gdGhlIHNlY29uZCBpdGVyYXRpb24sIHRoaXNcbiAgICAgICAgdmFyIGR5bmFtaWNCaXQgPSBzdXBwbGVtZW50YWwuY2hpbGRyZW4uc2hpZnQoKTtcblxuICAgICAgICBpZiAodHlwZW9mIGR5bmFtaWNCaXQgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgdG9BZGQucHVzaChUZXh0Tm9kZShkeW5hbWljQml0KSk7XG4gICAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShkeW5hbWljQml0KSkge1xuICAgICAgICAgIHRvQWRkLnB1c2guYXBwbHkodG9BZGQsIGR5bmFtaWNCaXQpO1xuICAgICAgICB9IGVsc2UgaWYgKGR5bmFtaWNCaXQub3duZXJEb2N1bWVudCkge1xuICAgICAgICAgIHRvQWRkLnB1c2goKDAsIF9tYWtlMi5kZWZhdWx0KShkeW5hbWljQml0KSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdG9BZGQucHVzaChkeW5hbWljQml0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRoaXMgaXMgYSB1c2VmdWwgVGV4dCBOb2RlLlxuICAgICAgICBpZiAodmFsdWUgJiYgdmFsdWUudHJpbSgpKSB7XG4gICAgICAgICAgdG9BZGQucHVzaChUZXh0Tm9kZSh2YWx1ZSkpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgY3VycmVudFBhcmVudC5jaGlsZE5vZGVzLnB1c2guYXBwbHkoY3VycmVudFBhcmVudC5jaGlsZE5vZGVzLCB0b0FkZCk7XG4gICAgfSkoKTtcbiAgfSBlbHNlIGlmIChzdHJpbmcgJiYgc3RyaW5nLmxlbmd0aCAmJiAhZG9jdHlwZUV4LmV4ZWMoc3RyaW5nKSkge1xuICAgIGN1cnJlbnRQYXJlbnQuY2hpbGROb2Rlcy5wdXNoKFRleHROb2RlKHN0cmluZykpO1xuICB9XG59O1xuXG4vKipcbiAqIFRleHROb2RlIHRvIGNvbnRhaW4gYSB0ZXh0IGVsZW1lbnQgaW4gRE9NIHRyZWUuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5vZGVWYWx1ZSAtIEEgdmFsdWUgdG8gc2V0IGluIHRoZSB0ZXh0LCwgc2V0IHVuZXNjYXBlZFxuICogQHJldHVybiB7T2JqZWN0fSAtIEEgVmlydHVhbCBUcmVlIGVsZW1lbnQgcmVwcmVzZW50aW5nIHRoZSBUZXh0IE5vZGVcbiAqL1xudmFyIFRleHROb2RlID0gZnVuY3Rpb24gVGV4dE5vZGUodmFsdWUpIHtcbiAgdmFyIHZUcmVlID0gKDAsIF9oZWxwZXJzLmNyZWF0ZUVsZW1lbnQpKCcjdGV4dCcsIFtdLCBbXSk7XG4gIHZUcmVlLm5vZGVWYWx1ZSA9IHZhbHVlO1xuICByZXR1cm4gdlRyZWU7XG59O1xuXG4vKipcbiAqIEhUTUxFbGVtZW50LCB3aGljaCBjb250YWlucyBhIHNldCBvZiBjaGlsZHJlbi5cbiAqXG4gKiBOb3RlOiB0aGlzIGlzIGEgbWluaW1hbGlzdCBpbXBsZW1lbnRhdGlvbiwgbm8gY29tcGxldGUgdHJlZSBzdHJ1Y3R1cmVcbiAqIHByb3ZpZGVkIChubyBwYXJlbnROb2RlLCBuZXh0U2libGluZywgcHJldmlvdXNTaWJsaW5nIGV0YykuXG4gKlxuICogQHBhcmFtIHtTdHJpbmd9IG5vZGVOYW1lIC0gRE9NIE5vZGUgbmFtZVxuICogQHBhcmFtIHtPYmplY3R9IHJhd0F0dHJzIC0gRE9NIE5vZGUgQXR0cmlidXRlc1xuICogQHBhcmFtIHtPYmplY3R9IHN1cHBsZW1lbnRhbCAtIEludGVycG9sYXRlZCBkYXRhIGZyb20gYSB0YWdnZWQgdGVtcGxhdGVcbiAqIEByZXR1cm4ge09iamVjdH0gdlRyZWVcbiAqL1xudmFyIEhUTUxFbGVtZW50ID0gZnVuY3Rpb24gSFRNTEVsZW1lbnQobm9kZU5hbWUsIHJhd0F0dHJzLCBzdXBwbGVtZW50YWwpIHtcbiAgdmFyIHZUcmVlID0gKDAsIF9oZWxwZXJzLmNyZWF0ZUVsZW1lbnQpKG5vZGVOYW1lLCBbXSwgW10pO1xuXG4gIGZvciAodmFyIG1hdGNoOyBtYXRjaCA9IGF0dHJFeC5leGVjKHJhd0F0dHJzIHx8ICcnKTspIHtcbiAgICB2YXIgbmFtZSA9IG1hdGNoWzFdO1xuICAgIHZhciB2YWx1ZSA9IG1hdGNoWzZdIHx8IG1hdGNoWzVdIHx8IG1hdGNoWzRdIHx8IG1hdGNoWzFdO1xuICAgIHZhciBhdHRyID0gKDAsIF9oZWxwZXJzLmNyZWF0ZUF0dHJpYnV0ZSkobmFtZSwgdmFsdWUpO1xuXG4gICAgaWYgKGF0dHIudmFsdWUgPT09IFRPS0VOKSB7XG4gICAgICBhdHRyLnZhbHVlID0gc3VwcGxlbWVudGFsLnByb3BzLnNoaWZ0KCk7XG4gICAgfVxuXG4gICAgLy8gSWYgYSBrZXkgYXR0cmlidXRlIGlzIGZvdW5kIGF0dGFjaCBkaXJlY3RseSB0byB0aGUgdlRyZWUuXG4gICAgaWYgKGF0dHIubmFtZSA9PT0gJ2tleScpIHtcbiAgICAgIHZUcmVlLmtleSA9IGF0dHIudmFsdWU7XG4gICAgfVxuXG4gICAgLy8gTG9vayBmb3IgZW1wdHkgYXR0cmlidXRlcy5cbiAgICBpZiAobWF0Y2hbNl0gPT09ICdcIlwiJykge1xuICAgICAgYXR0ci52YWx1ZSA9ICcnO1xuICAgIH1cblxuICAgIHZUcmVlLmF0dHJpYnV0ZXMucHVzaChhdHRyKTtcbiAgfVxuXG4gIHJldHVybiB2VHJlZTtcbn07XG5cbi8qKlxuICogUGFyc2VzIEhUTUwgYW5kIHJldHVybnMgYSByb290IGVsZW1lbnRcbiAqXG4gKiBAcGFyYW0ge1N0cmluZ30gaHRtbCAtIFN0cmluZyBvZiBIVE1MIG1hcmt1cCB0byBwYXJzZSBpbnRvIGEgVmlydHVhbCBUcmVlXG4gKiBAcGFyYW0ge09iamVjdH0gc3VwcGxlbWVudGFsIC0gRHluYW1pYyBpbnRlcnBvbGF0ZWQgZGF0YSB2YWx1ZXNcbiAqIEBwYXJhbSB7T2JqZWN0fSBvcHRpb25zIC0gQ29udGFpbnMgb3B0aW9ucyBsaWtlIHNpbGVuY2luZyB3YXJuaW5nc1xuICogQHJldHVybiB7T2JqZWN0fSAtIFBhcnNlZCBWaXJ0dWFsIFRyZWUgRWxlbWVudFxuICovXG5mdW5jdGlvbiBwYXJzZShodG1sLCBzdXBwbGVtZW50YWwpIHtcbiAgdmFyIG9wdGlvbnMgPSBhcmd1bWVudHMubGVuZ3RoIDw9IDIgfHwgYXJndW1lbnRzWzJdID09PSB1bmRlZmluZWQgPyB7fSA6IGFyZ3VtZW50c1syXTtcblxuICB2YXIgcm9vdCA9IEhUTUxFbGVtZW50KCcjZG9jdW1lbnQtZnJhZ21lbnQnKTtcbiAgdmFyIHN0YWNrID0gW3Jvb3RdO1xuICB2YXIgY3VycmVudFBhcmVudCA9IHJvb3Q7XG4gIHZhciBsYXN0VGV4dFBvcyA9IC0xO1xuXG4gIC8vIElmIHRoZXJlIGFyZSBubyBIVE1MIGVsZW1lbnRzLCB0cmVhdCB0aGUgcGFzc2VkIGluIGh0bWwgYXMgYSBzaW5nbGVcbiAgLy8gdGV4dCBub2RlLlxuICBpZiAoaHRtbC5pbmRleE9mKCc8JykgPT09IC0xICYmIGh0bWwpIHtcbiAgICBpbnRlcnBvbGF0ZUR5bmFtaWNCaXRzKGN1cnJlbnRQYXJlbnQsIGh0bWwsIHN1cHBsZW1lbnRhbCk7XG4gICAgcmV0dXJuIHJvb3Q7XG4gIH1cblxuICAvLyBMb29rIHRocm91Z2ggdGhlIEhUTUwgbWFya3VwIGZvciB2YWxpZCB0YWdzLlxuICBmb3IgKHZhciBtYXRjaCwgdGV4dDsgbWF0Y2ggPSB0YWdFeC5leGVjKGh0bWwpOykge1xuICAgIGlmIChsYXN0VGV4dFBvcyA+IC0xKSB7XG4gICAgICBpZiAobGFzdFRleHRQb3MgKyBtYXRjaFswXS5sZW5ndGggPCB0YWdFeC5sYXN0SW5kZXgpIHtcbiAgICAgICAgLy8gaWYgaGFzIGNvbnRlbnRcbiAgICAgICAgdGV4dCA9IGh0bWwuc2xpY2UobGFzdFRleHRQb3MsIHRhZ0V4Lmxhc3RJbmRleCAtIG1hdGNoWzBdLmxlbmd0aCk7XG5cbiAgICAgICAgaW50ZXJwb2xhdGVEeW5hbWljQml0cyhjdXJyZW50UGFyZW50LCB0ZXh0LCBzdXBwbGVtZW50YWwpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBtYXRjaE9mZnNldCA9IHRhZ0V4Lmxhc3RJbmRleCAtIG1hdGNoWzBdLmxlbmd0aDtcblxuICAgIGlmIChsYXN0VGV4dFBvcyA9PT0gLTEgJiYgbWF0Y2hPZmZzZXQgPiAwKSB7XG4gICAgICB2YXIgc3RyaW5nID0gaHRtbC5zbGljZSgwLCBtYXRjaE9mZnNldCk7XG5cbiAgICAgIGlmIChzdHJpbmcgJiYgc3RyaW5nLnRyaW0oKSAmJiAhZG9jdHlwZUV4LmV4ZWMoc3RyaW5nKSkge1xuICAgICAgICBpbnRlcnBvbGF0ZUR5bmFtaWNCaXRzKGN1cnJlbnRQYXJlbnQsIHN0cmluZywgc3VwcGxlbWVudGFsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBsYXN0VGV4dFBvcyA9IHRhZ0V4Lmxhc3RJbmRleDtcblxuICAgIC8vIFRoaXMgaXMgYSBjb21tZW50LlxuICAgIGlmIChtYXRjaFswXVsxXSA9PT0gJyEnKSB7XG4gICAgICBjb250aW51ZTtcbiAgICB9XG5cbiAgICBpZiAoIW1hdGNoWzFdKSB7XG4gICAgICAvLyBub3QgPC8gdGFnc1xuICAgICAgdmFyIGF0dHJzID0ge307XG5cbiAgICAgIGlmICghbWF0Y2hbNF0gJiYga0VsZW1lbnRzQ2xvc2VkQnlPcGVuaW5nW2N1cnJlbnRQYXJlbnQucmF3Tm9kZU5hbWVdKSB7XG4gICAgICAgIGlmIChrRWxlbWVudHNDbG9zZWRCeU9wZW5pbmdbY3VycmVudFBhcmVudC5yYXdOb2RlTmFtZV1bbWF0Y2hbMl1dKSB7XG4gICAgICAgICAgc3RhY2sucG9wKCk7XG4gICAgICAgICAgY3VycmVudFBhcmVudCA9IHN0YWNrW3N0YWNrLmxlbmd0aCAtIDFdO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGN1cnJlbnRQYXJlbnQgPSBjdXJyZW50UGFyZW50LmNoaWxkTm9kZXNbY3VycmVudFBhcmVudC5jaGlsZE5vZGVzLnB1c2goSFRNTEVsZW1lbnQobWF0Y2hbMl0sIG1hdGNoWzNdLCBzdXBwbGVtZW50YWwpKSAtIDFdO1xuXG4gICAgICBzdGFjay5wdXNoKGN1cnJlbnRQYXJlbnQpO1xuXG4gICAgICBpZiAoYmxvY2tUZXh0LmhhcyhtYXRjaFsyXSkpIHtcbiAgICAgICAgLy8gQSBsaXR0bGUgdGVzdCB0byBmaW5kIG5leHQgPC9zY3JpcHQ+IG9yIDwvc3R5bGU+IC4uLlxuICAgICAgICB2YXIgY2xvc2VNYXJrdXAgPSAnPC8nICsgbWF0Y2hbMl0gKyAnPic7XG4gICAgICAgIHZhciBpbmRleCA9IGh0bWwuaW5kZXhPZihjbG9zZU1hcmt1cCwgdGFnRXgubGFzdEluZGV4KTtcbiAgICAgICAgdmFyIGxlbmd0aCA9IG1hdGNoWzJdLmxlbmd0aDtcblxuICAgICAgICBpZiAoaW5kZXggPT09IC0xKSB7XG4gICAgICAgICAgbGFzdFRleHRQb3MgPSB0YWdFeC5sYXN0SW5kZXggPSBodG1sLmxlbmd0aCArIDE7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgbGFzdFRleHRQb3MgPSBpbmRleCArIGNsb3NlTWFya3VwLmxlbmd0aDtcbiAgICAgICAgICB0YWdFeC5sYXN0SW5kZXggPSBsYXN0VGV4dFBvcztcbiAgICAgICAgICBtYXRjaFsxXSA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgbmV3VGV4dCA9IGh0bWwuc2xpY2UobWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgsIGluZGV4KTtcbiAgICAgICAgaW50ZXJwb2xhdGVEeW5hbWljQml0cyhjdXJyZW50UGFyZW50LCBuZXdUZXh0LnRyaW0oKSwgc3VwcGxlbWVudGFsKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAobWF0Y2hbMV0gfHwgbWF0Y2hbNF0gfHwgc2VsZkNsb3NpbmcuaGFzKG1hdGNoWzJdKSkge1xuICAgICAgaWYgKG1hdGNoWzJdICE9PSBjdXJyZW50UGFyZW50LnJhd05vZGVOYW1lICYmIG9wdGlvbnMuc3RyaWN0KSB7XG4gICAgICAgIHZhciBub2RlTmFtZSA9IGN1cnJlbnRQYXJlbnQucmF3Tm9kZU5hbWU7XG5cbiAgICAgICAgLy8gRmluZCBhIHN1YnNldCBvZiB0aGUgbWFya3VwIHBhc3NlZCBpbiB0byB2YWxpZGF0ZS5cbiAgICAgICAgdmFyIG1hcmt1cCA9IGh0bWwuc2xpY2UodGFnRXgubGFzdEluZGV4IC0gbWF0Y2hbMF0ubGVuZ3RoKS5zcGxpdCgnXFxuJykuc2xpY2UoMCwgMyk7XG5cbiAgICAgICAgLy8gUG9zaXRpb24gdGhlIGNhcmV0IG5leHQgdG8gdGhlIGZpcnN0IG5vbi13aGl0ZXNwYWNlIGNoYXJhY3Rlci5cbiAgICAgICAgdmFyIGNhcmV0ID0gQXJyYXkoc3BhY2VFeC5leGVjKG1hcmt1cFswXSkuaW5kZXgpLmpvaW4oJyAnKSArICdeJztcblxuICAgICAgICAvLyBDcmFmdCB0aGUgd2FybmluZyBtZXNzYWdlIGFuZCBpbmplY3QgaXQgaW50byB0aGUgbWFya3VwLlxuICAgICAgICBtYXJrdXAuc3BsaWNlKDEsIDAsIGNhcmV0ICsgJ1xcblBvc3NpYmx5IGludmFsaWQgbWFya3VwLiBTYXcgJyArIG1hdGNoWzJdICsgJywgZXhwZWN0ZWQgJyArIG5vZGVOYW1lICsgJy4uLlxcbiAgICAgICAgJyk7XG5cbiAgICAgICAgLy8gVGhyb3cgYW4gZXJyb3IgbWVzc2FnZSBpZiB0aGUgbWFya3VwIGlzbid0IHdoYXQgd2UgZXhwZWN0ZWQuXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignJyArIG1hcmt1cC5qb2luKCdcXG4nKSk7XG4gICAgICB9XG5cbiAgICAgIC8vIDwvIG9yIC8+IG9yIDxicj4gZXRjLlxuICAgICAgd2hpbGUgKGN1cnJlbnRQYXJlbnQpIHtcbiAgICAgICAgaWYgKGN1cnJlbnRQYXJlbnQucmF3Tm9kZU5hbWUgPT0gbWF0Y2hbMl0pIHtcbiAgICAgICAgICBzdGFjay5wb3AoKTtcbiAgICAgICAgICBjdXJyZW50UGFyZW50ID0gc3RhY2tbc3RhY2subGVuZ3RoIC0gMV07XG5cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YXIgdGFnID0ga0VsZW1lbnRzQ2xvc2VkQnlDbG9zaW5nW2N1cnJlbnRQYXJlbnQucmF3Tm9kZU5hbWVdO1xuXG4gICAgICAgICAgLy8gVHJ5aW5nIHRvIGNsb3NlIGN1cnJlbnQgdGFnLCBhbmQgbW92ZSBvblxuICAgICAgICAgIGlmICh0YWcpIHtcblxuICAgICAgICAgICAgaWYgKHRhZ1ttYXRjaFsyXV0pIHtcbiAgICAgICAgICAgICAgc3RhY2sucG9wKCk7XG4gICAgICAgICAgICAgIGN1cnJlbnRQYXJlbnQgPSBzdGFja1tzdGFjay5sZW5ndGggLSAxXTtcblxuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG5cbiAgICAgICAgICAvLyBVc2UgYWdncmVzc2l2ZSBzdHJhdGVneSB0byBoYW5kbGUgdW5tYXRjaGluZyBtYXJrdXBzLlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gRmluZCBhbnkgbGFzdCByZW1haW5pbmcgdGV4dCBhZnRlciB0aGUgcGFyc2luZyBjb21wbGV0ZXMgb3ZlciB0YWdzLlxuICB2YXIgcmVtYWluaW5nVGV4dCA9IGh0bWwuc2xpY2UobGFzdFRleHRQb3MgPT09IC0xID8gMCA6IGxhc3RUZXh0UG9zKS50cmltKCk7XG5cbiAgLy8gSWYgdGhlIHRleHQgZXhpc3RzIGFuZCBpc24ndCBqdXN0IHdoaXRlc3BhY2UsIHB1c2ggaW50byBhIG5ldyBUZXh0Tm9kZS5cbiAgaW50ZXJwb2xhdGVEeW5hbWljQml0cyhjdXJyZW50UGFyZW50LCByZW1haW5pbmdUZXh0LCBzdXBwbGVtZW50YWwpO1xuXG4gIC8vIFRoaXMgaXMgYW4gZW50aXJlIGRvY3VtZW50LCBzbyBvbmx5IGFsbG93IHRoZSBIVE1MIGNoaWxkcmVuIHRvIGJlXG4gIC8vIGJvZHkgb3IgaGVhZC5cbiAgaWYgKHJvb3QuY2hpbGROb2Rlcy5sZW5ndGggJiYgcm9vdC5jaGlsZE5vZGVzWzBdLm5vZGVOYW1lID09PSAnaHRtbCcpIHtcbiAgICAoZnVuY3Rpb24gKCkge1xuICAgICAgLy8gU3RvcmUgZWxlbWVudHMgZnJvbSBiZWZvcmUgYm9keSBlbmQgYW5kIGFmdGVyIGJvZHkgZW5kLlxuICAgICAgdmFyIGhlYWQgPSB7IGJlZm9yZTogW10sIGFmdGVyOiBbXSB9O1xuICAgICAgdmFyIGJvZHkgPSB7IGFmdGVyOiBbXSB9O1xuICAgICAgdmFyIGJlZm9yZUhlYWQgPSB0cnVlO1xuICAgICAgdmFyIGJlZm9yZUJvZHkgPSB0cnVlO1xuICAgICAgdmFyIEhUTUwgPSByb290LmNoaWxkTm9kZXNbMF07XG5cbiAgICAgIC8vIEl0ZXJhdGUgdGhlIGNoaWxkcmVuIGFuZCBzdG9yZSBlbGVtZW50cyBpbiB0aGUgcHJvcGVyIGFycmF5IGZvclxuICAgICAgLy8gbGF0ZXIgY29uY2F0LCByZXBsYWNlIHRoZSBjdXJyZW50IGNoaWxkTm9kZXMgd2l0aCB0aGlzIG5ldyBhcnJheS5cbiAgICAgIEhUTUwuY2hpbGROb2RlcyA9IEhUTUwuY2hpbGROb2Rlcy5maWx0ZXIoZnVuY3Rpb24gKGVsKSB7XG4gICAgICAgIC8vIElmIGVpdGhlciBib2R5IG9yIGhlYWQsIGFsbG93IGFzIGEgdmFsaWQgZWxlbWVudC5cbiAgICAgICAgaWYgKGVsLm5vZGVOYW1lID09PSAnYm9keScgfHwgZWwubm9kZU5hbWUgPT09ICdoZWFkJykge1xuICAgICAgICAgIGlmIChlbC5ub2RlTmFtZSA9PT0gJ2hlYWQnKSB7XG4gICAgICAgICAgICBiZWZvcmVIZWFkID0gZmFsc2U7XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKGVsLm5vZGVOYW1lID09PSAnYm9keScpIHtcbiAgICAgICAgICAgIGJlZm9yZUJvZHkgPSBmYWxzZTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICAvLyBOb3QgYSB2YWxpZCBuZXN0ZWQgSFRNTCB0YWcgZWxlbWVudCwgbW92ZSB0byByZXNwZWN0aXZlIGNvbnRhaW5lci5cbiAgICAgICAgZWxzZSBpZiAoZWwubm9kZVR5cGUgPT09IDEpIHtcbiAgICAgICAgICAgIGlmIChiZWZvcmVIZWFkICYmIGJlZm9yZUJvZHkpIHtcbiAgICAgICAgICAgICAgaGVhZC5iZWZvcmUucHVzaChlbCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFiZWZvcmVIZWFkICYmIGJlZm9yZUJvZHkpIHtcbiAgICAgICAgICAgICAgaGVhZC5hZnRlci5wdXNoKGVsKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWJlZm9yZUJvZHkpIHtcbiAgICAgICAgICAgICAgYm9keS5hZnRlci5wdXNoKGVsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgLy8gRW5zdXJlIHRoZSBmaXJzdCBlbGVtZW50IGlzIHRoZSBIRUFEIHRhZy5cbiAgICAgIGlmICghSFRNTC5jaGlsZE5vZGVzWzBdIHx8IEhUTUwuY2hpbGROb2Rlc1swXS5ub2RlTmFtZSAhPT0gJ2hlYWQnKSB7XG4gICAgICAgIHZhciBoZWFkSW5zdGFuY2UgPSBfcG9vbHMucG9vbHMuZWxlbWVudE9iamVjdC5nZXQoKTtcbiAgICAgICAgaGVhZEluc3RhbmNlLm5vZGVOYW1lID0gJ2hlYWQnO1xuICAgICAgICBoZWFkSW5zdGFuY2UuY2hpbGROb2Rlcy5sZW5ndGggPSAwO1xuICAgICAgICBoZWFkSW5zdGFuY2UuYXR0cmlidXRlcy5sZW5ndGggPSAwO1xuXG4gICAgICAgIHZhciBleGlzdGluZyA9IGhlYWRJbnN0YW5jZS5jaGlsZE5vZGVzO1xuICAgICAgICBleGlzdGluZy51bnNoaWZ0LmFwcGx5KGV4aXN0aW5nLCBoZWFkLmJlZm9yZSk7XG4gICAgICAgIGV4aXN0aW5nLnB1c2guYXBwbHkoZXhpc3RpbmcsIGhlYWQuYWZ0ZXIpO1xuXG4gICAgICAgIEhUTUwuY2hpbGROb2Rlcy51bnNoaWZ0KGhlYWRJbnN0YW5jZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgX2V4aXN0aW5nID0gSFRNTC5jaGlsZE5vZGVzWzBdLmNoaWxkTm9kZXM7XG4gICAgICAgIF9leGlzdGluZy51bnNoaWZ0LmFwcGx5KF9leGlzdGluZywgaGVhZC5iZWZvcmUpO1xuICAgICAgICBfZXhpc3RpbmcucHVzaC5hcHBseShfZXhpc3RpbmcsIGhlYWQuYWZ0ZXIpO1xuICAgICAgfVxuXG4gICAgICAvLyBFbnN1cmUgdGhlIHNlY29uZCBlbGVtZW50IGlzIHRoZSBib2R5IHRhZy5cbiAgICAgIGlmICghSFRNTC5jaGlsZE5vZGVzWzFdIHx8IEhUTUwuY2hpbGROb2Rlc1sxXS5ub2RlTmFtZSAhPT0gJ2JvZHknKSB7XG4gICAgICAgIHZhciBib2R5SW5zdGFuY2UgPSBfcG9vbHMucG9vbHMuZWxlbWVudE9iamVjdC5nZXQoKTtcbiAgICAgICAgYm9keUluc3RhbmNlLm5vZGVOYW1lID0gJ2JvZHknO1xuICAgICAgICBib2R5SW5zdGFuY2UuY2hpbGROb2Rlcy5sZW5ndGggPSAwO1xuICAgICAgICBib2R5SW5zdGFuY2UuYXR0cmlidXRlcy5sZW5ndGggPSAwO1xuXG4gICAgICAgIHZhciBfZXhpc3RpbmcyID0gYm9keUluc3RhbmNlLmNoaWxkTm9kZXM7XG4gICAgICAgIF9leGlzdGluZzIucHVzaC5hcHBseShfZXhpc3RpbmcyLCBib2R5LmFmdGVyKTtcblxuICAgICAgICBIVE1MLmNoaWxkTm9kZXMucHVzaChib2R5SW5zdGFuY2UpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIF9leGlzdGluZzMgPSBIVE1MLmNoaWxkTm9kZXNbMV0uY2hpbGROb2RlcztcbiAgICAgICAgX2V4aXN0aW5nMy5wdXNoLmFwcGx5KF9leGlzdGluZzMsIGJvZHkuYWZ0ZXIpO1xuICAgICAgfVxuICAgIH0pKCk7XG4gIH1cblxuICByZXR1cm4gcm9vdDtcbn1cblxufSx7XCIuLi90cmVlL2hlbHBlcnNcIjo3LFwiLi4vdHJlZS9tYWtlXCI6OCxcIi4vZXNjYXBlXCI6MTIsXCIuL3Bvb2xzXCI6MTV9XSwxNTpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG5leHBvcnRzLmNyZWF0ZVBvb2wgPSBjcmVhdGVQb29sO1xuZXhwb3J0cy5pbml0aWFsaXplUG9vbHMgPSBpbml0aWFsaXplUG9vbHM7XG52YXIgcG9vbHMgPSBleHBvcnRzLnBvb2xzID0ge307XG52YXIgY291bnQgPSBleHBvcnRzLmNvdW50ID0gMTAwMDA7XG5cbi8qKlxuICogQ3JlYXRlcyBhIHBvb2wgdG8gcXVlcnkgbmV3IG9yIHJldXNlZCB2YWx1ZXMgZnJvbS5cbiAqXG4gKiBAcGFyYW0gbmFtZVxuICogQHBhcmFtIG9wdHNcbiAqIEByZXR1cm4ge09iamVjdH0gcG9vbFxuICovXG5mdW5jdGlvbiBjcmVhdGVQb29sKG5hbWUsIG9wdHMpIHtcbiAgdmFyIHNpemUgPSBvcHRzLnNpemU7XG4gIHZhciBmaWxsID0gb3B0cy5maWxsO1xuXG4gIHZhciBjYWNoZSA9IHtcbiAgICBmcmVlOiBbXSxcbiAgICBhbGxvY2F0ZWQ6IG5ldyBTZXQoKSxcbiAgICBwcm90ZWN0ZWQ6IG5ldyBTZXQoKVxuICB9O1xuXG4gIC8vIFByaW1lIHRoZSBjYWNoZSB3aXRoIG4gb2JqZWN0cy5cbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBzaXplOyBpKyspIHtcbiAgICBjYWNoZS5mcmVlLnB1c2goZmlsbCgpKTtcbiAgfVxuXG4gIHJldHVybiB7XG4gICAgY2FjaGU6IGNhY2hlLFxuXG4gICAgZ2V0OiBmdW5jdGlvbiBnZXQoKSB7XG4gICAgICB2YXIgdmFsdWUgPSBjYWNoZS5mcmVlLnBvcCgpIHx8IGZpbGwoKTtcbiAgICAgIGNhY2hlLmFsbG9jYXRlZC5hZGQodmFsdWUpO1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH0sXG4gICAgcHJvdGVjdDogZnVuY3Rpb24gcHJvdGVjdCh2YWx1ZSkge1xuICAgICAgY2FjaGUuYWxsb2NhdGVkLmRlbGV0ZSh2YWx1ZSk7XG4gICAgICBjYWNoZS5wcm90ZWN0ZWQuYWRkKHZhbHVlKTtcbiAgICB9LFxuICAgIHVucHJvdGVjdDogZnVuY3Rpb24gdW5wcm90ZWN0KHZhbHVlKSB7XG4gICAgICBpZiAoY2FjaGUucHJvdGVjdGVkLmhhcyh2YWx1ZSkpIHtcbiAgICAgICAgY2FjaGUucHJvdGVjdGVkLmRlbGV0ZSh2YWx1ZSk7XG4gICAgICAgIGNhY2hlLmZyZWUucHVzaCh2YWx1ZSk7XG4gICAgICB9XG4gICAgfVxuICB9O1xufVxuXG5mdW5jdGlvbiBpbml0aWFsaXplUG9vbHMoQ09VTlQpIHtcbiAgcG9vbHMuYXR0cmlidXRlT2JqZWN0ID0gY3JlYXRlUG9vbCgnYXR0cmlidXRlT2JqZWN0Jywge1xuICAgIHNpemU6IENPVU5ULFxuXG4gICAgZmlsbDogZnVuY3Rpb24gZmlsbCgpIHtcbiAgICAgIHJldHVybiB7IG5hbWU6ICcnLCB2YWx1ZTogJycgfTtcbiAgICB9XG4gIH0pO1xuXG4gIHBvb2xzLmVsZW1lbnRPYmplY3QgPSBjcmVhdGVQb29sKCdlbGVtZW50T2JqZWN0Jywge1xuICAgIHNpemU6IENPVU5ULFxuXG4gICAgZmlsbDogZnVuY3Rpb24gZmlsbCgpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJhd05vZGVOYW1lOiAnJyxcbiAgICAgICAgbm9kZU5hbWU6ICcnLFxuICAgICAgICBub2RlVmFsdWU6ICcnLFxuICAgICAgICBub2RlVHlwZTogMSxcbiAgICAgICAga2V5OiAnJyxcbiAgICAgICAgY2hpbGROb2RlczogW10sXG4gICAgICAgIGF0dHJpYnV0ZXM6IFtdXG4gICAgICB9O1xuICAgIH1cbiAgfSk7XG59XG5cbi8vIENyZWF0ZSAke0NPVU5UfSBpdGVtcyBvZiBlYWNoIHR5cGUuXG5pbml0aWFsaXplUG9vbHMoY291bnQpO1xuXG59LHt9XSwxNjpbZnVuY3Rpb24oX2RlcmVxXyxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCBcIl9fZXNNb2R1bGVcIiwge1xuICB2YWx1ZTogdHJ1ZVxufSk7XG4vLyBMaXN0IG9mIFNWRyBlbGVtZW50cy5cbnZhciBlbGVtZW50cyA9IGV4cG9ydHMuZWxlbWVudHMgPSBbJ2FsdEdseXBoJywgJ2FsdEdseXBoRGVmJywgJ2FsdEdseXBoSXRlbScsICdhbmltYXRlJywgJ2FuaW1hdGVDb2xvcicsICdhbmltYXRlTW90aW9uJywgJ2FuaW1hdGVUcmFuc2Zvcm0nLCAnY2lyY2xlJywgJ2NsaXBQYXRoJywgJ2NvbG9yLXByb2ZpbGUnLCAnY3Vyc29yJywgJ2RlZnMnLCAnZGVzYycsICdlbGxpcHNlJywgJ2ZlQmxlbmQnLCAnZmVDb2xvck1hdHJpeCcsICdmZUNvbXBvbmVudFRyYW5zZmVyJywgJ2ZlQ29tcG9zaXRlJywgJ2ZlQ29udm9sdmVNYXRyaXgnLCAnZmVEaWZmdXNlTGlnaHRpbmcnLCAnZmVEaXNwbGFjZW1lbnRNYXAnLCAnZmVEaXN0YW50TGlnaHQnLCAnZmVGbG9vZCcsICdmZUZ1bmNBJywgJ2ZlRnVuY0InLCAnZmVGdW5jRycsICdmZUZ1bmNSJywgJ2ZlR2F1c3NpYW5CbHVyJywgJ2ZlSW1hZ2UnLCAnZmVNZXJnZScsICdmZU1lcmdlTm9kZScsICdmZU1vcnBob2xvZ3knLCAnZmVPZmZzZXQnLCAnZmVQb2ludExpZ2h0JywgJ2ZlU3BlY3VsYXJMaWdodGluZycsICdmZVNwb3RMaWdodCcsICdmZVRpbGUnLCAnZmVUdXJidWxlbmNlJywgJ2ZpbHRlcicsICdmb250JywgJ2ZvbnQtZmFjZScsICdmb250LWZhY2UtZm9ybWF0JywgJ2ZvbnQtZmFjZS1uYW1lJywgJ2ZvbnQtZmFjZS1zcmMnLCAnZm9udC1mYWNlLXVyaScsICdmb3JlaWduT2JqZWN0JywgJ2cnLCAnZ2x5cGgnLCAnZ2x5cGhSZWYnLCAnaGtlcm4nLCAnaW1hZ2UnLCAnbGluZScsICdsaW5lYXJHcmFkaWVudCcsICdtYXJrZXInLCAnbWFzaycsICdtZXRhZGF0YScsICdtaXNzaW5nLWdseXBoJywgJ21wYXRoJywgJ3BhdGgnLCAncGF0dGVybicsICdwb2x5Z29uJywgJ3BvbHlsaW5lJywgJ3JhZGlhbEdyYWRpZW50JywgJ3JlY3QnLCAnc2V0JywgJ3N0b3AnLCAnc3ZnJywgJ3N3aXRjaCcsICdzeW1ib2wnLCAndGV4dCcsICd0ZXh0UGF0aCcsICd0cmVmJywgJ3RzcGFuJywgJ3VzZScsICd2aWV3JywgJ3ZrZXJuJ107XG5cbi8vIE5hbWVzcGFjZS5cbnZhciBuYW1lc3BhY2UgPSBleHBvcnRzLm5hbWVzcGFjZSA9ICdodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2Zyc7XG5cbn0se31dLDE3OltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcblxudmFyIF90eXBlb2YgPSB0eXBlb2YgU3ltYm9sID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIFN5bWJvbC5pdGVyYXRvciA9PT0gXCJzeW1ib2xcIiA/IGZ1bmN0aW9uIChvYmopIHsgcmV0dXJuIHR5cGVvZiBvYmo7IH0gOiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmogJiYgdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICYmIG9iai5jb25zdHJ1Y3RvciA9PT0gU3ltYm9sID8gXCJzeW1ib2xcIiA6IHR5cGVvZiBvYmo7IH07XG5cbmV4cG9ydHMuaHRtbCA9IGh0bWw7XG5cbnZhciBfcGFyc2VyID0gX2RlcmVxXygnLi9wYXJzZXInKTtcblxudmFyIF9lc2NhcGUgPSBfZGVyZXFfKCcuL2VzY2FwZScpO1xuXG52YXIgX2VzY2FwZTIgPSBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KF9lc2NhcGUpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcFJlcXVpcmVEZWZhdWx0KG9iaikgeyByZXR1cm4gb2JqICYmIG9iai5fX2VzTW9kdWxlID8gb2JqIDogeyBkZWZhdWx0OiBvYmogfTsgfVxuXG52YXIgaXNQcm9wRXggPSAvKD18J3xcIikvO1xudmFyIFRPS0VOID0gJ19fRElGRkhUTUxfXyc7XG5cbi8qKlxuICogR2V0IHRoZSBuZXh0IHZhbHVlIGZyb20gdGhlIGxpc3QuIElmIHRoZSBuZXh0IHZhbHVlIGlzIGEgc3RyaW5nLCBtYWtlIHN1cmVcbiAqIGl0IGlzIGVzY2FwZWQuXG4gKlxuICogQHBhcmFtIHtBcnJheX0gdmFsdWVzIC0gVmFsdWVzIGV4dHJhY3RlZCBmcm9tIHRhZ2dlZCB0ZW1wbGF0ZSBsaXRlcmFsXG4gKiBAcmV0dXJuIHtTdHJpbmd8Kn0gLSBFc2NhcGVkIHN0cmluZywgb3RoZXJ3aXNlIGFueSB2YWx1ZSBwYXNzZWRcbiAqL1xudmFyIG5leHRWYWx1ZSA9IGZ1bmN0aW9uIG5leHRWYWx1ZSh2YWx1ZXMpIHtcbiAgdmFyIHZhbHVlID0gdmFsdWVzLnNoaWZ0KCk7XG4gIHJldHVybiB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnID8gKDAsIF9lc2NhcGUyLmRlZmF1bHQpKHZhbHVlKSA6IHZhbHVlO1xufTtcblxuLyoqXG4gKiBQYXJzZXMgdGFnZ2VkIHRlbXBsYXRlIGNvbnRlbnRzIGludG8gYSBWaXJ0dWFsIFRyZWUuIFRoZXNlIHRhZ2dlZCB0ZW1wbGF0ZXNcbiAqIHNlcGFyYXRlIHN0YXRpYyBzdHJpbmdzIGZyb20gdmFsdWVzLCBzbyB3ZSBuZWVkIHRvIGRvIHNvbWUgc3BlY2lhbCB0b2tlblxuICogd29ya1xuICpcbiAqIEBwYXJhbSB7QXJyYXl9IHN0cmluZ3MgLSBBIGxpc3Qgb2Ygc3RhdGljIHN0cmluZ3MsIHNwbGl0IGJ5IHZhbHVlXG4gKiBAcGFyYW0ge0FycmF5fSAuLi52YWx1ZXMgLSBBIGxpc3Qgb2YgaW50ZXJwb2xhdGVkIHZhbHVlc1xuICogQHJldHVybiB7T2JqZWN0fEFycmF5fSAtIEEgVmlydHVhbCBUcmVlIEVsZW1lbnQgb3IgYXJyYXkgb2YgZWxlbWVudHNcbiAqL1xuZnVuY3Rpb24gaHRtbChzdHJpbmdzKSB7XG4gIGZvciAodmFyIF9sZW4gPSBhcmd1bWVudHMubGVuZ3RoLCB2YWx1ZXMgPSBBcnJheShfbGVuID4gMSA/IF9sZW4gLSAxIDogMCksIF9rZXkgPSAxOyBfa2V5IDwgX2xlbjsgX2tleSsrKSB7XG4gICAgdmFsdWVzW19rZXkgLSAxXSA9IGFyZ3VtZW50c1tfa2V5XTtcbiAgfVxuXG4gIC8vIEF1dG9tYXRpY2FsbHkgY29lcmNlIGEgc3RyaW5nIGxpdGVyYWwgdG8gYXJyYXkuXG4gIGlmICh0eXBlb2Ygc3RyaW5ncyA9PT0gJ3N0cmluZycpIHtcbiAgICBzdHJpbmdzID0gW3N0cmluZ3NdO1xuICB9XG5cbiAgLy8gRG8gbm90IGF0dGVtcHQgdG8gcGFyc2UgZW1wdHkgc3RyaW5ncy5cbiAgaWYgKCFzdHJpbmdzWzBdLmxlbmd0aCAmJiAhdmFsdWVzLmxlbmd0aCkge1xuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgLy8gUGFyc2Ugb25seSB0aGUgdGV4dCwgbm8gZHluYW1pYyBiaXRzLlxuICBpZiAoc3RyaW5ncy5sZW5ndGggPT09IDEgJiYgIXZhbHVlcy5sZW5ndGgpIHtcbiAgICB2YXIgX2NoaWxkTm9kZXMgPSAoMCwgX3BhcnNlci5wYXJzZSkoc3RyaW5nc1swXSkuY2hpbGROb2RlcztcbiAgICByZXR1cm4gX2NoaWxkTm9kZXMubGVuZ3RoID4gMSA/IF9jaGlsZE5vZGVzIDogX2NoaWxkTm9kZXNbMF07XG4gIH1cblxuICAvLyBVc2VkIHRvIHN0b3JlIG1hcmt1cCBhbmQgdG9rZW5zLlxuICB2YXIgcmV0VmFsID0gW107XG5cbiAgLy8gV2UgZmlsdGVyIHRoZSBzdXBwbGVtZW50YWwgdmFsdWVzIGJ5IHdoZXJlIHRoZXkgYXJlIHVzZWQuIFZhbHVlcyBhcmVcbiAgLy8gZWl0aGVyIHByb3BzIG9yIGNoaWxkcmVuLlxuICB2YXIgc3VwcGxlbWVudGFsID0ge1xuICAgIHByb3BzOiBbXSxcbiAgICBjaGlsZHJlbjogW11cbiAgfTtcblxuICAvLyBMb29wIG92ZXIgdGhlIHN0YXRpYyBzdHJpbmdzLCBlYWNoIGJyZWFrIGNvcnJlbGF0ZXMgdG8gYW4gaW50ZXJwb2xhdGVkXG4gIC8vIHZhbHVlLiBTaW5jZSB0aGVzZSB2YWx1ZXMgY2FuIGJlIGR5bmFtaWMsIHdlIGNhbm5vdCBwYXNzIHRoZW0gdG8gdGhlXG4gIC8vIGRpZmZIVE1MIEhUTUwgcGFyc2VyIGlubGluZS4gVGhleSBhcmUgcGFzc2VkIGFzIGFuIGFkZGl0aW9uYWwgYXJndW1lbnRcbiAgLy8gY2FsbGVkIHN1cHBsZW1lbnRhbC4gVGhlIGZvbGxvd2luZyBsb29wIGluc3RydW1lbnRzIHRoZSBtYXJrdXAgd2l0aCB0b2tlbnNcbiAgLy8gdGhhdCB0aGUgcGFyc2VyIHRoZW4gdXNlcyB0byBhc3NlbWJsZSB0aGUgY29ycmVjdCB0cmVlLlxuICBzdHJpbmdzLmZvckVhY2goZnVuY3Rpb24gKHN0cmluZykge1xuICAgIC8vIEFsd2F5cyBhZGQgdGhlIHN0cmluZywgd2UgbmVlZCBpdCB0byBwYXJzZSB0aGUgbWFya3VwIGxhdGVyLlxuICAgIHJldFZhbC5wdXNoKHN0cmluZyk7XG5cbiAgICBpZiAodmFsdWVzLmxlbmd0aCkge1xuICAgICAgdmFyIHZhbHVlID0gbmV4dFZhbHVlKHZhbHVlcyk7XG4gICAgICB2YXIgbGFzdFNlZ21lbnQgPSBzdHJpbmcuc3BsaXQoJyAnKS5wb3AoKTtcbiAgICAgIHZhciBsYXN0Q2hhcmFjdGVyID0gbGFzdFNlZ21lbnQudHJpbSgpLnNsaWNlKC0xKTtcbiAgICAgIHZhciBpc1Byb3AgPSBCb29sZWFuKGxhc3RDaGFyYWN0ZXIubWF0Y2goaXNQcm9wRXgpKTtcblxuICAgICAgaWYgKGlzUHJvcCkge1xuICAgICAgICBzdXBwbGVtZW50YWwucHJvcHMucHVzaCh2YWx1ZSk7XG4gICAgICAgIHJldFZhbC5wdXNoKFRPS0VOKTtcbiAgICAgIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkgfHwgKHR5cGVvZiB2YWx1ZSA9PT0gJ3VuZGVmaW5lZCcgPyAndW5kZWZpbmVkJyA6IF90eXBlb2YodmFsdWUpKSA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgc3VwcGxlbWVudGFsLmNoaWxkcmVuLnB1c2godmFsdWUpO1xuICAgICAgICByZXRWYWwucHVzaChUT0tFTik7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXRWYWwucHVzaCh2YWx1ZSk7XG4gICAgICB9XG4gICAgfVxuICB9KTtcblxuICAvLyBQYXJzZSB0aGUgaW5zdHJ1bWVudGVkIG1hcmt1cCB0byBnZXQgdGhlIFZpcnR1YWwgVHJlZS5cbiAgdmFyIGNoaWxkTm9kZXMgPSAoMCwgX3BhcnNlci5wYXJzZSkocmV0VmFsLmpvaW4oJycpLCBzdXBwbGVtZW50YWwpLmNoaWxkTm9kZXM7XG5cbiAgLy8gVGhpcyBtYWtlcyBpdCBlYXNpZXIgdG8gd29yayB3aXRoIGEgc2luZ2xlIGVsZW1lbnQgYXMgYSByb290LCBpbnN0ZWFkIG9mXG4gIC8vIGFsd2F5cyByZXR1cm4gYW4gYXJyYXkuXG4gIHJldHVybiBjaGlsZE5vZGVzLmxlbmd0aCA+IDEgPyBjaGlsZE5vZGVzIDogY2hpbGROb2Rlc1swXTtcbn1cblxufSx7XCIuL2VzY2FwZVwiOjEyLFwiLi9wYXJzZXJcIjoxNH1dLDE4OltmdW5jdGlvbihfZGVyZXFfLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxuT2JqZWN0LmRlZmluZVByb3BlcnR5KGV4cG9ydHMsIFwiX19lc01vZHVsZVwiLCB7XG4gIHZhbHVlOiB0cnVlXG59KTtcbmV4cG9ydHMuYnVpbGRUcmlnZ2VyID0gYnVpbGRUcmlnZ2VyO1xuZXhwb3J0cy5tYWtlUHJvbWlzZXMgPSBtYWtlUHJvbWlzZXM7XG52YXIgZm9yRWFjaCA9IEFycmF5LnByb3RvdHlwZS5mb3JFYWNoO1xuXG4vKipcbiAqIENvbnRhaW5zIGFycmF5cyB0byBzdG9yZSB0cmFuc2l0aW9uIGNhbGxiYWNrcy5cbiAqXG4gKiBhdHRhY2hlZFxuICogLS0tLS0tLS1cbiAqXG4gKiBGb3Igd2hlbiBlbGVtZW50cyBjb21lIGludG8gdGhlIERPTS4gVGhlIGNhbGxiYWNrIHRyaWdnZXJzIGltbWVkaWF0ZWx5IGFmdGVyXG4gKiB0aGUgZWxlbWVudCBlbnRlcnMgdGhlIERPTS4gSXQgaXMgY2FsbGVkIHdpdGggdGhlIGVsZW1lbnQgYXMgdGhlIG9ubHlcbiAqIGFyZ3VtZW50LlxuICpcbiAqIGRldGFjaGVkXG4gKiAtLS0tLS0tLVxuICpcbiAqIEZvciB3aGVuIGVsZW1lbnRzIGFyZSByZW1vdmVkIGZyb20gdGhlIERPTS4gVGhlIGNhbGxiYWNrIHRyaWdnZXJzIGp1c3RcbiAqIGJlZm9yZSB0aGUgZWxlbWVudCBsZWF2ZXMgdGhlIERPTS4gSXQgaXMgY2FsbGVkIHdpdGggdGhlIGVsZW1lbnQgYXMgdGhlIG9ubHlcbiAqIGFyZ3VtZW50LlxuICpcbiAqIHJlcGxhY2VkXG4gKiAtLS0tLS0tLVxuICpcbiAqIEZvciB3aGVuIGVsZW1lbnRzIGFyZSByZXBsYWNlZCBpbiB0aGUgRE9NLiBUaGUgY2FsbGJhY2sgdHJpZ2dlcnMgYWZ0ZXIgdGhlXG4gKiBuZXcgZWxlbWVudCBlbnRlcnMgdGhlIERPTSwgYW5kIGJlZm9yZSB0aGUgb2xkIGVsZW1lbnQgbGVhdmVzLiBJdCBpcyBjYWxsZWRcbiAqIHdpdGggb2xkIGFuZCBuZXcgZWxlbWVudHMgYXMgYXJndW1lbnRzLCBpbiB0aGF0IG9yZGVyLlxuICpcbiAqIGF0dHJpYnV0ZUNoYW5nZWRcbiAqIC0tLS0tLS0tLS0tLS0tLS1cbiAqXG4gKiBUcmlnZ2VyZWQgd2hlbiBhbiBlbGVtZW50J3MgYXR0cmlidXRlIGhhcyBjaGFuZ2VkLiBUaGUgY2FsbGJhY2sgdHJpZ2dlcnNcbiAqIGFmdGVyIHRoZSBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQgaW4gdGhlIERPTS4gSXQgaXMgY2FsbGVkIHdpdGggdGhlIGVsZW1lbnQsXG4gKiB0aGUgYXR0cmlidXRlIG5hbWUsIG9sZCB2YWx1ZSwgYW5kIGN1cnJlbnQgdmFsdWUuXG4gKlxuICogdGV4dENoYW5nZWRcbiAqIC0tLS0tLS0tLS0tXG4gKlxuICogVHJpZ2dlcmVkIHdoZW4gYW4gZWxlbWVudCdzIGB0ZXh0Q29udGVudGAgY2huYWdlcy4gVGhlIGNhbGxiYWNrIHRyaWdnZXJzXG4gKiBhZnRlciB0aGUgdGV4dENvbnRlbnQgaGFzIGNoYW5nZWQgaW4gdGhlIERPTS4gSXQgaXMgY2FsbGVkIHdpdGggdGhlIGVsZW1lbnQsXG4gKiB0aGUgb2xkIHZhbHVlLCBhbmQgY3VycmVudCB2YWx1ZS5cbiAqL1xudmFyIHN0YXRlcyA9IGV4cG9ydHMuc3RhdGVzID0ge1xuICBhdHRhY2hlZDogW10sXG4gIGRldGFjaGVkOiBbXSxcbiAgcmVwbGFjZWQ6IFtdLFxuICBhdHRyaWJ1dGVDaGFuZ2VkOiBbXSxcbiAgdGV4dENoYW5nZWQ6IFtdXG59O1xuXG4vLyBEZWZpbmUgdGhlIGN1c3RvbSBzaWduYXR1cmVzIG5lY2Vzc2FyeSBmb3IgdGhlIGxvb3AgdG8gZmlsbCBpbiB0aGUgXCJtYWdpY1wiXG4vLyBtZXRob2RzIHRoYXQgcHJvY2VzcyB0aGUgdHJhbnNpdGlvbnMgY29uc2lzdGVudGx5LlxudmFyIGZuU2lnbmF0dXJlcyA9IHtcbiAgYXR0YWNoZWQ6IGZ1bmN0aW9uIGF0dGFjaGVkKGVsKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChjYikge1xuICAgICAgcmV0dXJuIGNiKGVsKTtcbiAgICB9O1xuICB9LFxuICBkZXRhY2hlZDogZnVuY3Rpb24gZGV0YWNoZWQoZWwpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGNiKSB7XG4gICAgICByZXR1cm4gY2IoZWwpO1xuICAgIH07XG4gIH0sXG4gIHJlcGxhY2VkOiBmdW5jdGlvbiByZXBsYWNlZChvbGRFbCwgbmV3RWwpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGNiKSB7XG4gICAgICByZXR1cm4gY2Iob2xkRWwsIG5ld0VsKTtcbiAgICB9O1xuICB9LFxuICB0ZXh0Q2hhbmdlZDogZnVuY3Rpb24gdGV4dENoYW5nZWQoZWwsIG9sZFZhbCwgbmV3VmFsKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChjYikge1xuICAgICAgcmV0dXJuIGNiKGVsLCBvbGRWYWwsIG5ld1ZhbCk7XG4gICAgfTtcbiAgfSxcbiAgYXR0cmlidXRlQ2hhbmdlZDogZnVuY3Rpb24gYXR0cmlidXRlQ2hhbmdlZChlbCwgbmFtZSwgb2xkVmFsLCBuZXdWYWwpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKGNiKSB7XG4gICAgICByZXR1cm4gY2IoZWwsIG5hbWUsIG9sZFZhbCwgbmV3VmFsKTtcbiAgICB9O1xuICB9XG59O1xuXG52YXIgbWFrZSA9IHt9O1xuXG4vLyBEeW5hbWljYWxseSBmaWxsIGluIHRoZSBjdXN0b20gbWV0aG9kcyBpbnN0ZWFkIG9mIG1hbnVhbGx5IGNvbnN0cnVjdGluZ1xuLy8gdGhlbS5cbk9iamVjdC5rZXlzKHN0YXRlcykuZm9yRWFjaChmdW5jdGlvbiAoc3RhdGVOYW1lKSB7XG4gIHZhciBtYXBGbiA9IGZuU2lnbmF0dXJlc1tzdGF0ZU5hbWVdO1xuXG4gIC8qKlxuICAgKiBNYWtlJ3MgdGhlIHRyYW5zaXRpb24gcHJvbWlzZXMuXG4gICAqXG4gICAqIEBwYXJhbSBlbGVtZW50c1xuICAgKiBAcGFyYW0gYXJnc1xuICAgKiBAcGFyYW0gcHJvbWlzZXNcbiAgICovXG4gIG1ha2Vbc3RhdGVOYW1lXSA9IGZ1bmN0aW9uIG1ha2VUcmFuc2l0aW9uUHJvbWlzZXMoZWxlbWVudHMsIGFyZ3MsIHByb21pc2VzKSB7XG4gICAgLy8gU29tZXRpbWVzIGFuIGFycmF5LWxpa2UgaXMgcGFzc2VkIHNvIHVzaW5nIGZvckVhY2ggaW4gdGhpcyBtYW5uZXIgeWllbGRzXG4gICAgLy8gbW9yZSBjb25zaXN0ZW50IHJlc3VsdHMuXG4gICAgZm9yRWFjaC5jYWxsKGVsZW1lbnRzLCBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgLy8gTmV2ZXIgcGFzcyB0ZXh0IG5vZGVzIHRvIGEgc3RhdGUgY2FsbGJhY2sgdW5sZXNzIGl0IGlzIHRleHRDaGFuZ2VkLlxuICAgICAgaWYgKHN0YXRlTmFtZSAhPT0gJ3RleHRDaGFuZ2VkJyAmJiBlbGVtZW50Lm5vZGVUeXBlICE9PSAxKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgLy8gQ2FsbCB0aGUgbWFwIGZ1bmN0aW9uIHdpdGggZWFjaCBlbGVtZW50LlxuICAgICAgdmFyIG5ld1Byb21pc2VzID0gc3RhdGVzW3N0YXRlTmFtZV0ubWFwKG1hcEZuLmFwcGx5KG51bGwsIFtlbGVtZW50XS5jb25jYXQoYXJncykpKTtcblxuICAgICAgLy8gTWVyZ2UgdGhlc2UgUHJvbWlzZXMgaW50byB0aGUgbWFpbiBjYWNoZS5cbiAgICAgIHByb21pc2VzLnB1c2guYXBwbHkocHJvbWlzZXMsIG5ld1Byb21pc2VzKTtcblxuICAgICAgLy8gUmVjdXJzaXZlbHkgY2FsbCBpbnRvIHRoZSBjaGlsZHJlbiBpZiBhdHRhY2hlZCBvciBkZXRhY2hlZC5cbiAgICAgIGlmIChzdGF0ZU5hbWUgPT09ICdhdHRhY2hlZCcgfHwgc3RhdGVOYW1lID09PSAnZGV0YWNoZWQnKSB7XG4gICAgICAgIG1ha2Vbc3RhdGVOYW1lXShlbGVtZW50LmNoaWxkTm9kZXMsIGFyZ3MsIHByb21pc2VzKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIHJldHVybiBwcm9taXNlcy5maWx0ZXIoZnVuY3Rpb24gKHByb21pc2UpIHtcbiAgICAgIHJldHVybiBCb29sZWFuKHByb21pc2UgJiYgcHJvbWlzZS50aGVuKTtcbiAgICB9KTtcbiAgfTtcbn0pO1xuXG4vKipcbiAqIEJ1aWxkcyBhIHJldXNhYmxlIHRyaWdnZXIgbWVjaGFuaXNtIGZvciB0aGUgZWxlbWVudCB0cmFuc2l0aW9ucy5cbiAqXG4gKiBAcGFyYW0gYWxsUHJvbWlzZXNcbiAqL1xuZnVuY3Rpb24gYnVpbGRUcmlnZ2VyKGFsbFByb21pc2VzKSB7XG4gIHZhciBhZGRQcm9taXNlcyA9IGFsbFByb21pc2VzLnB1c2guYXBwbHkuYmluZChhbGxQcm9taXNlcy5wdXNoLCBhbGxQcm9taXNlcyk7XG5cbiAgLy8gVGhpcyBiZWNvbWVzIGB0cmlnZ2VyVHJhbnNpdGlvbmAgaW4gcHJvY2Vzcy5qcy5cbiAgcmV0dXJuIGZ1bmN0aW9uIChzdGF0ZU5hbWUsIG1ha2VQcm9taXNlc0NhbGxiYWNrLCBjYWxsYmFjaykge1xuICAgIGlmIChzdGF0ZXNbc3RhdGVOYW1lXSAmJiBzdGF0ZXNbc3RhdGVOYW1lXS5sZW5ndGgpIHtcbiAgICAgIC8vIENhbGxzIGludG8gZWFjaCBjdXN0b20gaG9vayB0byBiaW5kIFByb21pc2VzIGludG8gdGhlIGxvY2FsIGFycmF5LFxuICAgICAgLy8gdGhlc2Ugd2lsbCB0aGVuIGdldCBtZXJnZWQgaW50byB0aGUgbWFpbiBgYWxsUHJvbWlzZXNgIGFycmF5LlxuICAgICAgdmFyIHByb21pc2VzID0gbWFrZVByb21pc2VzQ2FsbGJhY2soW10pO1xuXG4gICAgICAvLyBBZGQgdGhlc2UgcHJvbWlzZXMgaW50byB0aGUgZ2xvYmFsIGNhY2hlLlxuICAgICAgYWRkUHJvbWlzZXMocHJvbWlzZXMpO1xuXG4gICAgICBpZiAoY2FsbGJhY2spIHtcbiAgICAgICAgY2FsbGJhY2socHJvbWlzZXMubGVuZ3RoID8gcHJvbWlzZXMgOiB1bmRlZmluZWQpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoY2FsbGJhY2spIHtcbiAgICAgIGNhbGxiYWNrKCk7XG4gICAgfVxuICB9O1xufVxuXG4vKipcbiAqIE1ha2UgYSByZXVzYWJsZSBmdW5jdGlvbiBmb3IgZWFzeSB0cmFuc2l0aW9uIGNhbGxpbmcuXG4gKlxuICogQHBhcmFtIHN0YXRlTmFtZVxuICovXG5mdW5jdGlvbiBtYWtlUHJvbWlzZXMoc3RhdGVOYW1lKSB7XG4gIGZvciAodmFyIF9sZW4gPSBhcmd1bWVudHMubGVuZ3RoLCBhcmdzID0gQXJyYXkoX2xlbiA+IDEgPyBfbGVuIC0gMSA6IDApLCBfa2V5ID0gMTsgX2tleSA8IF9sZW47IF9rZXkrKykge1xuICAgIGFyZ3NbX2tleSAtIDFdID0gYXJndW1lbnRzW19rZXldO1xuICB9XG5cbiAgLy8gRW5zdXJlIGVsZW1lbnRzIGlzIGFsd2F5cyBhbiBhcnJheS5cbiAgdmFyIGVsZW1lbnRzID0gW10uY29uY2F0KGFyZ3NbMF0pO1xuXG4gIC8vIEFjY2VwdHMgdGhlIGxvY2FsIEFycmF5IG9mIHByb21pc2VzIHRvIHVzZS5cbiAgcmV0dXJuIGZ1bmN0aW9uIChwcm9taXNlcykge1xuICAgIHJldHVybiBtYWtlW3N0YXRlTmFtZV0oZWxlbWVudHMsIGFyZ3Muc2xpY2UoMSksIHByb21pc2VzKTtcbiAgfTtcbn1cblxufSx7fV19LHt9LFsxXSkoMSlcbn0pOyJdfQ==
/* global document */
// Welcome! require() some modules from npm (like you were using browserify)
// and then hit Run Code to run your code on the right side.
// Modules get downloaded from browserify-cdn and bundled in your browser.
const diff = require('diffhtml');
const container = document.querySelector('.js-container');
document.querySelector('.js-add').addEventListener('click', () => {
/*
let div = document.createElement('div');
div.classList.add('box');
div.classList.add('js-box');
div.innerText = new Date().getSeconds();
container.appendChild(div);
*/
diff.innerHTML(
container,
container.innerHTML + `<div class="box js-box">${new Date().getSeconds()}</div>`
);
});
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"diffhtml": "0.9.2"
}
}
<div class="container js-container">
</div>
<hr/>
<button class="js-add">Add</button>
<style type="text/css">
.container {
border: 2px solid darkgray;
height: 4em;
width: 30em;
display: flex;
flex-direction: row;
justify-content: flex-end;
}
.box {
flex-shrink: 0;
height: 3.5em;
width: 3.5em;
border: 1px solid gray;
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment