made with requirebin
Last active
May 6, 2017 02:42
-
-
Save dreki/3c751d9a026b6d2f6d1ee1ce86e317a2 to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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>` | |
); | |
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "requirebin-sketch", | |
"version": "1.0.0", | |
"dependencies": { | |
"diffhtml": "0.9.2" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="container js-container"> | |
</div> | |
<hr/> | |
<button class="js-add">Add</button> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<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