Skip to content

Instantly share code, notes, and snippets.

@joshgillies
Created May 4, 2017 01:17
Show Gist options
  • Save joshgillies/7e9b5fee912239103707bb7b8082095e to your computer and use it in GitHub Desktop.
Save joshgillies/7e9b5fee912239103707bb7b8082095e to your computer and use it in GitHub Desktop.
requirebin sketch
const hyperHTML = require('hyperhtml')
const component = require('hypercomponent')
riot = {}
const _riot = require('riot')
function toRiot (name, component, riot) {
riot.tag(name, '', function (opts) {
var tag = this
var instance = null
tag.one('mount', function onMount () {
if (instance === null) {
instance = component(opts)
tag.root.appendChild(instance.render(tag.opts))
}
})
tag.on('update', function onUpdate () {
if (instance !== null) instance.render(tag.opts)
})
tag.on('unmount', function onUnmount () {
if (instance) element = null
})
})
}
const Button = component((render, data) => render`
<button>
${data.text}
</button>
`)
function List () {
var cache = []
return component((render, data) => {
if (cache.length > data.children.length) cache.splice(data.children.length)
return render`
<ul>${
data.children.map((child, i) =>
hyperHTML.wire(cache[i] || (cache[i] = {}))`<li>${child}</li>`)
}</ul>
`
})()
}
;(function (riot) {
toRiot('c-button', Button, riot)
toRiot('c-list', List, riot)
riot.tag('app', '<div><c-list children="{children}"></c-list><c-button text="{text}"></c-button><c-button text="Hello There!"></c-button></div>', function app (opts) {
var tag = this
var buttons = opts.data.map(Button)
tag.children = opts.data.map((data, i) => buttons[i].render({ text: data }))
tag.text = opts.text
tag.on('update', function onUpdate () {
if (buttons.length > tag.data.length) buttons.splice(tag.data.length)
tag.children = tag.data.map((data, i) => (buttons[i] || Button()).render({ text: data }))
})
})
var app = riot.mount(document.body, 'app', { text: 'Hey there', data: ['test', 'test1', 'test2'] })[0]
setTimeout(() => app.update({ text: 'Hey there, again', data: ['test1', 'test2'] }), 2000)
setTimeout(() => app.update({ text: 'Hey there, and again', data: ['test11', 'test2', 'test3'] }), 5000)
})(_riot)
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})({1:[function(require,module,exports){
},{}],2:[function(require,module,exports){
const hyperHTML = require('viperhtml')
function createWire (obj, type) {
var self = this
return function wire () {
return hyperHTML.wire(obj || self, type).apply(hyperHTML, arguments)
}
}
function html (obj) {
return (arguments.length > 1 || (obj && obj.raw))
? hyperHTML.wire(this).apply(hyperHTML, arguments)
: createWire.call(this, obj)
}
function svg (obj) {
return (arguments.length > 1 || (obj && obj.raw))
? hyperHTML.wire(this, 'svg').apply(hyperHTML, arguments)
: createWire.call(this, obj, 'svg')
}
module.exports = function render () {
return html.apply(this, arguments)
}
module.exports.html = html
module.exports.svg = svg
},{"viperhtml":3}],3:[function(require,module,exports){
/*! (C) 2017 Andrea Giammarchi @WebReflection (MIT) */
module.exports = typeof document === 'object' ?
require('hyperhtml') :
require('./viperhtml.js');
},{"./viperhtml.js":6,"hyperhtml":5}],4:[function(require,module,exports){
/*jslint indent: 2 */
var html = (function (O) {'use strict';
// Andrea Giammarchi - MIT Style License
var
reEscape = /[&<>'"]/g,
reUnescape = /&(?:amp|#38|lt|#60|gt|#62|apos|#39|quot|#34);/g,
oEscape = {
'&': '&amp;',
'<': '&lt;',
'>': '&gt;',
"'": '&#39;',
'"': '&quot;'
},
oUnescape = {
'&amp;': '&',
'&#38;': '&',
'&lt;': '<',
'&#60;': '<',
'&gt;': '>',
'&#62;': '>',
'&apos;': "'",
'&#39;': "'",
'&quot;': '"',
'&#34;': '"'
},
fnEscape = function (m) {
return oEscape[m];
},
fnUnescape = function (m) {
return oUnescape[m];
},
replace = ''.replace;
return (O.freeze || O)({
escape: function escape(s) {
return replace.call(s, reEscape, fnEscape);
},
unescape: function unescape(s) {
return replace.call(s, reUnescape, fnUnescape);
}
});
}(Object));
try { module.exports = html; } catch (ignore) {}
},{}],5:[function(require,module,exports){
var hyperHTML = (function () {'use strict';
/*! (C) 2017 Andrea Giammarchi @WebReflection (MIT) */
// hyperHTML \o/
//
// var render = hyperHTML.bind(document.body);
// setInterval(() => render`
// <h1>⚡️ hyperHTML ⚡️</h1>
// <p>
// ${(new Date).toLocaleString()}
// </p>
// `, 1000);
function hyperHTML(statics) {
return EXPANDO in this &&
this[EXPANDO].s === statics ?
update.apply(this, arguments) :
upgrade.apply(this, arguments);
}
// A wire ➰ is a bridge between a document fragment
// and its inevitably lost list of rendered nodes
//
// var render = hyperHTML.wire();
// render`
// <div>Hello Wired!</div>
// `;
//
// Every single invocation will return that div
// or the list of elements it contained as Array.
// This simplifies most task where hyperHTML
// is used to create the node itself, instead of
// populating an already known and bound one.
hyperHTML.wire = function wire(obj, type) {
return arguments.length < 1 ?
wireContent('html') :
(obj == null ?
wireContent(type || 'html') :
(wm.get(obj) || wireWeakly(obj, type || 'html'))
);
};
// - - - - - - - - - - - - - - - - - - - - - - -
// -------------------------
// DOM parsing & traversing
// -------------------------
// setup attributes for updates
//
// <p class="${state.class}" onclick="${event.click}"></p>
//
// Note: always use quotes around attributes, even for events,
// booleans, or numbers, otherwise this function fails.
function attributesSeeker(node, actions) {
for (var
attribute,
value = IE ? uid : uidc,
attributes = slice.call(node.attributes),
i = 0,
length = attributes.length;
i < length; i++
) {
attribute = attributes[i];
if (attribute.value === value) {
// with IE the order doesn't really matter
// as long as the right attribute is addressed
actions.push(setAttribute(node, IE ?
node.getAttributeNode(IEAttributes.shift()) :
attribute
));
}
}
}
// traverse the whole node in search of editable content
// decide what each future update should change
//
// <div atr="${some.attribute}">
// <h1>${some.HTML}</h1>
// <p>
// ${some.text}
// </p>
// </div>
function lukeTreeWalker(node, actions) {
for (var
child, text,
childNodes = slice.call(node.childNodes),
length = childNodes.length,
i = 0; i < length; i++
) {
child = childNodes[i];
switch (child.nodeType) {
case 1:
attributesSeeker(child, actions);
lukeTreeWalker(child, actions);
break;
case 8:
if (child.textContent === uid) {
if (length === 1) {
actions.push(setAnyContent(node));
node.removeChild(child);
} else if (
(i < 1 || childNodes[i - 1].nodeType === 1) &&
(i + 1 === length || childNodes[i + 1].nodeType === 1)
) {
actions.push(setVirtualContent(child));
} else {
text = node.ownerDocument.createTextNode('');
actions.push(setTextContent(text));
node.replaceChild(text, child);
}
}
break;
}
}
}
// -------------------------
// DOM manipulating
// -------------------------
// update regular bound nodes
//
// var render = hyperHTML.bind(node);
// function update() {
// render`template`;
// }
function setAnyContent(node) {
return function any(value) {
switch (typeof value) {
case 'string':
node.innerHTML = value;
break;
case 'number':
case 'boolean':
node.textContent = value;
break;
default:
if (Array.isArray(value)) {
if (value.length === 1) {
any(value[0]);
} else if(typeof value[0] === 'string') {
any(value.join(''));
} else {
var i = indexOfDiffereces(node.childNodes, value);
if (-1 < i) {
updateViaArray(node, value, i);
}
}
} else {
populateNode(node, value);
}
break;
}
};
}
// update attributes node
//
// render`<a href="${url}" onclick="${click}">${name}</a>`;
//
// Note: attributes with a special meaning like DOM Level 0
// listeners or accessors properties are directly set
function setAttribute(node, attribute) {
var
name = attribute.name,
isSpecial = name in node && !SHOULD_USE_ATTRIBUTE.test(name),
oldValue
;
if (isSpecial) node.removeAttribute(name);
return isSpecial ?
function specialAttr(newValue) {
if (oldValue !== newValue) {
node[name] = (oldValue = newValue);
}
} :
function attr(newValue) {
if (oldValue !== newValue) {
attribute.value = (oldValue = newValue);
}
};
}
// update the "emptiness"
// this function is used when template literals
// have sneaky html/fragment capable
// updates in the wild (no spaces around)
//
// render`
// <p>Content before</p>${
// 'any content in between'
// }<p>Content after</p>
// `;
//
// Note: this is the most expensive
// update of them all.
function setVirtualContent(node) {
var
fragment = document.createDocumentFragment(),
childNodes = []
;
return function any(value) {
var i, parentNode = node.parentNode;
switch (typeof value) {
case 'string':
case 'number':
case 'boolean':
removeNodeList(childNodes, 0);
injectHTML(fragment, value);
childNodes = slice.call(fragment.childNodes);
parentNode.insertBefore(fragment, node);
break;
default:
if (Array.isArray(value)) {
if (value.length === 0) {
any(value[0]);
} else if(typeof value[0] === 'string') {
any(value.join(''));
} else {
i = indexOfDiffereces(childNodes, value);
if (-1 < i) {
removeNodeList(childNodes, i);
value = value.slice(i);
appendNodes(fragment, value);
parentNode.insertBefore(fragment, node);
childNodes.push.apply(childNodes, value);
}
}
} else {
removeNodeList(childNodes, 0);
childNodes = value.nodeType === 11 ?
slice.call(value.childNodes) :
[value];
parentNode.insertBefore(value, node);
}
break;
}
};
}
// basic closure to update nodes textContent
//
// render`
// <p>
// ${'spaces around means textContent'}
// </p>`;
function setTextContent(node) {
var oldValue;
return function text(newValue) {
if (oldValue !== newValue) {
node.textContent = (oldValue = newValue);
}
};
}
// -------------------------
// Helpers
// -------------------------
// it does exactly what it says
function appendNodes(node, childNodes) {
for (var
i = 0,
length = childNodes.length;
i < length; i++
) {
node.appendChild(childNodes[i]);
}
}
// given two collections, find
// the first index that has different content.
// If the two lists are the same, return -1
// to indicate no differences were found.
function indexOfDiffereces(a, b) {
if (a === b) return -1;
var
i = 0,
aLength = a.length,
bLength = b.length
;
while (i < aLength) {
if (i < bLength && a[i] === b[i]) i++;
else return i;
}
return i === bLength ? -1 : i;
}
// inject HTML into a template node
// and populate a fragment with resulting nodes
//
// IE9~IE11 are not compatible with the template tag.
// If the content is a partial part of a table there is a fallback.
// Not the most elegant/robust way but good enough for common cases.
// (I don't want to include a whole DOM parser for IE only here).
function injectHTML(fragment, html) {
var
fallback = IE && /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html),
template = fragment.ownerDocument.createElement('template')
;
template.innerHTML = fallback ? ('<table>' + html + '</table>') : html;
if (fallback) {
template = {childNodes: template.querySelectorAll(RegExp.$1)};
}
appendNodes(
fragment,
slice.call((template.content || template).childNodes)
);
}
// accordingly with the kind of child
// it puts its content into a parent node
function populateNode(parent, child) {
switch (child.nodeType) {
case 1:
var
childNodes = parent.childNodes,
length = childNodes.length
;
if (0 < length && childNodes[0] === child) {
removeNodeList(childNodes, 1);
} else if (length !== 1) {
resetAndPopulate(parent, child);
}
break;
case 11:
if (-1 < indexOfDiffereces(parent.childNodes, child.childNodes)) {
resetAndPopulate(parent, child);
}
break;
case 3:
parent.textContent = child.textContent;
break;
}
}
// it does exactly what it says
function removeNodeList(list, startIndex) {
var length = list.length, child;
while (startIndex < length--) {
child = list[length];
child.parentNode.removeChild(child);
}
}
// drop all nodes and append a node
function resetAndPopulate(parent, child) {
parent.textContent = '';
parent.appendChild(child);
}
// the first time a hyperHTML.wire() is invoked
// remember the list of nodes that should be updated
// at every consequent render call.
// The resulting function might return the very first node
// or the Array of all nodes that might need updates.
function setupAndGetContent(node) {
for (var
child,
children = [],
childNodes = node.childNodes,
i = 0,
length = childNodes.length;
i < length; i++
) {
child = childNodes[i];
if (
1 === child.nodeType ||
0 < trim.call(child.textContent).length
) {
children.push(child);
}
}
length = children.length;
return length < 2 ?
((child = length < 1 ? node : children[0]),
function () { return child; }) :
function () { return children; };
}
// remove and/or and a list of nodes through an array
function updateViaArray(node, childNodes, i) {
var fragment = node.ownerDocument.createDocumentFragment();
if (0 < i) {
removeNodeList(node.childNodes, i);
appendNodes(fragment, childNodes.slice(i));
node.appendChild(fragment);
} else {
appendNodes(fragment, childNodes);
resetAndPopulate(node, fragment);
}
}
// create a new wire for generic DOM content
function wireContent(type) {
var content, container, fragment, render, setup, template;
return function update(statics) {
if (template !== statics) {
setup = true;
template = statics;
fragment = document.createDocumentFragment();
container = type === 'svg' ?
document.createElementNS('http://www.w3.org/2000/svg', 'svg') :
fragment;
render = hyperHTML.bind(container);
}
render.apply(null, arguments);
if (setup) {
setup = false;
if (type === 'svg') {
appendNodes(fragment, slice.call(container.childNodes));
}
content = setupAndGetContent(fragment);
}
return content();
};
}
// get or create a wired weak reference
function wireWeakly(obj, type) {
var wire = wireContent(type);
wm.set(obj, wire);
return wire;
}
// -------------------------
// Template setup
// -------------------------
// each known hyperHTML update is
// kept as simple as possible.
function update() {
for (var
i = 1,
length = arguments.length,
updates = this[EXPANDO].u;
i < length; i++
) {
updates[i - 1](arguments[i]);
}
return this;
}
// but the first time, it needs to be setup.
// From now on, only update(statics) will be called
// unless this node won't be used for other renderings.
function upgrade(statics) {
var
updates = [],
html = statics.join(uidc)
;
if (IE) {
IEAttributes = [];
injectHTML(this, html.replace(no, comments));
} else if (this.nodeType === 1) {
this.innerHTML = html;
} else {
injectHTML(this, html);
}
lukeTreeWalker(this, updates);
this[EXPANDO] = {s: statics, u: updates};
return update.apply(this, arguments);
}
// -------------------------
// the trash bin
// -------------------------
// IE used to suck.
/*
// even in a try/catch this throw an error
// since it's reliable though, I'll keep it around
function isIE() {
var p = document.createElement('p');
p.innerHTML = '<i onclick="<!---->">';
return p.childNodes[0].onclick == null;
}
//*/
// remove and/or add a list of nodes through a fragment
/* temporarily removed until it's demonstrated it's needed
function updateViaFragment(node, fragment, i) {
if (0 < i) {
removeNodeList(node.childNodes, i);
var slim = fragment.cloneNode();
appendNodes(slim, slice.call(fragment.childNodes, i));
node.appendChild(fragment, slim);
} else {
resetAndPopulate(node, fragment);
}
}
//*/
// -------------------------
// local variables
// -------------------------
var
// some attribute might be present on the element prototype but cannot be set directly
SHOULD_USE_ATTRIBUTE = /^style$/i,
// avoids WeakMap to avoid memory pressure, use CSS compatible syntax for IE
EXPANDO = '_hyper_html: ',
// use a pseudo unique id to avoid conflicts and normalize CSS style for IE
uid = EXPANDO + ((Math.random() * new Date) | 0) + ';',
// use comment nodes with pseudo unique content to setup
uidc = '<!--' + uid + '-->',
// threat it differently
IE = 'documentMode' in document,
no = IE && new RegExp('([^\\S][a-z]+[a-z0-9_-]*=)([\'"])' + uidc + '\\2', 'g'),
comments = IE && function ($0, $1, $2) {
IEAttributes.push($1.slice(1, -1));
return $1 + $2 + uid + $2;
},
// verify empty textContent on .wire() setup
trim = EXPANDO.trim || function () {
return this.replace(/^\s+|\s+$/g, '');
},
// convert DOM.childNodes into arrays to avoid
// DOM mutation backfiring on loops
slice = [].slice,
// used for weak references
// if WeakMap is not available
// it uses a configurable, non enumerable,
// quick and dirty expando property.
wm = typeof WeakMap === typeof wm ?
{
get: function (obj) { return obj[EXPANDO]; },
set: function (obj, value) {
Object.defineProperty(obj, EXPANDO, {
configurable: true,
value: value
});
}
} :
new WeakMap(),
IEAttributes
;
// -------------------------
// ⚡️ ️️The End ➰
// -------------------------
return hyperHTML;
}());
// umd.KISS
try { module.exports = hyperHTML; } catch(o_O) {}
},{}],6:[function(require,module,exports){
(function (global){
'use strict';
/*! (C) 2017 Andrea Giammarchi @WebReflection (MIT) */
// viperHTML \o/
//
// var render = viperHTML.bind(object);
// render`
// <h1>⚡️ viperHTML ⚡️</h1>
// <p>
// ${(new Date).toLocaleString()}
// </p>
// `;
function viperHTML(statics) {
var viper = vipers.get(this);
return viper && viper.s === statics ?
(isAsync(this) ?
this.update : update).apply(viper, arguments) :
upgrade.apply(this, arguments);
}
// A wire ➰ is a shortcut to relate a specific object,
// or a runtime created one, to a specific template.
//
// var render = viperHTML.wire();
// render`
// <div>Hello Wired!</div>
// `;
viperHTML.wire = function wire(object) {
return arguments.length < 1 ?
viperHTML.bind({}) :
(wires.get(object) || (
wires.set(object, wire()),
wire(object)
));
};
// An asynchronous wire ➰ is a weakly referenced callback,
// to be invoked right before the template literals
// to return a rendered capable of resolving chunks.
viperHTML.async = function getAsync(object) {
return arguments.length < 1 ?
createAsync() :
(asyncs.get(object) || (
asyncs.set(object, getAsync()),
getAsync(object)
));
};
// - - - - - - - - - - - - - - - - - - - - - - -
// -------------------------
// DOM investigation
// -------------------------
// if a gap is in between a node declaration
// and its attribute definition this is true
function isAttribute(copies, i) {
return ATTRIBUTE_BEFORE.test(copies.slice(0, i).join('')) &&
ATTRIBUTE_AFTER.test(copies.slice(i).join(''));
}
// if a gap is in between html elements
// allow any sort of HTML content
function isHTML(statics, i) {
return statics[i - 1].slice(-1) === '>' &&
statics[i][0] === '<';
}
// -------------------------
// Helpers
// -------------------------
// instrument a wire to work asynchronously
// passing along an optional resolved chunks
// interceptor callback
function createAsync() {
var
wired = new Async,
wire = viperHTML.bind(wired),
chunksReceiver
;
wired.update = function () {
this.a = chunksReceiver;
return chunks.apply(this, arguments);
};
return function (callback) {
chunksReceiver = callback || String;
return wire;
};
}
// if a node is an attribute, return the right function
// accordingly if that's an escape or a callback
function getUpdateForAttribute(copies, i) {
var name = copies[i - 1].replace(ATTRIBUTE_NAME, '$1');
return SPECIAL_ATTRIBUTE.test(name) ?
(ATTRIBUTE_EVENT.test(name) ?
updateEvent() :
updateBoolean(name, copies, i)) :
escape;
}
// if an interpolated value is an Array
// return Promise or join by empty string
function getUpdateForHTML(bound) {
return isAsync(bound) ?
function (value) { return value; } :
joinIfArray;
}
// multiple content joined as single string
function joinIfArray(value) {
return isArray(value) ? value.join('') : value;
}
// return the right callback to update a boolean attribute
// after modifying the template to ignore such attribute if falsy
function updateBoolean(name, copies, i) {
copies[i - 1] = copies[i - 1].slice(0, -(name.length + 3));
copies[i] = copies[i].slice(1);
name = ' ' + name;
return function (value) {
return value ? name : '';
};
}
// return the right callback to invoke an event
// stringifying the callback and invoking it
// to simulate a proper DOM behavior
function updateEvent() {
return function (value) {
var isFunction = typeof value === 'function';
return isFunction ?
('return (' + escape(
JS_SHORTCUT.test(value) && !JS_FUNCTION.test(value) ?
('function ' + value) :
('' + value)
) + ').call(this, event)') :
(value || '');
};
}
// -------------------------
// Template setup
// -------------------------
// resolves through promises and
// invoke a notifier per each resolved chunk
// the context will be a viper
function chunks() {
for (var
update,
out = [],
asyncCallback = this.a,
copies = this.c,
updates = this.u,
all = Promise.resolve(copies[0]),
chain = function (after) {
return all.then(function (through) {
notify(through);
return after;
});
},
getValue = function (value) {
if (isArray(value)) {
value.forEach(getValue);
} else {
all = chain(
Promise.resolve(value)
.then(joinIfArray)
.then(update)
);
}
},
notify = function (chunk) {
out.push(chunk);
asyncCallback(chunk);
},
i = 1,
length = arguments.length; i < length; i++
) {
update = updates[i - 1];
getValue(arguments[i]);
all = chain(copies[i]);
}
return all.then(notify).then(function () { return out; });
}
// each known hyperHTML update is
// kept as simple as possible.
// the context will be a viper
function update() {
for (var
c = this.c,
u = this.u,
out = [c[0]],
i = 1,
length = arguments.length;
i < length; i++
) {
out[i] = u[i - 1](arguments[i]) + c[i];
}
return out.join('');
}
// but the first time, it needs to be setup.
// From now on, only update(statics) will be called
// unless this context won't be used for other renderings.
// the context will be the one bound to viperHTML
function upgrade(statics) {
for (var
updates = [],
copies = updates.slice.call(statics),
viper = {s: statics, u: updates, c: copies},
i = 1,
length = statics.length;
i < length; i++
) {
updates[i - 1] = isHTML(statics, i) ?
getUpdateForHTML(this) :
(isAttribute(copies, i) ?
getUpdateForAttribute(copies, i) :
escape);
}
vipers.set(this, viper);
return viperHTML.apply(this, arguments);
}
// -------------------------
// local variables
// -------------------------
// hyperHTML might have document in the wild to feature detect IE
// viperHTML should not suffer browser feature detection
// this file is used only if no document is available
// so let's make it temporarily a thing
global.document = {};
var
ATTRIBUTE_BEFORE = /<[a-z]\S*[^\S]+(?:[a-z-]+(?:=(?:(["'])[^\1]*?\1|[^"'\s]+))?[^\S]+)*?[a-z-]+=["']$/i,
ATTRIBUTE_AFTER = /^"(?:[^\S]+[a-z-]+(?:=(?:(["'])[^\1]*?\1|[^"'\s]+))?)*?[^\S]*>/i,
ATTRIBUTE_NAME = /^[\s\S]*?([a-z-]+)="$/i,
ATTRIBUTE_EVENT = /^on[a-z]+$/,
JS_SHORTCUT = /^[a-z$_]\S*?\(/,
JS_FUNCTION = /^function\S*?\(/,
SPECIAL_ATTRIBUTE = /^(?:(?:on|allow)[a-z]+|async|autofocus|autoplay|capture|checked|controls|default|defer|disabled|formnovalidate|hidden|ismap|itemscope|loop|multiple|muted|nomodule|novalidate|open|playsinline|readonly|required|reversed|selected|truespeed|typemustmatch|usecache)$/,
htmlEscape = require('html-escaper').escape,
asyncs = new WeakMap(),
vipers = new WeakMap(),
wires = new WeakMap(),
escape = function (s) { return htmlEscape(String(s)); },
isAsync = function (o) { return o instanceof Async; },
isArray = Array.isArray
;
// let's cleanup this property now
delete global.document;
module.exports = viperHTML;
// local class to easily recognize async wires
function Async() {}
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"html-escaper":4}],7:[function(require,module,exports){
/* global MutationObserver */
var document = require('global/document')
var window = require('global/window')
var watch = Object.create(null)
var KEY_ID = 'onloadid' + (new Date() % 9e6).toString(36)
var KEY_ATTR = 'data-' + KEY_ID
var INDEX = 0
if (window && window.MutationObserver) {
var observer = new MutationObserver(function (mutations) {
if (Object.keys(watch).length < 1) return
for (var i = 0; i < mutations.length; i++) {
if (mutations[i].attributeName === KEY_ATTR) {
eachAttr(mutations[i], turnon, turnoff)
continue
}
eachMutation(mutations[i].removedNodes, turnoff)
eachMutation(mutations[i].addedNodes, turnon)
}
})
observer.observe(document.body, {
childList: true,
subtree: true,
attributes: true,
attributeOldValue: true,
attributeFilter: [KEY_ATTR]
})
}
module.exports = function onload (el, on, off, caller) {
on = on || function () {}
off = off || function () {}
el.setAttribute(KEY_ATTR, 'o' + INDEX)
watch['o' + INDEX] = [on, off, 0, caller || onload.caller]
INDEX += 1
return el
}
function turnon (index, el) {
if (watch[index][0] && watch[index][2] === 0) {
watch[index][0](el)
watch[index][2] = 1
}
}
function turnoff (index, el) {
if (watch[index][1] && watch[index][2] === 1) {
watch[index][1](el)
watch[index][2] = 0
}
}
function eachAttr (mutation, on, off) {
var newValue = mutation.target.getAttribute(KEY_ATTR)
if (sameOrigin(mutation.oldValue, newValue)) {
watch[newValue] = watch[mutation.oldValue]
return
}
if (watch[mutation.oldValue]) {
off(mutation.oldValue, mutation.target)
}
if (watch[newValue]) {
on(newValue, mutation.target)
}
}
function sameOrigin (oldValue, newValue) {
if (!oldValue || !newValue) return false
return watch[oldValue][3] === watch[newValue][3]
}
function eachMutation (nodes, fn) {
var keys = Object.keys(watch)
for (var i = 0; i < nodes.length; i++) {
if (nodes[i] && nodes[i].getAttribute && nodes[i].getAttribute(KEY_ATTR)) {
var onloadid = nodes[i].getAttribute(KEY_ATTR)
keys.forEach(function (k) {
if (onloadid === k) {
fn(k, nodes[i])
}
})
}
if (nodes[i].childNodes.length > 0) {
eachMutation(nodes[i].childNodes, fn)
}
}
}
},{"global/document":8,"global/window":9}],8:[function(require,module,exports){
(function (global){
var topLevel = typeof global !== 'undefined' ? global :
typeof window !== 'undefined' ? window : {}
var minDoc = require('min-document');
var doccy;
if (typeof document !== 'undefined') {
doccy = document;
} else {
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'];
if (!doccy) {
doccy = topLevel['__GLOBAL_DOCUMENT_CACHE@4'] = minDoc;
}
}
module.exports = doccy;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{"min-document":1}],9:[function(require,module,exports){
(function (global){
var win;
if (typeof window !== "undefined") {
win = window;
} else if (typeof global !== "undefined") {
win = global;
} else if (typeof self !== "undefined"){
win = self;
} else {
win = {};
}
module.exports = win;
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {})
},{}],"hypercomponent":[function(require,module,exports){
const onload = require('on-load')
const html = require('hyperrender').html
const svg = require('hyperrender').svg
const slice = Array.prototype.slice
module.exports = function hypercomponent (component) {
const symbol = {
render: typeof component === 'function' ? component : component.render,
load: component && component.load,
unload: component && component.unload
}
return function wireComponent () {
const instance = new Component()
instance._symbol = symbol
instance._loaded = !(symbol.load || symbol.unload)
instance._defaultArgs = slice.call(arguments)
return instance
}
}
function Component () {
const self = this
function wire () {
return wire.html.apply(self, arguments)
}
wire.html = html(this)
wire.svg = svg(this)
this._wire = wire
}
Component.prototype.render = function render () {
const self = this
let args = [this._wire] // first arg is always our wire
for (var
i = 0,
length = arguments.length;
i < length; i++
) {
args[i + 1] = arguments[i] === undefined
? this._defaultArgs[i] // assign default arg if incomming is undefined
: arguments[i]
}
if (this._loaded === false) {
return onload(this._symbol.render.apply(this, args), load, unload)
}
return this._symbol.render.apply(this, args)
function load () {
self._loaded = true
self._symbol.load.apply(null, arguments)
}
function unload () {
self._loaded = false
self._symbol.unload.apply(null, arguments)
}
}
},{"hyperrender":2,"on-load":7}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcmVzb2x2ZS9lbXB0eS5qcyIsIm5vZGVfbW9kdWxlcy9oeXBlcnJlbmRlci9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9oeXBlcnJlbmRlci9ub2RlX21vZHVsZXMvdmlwZXJodG1sL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL2h5cGVycmVuZGVyL25vZGVfbW9kdWxlcy92aXBlcmh0bWwvbm9kZV9tb2R1bGVzL2h0bWwtZXNjYXBlci9odG1sLmpzIiwibm9kZV9tb2R1bGVzL2h5cGVycmVuZGVyL25vZGVfbW9kdWxlcy92aXBlcmh0bWwvbm9kZV9tb2R1bGVzL2h5cGVyaHRtbC9oeXBlcmh0bWwuanMiLCJub2RlX21vZHVsZXMvaHlwZXJyZW5kZXIvbm9kZV9tb2R1bGVzL3ZpcGVyaHRtbC92aXBlcmh0bWwuanMiLCJub2RlX21vZHVsZXMvb24tbG9hZC9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9vbi1sb2FkL25vZGVfbW9kdWxlcy9nbG9iYWwvZG9jdW1lbnQuanMiLCJub2RlX21vZHVsZXMvb24tbG9hZC9ub2RlX21vZHVsZXMvZ2xvYmFsL3dpbmRvdy5qcyIsImh5cGVyY29tcG9uZW50Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBO0FDQUE7O0FDQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFCQTtBQUNBO0FBQ0E7QUFDQTs7QUNIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDdGlCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ3hRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FDdkZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUNqQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQ2JBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIiIsImNvbnN0IGh5cGVySFRNTCA9IHJlcXVpcmUoJ3ZpcGVyaHRtbCcpXG5cbmZ1bmN0aW9uIGNyZWF0ZVdpcmUgKG9iaiwgdHlwZSkge1xuICB2YXIgc2VsZiA9IHRoaXNcbiAgcmV0dXJuIGZ1bmN0aW9uIHdpcmUgKCkge1xuICAgIHJldHVybiBoeXBlckhUTUwud2lyZShvYmogfHwgc2VsZiwgdHlwZSkuYXBwbHkoaHlwZXJIVE1MLCBhcmd1bWVudHMpXG4gIH1cbn1cblxuZnVuY3Rpb24gaHRtbCAob2JqKSB7XG4gIHJldHVybiAoYXJndW1lbnRzLmxlbmd0aCA+IDEgfHwgKG9iaiAmJiBvYmoucmF3KSlcbiAgICA/IGh5cGVySFRNTC53aXJlKHRoaXMpLmFwcGx5KGh5cGVySFRNTCwgYXJndW1lbnRzKVxuICAgIDogY3JlYXRlV2lyZS5jYWxsKHRoaXMsIG9iailcbn1cblxuZnVuY3Rpb24gc3ZnIChvYmopIHtcbiAgcmV0dXJuIChhcmd1bWVudHMubGVuZ3RoID4gMSB8fCAob2JqICYmIG9iai5yYXcpKVxuICAgID8gaHlwZXJIVE1MLndpcmUodGhpcywgJ3N2ZycpLmFwcGx5KGh5cGVySFRNTCwgYXJndW1lbnRzKVxuICAgIDogY3JlYXRlV2lyZS5jYWxsKHRoaXMsIG9iaiwgJ3N2ZycpXG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gcmVuZGVyICgpIHtcbiAgcmV0dXJuIGh0bWwuYXBwbHkodGhpcywgYXJndW1lbnRzKVxufVxubW9kdWxlLmV4cG9ydHMuaHRtbCA9IGh0bWxcbm1vZHVsZS5leHBvcnRzLnN2ZyA9IHN2Z1xuIiwiLyohIChDKSAyMDE3IEFuZHJlYSBHaWFtbWFyY2hpIEBXZWJSZWZsZWN0aW9uIChNSVQpICovXG5tb2R1bGUuZXhwb3J0cyA9IHR5cGVvZiBkb2N1bWVudCA9PT0gJ29iamVjdCcgP1xuICByZXF1aXJlKCdoeXBlcmh0bWwnKSA6XG4gIHJlcXVpcmUoJy4vdmlwZXJodG1sLmpzJyk7IiwiLypqc2xpbnQgaW5kZW50OiAyICovXG52YXIgaHRtbCA9IChmdW5jdGlvbiAoTykgeyd1c2Ugc3RyaWN0JztcbiAgLy8gQW5kcmVhIEdpYW1tYXJjaGkgLSBNSVQgU3R5bGUgTGljZW5zZVxuICB2YXJcbiAgICByZUVzY2FwZSA9IC9bJjw+J1wiXS9nLFxuICAgIHJlVW5lc2NhcGUgPSAvJig/OmFtcHwjMzh8bHR8IzYwfGd0fCM2MnxhcG9zfCMzOXxxdW90fCMzNCk7L2csXG4gICAgb0VzY2FwZSA9IHtcbiAgICAgICcmJzogJyZhbXA7JyxcbiAgICAgICc8JzogJyZsdDsnLFxuICAgICAgJz4nOiAnJmd0OycsXG4gICAgICBcIidcIjogJyYjMzk7JyxcbiAgICAgICdcIic6ICcmcXVvdDsnXG4gICAgfSxcbiAgICBvVW5lc2NhcGUgPSB7XG4gICAgICAnJmFtcDsnOiAnJicsXG4gICAgICAnJiMzODsnOiAnJicsXG4gICAgICAnJmx0Oyc6ICc8JyxcbiAgICAgICcmIzYwOyc6ICc8JyxcbiAgICAgICcmZ3Q7JzogJz4nLFxuICAgICAgJyYjNjI7JzogJz4nLFxuICAgICAgJyZhcG9zOyc6IFwiJ1wiLFxuICAgICAgJyYjMzk7JzogXCInXCIsXG4gICAgICAnJnF1b3Q7JzogJ1wiJyxcbiAgICAgICcmIzM0Oyc6ICdcIidcbiAgICB9LFxuICAgIGZuRXNjYXBlID0gZnVuY3Rpb24gKG0pIHtcbiAgICAgIHJldHVybiBvRXNjYXBlW21dO1xuICAgIH0sXG4gICAgZm5VbmVzY2FwZSA9IGZ1bmN0aW9uIChtKSB7XG4gICAgICByZXR1cm4gb1VuZXNjYXBlW21dO1xuICAgIH0sXG4gICAgcmVwbGFjZSA9ICcnLnJlcGxhY2U7XG4gIHJldHVybiAoTy5mcmVlemUgfHwgTykoe1xuICAgIGVzY2FwZTogZnVuY3Rpb24gZXNjYXBlKHMpIHtcbiAgICAgIHJldHVybiByZXBsYWNlLmNhbGwocywgcmVFc2NhcGUsIGZuRXNjYXBlKTtcbiAgICB9LFxuICAgIHVuZXNjYXBlOiBmdW5jdGlvbiB1bmVzY2FwZShzKSB7XG4gICAgICByZXR1cm4gcmVwbGFjZS5jYWxsKHMsIHJlVW5lc2NhcGUsIGZuVW5lc2NhcGUpO1xuICAgIH1cbiAgfSk7XG4gIH0oT2JqZWN0KSk7XG5cbnRyeSB7IG1vZHVsZS5leHBvcnRzID0gaHRtbDsgfSBjYXRjaCAoaWdub3JlKSB7fSIsInZhciBoeXBlckhUTUwgPSAoZnVuY3Rpb24gKCkgeyd1c2Ugc3RyaWN0JztcblxuICAvKiEgKEMpIDIwMTcgQW5kcmVhIEdpYW1tYXJjaGkgQFdlYlJlZmxlY3Rpb24gKE1JVCkgKi9cblxuICAvLyBoeXBlckhUTUwgXFxvL1xuICAvL1xuICAvLyB2YXIgcmVuZGVyID0gaHlwZXJIVE1MLmJpbmQoZG9jdW1lbnQuYm9keSk7XG4gIC8vIHNldEludGVydmFsKCgpID0+IHJlbmRlcmBcbiAgLy8gIDxoMT7imqHvuI8gaHlwZXJIVE1MIOKaoe+4jzwvaDE+XG4gIC8vICA8cD5cbiAgLy8gICAgJHsobmV3IERhdGUpLnRvTG9jYWxlU3RyaW5nKCl9XG4gIC8vICA8L3A+XG4gIC8vIGAsIDEwMDApO1xuICBmdW5jdGlvbiBoeXBlckhUTUwoc3RhdGljcykge1xuICAgIHJldHVybiAgRVhQQU5ETyBpbiB0aGlzICYmXG4gICAgICAgICAgICB0aGlzW0VYUEFORE9dLnMgPT09IHN0YXRpY3MgP1xuICAgICAgICAgICAgICB1cGRhdGUuYXBwbHkodGhpcywgYXJndW1lbnRzKSA6XG4gICAgICAgICAgICAgIHVwZ3JhZGUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgfVxuXG4gIC8vIEEgd2lyZSDinrAgaXMgYSBicmlkZ2UgYmV0d2VlbiBhIGRvY3VtZW50IGZyYWdtZW50XG4gIC8vIGFuZCBpdHMgaW5ldml0YWJseSBsb3N0IGxpc3Qgb2YgcmVuZGVyZWQgbm9kZXNcbiAgLy9cbiAgLy8gdmFyIHJlbmRlciA9IGh5cGVySFRNTC53aXJlKCk7XG4gIC8vIHJlbmRlcmBcbiAgLy8gIDxkaXY+SGVsbG8gV2lyZWQhPC9kaXY+XG4gIC8vIGA7XG4gIC8vXG4gIC8vIEV2ZXJ5IHNpbmdsZSBpbnZvY2F0aW9uIHdpbGwgcmV0dXJuIHRoYXQgZGl2XG4gIC8vIG9yIHRoZSBsaXN0IG9mIGVsZW1lbnRzIGl0IGNvbnRhaW5lZCBhcyBBcnJheS5cbiAgLy8gVGhpcyBzaW1wbGlmaWVzIG1vc3QgdGFzayB3aGVyZSBoeXBlckhUTUxcbiAgLy8gaXMgdXNlZCB0byBjcmVhdGUgdGhlIG5vZGUgaXRzZWxmLCBpbnN0ZWFkIG9mXG4gIC8vIHBvcHVsYXRpbmcgYW4gYWxyZWFkeSBrbm93biBhbmQgYm91bmQgb25lLlxuICBoeXBlckhUTUwud2lyZSA9IGZ1bmN0aW9uIHdpcmUob2JqLCB0eXBlKSB7XG4gICAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPCAxID9cbiAgICAgIHdpcmVDb250ZW50KCdodG1sJykgOlxuICAgICAgKG9iaiA9PSBudWxsID9cbiAgICAgICAgd2lyZUNvbnRlbnQodHlwZSB8fCAnaHRtbCcpIDpcbiAgICAgICAgKHdtLmdldChvYmopIHx8IHdpcmVXZWFrbHkob2JqLCB0eXBlIHx8ICdodG1sJykpXG4gICAgICApO1xuICB9O1xuXG4gIC8vIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtICAtIC0gLSAtIC1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIERPTSBwYXJzaW5nICYgdHJhdmVyc2luZ1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gc2V0dXAgYXR0cmlidXRlcyBmb3IgdXBkYXRlc1xuICAvL1xuICAvLyA8cCBjbGFzcz1cIiR7c3RhdGUuY2xhc3N9XCIgb25jbGljaz1cIiR7ZXZlbnQuY2xpY2t9XCI+PC9wPlxuICAvL1xuICAvLyBOb3RlOiBhbHdheXMgdXNlIHF1b3RlcyBhcm91bmQgYXR0cmlidXRlcywgZXZlbiBmb3IgZXZlbnRzLFxuICAvLyAgICAgICBib29sZWFucywgb3IgbnVtYmVycywgb3RoZXJ3aXNlIHRoaXMgZnVuY3Rpb24gZmFpbHMuXG4gIGZ1bmN0aW9uIGF0dHJpYnV0ZXNTZWVrZXIobm9kZSwgYWN0aW9ucykge1xuICAgIGZvciAodmFyXG4gICAgICBhdHRyaWJ1dGUsXG4gICAgICB2YWx1ZSA9IElFID8gdWlkIDogdWlkYyxcbiAgICAgIGF0dHJpYnV0ZXMgPSBzbGljZS5jYWxsKG5vZGUuYXR0cmlidXRlcyksXG4gICAgICBpID0gMCxcbiAgICAgIGxlbmd0aCA9IGF0dHJpYnV0ZXMubGVuZ3RoO1xuICAgICAgaSA8IGxlbmd0aDsgaSsrXG4gICAgKSB7XG4gICAgICBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzW2ldO1xuICAgICAgaWYgKGF0dHJpYnV0ZS52YWx1ZSA9PT0gdmFsdWUpIHtcbiAgICAgICAgLy8gd2l0aCBJRSB0aGUgb3JkZXIgZG9lc24ndCByZWFsbHkgbWF0dGVyXG4gICAgICAgIC8vIGFzIGxvbmcgYXMgdGhlIHJpZ2h0IGF0dHJpYnV0ZSBpcyBhZGRyZXNzZWRcbiAgICAgICAgYWN0aW9ucy5wdXNoKHNldEF0dHJpYnV0ZShub2RlLCBJRSA/XG4gICAgICAgICAgbm9kZS5nZXRBdHRyaWJ1dGVOb2RlKElFQXR0cmlidXRlcy5zaGlmdCgpKSA6XG4gICAgICAgICAgYXR0cmlidXRlXG4gICAgICAgICkpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIHRyYXZlcnNlIHRoZSB3aG9sZSBub2RlIGluIHNlYXJjaCBvZiBlZGl0YWJsZSBjb250ZW50XG4gIC8vIGRlY2lkZSB3aGF0IGVhY2ggZnV0dXJlIHVwZGF0ZSBzaG91bGQgY2hhbmdlXG4gIC8vXG4gIC8vIDxkaXYgYXRyPVwiJHtzb21lLmF0dHJpYnV0ZX1cIj5cbiAgLy8gICAgPGgxPiR7c29tZS5IVE1MfTwvaDE+XG4gIC8vICAgIDxwPlxuICAvLyAgICAgICR7c29tZS50ZXh0fVxuICAvLyAgICA8L3A+XG4gIC8vIDwvZGl2PlxuICBmdW5jdGlvbiBsdWtlVHJlZVdhbGtlcihub2RlLCBhY3Rpb25zKSB7XG4gICAgZm9yICh2YXJcbiAgICAgIGNoaWxkLCB0ZXh0LFxuICAgICAgY2hpbGROb2RlcyA9IHNsaWNlLmNhbGwobm9kZS5jaGlsZE5vZGVzKSxcbiAgICAgIGxlbmd0aCA9IGNoaWxkTm9kZXMubGVuZ3RoLFxuICAgICAgaSA9IDA7IGkgPCBsZW5ndGg7IGkrK1xuICAgICkge1xuICAgICAgY2hpbGQgPSBjaGlsZE5vZGVzW2ldO1xuICAgICAgc3dpdGNoIChjaGlsZC5ub2RlVHlwZSkge1xuICAgICAgICBjYXNlIDE6XG4gICAgICAgICAgYXR0cmlidXRlc1NlZWtlcihjaGlsZCwgYWN0aW9ucyk7XG4gICAgICAgICAgbHVrZVRyZWVXYWxrZXIoY2hpbGQsIGFjdGlvbnMpO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIDg6XG4gICAgICAgICAgaWYgKGNoaWxkLnRleHRDb250ZW50ID09PSB1aWQpIHtcbiAgICAgICAgICAgIGlmIChsZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgYWN0aW9ucy5wdXNoKHNldEFueUNvbnRlbnQobm9kZSkpO1xuICAgICAgICAgICAgICBub2RlLnJlbW92ZUNoaWxkKGNoaWxkKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoXG4gICAgICAgICAgICAgIChpIDwgMSB8fCBjaGlsZE5vZGVzW2kgLSAxXS5ub2RlVHlwZSA9PT0gMSkgJiZcbiAgICAgICAgICAgICAgKGkgKyAxID09PSBsZW5ndGggfHwgY2hpbGROb2Rlc1tpICsgMV0ubm9kZVR5cGUgPT09IDEpXG4gICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgYWN0aW9ucy5wdXNoKHNldFZpcnR1YWxDb250ZW50KGNoaWxkKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0ZXh0ID0gbm9kZS5vd25lckRvY3VtZW50LmNyZWF0ZVRleHROb2RlKCcnKTtcbiAgICAgICAgICAgICAgYWN0aW9ucy5wdXNoKHNldFRleHRDb250ZW50KHRleHQpKTtcbiAgICAgICAgICAgICAgbm9kZS5yZXBsYWNlQ2hpbGQodGV4dCwgY2hpbGQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gRE9NIG1hbmlwdWxhdGluZ1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gdXBkYXRlIHJlZ3VsYXIgYm91bmQgbm9kZXNcbiAgLy9cbiAgLy8gdmFyIHJlbmRlciA9IGh5cGVySFRNTC5iaW5kKG5vZGUpO1xuICAvLyBmdW5jdGlvbiB1cGRhdGUoKSB7XG4gIC8vICByZW5kZXJgdGVtcGxhdGVgO1xuICAvLyB9XG4gIGZ1bmN0aW9uIHNldEFueUNvbnRlbnQobm9kZSkge1xuICAgIHJldHVybiBmdW5jdGlvbiBhbnkodmFsdWUpIHtcbiAgICAgIHN3aXRjaCAodHlwZW9mIHZhbHVlKSB7XG4gICAgICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICAgICAgbm9kZS5pbm5lckhUTUwgPSB2YWx1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnbnVtYmVyJzpcbiAgICAgICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICAgICAgbm9kZS50ZXh0Q29udGVudCA9IHZhbHVlO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGlmIChBcnJheS5pc0FycmF5KHZhbHVlKSkge1xuICAgICAgICAgICAgaWYgKHZhbHVlLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICBhbnkodmFsdWVbMF0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmKHR5cGVvZiB2YWx1ZVswXSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgYW55KHZhbHVlLmpvaW4oJycpKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHZhciBpID0gaW5kZXhPZkRpZmZlcmVjZXMobm9kZS5jaGlsZE5vZGVzLCB2YWx1ZSk7XG4gICAgICAgICAgICAgIGlmICgtMSA8IGkpIHtcbiAgICAgICAgICAgICAgICB1cGRhdGVWaWFBcnJheShub2RlLCB2YWx1ZSwgaSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcG9wdWxhdGVOb2RlKG5vZGUsIHZhbHVlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8vIHVwZGF0ZSBhdHRyaWJ1dGVzIG5vZGVcbiAgLy9cbiAgLy8gcmVuZGVyYDxhIGhyZWY9XCIke3VybH1cIiBvbmNsaWNrPVwiJHtjbGlja31cIj4ke25hbWV9PC9hPmA7XG4gIC8vXG4gIC8vIE5vdGU6IGF0dHJpYnV0ZXMgd2l0aCBhIHNwZWNpYWwgbWVhbmluZyBsaWtlIERPTSBMZXZlbCAwXG4gIC8vICAgICAgIGxpc3RlbmVycyBvciBhY2Nlc3NvcnMgcHJvcGVydGllcyBhcmUgZGlyZWN0bHkgc2V0XG4gIGZ1bmN0aW9uIHNldEF0dHJpYnV0ZShub2RlLCBhdHRyaWJ1dGUpIHtcbiAgICB2YXJcbiAgICAgIG5hbWUgPSBhdHRyaWJ1dGUubmFtZSxcbiAgICAgIGlzU3BlY2lhbCA9IG5hbWUgaW4gbm9kZSAmJiAhU0hPVUxEX1VTRV9BVFRSSUJVVEUudGVzdChuYW1lKSxcbiAgICAgIG9sZFZhbHVlXG4gICAgO1xuICAgIGlmIChpc1NwZWNpYWwpIG5vZGUucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xuICAgIHJldHVybiBpc1NwZWNpYWwgP1xuICAgICAgZnVuY3Rpb24gc3BlY2lhbEF0dHIobmV3VmFsdWUpIHtcbiAgICAgICAgaWYgKG9sZFZhbHVlICE9PSBuZXdWYWx1ZSkge1xuICAgICAgICAgIG5vZGVbbmFtZV0gPSAob2xkVmFsdWUgPSBuZXdWYWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH0gOlxuICAgICAgZnVuY3Rpb24gYXR0cihuZXdWYWx1ZSkge1xuICAgICAgICBpZiAob2xkVmFsdWUgIT09IG5ld1ZhbHVlKSB7XG4gICAgICAgICAgYXR0cmlidXRlLnZhbHVlID0gKG9sZFZhbHVlID0gbmV3VmFsdWUpO1xuICAgICAgICB9XG4gICAgICB9O1xuICB9XG5cbiAgLy8gdXBkYXRlIHRoZSBcImVtcHRpbmVzc1wiXG4gIC8vIHRoaXMgZnVuY3Rpb24gaXMgdXNlZCB3aGVuIHRlbXBsYXRlIGxpdGVyYWxzXG4gIC8vIGhhdmUgc25lYWt5IGh0bWwvZnJhZ21lbnQgY2FwYWJsZVxuICAvLyB1cGRhdGVzIGluIHRoZSB3aWxkIChubyBzcGFjZXMgYXJvdW5kKVxuICAvL1xuICAvLyByZW5kZXJgXG4gIC8vICA8cD5Db250ZW50IGJlZm9yZTwvcD4ke1xuICAvLyAgJ2FueSBjb250ZW50IGluIGJldHdlZW4nXG4gIC8vICB9PHA+Q29udGVudCBhZnRlcjwvcD5cbiAgLy8gYDtcbiAgLy9cbiAgLy8gTm90ZTogdGhpcyBpcyB0aGUgbW9zdCBleHBlbnNpdmVcbiAgLy8gICAgICAgdXBkYXRlIG9mIHRoZW0gYWxsLlxuICBmdW5jdGlvbiBzZXRWaXJ0dWFsQ29udGVudChub2RlKSB7XG4gICAgdmFyXG4gICAgICBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxcbiAgICAgIGNoaWxkTm9kZXMgPSBbXVxuICAgIDtcbiAgICByZXR1cm4gZnVuY3Rpb24gYW55KHZhbHVlKSB7XG4gICAgICB2YXIgaSwgcGFyZW50Tm9kZSA9IG5vZGUucGFyZW50Tm9kZTtcbiAgICAgIHN3aXRjaCAodHlwZW9mIHZhbHVlKSB7XG4gICAgICAgIGNhc2UgJ3N0cmluZyc6XG4gICAgICAgIGNhc2UgJ251bWJlcic6XG4gICAgICAgIGNhc2UgJ2Jvb2xlYW4nOlxuICAgICAgICAgIHJlbW92ZU5vZGVMaXN0KGNoaWxkTm9kZXMsIDApO1xuICAgICAgICAgIGluamVjdEhUTUwoZnJhZ21lbnQsIHZhbHVlKTtcbiAgICAgICAgICBjaGlsZE5vZGVzID0gc2xpY2UuY2FsbChmcmFnbWVudC5jaGlsZE5vZGVzKTtcbiAgICAgICAgICBwYXJlbnROb2RlLmluc2VydEJlZm9yZShmcmFnbWVudCwgbm9kZSk7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgaWYgKEFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgICAgICBpZiAodmFsdWUubGVuZ3RoID09PSAwKSB7XG4gICAgICAgICAgICAgIGFueSh2YWx1ZVswXSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYodHlwZW9mIHZhbHVlWzBdID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICBhbnkodmFsdWUuam9pbignJykpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaSA9IGluZGV4T2ZEaWZmZXJlY2VzKGNoaWxkTm9kZXMsIHZhbHVlKTtcbiAgICAgICAgICAgICAgaWYgKC0xIDwgaSkge1xuICAgICAgICAgICAgICAgIHJlbW92ZU5vZGVMaXN0KGNoaWxkTm9kZXMsIGkpO1xuICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWUuc2xpY2UoaSk7XG4gICAgICAgICAgICAgICAgYXBwZW5kTm9kZXMoZnJhZ21lbnQsIHZhbHVlKTtcbiAgICAgICAgICAgICAgICBwYXJlbnROb2RlLmluc2VydEJlZm9yZShmcmFnbWVudCwgbm9kZSk7XG4gICAgICAgICAgICAgICAgY2hpbGROb2Rlcy5wdXNoLmFwcGx5KGNoaWxkTm9kZXMsIHZhbHVlKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZW1vdmVOb2RlTGlzdChjaGlsZE5vZGVzLCAwKTtcbiAgICAgICAgICAgIGNoaWxkTm9kZXMgPSB2YWx1ZS5ub2RlVHlwZSA9PT0gMTEgP1xuICAgICAgICAgICAgICBzbGljZS5jYWxsKHZhbHVlLmNoaWxkTm9kZXMpIDpcbiAgICAgICAgICAgICAgW3ZhbHVlXTtcbiAgICAgICAgICAgIHBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKHZhbHVlLCBub2RlKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIC8vIGJhc2ljIGNsb3N1cmUgdG8gdXBkYXRlIG5vZGVzIHRleHRDb250ZW50XG4gIC8vXG4gIC8vIHJlbmRlcmBcbiAgLy8gIDxwPlxuICAvLyAgICAkeydzcGFjZXMgYXJvdW5kIG1lYW5zIHRleHRDb250ZW50J31cbiAgLy8gIDwvcD5gO1xuICBmdW5jdGlvbiBzZXRUZXh0Q29udGVudChub2RlKSB7XG4gICAgdmFyIG9sZFZhbHVlO1xuICAgIHJldHVybiBmdW5jdGlvbiB0ZXh0KG5ld1ZhbHVlKSB7XG4gICAgICBpZiAob2xkVmFsdWUgIT09IG5ld1ZhbHVlKSB7XG4gICAgICAgIG5vZGUudGV4dENvbnRlbnQgPSAob2xkVmFsdWUgPSBuZXdWYWx1ZSk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBIZWxwZXJzXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBpdCBkb2VzIGV4YWN0bHkgd2hhdCBpdCBzYXlzXG4gIGZ1bmN0aW9uIGFwcGVuZE5vZGVzKG5vZGUsIGNoaWxkTm9kZXMpIHtcbiAgICBmb3IgKHZhclxuICAgICAgaSA9IDAsXG4gICAgICBsZW5ndGggPSBjaGlsZE5vZGVzLmxlbmd0aDtcbiAgICAgIGkgPCBsZW5ndGg7IGkrK1xuICAgICkge1xuICAgICAgbm9kZS5hcHBlbmRDaGlsZChjaGlsZE5vZGVzW2ldKTtcbiAgICB9XG4gIH1cblxuICAvLyBnaXZlbiB0d28gY29sbGVjdGlvbnMsIGZpbmRcbiAgLy8gdGhlIGZpcnN0IGluZGV4IHRoYXQgaGFzIGRpZmZlcmVudCBjb250ZW50LlxuICAvLyBJZiB0aGUgdHdvIGxpc3RzIGFyZSB0aGUgc2FtZSwgcmV0dXJuIC0xXG4gIC8vIHRvIGluZGljYXRlIG5vIGRpZmZlcmVuY2VzIHdlcmUgZm91bmQuXG4gIGZ1bmN0aW9uIGluZGV4T2ZEaWZmZXJlY2VzKGEsIGIpIHtcbiAgICBpZiAoYSA9PT0gYikgcmV0dXJuIC0xO1xuICAgIHZhclxuICAgICAgaSA9IDAsXG4gICAgICBhTGVuZ3RoID0gYS5sZW5ndGgsXG4gICAgICBiTGVuZ3RoID0gYi5sZW5ndGhcbiAgICA7XG4gICAgd2hpbGUgKGkgPCBhTGVuZ3RoKSB7XG4gICAgICBpZiAoaSA8IGJMZW5ndGggJiYgYVtpXSA9PT0gYltpXSkgaSsrO1xuICAgICAgZWxzZSByZXR1cm4gaTtcbiAgICB9XG4gICAgcmV0dXJuIGkgPT09IGJMZW5ndGggPyAtMSA6IGk7XG4gIH1cblxuICAvLyBpbmplY3QgSFRNTCBpbnRvIGEgdGVtcGxhdGUgbm9kZVxuICAvLyBhbmQgcG9wdWxhdGUgYSBmcmFnbWVudCB3aXRoIHJlc3VsdGluZyBub2Rlc1xuICAvL1xuICAvLyBJRTl+SUUxMSBhcmUgbm90IGNvbXBhdGlibGUgd2l0aCB0aGUgdGVtcGxhdGUgdGFnLlxuICAvLyBJZiB0aGUgY29udGVudCBpcyBhIHBhcnRpYWwgcGFydCBvZiBhIHRhYmxlIHRoZXJlIGlzIGEgZmFsbGJhY2suXG4gIC8vIE5vdCB0aGUgbW9zdCBlbGVnYW50L3JvYnVzdCB3YXkgYnV0IGdvb2QgZW5vdWdoIGZvciBjb21tb24gY2FzZXMuXG4gIC8vIChJIGRvbid0IHdhbnQgdG8gaW5jbHVkZSBhIHdob2xlIERPTSBwYXJzZXIgZm9yIElFIG9ubHkgaGVyZSkuXG4gIGZ1bmN0aW9uIGluamVjdEhUTUwoZnJhZ21lbnQsIGh0bWwpIHtcbiAgICB2YXJcbiAgICAgIGZhbGxiYWNrID0gSUUgJiYgL15bXlxcU10qPzwodCg/OmhlYWR8Ym9keXxmb290fHJ8ZHxoKSkvaS50ZXN0KGh0bWwpLFxuICAgICAgdGVtcGxhdGUgPSBmcmFnbWVudC5vd25lckRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3RlbXBsYXRlJylcbiAgICA7XG4gICAgdGVtcGxhdGUuaW5uZXJIVE1MID0gZmFsbGJhY2sgPyAoJzx0YWJsZT4nICsgaHRtbCArICc8L3RhYmxlPicpIDogaHRtbDtcbiAgICBpZiAoZmFsbGJhY2spIHtcbiAgICAgIHRlbXBsYXRlID0ge2NoaWxkTm9kZXM6IHRlbXBsYXRlLnF1ZXJ5U2VsZWN0b3JBbGwoUmVnRXhwLiQxKX07XG4gICAgfVxuICAgIGFwcGVuZE5vZGVzKFxuICAgICAgZnJhZ21lbnQsXG4gICAgICBzbGljZS5jYWxsKCh0ZW1wbGF0ZS5jb250ZW50IHx8IHRlbXBsYXRlKS5jaGlsZE5vZGVzKVxuICAgICk7XG4gIH1cblxuICAvLyBhY2NvcmRpbmdseSB3aXRoIHRoZSBraW5kIG9mIGNoaWxkXG4gIC8vIGl0IHB1dHMgaXRzIGNvbnRlbnQgaW50byBhIHBhcmVudCBub2RlXG4gIGZ1bmN0aW9uIHBvcHVsYXRlTm9kZShwYXJlbnQsIGNoaWxkKSB7XG4gICAgc3dpdGNoIChjaGlsZC5ub2RlVHlwZSkge1xuICAgICAgY2FzZSAxOlxuICAgICAgICB2YXJcbiAgICAgICAgICBjaGlsZE5vZGVzID0gcGFyZW50LmNoaWxkTm9kZXMsXG4gICAgICAgICAgbGVuZ3RoID0gY2hpbGROb2Rlcy5sZW5ndGhcbiAgICAgICAgO1xuICAgICAgICBpZiAoMCA8IGxlbmd0aCAmJiBjaGlsZE5vZGVzWzBdID09PSBjaGlsZCkge1xuICAgICAgICAgIHJlbW92ZU5vZGVMaXN0KGNoaWxkTm9kZXMsIDEpO1xuICAgICAgICB9IGVsc2UgaWYgKGxlbmd0aCAhPT0gMSkge1xuICAgICAgICAgIHJlc2V0QW5kUG9wdWxhdGUocGFyZW50LCBjaGlsZCk7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDExOlxuICAgICAgICBpZiAoLTEgPCBpbmRleE9mRGlmZmVyZWNlcyhwYXJlbnQuY2hpbGROb2RlcywgY2hpbGQuY2hpbGROb2RlcykpIHtcbiAgICAgICAgICByZXNldEFuZFBvcHVsYXRlKHBhcmVudCwgY2hpbGQpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICBwYXJlbnQudGV4dENvbnRlbnQgPSBjaGlsZC50ZXh0Q29udGVudDtcbiAgICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG5cbiAgLy8gaXQgZG9lcyBleGFjdGx5IHdoYXQgaXQgc2F5c1xuICBmdW5jdGlvbiByZW1vdmVOb2RlTGlzdChsaXN0LCBzdGFydEluZGV4KSB7XG4gICAgdmFyIGxlbmd0aCA9IGxpc3QubGVuZ3RoLCBjaGlsZDtcbiAgICB3aGlsZSAoc3RhcnRJbmRleCA8IGxlbmd0aC0tKSB7XG4gICAgICBjaGlsZCA9IGxpc3RbbGVuZ3RoXTtcbiAgICAgIGNoaWxkLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoY2hpbGQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGRyb3AgYWxsIG5vZGVzIGFuZCBhcHBlbmQgYSBub2RlXG4gIGZ1bmN0aW9uIHJlc2V0QW5kUG9wdWxhdGUocGFyZW50LCBjaGlsZCkge1xuICAgIHBhcmVudC50ZXh0Q29udGVudCA9ICcnO1xuICAgIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7XG4gIH1cblxuICAvLyB0aGUgZmlyc3QgdGltZSBhIGh5cGVySFRNTC53aXJlKCkgaXMgaW52b2tlZFxuICAvLyByZW1lbWJlciB0aGUgbGlzdCBvZiBub2RlcyB0aGF0IHNob3VsZCBiZSB1cGRhdGVkXG4gIC8vIGF0IGV2ZXJ5IGNvbnNlcXVlbnQgcmVuZGVyIGNhbGwuXG4gIC8vIFRoZSByZXN1bHRpbmcgZnVuY3Rpb24gbWlnaHQgcmV0dXJuIHRoZSB2ZXJ5IGZpcnN0IG5vZGVcbiAgLy8gb3IgdGhlIEFycmF5IG9mIGFsbCBub2RlcyB0aGF0IG1pZ2h0IG5lZWQgdXBkYXRlcy5cbiAgZnVuY3Rpb24gc2V0dXBBbmRHZXRDb250ZW50KG5vZGUpIHtcbiAgICBmb3IgKHZhclxuICAgICAgY2hpbGQsXG4gICAgICBjaGlsZHJlbiA9IFtdLFxuICAgICAgY2hpbGROb2RlcyA9IG5vZGUuY2hpbGROb2RlcyxcbiAgICAgIGkgPSAwLFxuICAgICAgbGVuZ3RoID0gY2hpbGROb2Rlcy5sZW5ndGg7XG4gICAgICBpIDwgbGVuZ3RoOyBpKytcbiAgICApIHtcbiAgICAgIGNoaWxkID0gY2hpbGROb2Rlc1tpXTtcbiAgICAgIGlmIChcbiAgICAgICAgMSA9PT0gY2hpbGQubm9kZVR5cGUgfHxcbiAgICAgICAgMCA8IHRyaW0uY2FsbChjaGlsZC50ZXh0Q29udGVudCkubGVuZ3RoXG4gICAgICApIHtcbiAgICAgICAgY2hpbGRyZW4ucHVzaChjaGlsZCk7XG4gICAgICB9XG4gICAgfVxuICAgIGxlbmd0aCA9IGNoaWxkcmVuLmxlbmd0aDtcbiAgICByZXR1cm4gbGVuZ3RoIDwgMiA/XG4gICAgICAoKGNoaWxkID0gbGVuZ3RoIDwgMSA/IG5vZGUgOiBjaGlsZHJlblswXSksXG4gICAgICBmdW5jdGlvbiAoKSB7IHJldHVybiBjaGlsZDsgfSkgOlxuICAgICAgZnVuY3Rpb24gKCkgeyByZXR1cm4gY2hpbGRyZW47IH07XG4gIH1cblxuICAvLyByZW1vdmUgYW5kL29yIGFuZCBhIGxpc3Qgb2Ygbm9kZXMgdGhyb3VnaCBhbiBhcnJheVxuICBmdW5jdGlvbiB1cGRhdGVWaWFBcnJheShub2RlLCBjaGlsZE5vZGVzLCBpKSB7XG4gICAgdmFyIGZyYWdtZW50ID0gbm9kZS5vd25lckRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBpZiAoMCA8IGkpIHtcbiAgICAgIHJlbW92ZU5vZGVMaXN0KG5vZGUuY2hpbGROb2RlcywgaSk7XG4gICAgICBhcHBlbmROb2RlcyhmcmFnbWVudCwgY2hpbGROb2Rlcy5zbGljZShpKSk7XG4gICAgICBub2RlLmFwcGVuZENoaWxkKGZyYWdtZW50KTtcbiAgICB9IGVsc2Uge1xuICAgICAgYXBwZW5kTm9kZXMoZnJhZ21lbnQsIGNoaWxkTm9kZXMpO1xuICAgICAgcmVzZXRBbmRQb3B1bGF0ZShub2RlLCBmcmFnbWVudCk7XG4gICAgfVxuICB9XG5cbiAgLy8gY3JlYXRlIGEgbmV3IHdpcmUgZm9yIGdlbmVyaWMgRE9NIGNvbnRlbnRcbiAgZnVuY3Rpb24gd2lyZUNvbnRlbnQodHlwZSkge1xuICAgIHZhciBjb250ZW50LCBjb250YWluZXIsIGZyYWdtZW50LCByZW5kZXIsIHNldHVwLCB0ZW1wbGF0ZTtcbiAgICByZXR1cm4gZnVuY3Rpb24gdXBkYXRlKHN0YXRpY3MpIHtcbiAgICAgIGlmICh0ZW1wbGF0ZSAhPT0gc3RhdGljcykge1xuICAgICAgICBzZXR1cCA9IHRydWU7XG4gICAgICAgIHRlbXBsYXRlID0gc3RhdGljcztcbiAgICAgICAgZnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgICAgIGNvbnRhaW5lciA9IHR5cGUgPT09ICdzdmcnID9cbiAgICAgICAgICBkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMoJ2h0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnJywgJ3N2ZycpIDpcbiAgICAgICAgICBmcmFnbWVudDtcbiAgICAgICAgcmVuZGVyID0gaHlwZXJIVE1MLmJpbmQoY29udGFpbmVyKTtcbiAgICAgIH1cbiAgICAgIHJlbmRlci5hcHBseShudWxsLCBhcmd1bWVudHMpO1xuICAgICAgaWYgKHNldHVwKSB7XG4gICAgICAgIHNldHVwID0gZmFsc2U7XG4gICAgICAgIGlmICh0eXBlID09PSAnc3ZnJykge1xuICAgICAgICAgIGFwcGVuZE5vZGVzKGZyYWdtZW50LCBzbGljZS5jYWxsKGNvbnRhaW5lci5jaGlsZE5vZGVzKSk7XG4gICAgICAgIH1cbiAgICAgICAgY29udGVudCA9IHNldHVwQW5kR2V0Q29udGVudChmcmFnbWVudCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29udGVudCgpO1xuICAgIH07XG4gIH1cblxuICAvLyBnZXQgb3IgY3JlYXRlIGEgd2lyZWQgd2VhayByZWZlcmVuY2VcbiAgZnVuY3Rpb24gd2lyZVdlYWtseShvYmosIHR5cGUpIHtcbiAgICB2YXIgd2lyZSA9IHdpcmVDb250ZW50KHR5cGUpO1xuICAgIHdtLnNldChvYmosIHdpcmUpO1xuICAgIHJldHVybiB3aXJlO1xuICB9XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBUZW1wbGF0ZSBzZXR1cFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gZWFjaCBrbm93biBoeXBlckhUTUwgdXBkYXRlIGlzXG4gIC8vIGtlcHQgYXMgc2ltcGxlIGFzIHBvc3NpYmxlLlxuICBmdW5jdGlvbiB1cGRhdGUoKSB7XG4gICAgZm9yICh2YXJcbiAgICAgIGkgPSAxLFxuICAgICAgbGVuZ3RoID0gYXJndW1lbnRzLmxlbmd0aCxcbiAgICAgIHVwZGF0ZXMgPSB0aGlzW0VYUEFORE9dLnU7XG4gICAgICBpIDwgbGVuZ3RoOyBpKytcbiAgICApIHtcbiAgICAgIHVwZGF0ZXNbaSAtIDFdKGFyZ3VtZW50c1tpXSk7XG4gICAgfVxuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgLy8gYnV0IHRoZSBmaXJzdCB0aW1lLCBpdCBuZWVkcyB0byBiZSBzZXR1cC5cbiAgLy8gRnJvbSBub3cgb24sIG9ubHkgdXBkYXRlKHN0YXRpY3MpIHdpbGwgYmUgY2FsbGVkXG4gIC8vIHVubGVzcyB0aGlzIG5vZGUgd29uJ3QgYmUgdXNlZCBmb3Igb3RoZXIgcmVuZGVyaW5ncy5cbiAgZnVuY3Rpb24gdXBncmFkZShzdGF0aWNzKSB7XG4gICAgdmFyXG4gICAgICB1cGRhdGVzID0gW10sXG4gICAgICBodG1sID0gc3RhdGljcy5qb2luKHVpZGMpXG4gICAgO1xuICAgIGlmIChJRSkge1xuICAgICAgSUVBdHRyaWJ1dGVzID0gW107XG4gICAgICBpbmplY3RIVE1MKHRoaXMsIGh0bWwucmVwbGFjZShubywgY29tbWVudHMpKTtcbiAgICB9IGVsc2UgaWYgKHRoaXMubm9kZVR5cGUgPT09IDEpIHtcbiAgICAgIHRoaXMuaW5uZXJIVE1MID0gaHRtbDtcbiAgICB9IGVsc2Uge1xuICAgICAgaW5qZWN0SFRNTCh0aGlzLCBodG1sKTtcbiAgICB9XG4gICAgbHVrZVRyZWVXYWxrZXIodGhpcywgdXBkYXRlcyk7XG4gICAgdGhpc1tFWFBBTkRPXSA9IHtzOiBzdGF0aWNzLCB1OiB1cGRhdGVzfTtcbiAgICByZXR1cm4gdXBkYXRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIHRoZSB0cmFzaCBiaW5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIElFIHVzZWQgdG8gc3Vjay5cbiAgLypcbiAgLy8gZXZlbiBpbiBhIHRyeS9jYXRjaCB0aGlzIHRocm93IGFuIGVycm9yXG4gIC8vIHNpbmNlIGl0J3MgcmVsaWFibGUgdGhvdWdoLCBJJ2xsIGtlZXAgaXQgYXJvdW5kXG4gIGZ1bmN0aW9uIGlzSUUoKSB7XG4gICAgdmFyIHAgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdwJyk7XG4gICAgcC5pbm5lckhUTUwgPSAnPGkgb25jbGljaz1cIjwhLS0tLT5cIj4nO1xuICAgIHJldHVybiBwLmNoaWxkTm9kZXNbMF0ub25jbGljayA9PSBudWxsO1xuICB9XG4gIC8vKi9cblxuICAvLyByZW1vdmUgYW5kL29yIGFkZCBhIGxpc3Qgb2Ygbm9kZXMgdGhyb3VnaCBhIGZyYWdtZW50XG4gIC8qIHRlbXBvcmFyaWx5IHJlbW92ZWQgdW50aWwgaXQncyBkZW1vbnN0cmF0ZWQgaXQncyBuZWVkZWRcbiAgZnVuY3Rpb24gdXBkYXRlVmlhRnJhZ21lbnQobm9kZSwgZnJhZ21lbnQsIGkpIHtcbiAgICBpZiAoMCA8IGkpIHtcbiAgICAgIHJlbW92ZU5vZGVMaXN0KG5vZGUuY2hpbGROb2RlcywgaSk7XG4gICAgICB2YXIgc2xpbSA9IGZyYWdtZW50LmNsb25lTm9kZSgpO1xuICAgICAgYXBwZW5kTm9kZXMoc2xpbSwgc2xpY2UuY2FsbChmcmFnbWVudC5jaGlsZE5vZGVzLCBpKSk7XG4gICAgICBub2RlLmFwcGVuZENoaWxkKGZyYWdtZW50LCBzbGltKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVzZXRBbmRQb3B1bGF0ZShub2RlLCBmcmFnbWVudCk7XG4gICAgfVxuICB9XG4gIC8vKi9cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIGxvY2FsIHZhcmlhYmxlc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgdmFyXG4gICAgLy8gc29tZSBhdHRyaWJ1dGUgbWlnaHQgYmUgcHJlc2VudCBvbiB0aGUgZWxlbWVudCBwcm90b3R5cGUgYnV0IGNhbm5vdCBiZSBzZXQgZGlyZWN0bHlcbiAgICBTSE9VTERfVVNFX0FUVFJJQlVURSA9IC9ec3R5bGUkL2ksXG4gICAgLy8gYXZvaWRzIFdlYWtNYXAgdG8gYXZvaWQgbWVtb3J5IHByZXNzdXJlLCB1c2UgQ1NTIGNvbXBhdGlibGUgc3ludGF4IGZvciBJRVxuICAgIEVYUEFORE8gPSAnX2h5cGVyX2h0bWw6ICcsXG4gICAgLy8gdXNlIGEgcHNldWRvIHVuaXF1ZSBpZCB0byBhdm9pZCBjb25mbGljdHMgYW5kIG5vcm1hbGl6ZSBDU1Mgc3R5bGUgZm9yIElFXG4gICAgdWlkID0gRVhQQU5ETyArICgoTWF0aC5yYW5kb20oKSAqIG5ldyBEYXRlKSB8IDApICsgJzsnLFxuICAgIC8vIHVzZSBjb21tZW50IG5vZGVzIHdpdGggcHNldWRvIHVuaXF1ZSBjb250ZW50IHRvIHNldHVwXG4gICAgdWlkYyA9ICc8IS0tJyArIHVpZCArICctLT4nLFxuICAgIC8vIHRocmVhdCBpdCBkaWZmZXJlbnRseVxuICAgIElFID0gJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQsXG4gICAgbm8gPSBJRSAmJiBuZXcgUmVnRXhwKCcoW15cXFxcU11bYS16XStbYS16MC05Xy1dKj0pKFtcXCdcIl0pJyArIHVpZGMgKyAnXFxcXDInLCAnZycpLFxuICAgIGNvbW1lbnRzID0gSUUgJiYgZnVuY3Rpb24gKCQwLCAkMSwgJDIpIHtcbiAgICAgIElFQXR0cmlidXRlcy5wdXNoKCQxLnNsaWNlKDEsIC0xKSk7XG4gICAgICByZXR1cm4gJDEgKyAkMiArIHVpZCArICQyO1xuICAgIH0sXG4gICAgLy8gdmVyaWZ5IGVtcHR5IHRleHRDb250ZW50IG9uIC53aXJlKCkgc2V0dXBcbiAgICB0cmltID0gRVhQQU5ETy50cmltIHx8IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0aGlzLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKTtcbiAgICB9LFxuICAgIC8vIGNvbnZlcnQgRE9NLmNoaWxkTm9kZXMgaW50byBhcnJheXMgdG8gYXZvaWRcbiAgICAvLyBET00gbXV0YXRpb24gYmFja2ZpcmluZyBvbiBsb29wc1xuICAgIHNsaWNlID0gW10uc2xpY2UsXG4gICAgLy8gdXNlZCBmb3Igd2VhayByZWZlcmVuY2VzXG4gICAgLy8gaWYgV2Vha01hcCBpcyBub3QgYXZhaWxhYmxlXG4gICAgLy8gaXQgdXNlcyBhIGNvbmZpZ3VyYWJsZSwgbm9uIGVudW1lcmFibGUsXG4gICAgLy8gcXVpY2sgYW5kIGRpcnR5IGV4cGFuZG8gcHJvcGVydHkuXG4gICAgd20gPSB0eXBlb2YgV2Vha01hcCA9PT0gdHlwZW9mIHdtID9cbiAgICAgIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmpbRVhQQU5ET107IH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKG9iaiwgdmFsdWUpIHtcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqLCBFWFBBTkRPLCB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSA6XG4gICAgICBuZXcgV2Vha01hcCgpLFxuICAgIElFQXR0cmlidXRlc1xuICA7XG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyDimqHvuI8g77iP77iPVGhlIEVuZCDinrBcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICByZXR1cm4gaHlwZXJIVE1MO1xuXG59KCkpO1xuXG4vLyB1bWQuS0lTU1xudHJ5IHsgbW9kdWxlLmV4cG9ydHMgPSBoeXBlckhUTUw7IH0gY2F0Y2gob19PKSB7fVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vKiEgKEMpIDIwMTcgQW5kcmVhIEdpYW1tYXJjaGkgQFdlYlJlZmxlY3Rpb24gKE1JVCkgKi9cblxuLy8gdmlwZXJIVE1MIFxcby9cbi8vXG4vLyB2YXIgcmVuZGVyID0gdmlwZXJIVE1MLmJpbmQob2JqZWN0KTtcbi8vIHJlbmRlcmBcbi8vICA8aDE+4pqh77iPIHZpcGVySFRNTCDimqHvuI88L2gxPlxuLy8gIDxwPlxuLy8gICAgJHsobmV3IERhdGUpLnRvTG9jYWxlU3RyaW5nKCl9XG4vLyAgPC9wPlxuLy8gYDtcbmZ1bmN0aW9uIHZpcGVySFRNTChzdGF0aWNzKSB7XG4gIHZhciB2aXBlciA9IHZpcGVycy5nZXQodGhpcyk7XG4gIHJldHVybiB2aXBlciAmJiB2aXBlci5zID09PSBzdGF0aWNzID9cbiAgICAoaXNBc3luYyh0aGlzKSA/XG4gICAgICB0aGlzLnVwZGF0ZSA6IHVwZGF0ZSkuYXBwbHkodmlwZXIsIGFyZ3VtZW50cykgOlxuICAgIHVwZ3JhZGUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbn1cblxuLy8gQSB3aXJlIOKesCBpcyBhIHNob3J0Y3V0IHRvIHJlbGF0ZSBhIHNwZWNpZmljIG9iamVjdCxcbi8vIG9yIGEgcnVudGltZSBjcmVhdGVkIG9uZSwgdG8gYSBzcGVjaWZpYyB0ZW1wbGF0ZS5cbi8vXG4vLyB2YXIgcmVuZGVyID0gdmlwZXJIVE1MLndpcmUoKTtcbi8vIHJlbmRlcmBcbi8vICA8ZGl2PkhlbGxvIFdpcmVkITwvZGl2PlxuLy8gYDtcbnZpcGVySFRNTC53aXJlID0gZnVuY3Rpb24gd2lyZShvYmplY3QpIHtcbiAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPCAxID9cbiAgICB2aXBlckhUTUwuYmluZCh7fSkgOlxuICAgICh3aXJlcy5nZXQob2JqZWN0KSB8fCAoXG4gICAgICB3aXJlcy5zZXQob2JqZWN0LCB3aXJlKCkpLFxuICAgICAgd2lyZShvYmplY3QpXG4gICAgKSk7XG59O1xuXG4vLyBBbiBhc3luY2hyb25vdXMgd2lyZSDinrAgaXMgYSB3ZWFrbHkgcmVmZXJlbmNlZCBjYWxsYmFjayxcbi8vIHRvIGJlIGludm9rZWQgcmlnaHQgYmVmb3JlIHRoZSB0ZW1wbGF0ZSBsaXRlcmFsc1xuLy8gdG8gcmV0dXJuIGEgcmVuZGVyZWQgY2FwYWJsZSBvZiByZXNvbHZpbmcgY2h1bmtzLlxudmlwZXJIVE1MLmFzeW5jID0gZnVuY3Rpb24gZ2V0QXN5bmMob2JqZWN0KSB7XG4gIHJldHVybiBhcmd1bWVudHMubGVuZ3RoIDwgMSA/XG4gICAgY3JlYXRlQXN5bmMoKSA6XG4gICAgKGFzeW5jcy5nZXQob2JqZWN0KSB8fCAoXG4gICAgICBhc3luY3Muc2V0KG9iamVjdCwgZ2V0QXN5bmMoKSksXG4gICAgICBnZXRBc3luYyhvYmplY3QpXG4gICAgKSk7XG59O1xuXG4vLyAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAgLSAtIC0gLSAtXG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERPTSBpbnZlc3RpZ2F0aW9uXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8vIGlmIGEgZ2FwIGlzIGluIGJldHdlZW4gYSBub2RlIGRlY2xhcmF0aW9uXG4vLyBhbmQgaXRzIGF0dHJpYnV0ZSBkZWZpbml0aW9uIHRoaXMgaXMgdHJ1ZVxuZnVuY3Rpb24gaXNBdHRyaWJ1dGUoY29waWVzLCBpKSB7XG4gIHJldHVybiBBVFRSSUJVVEVfQkVGT1JFLnRlc3QoY29waWVzLnNsaWNlKDAsIGkpLmpvaW4oJycpKSAmJlxuICAgICAgICAgQVRUUklCVVRFX0FGVEVSLnRlc3QoY29waWVzLnNsaWNlKGkpLmpvaW4oJycpKTtcbn1cblxuLy8gaWYgYSBnYXAgaXMgaW4gYmV0d2VlbiBodG1sIGVsZW1lbnRzXG4vLyBhbGxvdyBhbnkgc29ydCBvZiBIVE1MIGNvbnRlbnRcbmZ1bmN0aW9uIGlzSFRNTChzdGF0aWNzLCBpKSB7XG4gIHJldHVybiBzdGF0aWNzW2kgLSAxXS5zbGljZSgtMSkgPT09ICc+JyAmJlxuICAgICAgICAgc3RhdGljc1tpXVswXSA9PT0gJzwnO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBIZWxwZXJzXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbi8vIGluc3RydW1lbnQgYSB3aXJlIHRvIHdvcmsgYXN5bmNocm9ub3VzbHlcbi8vIHBhc3NpbmcgYWxvbmcgYW4gb3B0aW9uYWwgcmVzb2x2ZWQgY2h1bmtzXG4vLyBpbnRlcmNlcHRvciBjYWxsYmFja1xuZnVuY3Rpb24gY3JlYXRlQXN5bmMoKSB7XG4gIHZhclxuICAgIHdpcmVkID0gbmV3IEFzeW5jLFxuICAgIHdpcmUgPSB2aXBlckhUTUwuYmluZCh3aXJlZCksXG4gICAgY2h1bmtzUmVjZWl2ZXJcbiAgO1xuICB3aXJlZC51cGRhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5hID0gY2h1bmtzUmVjZWl2ZXI7XG4gICAgcmV0dXJuIGNodW5rcy5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICB9O1xuICByZXR1cm4gZnVuY3Rpb24gKGNhbGxiYWNrKSB7XG4gICAgY2h1bmtzUmVjZWl2ZXIgPSBjYWxsYmFjayB8fCBTdHJpbmc7XG4gICAgcmV0dXJuIHdpcmU7XG4gIH07XG59XG5cbi8vIGlmIGEgbm9kZSBpcyBhbiBhdHRyaWJ1dGUsIHJldHVybiB0aGUgcmlnaHQgZnVuY3Rpb25cbi8vIGFjY29yZGluZ2x5IGlmIHRoYXQncyBhbiBlc2NhcGUgb3IgYSBjYWxsYmFja1xuZnVuY3Rpb24gZ2V0VXBkYXRlRm9yQXR0cmlidXRlKGNvcGllcywgaSkge1xuICB2YXIgbmFtZSA9IGNvcGllc1tpIC0gMV0ucmVwbGFjZShBVFRSSUJVVEVfTkFNRSwgJyQxJyk7XG4gIHJldHVybiBTUEVDSUFMX0FUVFJJQlVURS50ZXN0KG5hbWUpID9cbiAgICAoQVRUUklCVVRFX0VWRU5ULnRlc3QobmFtZSkgP1xuICAgICAgdXBkYXRlRXZlbnQoKSA6XG4gICAgICB1cGRhdGVCb29sZWFuKG5hbWUsIGNvcGllcywgaSkpIDpcbiAgICBlc2NhcGU7XG59XG5cbi8vIGlmIGFuIGludGVycG9sYXRlZCB2YWx1ZSBpcyBhbiBBcnJheVxuLy8gcmV0dXJuIFByb21pc2Ugb3Igam9pbiBieSBlbXB0eSBzdHJpbmdcbmZ1bmN0aW9uIGdldFVwZGF0ZUZvckhUTUwoYm91bmQpIHtcbiAgcmV0dXJuIGlzQXN5bmMoYm91bmQpID9cbiAgICBmdW5jdGlvbiAodmFsdWUpIHsgcmV0dXJuIHZhbHVlOyB9IDpcbiAgICBqb2luSWZBcnJheTtcbn1cblxuLy8gbXVsdGlwbGUgY29udGVudCBqb2luZWQgYXMgc2luZ2xlIHN0cmluZ1xuZnVuY3Rpb24gam9pbklmQXJyYXkodmFsdWUpIHtcbiAgcmV0dXJuIGlzQXJyYXkodmFsdWUpID8gdmFsdWUuam9pbignJykgOiB2YWx1ZTtcbn1cblxuLy8gcmV0dXJuIHRoZSByaWdodCBjYWxsYmFjayB0byB1cGRhdGUgYSBib29sZWFuIGF0dHJpYnV0ZVxuLy8gYWZ0ZXIgbW9kaWZ5aW5nIHRoZSB0ZW1wbGF0ZSB0byBpZ25vcmUgc3VjaCBhdHRyaWJ1dGUgaWYgZmFsc3lcbmZ1bmN0aW9uIHVwZGF0ZUJvb2xlYW4obmFtZSwgY29waWVzLCBpKSB7XG4gIGNvcGllc1tpIC0gMV0gPSBjb3BpZXNbaSAtIDFdLnNsaWNlKDAsIC0obmFtZS5sZW5ndGggKyAzKSk7XG4gIGNvcGllc1tpXSA9IGNvcGllc1tpXS5zbGljZSgxKTtcbiAgbmFtZSA9ICcgJyArIG5hbWU7XG4gIHJldHVybiBmdW5jdGlvbiAodmFsdWUpIHtcbiAgICByZXR1cm4gdmFsdWUgPyBuYW1lIDogJyc7XG4gIH07XG59XG5cbi8vIHJldHVybiB0aGUgcmlnaHQgY2FsbGJhY2sgdG8gaW52b2tlIGFuIGV2ZW50XG4vLyBzdHJpbmdpZnlpbmcgdGhlIGNhbGxiYWNrIGFuZCBpbnZva2luZyBpdFxuLy8gdG8gc2ltdWxhdGUgYSBwcm9wZXIgRE9NIGJlaGF2aW9yXG5mdW5jdGlvbiB1cGRhdGVFdmVudCgpIHtcbiAgcmV0dXJuIGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgIHZhciBpc0Z1bmN0aW9uID0gdHlwZW9mIHZhbHVlID09PSAnZnVuY3Rpb24nO1xuICAgIHJldHVybiBpc0Z1bmN0aW9uID9cbiAgICAgICgncmV0dXJuICgnICsgZXNjYXBlKFxuICAgICAgICBKU19TSE9SVENVVC50ZXN0KHZhbHVlKSAmJiAhSlNfRlVOQ1RJT04udGVzdCh2YWx1ZSkgP1xuICAgICAgICAgICgnZnVuY3Rpb24gJyArIHZhbHVlKSA6XG4gICAgICAgICAgKCcnICsgdmFsdWUpXG4gICAgICApICsgJykuY2FsbCh0aGlzLCBldmVudCknKSA6XG4gICAgICAodmFsdWUgfHwgJycpO1xuICB9O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBUZW1wbGF0ZSBzZXR1cFxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vLyByZXNvbHZlcyB0aHJvdWdoIHByb21pc2VzIGFuZFxuLy8gaW52b2tlIGEgbm90aWZpZXIgcGVyIGVhY2ggcmVzb2x2ZWQgY2h1bmtcbi8vIHRoZSBjb250ZXh0IHdpbGwgYmUgYSB2aXBlclxuZnVuY3Rpb24gY2h1bmtzKCkge1xuICBmb3IgKHZhclxuICAgIHVwZGF0ZSxcbiAgICBvdXQgPSBbXSxcbiAgICBhc3luY0NhbGxiYWNrID0gdGhpcy5hLFxuICAgIGNvcGllcyA9IHRoaXMuYyxcbiAgICB1cGRhdGVzID0gdGhpcy51LFxuICAgIGFsbCA9IFByb21pc2UucmVzb2x2ZShjb3BpZXNbMF0pLFxuICAgIGNoYWluID0gZnVuY3Rpb24gKGFmdGVyKSB7XG4gICAgICByZXR1cm4gYWxsLnRoZW4oZnVuY3Rpb24gKHRocm91Z2gpIHtcbiAgICAgICAgICAgICAgICAgIG5vdGlmeSh0aHJvdWdoKTtcbiAgICAgICAgICAgICAgICAgIHJldHVybiBhZnRlcjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICB9LFxuICAgIGdldFZhbHVlID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICBpZiAoaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgdmFsdWUuZm9yRWFjaChnZXRWYWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBhbGwgPSBjaGFpbihcbiAgICAgICAgICBQcm9taXNlLnJlc29sdmUodmFsdWUpXG4gICAgICAgICAgICAgICAgIC50aGVuKGpvaW5JZkFycmF5KVxuICAgICAgICAgICAgICAgICAudGhlbih1cGRhdGUpXG4gICAgICAgICk7XG4gICAgICB9XG4gICAgfSxcbiAgICBub3RpZnkgPSBmdW5jdGlvbiAoY2h1bmspIHtcbiAgICAgIG91dC5wdXNoKGNodW5rKTtcbiAgICAgIGFzeW5jQ2FsbGJhY2soY2h1bmspO1xuICAgIH0sXG4gICAgaSA9IDEsXG4gICAgbGVuZ3RoID0gYXJndW1lbnRzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrXG4gICkge1xuICAgIHVwZGF0ZSA9IHVwZGF0ZXNbaSAtIDFdO1xuICAgIGdldFZhbHVlKGFyZ3VtZW50c1tpXSk7XG4gICAgYWxsID0gY2hhaW4oY29waWVzW2ldKTtcbiAgfVxuICByZXR1cm4gYWxsLnRoZW4obm90aWZ5KS50aGVuKGZ1bmN0aW9uICgpIHsgcmV0dXJuIG91dDsgfSk7XG59XG5cbi8vIGVhY2gga25vd24gaHlwZXJIVE1MIHVwZGF0ZSBpc1xuLy8ga2VwdCBhcyBzaW1wbGUgYXMgcG9zc2libGUuXG4vLyB0aGUgY29udGV4dCB3aWxsIGJlIGEgdmlwZXJcbmZ1bmN0aW9uIHVwZGF0ZSgpIHtcbiAgZm9yICh2YXJcbiAgICBjID0gdGhpcy5jLFxuICAgIHUgPSB0aGlzLnUsXG4gICAgb3V0ID0gW2NbMF1dLFxuICAgIGkgPSAxLFxuICAgIGxlbmd0aCA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgaSA8IGxlbmd0aDsgaSsrXG4gICkge1xuICAgIG91dFtpXSA9IHVbaSAtIDFdKGFyZ3VtZW50c1tpXSkgKyBjW2ldO1xuICB9XG4gIHJldHVybiBvdXQuam9pbignJyk7XG59XG5cbi8vIGJ1dCB0aGUgZmlyc3QgdGltZSwgaXQgbmVlZHMgdG8gYmUgc2V0dXAuXG4vLyBGcm9tIG5vdyBvbiwgb25seSB1cGRhdGUoc3RhdGljcykgd2lsbCBiZSBjYWxsZWRcbi8vIHVubGVzcyB0aGlzIGNvbnRleHQgd29uJ3QgYmUgdXNlZCBmb3Igb3RoZXIgcmVuZGVyaW5ncy5cbi8vIHRoZSBjb250ZXh0IHdpbGwgYmUgdGhlIG9uZSBib3VuZCB0byB2aXBlckhUTUxcbmZ1bmN0aW9uIHVwZ3JhZGUoc3RhdGljcykge1xuICBmb3IgKHZhclxuICAgIHVwZGF0ZXMgPSBbXSxcbiAgICBjb3BpZXMgPSB1cGRhdGVzLnNsaWNlLmNhbGwoc3RhdGljcyksXG4gICAgdmlwZXIgPSB7czogc3RhdGljcywgdTogdXBkYXRlcywgYzogY29waWVzfSxcbiAgICBpID0gMSxcbiAgICBsZW5ndGggPSBzdGF0aWNzLmxlbmd0aDtcbiAgICBpIDwgbGVuZ3RoOyBpKytcbiAgKSB7XG4gICAgdXBkYXRlc1tpIC0gMV0gPSBpc0hUTUwoc3RhdGljcywgaSkgP1xuICAgICAgZ2V0VXBkYXRlRm9ySFRNTCh0aGlzKSA6XG4gICAgICAoaXNBdHRyaWJ1dGUoY29waWVzLCBpKSA/XG4gICAgICAgIGdldFVwZGF0ZUZvckF0dHJpYnV0ZShjb3BpZXMsIGkpIDpcbiAgICAgICAgZXNjYXBlKTtcbiAgfVxuICB2aXBlcnMuc2V0KHRoaXMsIHZpcGVyKTtcbiAgcmV0dXJuIHZpcGVySFRNTC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBsb2NhbCB2YXJpYWJsZXNcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuLy8gaHlwZXJIVE1MIG1pZ2h0IGhhdmUgZG9jdW1lbnQgaW4gdGhlIHdpbGQgdG8gZmVhdHVyZSBkZXRlY3QgSUVcbi8vIHZpcGVySFRNTCBzaG91bGQgbm90IHN1ZmZlciBicm93c2VyIGZlYXR1cmUgZGV0ZWN0aW9uXG4vLyB0aGlzIGZpbGUgaXMgdXNlZCBvbmx5IGlmIG5vIGRvY3VtZW50IGlzIGF2YWlsYWJsZVxuLy8gc28gbGV0J3MgbWFrZSBpdCB0ZW1wb3JhcmlseSBhIHRoaW5nXG5cbmdsb2JhbC5kb2N1bWVudCA9IHt9O1xuXG52YXJcbiAgQVRUUklCVVRFX0JFRk9SRSA9IC88W2Etel1cXFMqW15cXFNdKyg/OlthLXotXSsoPzo9KD86KFtcIiddKVteXFwxXSo/XFwxfFteXCInXFxzXSspKT9bXlxcU10rKSo/W2Etei1dKz1bXCInXSQvaSxcbiAgQVRUUklCVVRFX0FGVEVSID0gL15cIig/OlteXFxTXStbYS16LV0rKD86PSg/OihbXCInXSlbXlxcMV0qP1xcMXxbXlwiJ1xcc10rKSk/KSo/W15cXFNdKj4vaSxcbiAgQVRUUklCVVRFX05BTUUgPSAvXltcXHNcXFNdKj8oW2Etei1dKyk9XCIkL2ksXG4gIEFUVFJJQlVURV9FVkVOVCA9IC9eb25bYS16XSskLyxcbiAgSlNfU0hPUlRDVVQgPSAvXlthLXokX11cXFMqP1xcKC8sXG4gIEpTX0ZVTkNUSU9OID0gL15mdW5jdGlvblxcUyo/XFwoLyxcbiAgU1BFQ0lBTF9BVFRSSUJVVEUgPSAvXig/Oig/Om9ufGFsbG93KVthLXpdK3xhc3luY3xhdXRvZm9jdXN8YXV0b3BsYXl8Y2FwdHVyZXxjaGVja2VkfGNvbnRyb2xzfGRlZmF1bHR8ZGVmZXJ8ZGlzYWJsZWR8Zm9ybW5vdmFsaWRhdGV8aGlkZGVufGlzbWFwfGl0ZW1zY29wZXxsb29wfG11bHRpcGxlfG11dGVkfG5vbW9kdWxlfG5vdmFsaWRhdGV8b3BlbnxwbGF5c2lubGluZXxyZWFkb25seXxyZXF1aXJlZHxyZXZlcnNlZHxzZWxlY3RlZHx0cnVlc3BlZWR8dHlwZW11c3RtYXRjaHx1c2VjYWNoZSkkLyxcbiAgaHRtbEVzY2FwZSA9IHJlcXVpcmUoJ2h0bWwtZXNjYXBlcicpLmVzY2FwZSxcbiAgYXN5bmNzID0gbmV3IFdlYWtNYXAoKSxcbiAgdmlwZXJzID0gbmV3IFdlYWtNYXAoKSxcbiAgd2lyZXMgPSBuZXcgV2Vha01hcCgpLFxuICBlc2NhcGUgPSBmdW5jdGlvbiAocykgeyByZXR1cm4gaHRtbEVzY2FwZShTdHJpbmcocykpOyB9LFxuICBpc0FzeW5jID0gZnVuY3Rpb24gKG8pIHsgcmV0dXJuIG8gaW5zdGFuY2VvZiBBc3luYzsgfSxcbiAgaXNBcnJheSA9IEFycmF5LmlzQXJyYXlcbjtcblxuLy8gbGV0J3MgY2xlYW51cCB0aGlzIHByb3BlcnR5IG5vd1xuZGVsZXRlIGdsb2JhbC5kb2N1bWVudDtcblxubW9kdWxlLmV4cG9ydHMgPSB2aXBlckhUTUw7XG5cbi8vIGxvY2FsIGNsYXNzIHRvIGVhc2lseSByZWNvZ25pemUgYXN5bmMgd2lyZXNcbmZ1bmN0aW9uIEFzeW5jKCkge31cbiIsIi8qIGdsb2JhbCBNdXRhdGlvbk9ic2VydmVyICovXG52YXIgZG9jdW1lbnQgPSByZXF1aXJlKCdnbG9iYWwvZG9jdW1lbnQnKVxudmFyIHdpbmRvdyA9IHJlcXVpcmUoJ2dsb2JhbC93aW5kb3cnKVxudmFyIHdhdGNoID0gT2JqZWN0LmNyZWF0ZShudWxsKVxudmFyIEtFWV9JRCA9ICdvbmxvYWRpZCcgKyAobmV3IERhdGUoKSAlIDllNikudG9TdHJpbmcoMzYpXG52YXIgS0VZX0FUVFIgPSAnZGF0YS0nICsgS0VZX0lEXG52YXIgSU5ERVggPSAwXG5cbmlmICh3aW5kb3cgJiYgd2luZG93Lk11dGF0aW9uT2JzZXJ2ZXIpIHtcbiAgdmFyIG9ic2VydmVyID0gbmV3IE11dGF0aW9uT2JzZXJ2ZXIoZnVuY3Rpb24gKG11dGF0aW9ucykge1xuICAgIGlmIChPYmplY3Qua2V5cyh3YXRjaCkubGVuZ3RoIDwgMSkgcmV0dXJuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtdXRhdGlvbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGlmIChtdXRhdGlvbnNbaV0uYXR0cmlidXRlTmFtZSA9PT0gS0VZX0FUVFIpIHtcbiAgICAgICAgZWFjaEF0dHIobXV0YXRpb25zW2ldLCB0dXJub24sIHR1cm5vZmYpXG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICBlYWNoTXV0YXRpb24obXV0YXRpb25zW2ldLnJlbW92ZWROb2RlcywgdHVybm9mZilcbiAgICAgIGVhY2hNdXRhdGlvbihtdXRhdGlvbnNbaV0uYWRkZWROb2RlcywgdHVybm9uKVxuICAgIH1cbiAgfSlcbiAgb2JzZXJ2ZXIub2JzZXJ2ZShkb2N1bWVudC5ib2R5LCB7XG4gICAgY2hpbGRMaXN0OiB0cnVlLFxuICAgIHN1YnRyZWU6IHRydWUsXG4gICAgYXR0cmlidXRlczogdHJ1ZSxcbiAgICBhdHRyaWJ1dGVPbGRWYWx1ZTogdHJ1ZSxcbiAgICBhdHRyaWJ1dGVGaWx0ZXI6IFtLRVlfQVRUUl1cbiAgfSlcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBvbmxvYWQgKGVsLCBvbiwgb2ZmLCBjYWxsZXIpIHtcbiAgb24gPSBvbiB8fCBmdW5jdGlvbiAoKSB7fVxuICBvZmYgPSBvZmYgfHwgZnVuY3Rpb24gKCkge31cbiAgZWwuc2V0QXR0cmlidXRlKEtFWV9BVFRSLCAnbycgKyBJTkRFWClcbiAgd2F0Y2hbJ28nICsgSU5ERVhdID0gW29uLCBvZmYsIDAsIGNhbGxlciB8fCBvbmxvYWQuY2FsbGVyXVxuICBJTkRFWCArPSAxXG4gIHJldHVybiBlbFxufVxuXG5mdW5jdGlvbiB0dXJub24gKGluZGV4LCBlbCkge1xuICBpZiAod2F0Y2hbaW5kZXhdWzBdICYmIHdhdGNoW2luZGV4XVsyXSA9PT0gMCkge1xuICAgIHdhdGNoW2luZGV4XVswXShlbClcbiAgICB3YXRjaFtpbmRleF1bMl0gPSAxXG4gIH1cbn1cblxuZnVuY3Rpb24gdHVybm9mZiAoaW5kZXgsIGVsKSB7XG4gIGlmICh3YXRjaFtpbmRleF1bMV0gJiYgd2F0Y2hbaW5kZXhdWzJdID09PSAxKSB7XG4gICAgd2F0Y2hbaW5kZXhdWzFdKGVsKVxuICAgIHdhdGNoW2luZGV4XVsyXSA9IDBcbiAgfVxufVxuXG5mdW5jdGlvbiBlYWNoQXR0ciAobXV0YXRpb24sIG9uLCBvZmYpIHtcbiAgdmFyIG5ld1ZhbHVlID0gbXV0YXRpb24udGFyZ2V0LmdldEF0dHJpYnV0ZShLRVlfQVRUUilcbiAgaWYgKHNhbWVPcmlnaW4obXV0YXRpb24ub2xkVmFsdWUsIG5ld1ZhbHVlKSkge1xuICAgIHdhdGNoW25ld1ZhbHVlXSA9IHdhdGNoW211dGF0aW9uLm9sZFZhbHVlXVxuICAgIHJldHVyblxuICB9XG4gIGlmICh3YXRjaFttdXRhdGlvbi5vbGRWYWx1ZV0pIHtcbiAgICBvZmYobXV0YXRpb24ub2xkVmFsdWUsIG11dGF0aW9uLnRhcmdldClcbiAgfVxuICBpZiAod2F0Y2hbbmV3VmFsdWVdKSB7XG4gICAgb24obmV3VmFsdWUsIG11dGF0aW9uLnRhcmdldClcbiAgfVxufVxuXG5mdW5jdGlvbiBzYW1lT3JpZ2luIChvbGRWYWx1ZSwgbmV3VmFsdWUpIHtcbiAgaWYgKCFvbGRWYWx1ZSB8fCAhbmV3VmFsdWUpIHJldHVybiBmYWxzZVxuICByZXR1cm4gd2F0Y2hbb2xkVmFsdWVdWzNdID09PSB3YXRjaFtuZXdWYWx1ZV1bM11cbn1cblxuZnVuY3Rpb24gZWFjaE11dGF0aW9uIChub2RlcywgZm4pIHtcbiAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyh3YXRjaClcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCBub2Rlcy5sZW5ndGg7IGkrKykge1xuICAgIGlmIChub2Rlc1tpXSAmJiBub2Rlc1tpXS5nZXRBdHRyaWJ1dGUgJiYgbm9kZXNbaV0uZ2V0QXR0cmlidXRlKEtFWV9BVFRSKSkge1xuICAgICAgdmFyIG9ubG9hZGlkID0gbm9kZXNbaV0uZ2V0QXR0cmlidXRlKEtFWV9BVFRSKVxuICAgICAga2V5cy5mb3JFYWNoKGZ1bmN0aW9uIChrKSB7XG4gICAgICAgIGlmIChvbmxvYWRpZCA9PT0gaykge1xuICAgICAgICAgIGZuKGssIG5vZGVzW2ldKVxuICAgICAgICB9XG4gICAgICB9KVxuICAgIH1cbiAgICBpZiAobm9kZXNbaV0uY2hpbGROb2Rlcy5sZW5ndGggPiAwKSB7XG4gICAgICBlYWNoTXV0YXRpb24obm9kZXNbaV0uY2hpbGROb2RlcywgZm4pXG4gICAgfVxuICB9XG59XG4iLCJ2YXIgdG9wTGV2ZWwgPSB0eXBlb2YgZ2xvYmFsICE9PSAndW5kZWZpbmVkJyA/IGdsb2JhbCA6XG4gICAgdHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcgPyB3aW5kb3cgOiB7fVxudmFyIG1pbkRvYyA9IHJlcXVpcmUoJ21pbi1kb2N1bWVudCcpO1xuXG52YXIgZG9jY3k7XG5cbmlmICh0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgZG9jY3kgPSBkb2N1bWVudDtcbn0gZWxzZSB7XG4gICAgZG9jY3kgPSB0b3BMZXZlbFsnX19HTE9CQUxfRE9DVU1FTlRfQ0FDSEVANCddO1xuXG4gICAgaWYgKCFkb2NjeSkge1xuICAgICAgICBkb2NjeSA9IHRvcExldmVsWydfX0dMT0JBTF9ET0NVTUVOVF9DQUNIRUA0J10gPSBtaW5Eb2M7XG4gICAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGRvY2N5O1xuIiwidmFyIHdpbjtcblxuaWYgKHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICB3aW4gPSB3aW5kb3c7XG59IGVsc2UgaWYgKHR5cGVvZiBnbG9iYWwgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICB3aW4gPSBnbG9iYWw7XG59IGVsc2UgaWYgKHR5cGVvZiBzZWxmICE9PSBcInVuZGVmaW5lZFwiKXtcbiAgICB3aW4gPSBzZWxmO1xufSBlbHNlIHtcbiAgICB3aW4gPSB7fTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB3aW47XG4iLCJjb25zdCBvbmxvYWQgPSByZXF1aXJlKCdvbi1sb2FkJylcbmNvbnN0IGh0bWwgPSByZXF1aXJlKCdoeXBlcnJlbmRlcicpLmh0bWxcbmNvbnN0IHN2ZyA9IHJlcXVpcmUoJ2h5cGVycmVuZGVyJykuc3ZnXG5jb25zdCBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGh5cGVyY29tcG9uZW50IChjb21wb25lbnQpIHtcbiAgY29uc3Qgc3ltYm9sID0ge1xuICAgIHJlbmRlcjogdHlwZW9mIGNvbXBvbmVudCA9PT0gJ2Z1bmN0aW9uJyA/IGNvbXBvbmVudCA6IGNvbXBvbmVudC5yZW5kZXIsXG4gICAgbG9hZDogY29tcG9uZW50ICYmIGNvbXBvbmVudC5sb2FkLFxuICAgIHVubG9hZDogY29tcG9uZW50ICYmIGNvbXBvbmVudC51bmxvYWRcbiAgfVxuICByZXR1cm4gZnVuY3Rpb24gd2lyZUNvbXBvbmVudCAoKSB7XG4gICAgY29uc3QgaW5zdGFuY2UgPSBuZXcgQ29tcG9uZW50KClcbiAgICBpbnN0YW5jZS5fc3ltYm9sID0gc3ltYm9sXG4gICAgaW5zdGFuY2UuX2xvYWRlZCA9ICEoc3ltYm9sLmxvYWQgfHwgc3ltYm9sLnVubG9hZClcbiAgICBpbnN0YW5jZS5fZGVmYXVsdEFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cylcbiAgICByZXR1cm4gaW5zdGFuY2VcbiAgfVxufVxuXG5mdW5jdGlvbiBDb21wb25lbnQgKCkge1xuICBjb25zdCBzZWxmID0gdGhpc1xuXG4gIGZ1bmN0aW9uIHdpcmUgKCkge1xuICAgIHJldHVybiB3aXJlLmh0bWwuYXBwbHkoc2VsZiwgYXJndW1lbnRzKVxuICB9XG5cbiAgd2lyZS5odG1sID0gaHRtbCh0aGlzKVxuICB3aXJlLnN2ZyA9IHN2Zyh0aGlzKVxuXG4gIHRoaXMuX3dpcmUgPSB3aXJlXG59XG5cbkNvbXBvbmVudC5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gcmVuZGVyICgpIHtcbiAgY29uc3Qgc2VsZiA9IHRoaXNcbiAgbGV0IGFyZ3MgPSBbdGhpcy5fd2lyZV0gLy8gZmlyc3QgYXJnIGlzIGFsd2F5cyBvdXIgd2lyZVxuXG4gIGZvciAodmFyXG4gICAgaSA9IDAsXG4gICAgbGVuZ3RoID0gYXJndW1lbnRzLmxlbmd0aDtcbiAgICBpIDwgbGVuZ3RoOyBpKytcbiAgKSB7XG4gICAgYXJnc1tpICsgMV0gPSBhcmd1bWVudHNbaV0gPT09IHVuZGVmaW5lZFxuICAgICAgPyB0aGlzLl9kZWZhdWx0QXJnc1tpXSAvLyBhc3NpZ24gZGVmYXVsdCBhcmcgaWYgaW5jb21taW5nIGlzIHVuZGVmaW5lZFxuICAgICAgOiBhcmd1bWVudHNbaV1cbiAgfVxuXG4gIGlmICh0aGlzLl9sb2FkZWQgPT09IGZhbHNlKSB7XG4gICAgcmV0dXJuIG9ubG9hZCh0aGlzLl9zeW1ib2wucmVuZGVyLmFwcGx5KHRoaXMsIGFyZ3MpLCBsb2FkLCB1bmxvYWQpXG4gIH1cblxuICByZXR1cm4gdGhpcy5fc3ltYm9sLnJlbmRlci5hcHBseSh0aGlzLCBhcmdzKVxuXG4gIGZ1bmN0aW9uIGxvYWQgKCkge1xuICAgIHNlbGYuX2xvYWRlZCA9IHRydWVcbiAgICBzZWxmLl9zeW1ib2wubG9hZC5hcHBseShudWxsLCBhcmd1bWVudHMpXG4gIH1cblxuICBmdW5jdGlvbiB1bmxvYWQgKCkge1xuICAgIHNlbGYuX2xvYWRlZCA9IGZhbHNlXG4gICAgc2VsZi5fc3ltYm9sLnVubG9hZC5hcHBseShudWxsLCBhcmd1bWVudHMpXG4gIH1cbn1cbiJdfQ==
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})({"hyperhtml":[function(require,module,exports){
var hyperHTML = (function () {'use strict';
/*! (C) 2017 Andrea Giammarchi @WebReflection (MIT) */
// hyperHTML \o/
//
// var render = hyperHTML.bind(document.body);
// setInterval(() => render`
// <h1>⚡️ hyperHTML ⚡️</h1>
// <p>
// ${(new Date).toLocaleString()}
// </p>
// `, 1000);
function hyperHTML(statics) {
return EXPANDO in this &&
this[EXPANDO].s === statics ?
update.apply(this, arguments) :
upgrade.apply(this, arguments);
}
// A wire ➰ is a bridge between a document fragment
// and its inevitably lost list of rendered nodes
//
// var render = hyperHTML.wire();
// render`
// <div>Hello Wired!</div>
// `;
//
// Every single invocation will return that div
// or the list of elements it contained as Array.
// This simplifies most task where hyperHTML
// is used to create the node itself, instead of
// populating an already known and bound one.
hyperHTML.wire = function wire(obj) {
return arguments.length < 1 ?
wireContent() :
wireWeakly(obj);
};
// - - - - - - - - - - - - - - - - - - - - - - -
// -------------------------
// DOM parsing & traversing
// -------------------------
// setup attributes for updates
//
// <p class="${state.class}" onclick="${event.click}"></p>
//
// Note: always use quotes around attributes, even for events,
// booleans, or numbers, otherwise this function fails.
function attributesSeeker(node, actions) {
for (var
attribute,
value = IE ? uid : uidc,
attributes = slice.call(node.attributes),
i = 0,
length = attributes.length;
i < length; i++
) {
attribute = attributes[i];
if (attribute.value === value) {
// with IE the order doesn't really matter
// as long as the right attribute is addressed
actions.push(setAttribute(node, IE ?
node.getAttributeNode(IEAttributes.shift()) :
attribute
));
}
}
}
// traverse the whole node in search of editable content
// decide what each future update should change
//
// <div atr="${some.attribute}">
// <h1>${some.HTML}</h1>
// <p>
// ${some.text}
// </p>
// </div>
function lukeTreeWalker(node, actions) {
for (var
child, text,
childNodes = slice.call(node.childNodes),
length = childNodes.length,
i = 0; i < length; i++
) {
child = childNodes[i];
switch (child.nodeType) {
case 1:
attributesSeeker(child, actions);
lukeTreeWalker(child, actions);
break;
case 8:
if (child.textContent === uid) {
if (length === 1) {
actions.push(setAnyContent(node));
node.removeChild(child);
} else if (
(i < 1 || childNodes[i - 1].nodeType === 1) &&
(i + 1 === length || childNodes[i + 1].nodeType === 1)
) {
actions.push(setVirtualContent(child));
} else {
text = node.ownerDocument.createTextNode('');
actions.push(setTextContent(text));
node.replaceChild(text, child);
}
}
break;
}
}
}
// -------------------------
// DOM manipulating
// -------------------------
// update regular bound nodes
//
// var render = hyperHTML.bind(node);
// function update() {
// render`template`;
// }
function setAnyContent(node) {
return function any(value) {
switch (typeof value) {
case 'string':
node.innerHTML = value;
break;
case 'number':
case 'boolean':
node.textContent = value;
break;
default:
if (Array.isArray(value)) {
if (value.length === 1) {
any(value[0]);
} else if(typeof value[0] === 'string') {
any(value.join(''));
} else {
var i = indexOfDiffereces(node.childNodes, value);
if (-1 < i) {
updateViaArray(node, value, i);
}
}
} else {
populateNode(node, value);
}
break;
}
};
}
// update attributes node
//
// render`<a href="${url}" onclick="${click}">${name}</a>`;
//
// Note: attributes with `on` prefix are set directly as callbacks.
// These won't ever be transformed into strings while other
// attributes will be automatically sanitized.
function setAttribute(node, attribute) {
var
name = attribute.name,
isSpecial = SPECIAL_ATTRIBUTE.test(name)
;
if (isSpecial) node.removeAttribute(name);
return isSpecial ?
function event(value) {
node[name] = value;
} :
function attr(value) {
attribute.value = value;
};
}
// update the "emptiness"
// this function is used when template literals
// have sneaky html/fragment capable
// updates in the wild (no spaces around)
//
// render`
// <p>Content before</p>${
// 'any content in between'
// }<p>Content after</p>
// `;
//
// Note: this is the most expensive
// update of them all.
function setVirtualContent(node) {
var
fragment = document.createDocumentFragment(),
childNodes = []
;
return function any(value) {
var i, parentNode = node.parentNode;
switch (typeof value) {
case 'string':
case 'number':
case 'boolean':
removeNodeList(childNodes, 0);
injectHTML(fragment, value);
childNodes = slice.call(fragment.childNodes);
parentNode.insertBefore(fragment, node);
break;
default:
if (Array.isArray(value)) {
if (value.length === 0) {
any(value[0]);
} else if(typeof value[0] === 'string') {
any(value.join(''));
} else {
i = indexOfDiffereces(childNodes, value);
if (-1 < i) {
removeNodeList(childNodes, i);
value = value.slice(i);
appendNodes(fragment, value);
parentNode.insertBefore(fragment, node);
childNodes.push.apply(childNodes, value);
}
}
} else {
removeNodeList(childNodes, 0);
childNodes = value.nodeType === 11 ?
slice.call(value.childNodes) :
[value];
parentNode.insertBefore(value, node);
}
break;
}
};
}
// basic closure to update nodes textContent
//
// render`
// <p>
// ${'spaces around means textContent'}
// </p>`;
function setTextContent(node) {
return function text(value) {
node.textContent = value;
};
}
// -------------------------
// Helpers
// -------------------------
// it does exactly what it says
function appendNodes(node, childNodes) {
for (var
i = 0,
length = childNodes.length;
i < length; i++
) {
node.appendChild(childNodes[i]);
}
}
// given two collections, find
// the first index that has different content.
// If the two lists are the same, return -1
// to indicate no differences were found.
function indexOfDiffereces(a, b) {
if (a === b) return -1;
var
i = 0,
aLength = a.length,
bLength = b.length
;
while (i < aLength) {
if (i < bLength && a[i] === b[i]) i++;
else return i;
}
return i === bLength ? -1 : i;
}
// inject HTML into a template node
// and populate a fragment with resulting nodes
//
// IE9~IE11 are not compatible with the template tag.
// If the content is a partial part of a table there is a fallback.
// Not the most elegant/robust way but good enough for common cases.
// (I don't want to include a whole DOM parser for IE only here).
function injectHTML(fragment, html) {
var
fallback = IE && /^[^\S]*?<(t(?:head|body|foot|r|d|h))/i.test(html),
template = fragment.ownerDocument.createElement('template')
;
template.innerHTML = fallback ? ('<table>' + html + '</table>') : html;
if (fallback) {
template = {childNodes: template.querySelectorAll(RegExp.$1)};
}
appendNodes(
fragment,
slice.call((template.content || template).childNodes)
);
}
// accordingly with the kind of child
// it put its content into a parent node
function populateNode(parent, child) {
switch (child.nodeType) {
case 1:
var childNodes = parent.childNodes;
if (childNodes.length !== 1 || childNodes[0] !== child) {
resetAndPopulate(parent, child);
}
break;
case 11:
if (-1 < indexOfDiffereces(parent.childNodes, child.childNodes)) {
resetAndPopulate(parent, child);
}
break;
case 3:
parent.textContent = child.textContent;
break;
}
}
// it does exactly what it says
function removeNodeList(list, startIndex) {
var length = list.length, child;
while (startIndex < length--) {
child = list[length];
child.parentNode.removeChild(child);
}
}
// drop all nodes and append a node
function resetAndPopulate(parent, child) {
parent.textContent = '';
parent.appendChild(child);
}
// the first time a hyperHTML.wire() is invoked
// remember the list of nodes that should be updated
// at every consequent render call.
// The resulting function might return the very first node
// or the Array of all nodes that might need updates.
function setupAndGetContent(node) {
for (var
child,
children = [],
childNodes = node.childNodes,
i = 0,
length = childNodes.length;
i < length; i++
) {
child = childNodes[i];
if (
1 === child.nodeType ||
0 < trim.call(child.textContent).length
) {
children.push(child);
}
}
length = children.length;
return length < 2 ?
((child = length < 1 ? node : children[0]),
function () { return child; }) :
function () { return children; };
}
// remove and/or and a list of nodes through an array
function updateViaArray(node, childNodes, i) {
var fragment = node.ownerDocument.createDocumentFragment();
if (0 < i) {
removeNodeList(node.childNodes, i);
appendNodes(fragment, childNodes.slice(i));
node.appendChild(fragment);
} else {
appendNodes(fragment, childNodes);
resetAndPopulate(node, fragment);
}
}
// create a new wire for generic DOM content
function wireContent() {
var content, fragment, render, setup, template;
return function update(statics) {
if (template !== statics) {
setup = true;
template = statics;
fragment = document.createDocumentFragment();
render = hyperHTML.bind(fragment);
}
render.apply(null, arguments);
if (setup) {
setup = false;
content = setupAndGetContent(fragment);
}
return content();
};
}
// get or create a wired weak reference
function wireWeakly(obj) {
return wm.get(obj) || (
wm.set(obj, wireContent()),
wireWeakly(obj)
);
}
// -------------------------
// Template setup
// -------------------------
// each known hyperHTML update is
// kept as simple as possible.
function update() {
for (var
i = 1,
length = arguments.length,
updates = this[EXPANDO].u;
i < length; i++
) {
updates[i - 1](arguments[i]);
}
return this;
}
// but the first time, it needs to be setup.
// From now on, only update(statics) will be called
// unless this node won't be used for other renderings.
function upgrade(statics) {
var
updates = [],
html = statics.join(uidc)
;
if (IE) {
IEAttributes = [];
injectHTML(this, html.replace(no, comments));
} else if (this.nodeType === 1) {
this.innerHTML = html;
} else {
injectHTML(this, html);
}
lukeTreeWalker(this, updates);
this[EXPANDO] = {s: statics, u: updates};
return update.apply(this, arguments);
}
// -------------------------
// the trash bin
// -------------------------
// IE used to suck.
/*
// even in a try/catch this throw an error
// since it's reliable though, I'll keep it around
function isIE() {
var p = document.createElement('p');
p.innerHTML = '<i onclick="<!---->">';
return p.childNodes[0].onclick == null;
}
//*/
// remove and/or and a list of nodes through a fragment
/* temporarily removed until it's demonstrated it's needed
function updateViaFragment(node, fragment, i) {
if (0 < i) {
removeNodeList(node.childNodes, i);
var slim = fragment.cloneNode();
appendNodes(slim, slice.call(fragment.childNodes, i));
node.appendChild(fragment, slim);
} else {
resetAndPopulate(node, fragment);
}
}
//*/
// -------------------------
// local variables
// -------------------------
var
// decide special attributes behavior
SPECIAL_ATTRIBUTE = /^(?:on[a-z]+|async|autofocus|autoplay|capture|checked|controls|deferred|disabled|formnovalidate|hidden|loop|multiple|muted|required)$/,
// avoids WeakMap to avoid memory pressure, use CSS compatible syntax for IE
EXPANDO = '_hyper_html: ',
// use a pseudo unique id to avoid conflicts and normalize CSS style for IE
uid = EXPANDO + ((Math.random() * new Date) | 0) + ';',
// use comment nodes with pseudo unique content to setup
uidc = '<!--' + uid + '-->',
// threat it differently
IE = 'documentMode' in document,
no = IE && new RegExp('([^\\S][a-z]+[a-z0-9_-]*=)([\'"])' + uidc + '\\2', 'g'),
comments = IE && function ($0, $1, $2) {
IEAttributes.push($1.slice(1, -1));
return $1 + $2 + uid + $2;
},
// verify empty textContent on .wire() setup
trim = EXPANDO.trim || function () {
return this.replace(/^\s+|\s+$/g, '');
},
// convert DOM.childNodes into arrays to avoid
// DOM mutation backfiring on loops
slice = [].slice,
// used for weak references
// if WeakMap is not available
// it uses a configurable, non enumerable,
// quick and dirty expando property.
wm = typeof WeakMap === typeof wm ?
{
get: function (obj) { return obj[EXPANDO]; },
set: function (obj, value) {
Object.defineProperty(obj, EXPANDO, {
configurable: true,
value: value
});
}
} :
new WeakMap(),
IEAttributes
;
// Simply to avoid duplicated RegExp in viperHTML
hyperHTML.SPECIAL_ATTRIBUTE = SPECIAL_ATTRIBUTE;
// -------------------------
// ⚡️ ️️The End ➰
// -------------------------
return hyperHTML;
}());
// umd.KISS
try { module.exports = hyperHTML; } catch(o_O) {}
},{}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImh5cGVyaHRtbCJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQ0FBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCJ2YXIgaHlwZXJIVE1MID0gKGZ1bmN0aW9uICgpIHsndXNlIHN0cmljdCc7XG5cbiAgLyohIChDKSAyMDE3IEFuZHJlYSBHaWFtbWFyY2hpIEBXZWJSZWZsZWN0aW9uIChNSVQpICovXG5cbiAgLy8gaHlwZXJIVE1MIFxcby9cbiAgLy9cbiAgLy8gdmFyIHJlbmRlciA9IGh5cGVySFRNTC5iaW5kKGRvY3VtZW50LmJvZHkpO1xuICAvLyBzZXRJbnRlcnZhbCgoKSA9PiByZW5kZXJgXG4gIC8vICA8aDE+4pqh77iPIGh5cGVySFRNTCDimqHvuI88L2gxPlxuICAvLyAgPHA+XG4gIC8vICAgICR7KG5ldyBEYXRlKS50b0xvY2FsZVN0cmluZygpfVxuICAvLyAgPC9wPlxuICAvLyBgLCAxMDAwKTtcbiAgZnVuY3Rpb24gaHlwZXJIVE1MKHN0YXRpY3MpIHtcbiAgICByZXR1cm4gIEVYUEFORE8gaW4gdGhpcyAmJlxuICAgICAgICAgICAgdGhpc1tFWFBBTkRPXS5zID09PSBzdGF0aWNzID9cbiAgICAgICAgICAgICAgdXBkYXRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgOlxuICAgICAgICAgICAgICB1cGdyYWRlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH1cblxuICAvLyBBIHdpcmUg4p6wIGlzIGEgYnJpZGdlIGJldHdlZW4gYSBkb2N1bWVudCBmcmFnbWVudFxuICAvLyBhbmQgaXRzIGluZXZpdGFibHkgbG9zdCBsaXN0IG9mIHJlbmRlcmVkIG5vZGVzXG4gIC8vXG4gIC8vIHZhciByZW5kZXIgPSBoeXBlckhUTUwud2lyZSgpO1xuICAvLyByZW5kZXJgXG4gIC8vICA8ZGl2PkhlbGxvIFdpcmVkITwvZGl2PlxuICAvLyBgO1xuICAvL1xuICAvLyBFdmVyeSBzaW5nbGUgaW52b2NhdGlvbiB3aWxsIHJldHVybiB0aGF0IGRpdlxuICAvLyBvciB0aGUgbGlzdCBvZiBlbGVtZW50cyBpdCBjb250YWluZWQgYXMgQXJyYXkuXG4gIC8vIFRoaXMgc2ltcGxpZmllcyBtb3N0IHRhc2sgd2hlcmUgaHlwZXJIVE1MXG4gIC8vIGlzIHVzZWQgdG8gY3JlYXRlIHRoZSBub2RlIGl0c2VsZiwgaW5zdGVhZCBvZlxuICAvLyBwb3B1bGF0aW5nIGFuIGFscmVhZHkga25vd24gYW5kIGJvdW5kIG9uZS5cbiAgaHlwZXJIVE1MLndpcmUgPSBmdW5jdGlvbiB3aXJlKG9iaikge1xuICAgIHJldHVybiBhcmd1bWVudHMubGVuZ3RoIDwgMSA/XG4gICAgICB3aXJlQ29udGVudCgpIDpcbiAgICAgIHdpcmVXZWFrbHkob2JqKTtcbiAgfTtcblxuICAvLyAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAtIC0gLSAgLSAtIC0gLSAtXG5cbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAvLyBET00gcGFyc2luZyAmIHRyYXZlcnNpbmdcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIHNldHVwIGF0dHJpYnV0ZXMgZm9yIHVwZGF0ZXNcbiAgLy9cbiAgLy8gPHAgY2xhc3M9XCIke3N0YXRlLmNsYXNzfVwiIG9uY2xpY2s9XCIke2V2ZW50LmNsaWNrfVwiPjwvcD5cbiAgLy9cbiAgLy8gTm90ZTogYWx3YXlzIHVzZSBxdW90ZXMgYXJvdW5kIGF0dHJpYnV0ZXMsIGV2ZW4gZm9yIGV2ZW50cyxcbiAgLy8gICAgICAgYm9vbGVhbnMsIG9yIG51bWJlcnMsIG90aGVyd2lzZSB0aGlzIGZ1bmN0aW9uIGZhaWxzLlxuICBmdW5jdGlvbiBhdHRyaWJ1dGVzU2Vla2VyKG5vZGUsIGFjdGlvbnMpIHtcbiAgICBmb3IgKHZhclxuICAgICAgYXR0cmlidXRlLFxuICAgICAgdmFsdWUgPSBJRSA/IHVpZCA6IHVpZGMsXG4gICAgICBhdHRyaWJ1dGVzID0gc2xpY2UuY2FsbChub2RlLmF0dHJpYnV0ZXMpLFxuICAgICAgaSA9IDAsXG4gICAgICBsZW5ndGggPSBhdHRyaWJ1dGVzLmxlbmd0aDtcbiAgICAgIGkgPCBsZW5ndGg7IGkrK1xuICAgICkge1xuICAgICAgYXR0cmlidXRlID0gYXR0cmlidXRlc1tpXTtcbiAgICAgIGlmIChhdHRyaWJ1dGUudmFsdWUgPT09IHZhbHVlKSB7XG4gICAgICAgIC8vIHdpdGggSUUgdGhlIG9yZGVyIGRvZXNuJ3QgcmVhbGx5IG1hdHRlclxuICAgICAgICAvLyBhcyBsb25nIGFzIHRoZSByaWdodCBhdHRyaWJ1dGUgaXMgYWRkcmVzc2VkXG4gICAgICAgIGFjdGlvbnMucHVzaChzZXRBdHRyaWJ1dGUobm9kZSwgSUUgP1xuICAgICAgICAgIG5vZGUuZ2V0QXR0cmlidXRlTm9kZShJRUF0dHJpYnV0ZXMuc2hpZnQoKSkgOlxuICAgICAgICAgIGF0dHJpYnV0ZVxuICAgICAgICApKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyB0cmF2ZXJzZSB0aGUgd2hvbGUgbm9kZSBpbiBzZWFyY2ggb2YgZWRpdGFibGUgY29udGVudFxuICAvLyBkZWNpZGUgd2hhdCBlYWNoIGZ1dHVyZSB1cGRhdGUgc2hvdWxkIGNoYW5nZVxuICAvL1xuICAvLyA8ZGl2IGF0cj1cIiR7c29tZS5hdHRyaWJ1dGV9XCI+XG4gIC8vICAgIDxoMT4ke3NvbWUuSFRNTH08L2gxPlxuICAvLyAgICA8cD5cbiAgLy8gICAgICAke3NvbWUudGV4dH1cbiAgLy8gICAgPC9wPlxuICAvLyA8L2Rpdj5cbiAgZnVuY3Rpb24gbHVrZVRyZWVXYWxrZXIobm9kZSwgYWN0aW9ucykge1xuICAgIGZvciAodmFyXG4gICAgICBjaGlsZCwgdGV4dCxcbiAgICAgIGNoaWxkTm9kZXMgPSBzbGljZS5jYWxsKG5vZGUuY2hpbGROb2RlcyksXG4gICAgICBsZW5ndGggPSBjaGlsZE5vZGVzLmxlbmd0aCxcbiAgICAgIGkgPSAwOyBpIDwgbGVuZ3RoOyBpKytcbiAgICApIHtcbiAgICAgIGNoaWxkID0gY2hpbGROb2Rlc1tpXTtcbiAgICAgIHN3aXRjaCAoY2hpbGQubm9kZVR5cGUpIHtcbiAgICAgICAgY2FzZSAxOlxuICAgICAgICAgIGF0dHJpYnV0ZXNTZWVrZXIoY2hpbGQsIGFjdGlvbnMpO1xuICAgICAgICAgIGx1a2VUcmVlV2Fsa2VyKGNoaWxkLCBhY3Rpb25zKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSA4OlxuICAgICAgICAgIGlmIChjaGlsZC50ZXh0Q29udGVudCA9PT0gdWlkKSB7XG4gICAgICAgICAgICBpZiAobGVuZ3RoID09PSAxKSB7XG4gICAgICAgICAgICAgIGFjdGlvbnMucHVzaChzZXRBbnlDb250ZW50KG5vZGUpKTtcbiAgICAgICAgICAgICAgbm9kZS5yZW1vdmVDaGlsZChjaGlsZCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKFxuICAgICAgICAgICAgICAoaSA8IDEgfHwgY2hpbGROb2Rlc1tpIC0gMV0ubm9kZVR5cGUgPT09IDEpICYmXG4gICAgICAgICAgICAgIChpICsgMSA9PT0gbGVuZ3RoIHx8IGNoaWxkTm9kZXNbaSArIDFdLm5vZGVUeXBlID09PSAxKVxuICAgICAgICAgICAgKSB7XG4gICAgICAgICAgICAgIGFjdGlvbnMucHVzaChzZXRWaXJ0dWFsQ29udGVudChjaGlsZCkpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGV4dCA9IG5vZGUub3duZXJEb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnJyk7XG4gICAgICAgICAgICAgIGFjdGlvbnMucHVzaChzZXRUZXh0Q29udGVudCh0ZXh0KSk7XG4gICAgICAgICAgICAgIG5vZGUucmVwbGFjZUNoaWxkKHRleHQsIGNoaWxkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIERPTSBtYW5pcHVsYXRpbmdcbiAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gIC8vIHVwZGF0ZSByZWd1bGFyIGJvdW5kIG5vZGVzXG4gIC8vXG4gIC8vIHZhciByZW5kZXIgPSBoeXBlckhUTUwuYmluZChub2RlKTtcbiAgLy8gZnVuY3Rpb24gdXBkYXRlKCkge1xuICAvLyAgcmVuZGVyYHRlbXBsYXRlYDtcbiAgLy8gfVxuICBmdW5jdGlvbiBzZXRBbnlDb250ZW50KG5vZGUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gYW55KHZhbHVlKSB7XG4gICAgICBzd2l0Y2ggKHR5cGVvZiB2YWx1ZSkge1xuICAgICAgICBjYXNlICdzdHJpbmcnOlxuICAgICAgICAgIG5vZGUuaW5uZXJIVE1MID0gdmFsdWU7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ251bWJlcic6XG4gICAgICAgIGNhc2UgJ2Jvb2xlYW4nOlxuICAgICAgICAgIG5vZGUudGV4dENvbnRlbnQgPSB2YWx1ZTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgYW55KHZhbHVlWzBdKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZih0eXBlb2YgdmFsdWVbMF0gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgIGFueSh2YWx1ZS5qb2luKCcnKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB2YXIgaSA9IGluZGV4T2ZEaWZmZXJlY2VzKG5vZGUuY2hpbGROb2RlcywgdmFsdWUpO1xuICAgICAgICAgICAgICBpZiAoLTEgPCBpKSB7XG4gICAgICAgICAgICAgICAgdXBkYXRlVmlhQXJyYXkobm9kZSwgdmFsdWUsIGkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHBvcHVsYXRlTm9kZShub2RlLCB2YWx1ZSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH07XG4gIH1cblxuICAvLyB1cGRhdGUgYXR0cmlidXRlcyBub2RlXG4gIC8vXG4gIC8vIHJlbmRlcmA8YSBocmVmPVwiJHt1cmx9XCIgb25jbGljaz1cIiR7Y2xpY2t9XCI+JHtuYW1lfTwvYT5gO1xuICAvL1xuICAvLyBOb3RlOiBhdHRyaWJ1dGVzIHdpdGggYG9uYCBwcmVmaXggYXJlIHNldCBkaXJlY3RseSBhcyBjYWxsYmFja3MuXG4gIC8vICAgICAgIFRoZXNlIHdvbid0IGV2ZXIgYmUgdHJhbnNmb3JtZWQgaW50byBzdHJpbmdzIHdoaWxlIG90aGVyXG4gIC8vICAgICAgIGF0dHJpYnV0ZXMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IHNhbml0aXplZC5cbiAgZnVuY3Rpb24gc2V0QXR0cmlidXRlKG5vZGUsIGF0dHJpYnV0ZSkge1xuICAgIHZhclxuICAgICAgbmFtZSA9IGF0dHJpYnV0ZS5uYW1lLFxuICAgICAgaXNTcGVjaWFsID0gU1BFQ0lBTF9BVFRSSUJVVEUudGVzdChuYW1lKVxuICAgIDtcbiAgICBpZiAoaXNTcGVjaWFsKSBub2RlLnJlbW92ZUF0dHJpYnV0ZShuYW1lKTtcbiAgICByZXR1cm4gaXNTcGVjaWFsID9cbiAgICAgIGZ1bmN0aW9uIGV2ZW50KHZhbHVlKSB7XG4gICAgICAgIG5vZGVbbmFtZV0gPSB2YWx1ZTtcbiAgICAgIH0gOlxuICAgICAgZnVuY3Rpb24gYXR0cih2YWx1ZSkge1xuICAgICAgICBhdHRyaWJ1dGUudmFsdWUgPSB2YWx1ZTtcbiAgICAgIH07XG4gIH1cblxuICAvLyB1cGRhdGUgdGhlIFwiZW1wdGluZXNzXCJcbiAgLy8gdGhpcyBmdW5jdGlvbiBpcyB1c2VkIHdoZW4gdGVtcGxhdGUgbGl0ZXJhbHNcbiAgLy8gaGF2ZSBzbmVha3kgaHRtbC9mcmFnbWVudCBjYXBhYmxlXG4gIC8vIHVwZGF0ZXMgaW4gdGhlIHdpbGQgKG5vIHNwYWNlcyBhcm91bmQpXG4gIC8vXG4gIC8vIHJlbmRlcmBcbiAgLy8gIDxwPkNvbnRlbnQgYmVmb3JlPC9wPiR7XG4gIC8vICAnYW55IGNvbnRlbnQgaW4gYmV0d2VlbidcbiAgLy8gIH08cD5Db250ZW50IGFmdGVyPC9wPlxuICAvLyBgO1xuICAvL1xuICAvLyBOb3RlOiB0aGlzIGlzIHRoZSBtb3N0IGV4cGVuc2l2ZVxuICAvLyAgICAgICB1cGRhdGUgb2YgdGhlbSBhbGwuXG4gIGZ1bmN0aW9uIHNldFZpcnR1YWxDb250ZW50KG5vZGUpIHtcbiAgICB2YXJcbiAgICAgIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxuICAgICAgY2hpbGROb2RlcyA9IFtdXG4gICAgO1xuICAgIHJldHVybiBmdW5jdGlvbiBhbnkodmFsdWUpIHtcbiAgICAgIHZhciBpLCBwYXJlbnROb2RlID0gbm9kZS5wYXJlbnROb2RlO1xuICAgICAgc3dpdGNoICh0eXBlb2YgdmFsdWUpIHtcbiAgICAgICAgY2FzZSAnc3RyaW5nJzpcbiAgICAgICAgY2FzZSAnbnVtYmVyJzpcbiAgICAgICAgY2FzZSAnYm9vbGVhbic6XG4gICAgICAgICAgcmVtb3ZlTm9kZUxpc3QoY2hpbGROb2RlcywgMCk7XG4gICAgICAgICAgaW5qZWN0SFRNTChmcmFnbWVudCwgdmFsdWUpO1xuICAgICAgICAgIGNoaWxkTm9kZXMgPSBzbGljZS5jYWxsKGZyYWdtZW50LmNoaWxkTm9kZXMpO1xuICAgICAgICAgIHBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGZyYWdtZW50LCBub2RlKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZS5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgYW55KHZhbHVlWzBdKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZih0eXBlb2YgdmFsdWVbMF0gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgIGFueSh2YWx1ZS5qb2luKCcnKSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpID0gaW5kZXhPZkRpZmZlcmVjZXMoY2hpbGROb2RlcywgdmFsdWUpO1xuICAgICAgICAgICAgICBpZiAoLTEgPCBpKSB7XG4gICAgICAgICAgICAgICAgcmVtb3ZlTm9kZUxpc3QoY2hpbGROb2RlcywgaSk7XG4gICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5zbGljZShpKTtcbiAgICAgICAgICAgICAgICBhcHBlbmROb2RlcyhmcmFnbWVudCwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIHBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGZyYWdtZW50LCBub2RlKTtcbiAgICAgICAgICAgICAgICBjaGlsZE5vZGVzLnB1c2guYXBwbHkoY2hpbGROb2RlcywgdmFsdWUpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJlbW92ZU5vZGVMaXN0KGNoaWxkTm9kZXMsIDApO1xuICAgICAgICAgICAgY2hpbGROb2RlcyA9IHZhbHVlLm5vZGVUeXBlID09PSAxMSA/XG4gICAgICAgICAgICAgIHNsaWNlLmNhbGwodmFsdWUuY2hpbGROb2RlcykgOlxuICAgICAgICAgICAgICBbdmFsdWVdO1xuICAgICAgICAgICAgcGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUodmFsdWUsIG5vZGUpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLy8gYmFzaWMgY2xvc3VyZSB0byB1cGRhdGUgbm9kZXMgdGV4dENvbnRlbnRcbiAgLy9cbiAgLy8gcmVuZGVyYFxuICAvLyAgPHA+XG4gIC8vICAgICR7J3NwYWNlcyBhcm91bmQgbWVhbnMgdGV4dENvbnRlbnQnfVxuICAvLyAgPC9wPmA7XG4gIGZ1bmN0aW9uIHNldFRleHRDb250ZW50KG5vZGUpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gdGV4dCh2YWx1ZSkge1xuICAgICAgbm9kZS50ZXh0Q29udGVudCA9IHZhbHVlO1xuICAgIH07XG4gIH1cblxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gSGVscGVyc1xuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gaXQgZG9lcyBleGFjdGx5IHdoYXQgaXQgc2F5c1xuICBmdW5jdGlvbiBhcHBlbmROb2Rlcyhub2RlLCBjaGlsZE5vZGVzKSB7XG4gICAgZm9yICh2YXJcbiAgICAgIGkgPSAwLFxuICAgICAgbGVuZ3RoID0gY2hpbGROb2Rlcy5sZW5ndGg7XG4gICAgICBpIDwgbGVuZ3RoOyBpKytcbiAgICApIHtcbiAgICAgIG5vZGUuYXBwZW5kQ2hpbGQoY2hpbGROb2Rlc1tpXSk7XG4gICAgfVxuICB9XG5cbiAgLy8gZ2l2ZW4gdHdvIGNvbGxlY3Rpb25zLCBmaW5kXG4gIC8vIHRoZSBmaXJzdCBpbmRleCB0aGF0IGhhcyBkaWZmZXJlbnQgY29udGVudC5cbiAgLy8gSWYgdGhlIHR3byBsaXN0cyBhcmUgdGhlIHNhbWUsIHJldHVybiAtMVxuICAvLyB0byBpbmRpY2F0ZSBubyBkaWZmZXJlbmNlcyB3ZXJlIGZvdW5kLlxuICBmdW5jdGlvbiBpbmRleE9mRGlmZmVyZWNlcyhhLCBiKSB7XG4gICAgaWYgKGEgPT09IGIpIHJldHVybiAtMTtcbiAgICB2YXJcbiAgICAgIGkgPSAwLFxuICAgICAgYUxlbmd0aCA9IGEubGVuZ3RoLFxuICAgICAgYkxlbmd0aCA9IGIubGVuZ3RoXG4gICAgO1xuICAgIHdoaWxlIChpIDwgYUxlbmd0aCkge1xuICAgICAgaWYgKGkgPCBiTGVuZ3RoICYmIGFbaV0gPT09IGJbaV0pIGkrKztcbiAgICAgIGVsc2UgcmV0dXJuIGk7XG4gICAgfVxuICAgIHJldHVybiBpID09PSBiTGVuZ3RoID8gLTEgOiBpO1xuICB9XG5cbiAgLy8gaW5qZWN0IEhUTUwgaW50byBhIHRlbXBsYXRlIG5vZGVcbiAgLy8gYW5kIHBvcHVsYXRlIGEgZnJhZ21lbnQgd2l0aCByZXN1bHRpbmcgbm9kZXNcbiAgLy9cbiAgLy8gSUU5fklFMTEgYXJlIG5vdCBjb21wYXRpYmxlIHdpdGggdGhlIHRlbXBsYXRlIHRhZy5cbiAgLy8gSWYgdGhlIGNvbnRlbnQgaXMgYSBwYXJ0aWFsIHBhcnQgb2YgYSB0YWJsZSB0aGVyZSBpcyBhIGZhbGxiYWNrLlxuICAvLyBOb3QgdGhlIG1vc3QgZWxlZ2FudC9yb2J1c3Qgd2F5IGJ1dCBnb29kIGVub3VnaCBmb3IgY29tbW9uIGNhc2VzLlxuICAvLyAoSSBkb24ndCB3YW50IHRvIGluY2x1ZGUgYSB3aG9sZSBET00gcGFyc2VyIGZvciBJRSBvbmx5IGhlcmUpLlxuICBmdW5jdGlvbiBpbmplY3RIVE1MKGZyYWdtZW50LCBodG1sKSB7XG4gICAgdmFyXG4gICAgICBmYWxsYmFjayA9IElFICYmIC9eW15cXFNdKj88KHQoPzpoZWFkfGJvZHl8Zm9vdHxyfGR8aCkpL2kudGVzdChodG1sKSxcbiAgICAgIHRlbXBsYXRlID0gZnJhZ21lbnQub3duZXJEb2N1bWVudC5jcmVhdGVFbGVtZW50KCd0ZW1wbGF0ZScpXG4gICAgO1xuICAgIHRlbXBsYXRlLmlubmVySFRNTCA9IGZhbGxiYWNrID8gKCc8dGFibGU+JyArIGh0bWwgKyAnPC90YWJsZT4nKSA6IGh0bWw7XG4gICAgaWYgKGZhbGxiYWNrKSB7XG4gICAgICB0ZW1wbGF0ZSA9IHtjaGlsZE5vZGVzOiB0ZW1wbGF0ZS5xdWVyeVNlbGVjdG9yQWxsKFJlZ0V4cC4kMSl9O1xuICAgIH1cbiAgICBhcHBlbmROb2RlcyhcbiAgICAgIGZyYWdtZW50LFxuICAgICAgc2xpY2UuY2FsbCgodGVtcGxhdGUuY29udGVudCB8fCB0ZW1wbGF0ZSkuY2hpbGROb2RlcylcbiAgICApO1xuICB9XG5cbiAgLy8gYWNjb3JkaW5nbHkgd2l0aCB0aGUga2luZCBvZiBjaGlsZFxuICAvLyBpdCBwdXQgaXRzIGNvbnRlbnQgaW50byBhIHBhcmVudCBub2RlXG4gIGZ1bmN0aW9uIHBvcHVsYXRlTm9kZShwYXJlbnQsIGNoaWxkKSB7XG4gICAgc3dpdGNoIChjaGlsZC5ub2RlVHlwZSkge1xuICAgICAgY2FzZSAxOlxuICAgICAgICB2YXIgY2hpbGROb2RlcyA9IHBhcmVudC5jaGlsZE5vZGVzO1xuICAgICAgICBpZiAoY2hpbGROb2Rlcy5sZW5ndGggIT09IDEgfHwgY2hpbGROb2Rlc1swXSAhPT0gY2hpbGQpIHtcbiAgICAgICAgICByZXNldEFuZFBvcHVsYXRlKHBhcmVudCwgY2hpbGQpO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAxMTpcbiAgICAgICAgaWYgKC0xIDwgaW5kZXhPZkRpZmZlcmVjZXMocGFyZW50LmNoaWxkTm9kZXMsIGNoaWxkLmNoaWxkTm9kZXMpKSB7XG4gICAgICAgICAgcmVzZXRBbmRQb3B1bGF0ZShwYXJlbnQsIGNoaWxkKTtcbiAgICAgICAgfVxuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgcGFyZW50LnRleHRDb250ZW50ID0gY2hpbGQudGV4dENvbnRlbnQ7XG4gICAgICAgIGJyZWFrO1xuICAgIH1cbiAgfVxuXG4gIC8vIGl0IGRvZXMgZXhhY3RseSB3aGF0IGl0IHNheXNcbiAgZnVuY3Rpb24gcmVtb3ZlTm9kZUxpc3QobGlzdCwgc3RhcnRJbmRleCkge1xuICAgIHZhciBsZW5ndGggPSBsaXN0Lmxlbmd0aCwgY2hpbGQ7XG4gICAgd2hpbGUgKHN0YXJ0SW5kZXggPCBsZW5ndGgtLSkge1xuICAgICAgY2hpbGQgPSBsaXN0W2xlbmd0aF07XG4gICAgICBjaGlsZC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGNoaWxkKTtcbiAgICB9XG4gIH1cblxuICAvLyBkcm9wIGFsbCBub2RlcyBhbmQgYXBwZW5kIGEgbm9kZVxuICBmdW5jdGlvbiByZXNldEFuZFBvcHVsYXRlKHBhcmVudCwgY2hpbGQpIHtcbiAgICBwYXJlbnQudGV4dENvbnRlbnQgPSAnJztcbiAgICBwYXJlbnQuYXBwZW5kQ2hpbGQoY2hpbGQpO1xuICB9XG5cbiAgLy8gdGhlIGZpcnN0IHRpbWUgYSBoeXBlckhUTUwud2lyZSgpIGlzIGludm9rZWRcbiAgLy8gcmVtZW1iZXIgdGhlIGxpc3Qgb2Ygbm9kZXMgdGhhdCBzaG91bGQgYmUgdXBkYXRlZFxuICAvLyBhdCBldmVyeSBjb25zZXF1ZW50IHJlbmRlciBjYWxsLlxuICAvLyBUaGUgcmVzdWx0aW5nIGZ1bmN0aW9uIG1pZ2h0IHJldHVybiB0aGUgdmVyeSBmaXJzdCBub2RlXG4gIC8vIG9yIHRoZSBBcnJheSBvZiBhbGwgbm9kZXMgdGhhdCBtaWdodCBuZWVkIHVwZGF0ZXMuXG4gIGZ1bmN0aW9uIHNldHVwQW5kR2V0Q29udGVudChub2RlKSB7XG4gICAgZm9yICh2YXJcbiAgICAgIGNoaWxkLFxuICAgICAgY2hpbGRyZW4gPSBbXSxcbiAgICAgIGNoaWxkTm9kZXMgPSBub2RlLmNoaWxkTm9kZXMsXG4gICAgICBpID0gMCxcbiAgICAgIGxlbmd0aCA9IGNoaWxkTm9kZXMubGVuZ3RoO1xuICAgICAgaSA8IGxlbmd0aDsgaSsrXG4gICAgKSB7XG4gICAgICBjaGlsZCA9IGNoaWxkTm9kZXNbaV07XG4gICAgICBpZiAoXG4gICAgICAgIDEgPT09IGNoaWxkLm5vZGVUeXBlIHx8XG4gICAgICAgIDAgPCB0cmltLmNhbGwoY2hpbGQudGV4dENvbnRlbnQpLmxlbmd0aFxuICAgICAgKSB7XG4gICAgICAgIGNoaWxkcmVuLnB1c2goY2hpbGQpO1xuICAgICAgfVxuICAgIH1cbiAgICBsZW5ndGggPSBjaGlsZHJlbi5sZW5ndGg7XG4gICAgcmV0dXJuIGxlbmd0aCA8IDIgP1xuICAgICAgKChjaGlsZCA9IGxlbmd0aCA8IDEgPyBub2RlIDogY2hpbGRyZW5bMF0pLFxuICAgICAgZnVuY3Rpb24gKCkgeyByZXR1cm4gY2hpbGQ7IH0pIDpcbiAgICAgIGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNoaWxkcmVuOyB9O1xuICB9XG5cbiAgLy8gcmVtb3ZlIGFuZC9vciBhbmQgYSBsaXN0IG9mIG5vZGVzIHRocm91Z2ggYW4gYXJyYXlcbiAgZnVuY3Rpb24gdXBkYXRlVmlhQXJyYXkobm9kZSwgY2hpbGROb2RlcywgaSkge1xuICAgIHZhciBmcmFnbWVudCA9IG5vZGUub3duZXJEb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgaWYgKDAgPCBpKSB7XG4gICAgICByZW1vdmVOb2RlTGlzdChub2RlLmNoaWxkTm9kZXMsIGkpO1xuICAgICAgYXBwZW5kTm9kZXMoZnJhZ21lbnQsIGNoaWxkTm9kZXMuc2xpY2UoaSkpO1xuICAgICAgbm9kZS5hcHBlbmRDaGlsZChmcmFnbWVudCk7XG4gICAgfSBlbHNlIHtcbiAgICAgIGFwcGVuZE5vZGVzKGZyYWdtZW50LCBjaGlsZE5vZGVzKTtcbiAgICAgIHJlc2V0QW5kUG9wdWxhdGUobm9kZSwgZnJhZ21lbnQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGNyZWF0ZSBhIG5ldyB3aXJlIGZvciBnZW5lcmljIERPTSBjb250ZW50XG4gIGZ1bmN0aW9uIHdpcmVDb250ZW50KCkge1xuICAgIHZhciBjb250ZW50LCBmcmFnbWVudCwgcmVuZGVyLCBzZXR1cCwgdGVtcGxhdGU7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIHVwZGF0ZShzdGF0aWNzKSB7XG4gICAgICBpZiAodGVtcGxhdGUgIT09IHN0YXRpY3MpIHtcbiAgICAgICAgc2V0dXAgPSB0cnVlO1xuICAgICAgICB0ZW1wbGF0ZSA9IHN0YXRpY3M7XG4gICAgICAgIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuICAgICAgICByZW5kZXIgPSBoeXBlckhUTUwuYmluZChmcmFnbWVudCk7XG4gICAgICB9XG4gICAgICByZW5kZXIuYXBwbHkobnVsbCwgYXJndW1lbnRzKTtcbiAgICAgIGlmIChzZXR1cCkge1xuICAgICAgICBzZXR1cCA9IGZhbHNlO1xuICAgICAgICBjb250ZW50ID0gc2V0dXBBbmRHZXRDb250ZW50KGZyYWdtZW50KTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBjb250ZW50KCk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIGdldCBvciBjcmVhdGUgYSB3aXJlZCB3ZWFrIHJlZmVyZW5jZVxuICBmdW5jdGlvbiB3aXJlV2Vha2x5KG9iaikge1xuICAgIHJldHVybiB3bS5nZXQob2JqKSB8fCAoXG4gICAgICB3bS5zZXQob2JqLCB3aXJlQ29udGVudCgpKSxcbiAgICAgIHdpcmVXZWFrbHkob2JqKVxuICAgICk7XG4gIH1cblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIFRlbXBsYXRlIHNldHVwXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICAvLyBlYWNoIGtub3duIGh5cGVySFRNTCB1cGRhdGUgaXNcbiAgLy8ga2VwdCBhcyBzaW1wbGUgYXMgcG9zc2libGUuXG4gIGZ1bmN0aW9uIHVwZGF0ZSgpIHtcbiAgICBmb3IgKHZhclxuICAgICAgaSA9IDEsXG4gICAgICBsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoLFxuICAgICAgdXBkYXRlcyA9IHRoaXNbRVhQQU5ET10udTtcbiAgICAgIGkgPCBsZW5ndGg7IGkrK1xuICAgICkge1xuICAgICAgdXBkYXRlc1tpIC0gMV0oYXJndW1lbnRzW2ldKTtcbiAgICB9XG4gICAgcmV0dXJuIHRoaXM7XG4gIH1cblxuICAvLyBidXQgdGhlIGZpcnN0IHRpbWUsIGl0IG5lZWRzIHRvIGJlIHNldHVwLlxuICAvLyBGcm9tIG5vdyBvbiwgb25seSB1cGRhdGUoc3RhdGljcykgd2lsbCBiZSBjYWxsZWRcbiAgLy8gdW5sZXNzIHRoaXMgbm9kZSB3b24ndCBiZSB1c2VkIGZvciBvdGhlciByZW5kZXJpbmdzLlxuICBmdW5jdGlvbiB1cGdyYWRlKHN0YXRpY3MpIHtcbiAgICB2YXJcbiAgICAgIHVwZGF0ZXMgPSBbXSxcbiAgICAgIGh0bWwgPSBzdGF0aWNzLmpvaW4odWlkYylcbiAgICA7XG4gICAgaWYgKElFKSB7XG4gICAgICBJRUF0dHJpYnV0ZXMgPSBbXTtcbiAgICAgIGluamVjdEhUTUwodGhpcywgaHRtbC5yZXBsYWNlKG5vLCBjb21tZW50cykpO1xuICAgIH0gZWxzZSBpZiAodGhpcy5ub2RlVHlwZSA9PT0gMSkge1xuICAgICAgdGhpcy5pbm5lckhUTUwgPSBodG1sO1xuICAgIH0gZWxzZSB7XG4gICAgICBpbmplY3RIVE1MKHRoaXMsIGh0bWwpO1xuICAgIH1cbiAgICBsdWtlVHJlZVdhbGtlcih0aGlzLCB1cGRhdGVzKTtcbiAgICB0aGlzW0VYUEFORE9dID0ge3M6IHN0YXRpY3MsIHU6IHVwZGF0ZXN9O1xuICAgIHJldHVybiB1cGRhdGUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgfVxuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gdGhlIHRyYXNoIGJpblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbiAgLy8gSUUgdXNlZCB0byBzdWNrLlxuICAvKlxuICAvLyBldmVuIGluIGEgdHJ5L2NhdGNoIHRoaXMgdGhyb3cgYW4gZXJyb3JcbiAgLy8gc2luY2UgaXQncyByZWxpYWJsZSB0aG91Z2gsIEknbGwga2VlcCBpdCBhcm91bmRcbiAgZnVuY3Rpb24gaXNJRSgpIHtcbiAgICB2YXIgcCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3AnKTtcbiAgICBwLmlubmVySFRNTCA9ICc8aSBvbmNsaWNrPVwiPCEtLS0tPlwiPic7XG4gICAgcmV0dXJuIHAuY2hpbGROb2Rlc1swXS5vbmNsaWNrID09IG51bGw7XG4gIH1cbiAgLy8qL1xuXG4gIC8vIHJlbW92ZSBhbmQvb3IgYW5kIGEgbGlzdCBvZiBub2RlcyB0aHJvdWdoIGEgZnJhZ21lbnRcbiAgLyogdGVtcG9yYXJpbHkgcmVtb3ZlZCB1bnRpbCBpdCdzIGRlbW9uc3RyYXRlZCBpdCdzIG5lZWRlZFxuICBmdW5jdGlvbiB1cGRhdGVWaWFGcmFnbWVudChub2RlLCBmcmFnbWVudCwgaSkge1xuICAgIGlmICgwIDwgaSkge1xuICAgICAgcmVtb3ZlTm9kZUxpc3Qobm9kZS5jaGlsZE5vZGVzLCBpKTtcbiAgICAgIHZhciBzbGltID0gZnJhZ21lbnQuY2xvbmVOb2RlKCk7XG4gICAgICBhcHBlbmROb2RlcyhzbGltLCBzbGljZS5jYWxsKGZyYWdtZW50LmNoaWxkTm9kZXMsIGkpKTtcbiAgICAgIG5vZGUuYXBwZW5kQ2hpbGQoZnJhZ21lbnQsIHNsaW0pO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXNldEFuZFBvcHVsYXRlKG5vZGUsIGZyYWdtZW50KTtcbiAgICB9XG4gIH1cbiAgLy8qL1xuXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbiAgLy8gbG9jYWwgdmFyaWFibGVzXG4gIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuICB2YXJcbiAgICAvLyBkZWNpZGUgc3BlY2lhbCBhdHRyaWJ1dGVzIGJlaGF2aW9yXG4gICAgU1BFQ0lBTF9BVFRSSUJVVEUgPSAvXig/Om9uW2Etel0rfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjYXB0dXJlfGNoZWNrZWR8Y29udHJvbHN8ZGVmZXJyZWR8ZGlzYWJsZWR8Zm9ybW5vdmFsaWRhdGV8aGlkZGVufGxvb3B8bXVsdGlwbGV8bXV0ZWR8cmVxdWlyZWQpJC8sXG4gICAgLy8gYXZvaWRzIFdlYWtNYXAgdG8gYXZvaWQgbWVtb3J5IHByZXNzdXJlLCB1c2UgQ1NTIGNvbXBhdGlibGUgc3ludGF4IGZvciBJRVxuICAgIEVYUEFORE8gPSAnX2h5cGVyX2h0bWw6ICcsXG4gICAgLy8gdXNlIGEgcHNldWRvIHVuaXF1ZSBpZCB0byBhdm9pZCBjb25mbGljdHMgYW5kIG5vcm1hbGl6ZSBDU1Mgc3R5bGUgZm9yIElFXG4gICAgdWlkID0gRVhQQU5ETyArICgoTWF0aC5yYW5kb20oKSAqIG5ldyBEYXRlKSB8IDApICsgJzsnLFxuICAgIC8vIHVzZSBjb21tZW50IG5vZGVzIHdpdGggcHNldWRvIHVuaXF1ZSBjb250ZW50IHRvIHNldHVwXG4gICAgdWlkYyA9ICc8IS0tJyArIHVpZCArICctLT4nLFxuICAgIC8vIHRocmVhdCBpdCBkaWZmZXJlbnRseVxuICAgIElFID0gJ2RvY3VtZW50TW9kZScgaW4gZG9jdW1lbnQsXG4gICAgbm8gPSBJRSAmJiBuZXcgUmVnRXhwKCcoW15cXFxcU11bYS16XStbYS16MC05Xy1dKj0pKFtcXCdcIl0pJyArIHVpZGMgKyAnXFxcXDInLCAnZycpLFxuICAgIGNvbW1lbnRzID0gSUUgJiYgZnVuY3Rpb24gKCQwLCAkMSwgJDIpIHtcbiAgICAgIElFQXR0cmlidXRlcy5wdXNoKCQxLnNsaWNlKDEsIC0xKSk7XG4gICAgICByZXR1cm4gJDEgKyAkMiArIHVpZCArICQyO1xuICAgIH0sXG4gICAgLy8gdmVyaWZ5IGVtcHR5IHRleHRDb250ZW50IG9uIC53aXJlKCkgc2V0dXBcbiAgICB0cmltID0gRVhQQU5ETy50cmltIHx8IGZ1bmN0aW9uICgpIHtcbiAgICAgIHJldHVybiB0aGlzLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKTtcbiAgICB9LFxuICAgIC8vIGNvbnZlcnQgRE9NLmNoaWxkTm9kZXMgaW50byBhcnJheXMgdG8gYXZvaWRcbiAgICAvLyBET00gbXV0YXRpb24gYmFja2ZpcmluZyBvbiBsb29wc1xuICAgIHNsaWNlID0gW10uc2xpY2UsXG4gICAgLy8gdXNlZCBmb3Igd2VhayByZWZlcmVuY2VzXG4gICAgLy8gaWYgV2Vha01hcCBpcyBub3QgYXZhaWxhYmxlXG4gICAgLy8gaXQgdXNlcyBhIGNvbmZpZ3VyYWJsZSwgbm9uIGVudW1lcmFibGUsXG4gICAgLy8gcXVpY2sgYW5kIGRpcnR5IGV4cGFuZG8gcHJvcGVydHkuXG4gICAgd20gPSB0eXBlb2YgV2Vha01hcCA9PT0gdHlwZW9mIHdtID9cbiAgICAgIHtcbiAgICAgICAgZ2V0OiBmdW5jdGlvbiAob2JqKSB7IHJldHVybiBvYmpbRVhQQU5ET107IH0sXG4gICAgICAgIHNldDogZnVuY3Rpb24gKG9iaiwgdmFsdWUpIHtcbiAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqLCBFWFBBTkRPLCB7XG4gICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICB2YWx1ZTogdmFsdWVcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgfSA6XG4gICAgICBuZXcgV2Vha01hcCgpLFxuICAgIElFQXR0cmlidXRlc1xuICA7XG5cbiAgLy8gU2ltcGx5IHRvIGF2b2lkIGR1cGxpY2F0ZWQgUmVnRXhwIGluIHZpcGVySFRNTFxuICBoeXBlckhUTUwuU1BFQ0lBTF9BVFRSSUJVVEUgPSBTUEVDSUFMX0FUVFJJQlVURTtcblxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIC8vIOKaoe+4jyDvuI/vuI9UaGUgRW5kIOKesFxuICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gIHJldHVybiBoeXBlckhUTUw7XG5cbn0oKSk7XG5cbi8vIHVtZC5LSVNTXG50cnkgeyBtb2R1bGUuZXhwb3J0cyA9IGh5cGVySFRNTDsgfSBjYXRjaChvX08pIHt9XG4iXX0=
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})({"riot":[function(require,module,exports){
/* Riot v3.4.0, @license MIT */
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
(factory((global.riot = global.riot || {})));
}(this, (function (exports) { 'use strict';
var __TAGS_CACHE = [];
var __TAG_IMPL = {};
var GLOBAL_MIXIN = '__global_mixin';
var ATTRS_PREFIX = 'riot-';
var REF_DIRECTIVES = ['ref', 'data-ref'];
var IS_DIRECTIVE = 'data-is';
var CONDITIONAL_DIRECTIVE = 'if';
var LOOP_DIRECTIVE = 'each';
var LOOP_NO_REORDER_DIRECTIVE = 'no-reorder';
var SHOW_DIRECTIVE = 'show';
var HIDE_DIRECTIVE = 'hide';
var T_STRING = 'string';
var T_OBJECT = 'object';
var T_UNDEF = 'undefined';
var T_FUNCTION = 'function';
var XLINK_NS = 'http://www.w3.org/1999/xlink';
var XLINK_REGEX = /^xlink:(\w+)/;
var WIN = typeof window === T_UNDEF ? undefined : window;
var RE_SPECIAL_TAGS = /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?|opt(?:ion|group))$/;
var RE_SPECIAL_TAGS_NO_OPTION = /^(?:t(?:body|head|foot|[rhd])|caption|col(?:group)?)$/;
var RE_RESERVED_NAMES = /^(?:_(?:item|id|parent)|update|root|(?:un)?mount|mixin|is(?:Mounted|Loop)|tags|refs|parent|opts|trigger|o(?:n|ff|ne))$/;
var RE_HTML_ATTRS = /([-\w]+) ?= ?(?:"([^"]*)|'([^']*)|({[^}]*}))/g;
var CASE_SENSITIVE_ATTRIBUTES = { 'viewbox': 'viewBox' };
var RE_BOOL_ATTRS = /^(?:disabled|checked|readonly|required|allowfullscreen|auto(?:focus|play)|compact|controls|default|formnovalidate|hidden|ismap|itemscope|loop|multiple|muted|no(?:resize|shade|validate|wrap)?|open|reversed|seamless|selected|sortable|truespeed|typemustmatch)$/;
var IE_VERSION = (WIN && WIN.document || {}).documentMode | 0;
/**
* Check Check if the passed argument is undefined
* @param { String } value -
* @returns { Boolean } -
*/
function isBoolAttr(value) {
return RE_BOOL_ATTRS.test(value)
}
/**
* Check if passed argument is a function
* @param { * } value -
* @returns { Boolean } -
*/
function isFunction(value) {
return typeof value === T_FUNCTION
}
/**
* Check if passed argument is an object, exclude null
* NOTE: use isObject(x) && !isArray(x) to excludes arrays.
* @param { * } value -
* @returns { Boolean } -
*/
function isObject(value) {
return value && typeof value === T_OBJECT // typeof null is 'object'
}
/**
* Check if passed argument is undefined
* @param { * } value -
* @returns { Boolean } -
*/
function isUndefined(value) {
return typeof value === T_UNDEF
}
/**
* Check if passed argument is a string
* @param { * } value -
* @returns { Boolean } -
*/
function isString(value) {
return typeof value === T_STRING
}
/**
* Check if passed argument is empty. Different from falsy, because we dont consider 0 or false to be blank
* @param { * } value -
* @returns { Boolean } -
*/
function isBlank(value) {
return isUndefined(value) || value === null || value === ''
}
/**
* Check if passed argument is a kind of array
* @param { * } value -
* @returns { Boolean } -
*/
function isArray(value) {
return Array.isArray(value) || value instanceof Array
}
/**
* Check whether object's property could be overridden
* @param { Object } obj - source object
* @param { String } key - object property
* @returns { Boolean } -
*/
function isWritable(obj, key) {
var descriptor = Object.getOwnPropertyDescriptor(obj, key);
return isUndefined(obj[key]) || descriptor && descriptor.writable
}
/**
* Check if passed argument is a reserved name
* @param { String } value -
* @returns { Boolean } -
*/
function isReservedName(value) {
return RE_RESERVED_NAMES.test(value)
}
var check = Object.freeze({
isBoolAttr: isBoolAttr,
isFunction: isFunction,
isObject: isObject,
isUndefined: isUndefined,
isString: isString,
isBlank: isBlank,
isArray: isArray,
isWritable: isWritable,
isReservedName: isReservedName
});
/**
* Shorter and fast way to select multiple nodes in the DOM
* @param { String } selector - DOM selector
* @param { Object } ctx - DOM node where the targets of our search will is located
* @returns { Object } dom nodes found
*/
function $$(selector, ctx) {
return (ctx || document).querySelectorAll(selector)
}
/**
* Shorter and fast way to select a single node in the DOM
* @param { String } selector - unique dom selector
* @param { Object } ctx - DOM node where the target of our search will is located
* @returns { Object } dom node found
*/
function $(selector, ctx) {
return (ctx || document).querySelector(selector)
}
/**
* Create a document fragment
* @returns { Object } document fragment
*/
function createFrag() {
return document.createDocumentFragment()
}
/**
* Create a document text node
* @returns { Object } create a text node to use as placeholder
*/
function createDOMPlaceholder() {
return document.createTextNode('')
}
/**
* Create a generic DOM node
* @param { String } name - name of the DOM node we want to create
* @returns { Object } DOM node just created
*/
function mkEl(name) {
return document.createElement(name)
}
/**
* Set the inner html of any DOM node SVGs included
* @param { Object } container - DOM node where we'll inject new html
* @param { String } html - html to inject
*/
/* istanbul ignore next */
function setInnerHTML(container, html) {
if (!isUndefined(container.innerHTML))
{ container.innerHTML = html; }
// some browsers do not support innerHTML on the SVGs tags
else {
var doc = new DOMParser().parseFromString(html, 'application/xml');
var node = container.ownerDocument.importNode(doc.documentElement, true);
container.appendChild(node);
}
}
/**
* Toggle the visibility of any DOM node
* @param { Object } dom - DOM node we want to hide
* @param { Boolean } show - do we want to show it?
*/
function toggleVisibility(dom, show) {
dom.style.display = show ? '' : 'none';
dom['hidden'] = show ? false : true;
}
/**
* Remove any DOM attribute from a node
* @param { Object } dom - DOM node we want to update
* @param { String } name - name of the property we want to remove
*/
function remAttr(dom, name) {
dom.removeAttribute(name);
}
/**
* Convert a style object to a string
* @param { Object } style - style object we need to parse
* @returns { String } resulting css string
* @example
* styleObjectToString({ color: 'red', height: '10px'}) // => 'color: red; height: 10px'
*/
function styleObjectToString(style) {
return Object.keys(style).reduce(function (acc, prop) {
return (acc + " " + prop + ": " + (style[prop]) + ";")
}, '')
}
/**
* Get the value of any DOM attribute on a node
* @param { Object } dom - DOM node we want to parse
* @param { String } name - name of the attribute we want to get
* @returns { String | undefined } name of the node attribute whether it exists
*/
function getAttr(dom, name) {
return dom.getAttribute(name)
}
/**
* Set any DOM attribute
* @param { Object } dom - DOM node we want to update
* @param { String } name - name of the property we want to set
* @param { String } val - value of the property we want to set
*/
function setAttr(dom, name, val) {
var xlink = XLINK_REGEX.exec(name);
if (xlink && xlink[1])
{ dom.setAttributeNS(XLINK_NS, xlink[1], val); }
else
{ dom.setAttribute(name, val); }
}
/**
* Insert safely a tag to fix #1962 #1649
* @param { HTMLElement } root - children container
* @param { HTMLElement } curr - node to insert
* @param { HTMLElement } next - node that should preceed the current node inserted
*/
function safeInsert(root, curr, next) {
root.insertBefore(curr, next.parentNode && next);
}
/**
* Minimize risk: only zero or one _space_ between attr & value
* @param { String } html - html string we want to parse
* @param { Function } fn - callback function to apply on any attribute found
*/
function walkAttrs(html, fn) {
if (!html)
{ return }
var m;
while (m = RE_HTML_ATTRS.exec(html))
{ fn(m[1].toLowerCase(), m[2] || m[3] || m[4]); }
}
/**
* Walk down recursively all the children tags starting dom node
* @param { Object } dom - starting node where we will start the recursion
* @param { Function } fn - callback to transform the child node just found
* @param { Object } context - fn can optionally return an object, which is passed to children
*/
function walkNodes(dom, fn, context) {
if (dom) {
var res = fn(dom, context);
var next;
// stop the recursion
if (res === false) { return }
dom = dom.firstChild;
while (dom) {
next = dom.nextSibling;
walkNodes(dom, fn, res);
dom = next;
}
}
}
var dom = Object.freeze({
$$: $$,
$: $,
createFrag: createFrag,
createDOMPlaceholder: createDOMPlaceholder,
mkEl: mkEl,
setInnerHTML: setInnerHTML,
toggleVisibility: toggleVisibility,
remAttr: remAttr,
styleObjectToString: styleObjectToString,
getAttr: getAttr,
setAttr: setAttr,
safeInsert: safeInsert,
walkAttrs: walkAttrs,
walkNodes: walkNodes
});
var styleNode;
var cssTextProp;
var byName = {};
var remainder = [];
var needsInject = false;
// skip the following code on the server
if (WIN) {
styleNode = (function () {
// create a new style element with the correct type
var newNode = mkEl('style');
setAttr(newNode, 'type', 'text/css');
// replace any user node or insert the new one into the head
var userNode = $('style[type=riot]');
/* istanbul ignore next */
if (userNode) {
if (userNode.id) { newNode.id = userNode.id; }
userNode.parentNode.replaceChild(newNode, userNode);
}
else { document.getElementsByTagName('head')[0].appendChild(newNode); }
return newNode
})();
cssTextProp = styleNode.styleSheet;
}
/**
* Object that will be used to inject and manage the css of every tag instance
*/
var styleManager = {
styleNode: styleNode,
/**
* Save a tag style to be later injected into DOM
* @param { String } css - css string
* @param { String } name - if it's passed we will map the css to a tagname
*/
add: function add(css, name) {
if (name) { byName[name] = css; }
else { remainder.push(css); }
needsInject = true;
},
/**
* Inject all previously saved tag styles into DOM
* innerHTML seems slow: http://jsperf.com/riot-insert-style
*/
inject: function inject() {
if (!WIN || !needsInject) { return }
needsInject = false;
var style = Object.keys(byName)
.map(function(k) { return byName[k] })
.concat(remainder).join('\n');
/* istanbul ignore next */
if (cssTextProp) { cssTextProp.cssText = style; }
else { styleNode.innerHTML = style; }
}
};
/**
* The riot template engine
* @version v3.0.3
*/
/**
* riot.util.brackets
*
* - `brackets ` - Returns a string or regex based on its parameter
* - `brackets.set` - Change the current riot brackets
*
* @module
*/
/* global riot */
/* istanbul ignore next */
var brackets = (function (UNDEF) {
var
REGLOB = 'g',
R_MLCOMMS = /\/\*[^*]*\*+(?:[^*\/][^*]*\*+)*\//g,
R_STRINGS = /"[^"\\]*(?:\\[\S\s][^"\\]*)*"|'[^'\\]*(?:\\[\S\s][^'\\]*)*'|`[^`\\]*(?:\\[\S\s][^`\\]*)*`/g,
S_QBLOCKS = R_STRINGS.source + '|' +
/(?:\breturn\s+|(?:[$\w\)\]]|\+\+|--)\s*(\/)(?![*\/]))/.source + '|' +
/\/(?=[^*\/])[^[\/\\]*(?:(?:\[(?:\\.|[^\]\\]*)*\]|\\.)[^[\/\\]*)*?(\/)[gim]*/.source,
UNSUPPORTED = RegExp('[\\' + 'x00-\\x1F<>a-zA-Z0-9\'",;\\\\]'),
NEED_ESCAPE = /(?=[[\]()*+?.^$|])/g,
FINDBRACES = {
'(': RegExp('([()])|' + S_QBLOCKS, REGLOB),
'[': RegExp('([[\\]])|' + S_QBLOCKS, REGLOB),
'{': RegExp('([{}])|' + S_QBLOCKS, REGLOB)
},
DEFAULT = '{ }';
var _pairs = [
'{', '}',
'{', '}',
/{[^}]*}/,
/\\([{}])/g,
/\\({)|{/g,
RegExp('\\\\(})|([[({])|(})|' + S_QBLOCKS, REGLOB),
DEFAULT,
/^\s*{\^?\s*([$\w]+)(?:\s*,\s*(\S+))?\s+in\s+(\S.*)\s*}/,
/(^|[^\\]){=[\S\s]*?}/
];
var
cachedBrackets = UNDEF,
_regex,
_cache = [],
_settings;
function _loopback (re) { return re }
function _rewrite (re, bp) {
if (!bp) { bp = _cache; }
return new RegExp(
re.source.replace(/{/g, bp[2]).replace(/}/g, bp[3]), re.global ? REGLOB : ''
)
}
function _create (pair) {
if (pair === DEFAULT) { return _pairs }
var arr = pair.split(' ');
if (arr.length !== 2 || UNSUPPORTED.test(pair)) {
throw new Error('Unsupported brackets "' + pair + '"')
}
arr = arr.concat(pair.replace(NEED_ESCAPE, '\\').split(' '));
arr[4] = _rewrite(arr[1].length > 1 ? /{[\S\s]*?}/ : _pairs[4], arr);
arr[5] = _rewrite(pair.length > 3 ? /\\({|})/g : _pairs[5], arr);
arr[6] = _rewrite(_pairs[6], arr);
arr[7] = RegExp('\\\\(' + arr[3] + ')|([[({])|(' + arr[3] + ')|' + S_QBLOCKS, REGLOB);
arr[8] = pair;
return arr
}
function _brackets (reOrIdx) {
return reOrIdx instanceof RegExp ? _regex(reOrIdx) : _cache[reOrIdx]
}
_brackets.split = function split (str, tmpl, _bp) {
// istanbul ignore next: _bp is for the compiler
if (!_bp) { _bp = _cache; }
var
parts = [],
match,
isexpr,
start,
pos,
re = _bp[6];
isexpr = start = re.lastIndex = 0;
while ((match = re.exec(str))) {
pos = match.index;
if (isexpr) {
if (match[2]) {
re.lastIndex = skipBraces(str, match[2], re.lastIndex);
continue
}
if (!match[3]) {
continue
}
}
if (!match[1]) {
unescapeStr(str.slice(start, pos));
start = re.lastIndex;
re = _bp[6 + (isexpr ^= 1)];
re.lastIndex = start;
}
}
if (str && start < str.length) {
unescapeStr(str.slice(start));
}
return parts
function unescapeStr (s) {
if (tmpl || isexpr) {
parts.push(s && s.replace(_bp[5], '$1'));
} else {
parts.push(s);
}
}
function skipBraces (s, ch, ix) {
var
match,
recch = FINDBRACES[ch];
recch.lastIndex = ix;
ix = 1;
while ((match = recch.exec(s))) {
if (match[1] &&
!(match[1] === ch ? ++ix : --ix)) { break }
}
return ix ? s.length : recch.lastIndex
}
};
_brackets.hasExpr = function hasExpr (str) {
return _cache[4].test(str)
};
_brackets.loopKeys = function loopKeys (expr) {
var m = expr.match(_cache[9]);
return m
? { key: m[1], pos: m[2], val: _cache[0] + m[3].trim() + _cache[1] }
: { val: expr.trim() }
};
_brackets.array = function array (pair) {
return pair ? _create(pair) : _cache
};
function _reset (pair) {
if ((pair || (pair = DEFAULT)) !== _cache[8]) {
_cache = _create(pair);
_regex = pair === DEFAULT ? _loopback : _rewrite;
_cache[9] = _regex(_pairs[9]);
}
cachedBrackets = pair;
}
function _setSettings (o) {
var b;
o = o || {};
b = o.brackets;
Object.defineProperty(o, 'brackets', {
set: _reset,
get: function () { return cachedBrackets },
enumerable: true
});
_settings = o;
_reset(b);
}
Object.defineProperty(_brackets, 'settings', {
set: _setSettings,
get: function () { return _settings }
});
/* istanbul ignore next: in the browser riot is always in the scope */
_brackets.settings = typeof riot !== 'undefined' && riot.settings || {};
_brackets.set = _reset;
_brackets.R_STRINGS = R_STRINGS;
_brackets.R_MLCOMMS = R_MLCOMMS;
_brackets.S_QBLOCKS = S_QBLOCKS;
return _brackets
})();
/**
* @module tmpl
*
* tmpl - Root function, returns the template value, render with data
* tmpl.hasExpr - Test the existence of a expression inside a string
* tmpl.loopKeys - Get the keys for an 'each' loop (used by `_each`)
*/
/* istanbul ignore next */
var tmpl = (function () {
var _cache = {};
function _tmpl (str, data) {
if (!str) { return str }
return (_cache[str] || (_cache[str] = _create(str))).call(data, _logErr)
}
_tmpl.hasExpr = brackets.hasExpr;
_tmpl.loopKeys = brackets.loopKeys;
// istanbul ignore next
_tmpl.clearCache = function () { _cache = {}; };
_tmpl.errorHandler = null;
function _logErr (err, ctx) {
err.riotData = {
tagName: ctx && ctx.__ && ctx.__.tagName,
_riot_id: ctx && ctx._riot_id //eslint-disable-line camelcase
};
if (_tmpl.errorHandler) { _tmpl.errorHandler(err); }
else if (
typeof console !== 'undefined' &&
typeof console.error === 'function'
) {
if (err.riotData.tagName) {
console.error('Riot template error thrown in the <%s> tag', err.riotData.tagName);
}
console.error(err);
}
}
function _create (str) {
var expr = _getTmpl(str);
if (expr.slice(0, 11) !== 'try{return ') { expr = 'return ' + expr; }
return new Function('E', expr + ';') // eslint-disable-line no-new-func
}
var
CH_IDEXPR = String.fromCharCode(0x2057),
RE_CSNAME = /^(?:(-?[_A-Za-z\xA0-\xFF][-\w\xA0-\xFF]*)|\u2057(\d+)~):/,
RE_QBLOCK = RegExp(brackets.S_QBLOCKS, 'g'),
RE_DQUOTE = /\u2057/g,
RE_QBMARK = /\u2057(\d+)~/g;
function _getTmpl (str) {
var
qstr = [],
expr,
parts = brackets.split(str.replace(RE_DQUOTE, '"'), 1);
if (parts.length > 2 || parts[0]) {
var i, j, list = [];
for (i = j = 0; i < parts.length; ++i) {
expr = parts[i];
if (expr && (expr = i & 1
? _parseExpr(expr, 1, qstr)
: '"' + expr
.replace(/\\/g, '\\\\')
.replace(/\r\n?|\n/g, '\\n')
.replace(/"/g, '\\"') +
'"'
)) { list[j++] = expr; }
}
expr = j < 2 ? list[0]
: '[' + list.join(',') + '].join("")';
} else {
expr = _parseExpr(parts[1], 0, qstr);
}
if (qstr[0]) {
expr = expr.replace(RE_QBMARK, function (_, pos) {
return qstr[pos]
.replace(/\r/g, '\\r')
.replace(/\n/g, '\\n')
});
}
return expr
}
var
RE_BREND = {
'(': /[()]/g,
'[': /[[\]]/g,
'{': /[{}]/g
};
function _parseExpr (expr, asText, qstr) {
expr = expr
.replace(RE_QBLOCK, function (s, div) {
return s.length > 2 && !div ? CH_IDEXPR + (qstr.push(s) - 1) + '~' : s
})
.replace(/\s+/g, ' ').trim()
.replace(/\ ?([[\({},?\.:])\ ?/g, '$1');
if (expr) {
var
list = [],
cnt = 0,
match;
while (expr &&
(match = expr.match(RE_CSNAME)) &&
!match.index
) {
var
key,
jsb,
re = /,|([[{(])|$/g;
expr = RegExp.rightContext;
key = match[2] ? qstr[match[2]].slice(1, -1).trim().replace(/\s+/g, ' ') : match[1];
while (jsb = (match = re.exec(expr))[1]) { skipBraces(jsb, re); }
jsb = expr.slice(0, match.index);
expr = RegExp.rightContext;
list[cnt++] = _wrapExpr(jsb, 1, key);
}
expr = !cnt ? _wrapExpr(expr, asText)
: cnt > 1 ? '[' + list.join(',') + '].join(" ").trim()' : list[0];
}
return expr
function skipBraces (ch, re) {
var
mm,
lv = 1,
ir = RE_BREND[ch];
ir.lastIndex = re.lastIndex;
while (mm = ir.exec(expr)) {
if (mm[0] === ch) { ++lv; }
else if (!--lv) { break }
}
re.lastIndex = lv ? expr.length : ir.lastIndex;
}
}
// istanbul ignore next: not both
var // eslint-disable-next-line max-len
JS_CONTEXT = '"in this?this:' + (typeof window !== 'object' ? 'global' : 'window') + ').',
JS_VARNAME = /[,{][\$\w]+(?=:)|(^ *|[^$\w\.{])(?!(?:typeof|true|false|null|undefined|in|instanceof|is(?:Finite|NaN)|void|NaN|new|Date|RegExp|Math)(?![$\w]))([$_A-Za-z][$\w]*)/g,
JS_NOPROPS = /^(?=(\.[$\w]+))\1(?:[^.[(]|$)/;
function _wrapExpr (expr, asText, key) {
var tb;
expr = expr.replace(JS_VARNAME, function (match, p, mvar, pos, s) {
if (mvar) {
pos = tb ? 0 : pos + match.length;
if (mvar !== 'this' && mvar !== 'global' && mvar !== 'window') {
match = p + '("' + mvar + JS_CONTEXT + mvar;
if (pos) { tb = (s = s[pos]) === '.' || s === '(' || s === '['; }
} else if (pos) {
tb = !JS_NOPROPS.test(s.slice(pos));
}
}
return match
});
if (tb) {
expr = 'try{return ' + expr + '}catch(e){E(e,this)}';
}
if (key) {
expr = (tb
? 'function(){' + expr + '}.call(this)' : '(' + expr + ')'
) + '?"' + key + '":""';
} else if (asText) {
expr = 'function(v){' + (tb
? expr.replace('return ', 'v=') : 'v=(' + expr + ')'
) + ';return v||v===0?v:""}.call(this)';
}
return expr
}
_tmpl.version = brackets.version = 'v3.0.3';
return _tmpl
})();
/* istanbul ignore next */
var observable$1 = function(el) {
/**
* Extend the original object or create a new empty one
* @type { Object }
*/
el = el || {};
/**
* Private variables
*/
var callbacks = {},
slice = Array.prototype.slice;
/**
* Public Api
*/
// extend the el object adding the observable methods
Object.defineProperties(el, {
/**
* Listen to the given `event` ands
* execute the `callback` each time an event is triggered.
* @param { String } event - event id
* @param { Function } fn - callback function
* @returns { Object } el
*/
on: {
value: function(event, fn) {
if (typeof fn == 'function')
{ (callbacks[event] = callbacks[event] || []).push(fn); }
return el
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Removes the given `event` listeners
* @param { String } event - event id
* @param { Function } fn - callback function
* @returns { Object } el
*/
off: {
value: function(event, fn) {
if (event == '*' && !fn) { callbacks = {}; }
else {
if (fn) {
var arr = callbacks[event];
for (var i = 0, cb; cb = arr && arr[i]; ++i) {
if (cb == fn) { arr.splice(i--, 1); }
}
} else { delete callbacks[event]; }
}
return el
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Listen to the given `event` and
* execute the `callback` at most once
* @param { String } event - event id
* @param { Function } fn - callback function
* @returns { Object } el
*/
one: {
value: function(event, fn) {
function on() {
el.off(event, on);
fn.apply(el, arguments);
}
return el.on(event, on)
},
enumerable: false,
writable: false,
configurable: false
},
/**
* Execute all callback functions that listen to
* the given `event`
* @param { String } event - event id
* @returns { Object } el
*/
trigger: {
value: function(event) {
var arguments$1 = arguments;
// getting the arguments
var arglen = arguments.length - 1,
args = new Array(arglen),
fns,
fn,
i;
for (i = 0; i < arglen; i++) {
args[i] = arguments$1[i + 1]; // skip first argument
}
fns = slice.call(callbacks[event] || [], 0);
for (i = 0; fn = fns[i]; ++i) {
fn.apply(el, args);
}
if (callbacks['*'] && event != '*')
{ el.trigger.apply(el, ['*', event].concat(args)); }
return el
},
enumerable: false,
writable: false,
configurable: false
}
});
return el
};
/**
* Specialized function for looping an array-like collection with `each={}`
* @param { Array } list - collection of items
* @param {Function} fn - callback function
* @returns { Array } the array looped
*/
function each(list, fn) {
var len = list ? list.length : 0;
var i = 0;
for (; i < len; ++i) {
fn(list[i], i);
}
return list
}
/**
* Check whether an array contains an item
* @param { Array } array - target array
* @param { * } item - item to test
* @returns { Boolean } -
*/
function contains(array, item) {
return array.indexOf(item) !== -1
}
/**
* Convert a string containing dashes to camel case
* @param { String } str - input string
* @returns { String } my-string -> myString
*/
function toCamel(str) {
return str.replace(/-(\w)/g, function (_, c) { return c.toUpperCase(); })
}
/**
* Faster String startsWith alternative
* @param { String } str - source string
* @param { String } value - test string
* @returns { Boolean } -
*/
function startsWith(str, value) {
return str.slice(0, value.length) === value
}
/**
* Helper function to set an immutable property
* @param { Object } el - object where the new property will be set
* @param { String } key - object key where the new property will be stored
* @param { * } value - value of the new property
* @param { Object } options - set the propery overriding the default options
* @returns { Object } - the initial object
*/
function defineProperty(el, key, value, options) {
Object.defineProperty(el, key, extend({
value: value,
enumerable: false,
writable: false,
configurable: true
}, options));
return el
}
/**
* Extend any object with other properties
* @param { Object } src - source object
* @returns { Object } the resulting extended object
*
* var obj = { foo: 'baz' }
* extend(obj, {bar: 'bar', foo: 'bar'})
* console.log(obj) => {bar: 'bar', foo: 'bar'}
*
*/
function extend(src) {
var obj, args = arguments;
for (var i = 1; i < args.length; ++i) {
if (obj = args[i]) {
for (var key in obj) {
// check if this property of the source object could be overridden
if (isWritable(src, key))
{ src[key] = obj[key]; }
}
}
}
return src
}
var misc = Object.freeze({
each: each,
contains: contains,
toCamel: toCamel,
startsWith: startsWith,
defineProperty: defineProperty,
extend: extend
});
var settings$1 = extend(Object.create(brackets.settings), {
skipAnonymousTags: true
});
var EVENTS_PREFIX_REGEX = /^on/;
/**
* Trigger DOM events
* @param { HTMLElement } dom - dom element target of the event
* @param { Function } handler - user function
* @param { Object } e - event object
*/
function handleEvent(dom, handler, e) {
var ptag = this.__.parent,
item = this.__.item;
if (!item)
{ while (ptag && !item) {
item = ptag.__.item;
ptag = ptag.__.parent;
} }
// override the event properties
/* istanbul ignore next */
if (isWritable(e, 'currentTarget')) { e.currentTarget = dom; }
/* istanbul ignore next */
if (isWritable(e, 'target')) { e.target = e.srcElement; }
/* istanbul ignore next */
if (isWritable(e, 'which')) { e.which = e.charCode || e.keyCode; }
e.item = item;
handler.call(this, e);
if (!e.preventUpdate) {
var p = getImmediateCustomParentTag(this);
// fixes #2083
if (p.isMounted) { p.update(); }
}
}
/**
* Attach an event to a DOM node
* @param { String } name - event name
* @param { Function } handler - event callback
* @param { Object } dom - dom node
* @param { Tag } tag - tag instance
*/
function setEventHandler(name, handler, dom, tag) {
var eventName,
cb = handleEvent.bind(tag, dom, handler);
// avoid to bind twice the same event
dom[name] = null;
// normalize event name
eventName = name.replace(EVENTS_PREFIX_REGEX, '');
// cache the callback directly on the DOM node
if (!dom._riotEvents) { dom._riotEvents = {}; }
if (dom._riotEvents[name])
{ dom.removeEventListener(eventName, dom._riotEvents[name]); }
dom._riotEvents[name] = cb;
dom.addEventListener(eventName, cb, false);
}
/**
* Update dynamically created data-is tags with changing expressions
* @param { Object } expr - expression tag and expression info
* @param { Tag } parent - parent for tag creation
* @param { String } tagName - tag implementation we want to use
*/
function updateDataIs(expr, parent, tagName) {
var conf, isVirtual, head, ref;
if (expr.tag && expr.tagName === tagName) {
expr.tag.update();
return
}
isVirtual = expr.dom.tagName === 'VIRTUAL';
// sync _parent to accommodate changing tagnames
if (expr.tag) {
// need placeholder before unmount
if(isVirtual) {
head = expr.tag.__.head;
ref = createDOMPlaceholder();
head.parentNode.insertBefore(ref, head);
}
expr.tag.unmount(true);
}
expr.impl = __TAG_IMPL[tagName];
conf = {root: expr.dom, parent: parent, hasImpl: true, tagName: tagName};
expr.tag = initChildTag(expr.impl, conf, expr.dom.innerHTML, parent);
each(expr.attrs, function (a) { return setAttr(expr.tag.root, a.name, a.value); });
expr.tagName = tagName;
expr.tag.mount();
if (isVirtual)
{ makeReplaceVirtual(expr.tag, ref || expr.tag.root); } // root exist first time, after use placeholder
// parent is the placeholder tag, not the dynamic tag so clean up
parent.__.onUnmount = function() {
var delName = expr.tag.opts.dataIs,
tags = expr.tag.parent.tags,
_tags = expr.tag.__.parent.tags;
arrayishRemove(tags, delName, expr.tag);
arrayishRemove(_tags, delName, expr.tag);
expr.tag.unmount();
};
}
/**
* Nomalize any attribute removing the "riot-" prefix
* @param { String } attrName - original attribute name
* @returns { String } valid html attribute name
*/
function normalizeAttrName(attrName) {
if (!attrName) { return null }
attrName = attrName.replace(ATTRS_PREFIX, '');
if (CASE_SENSITIVE_ATTRIBUTES[attrName]) { attrName = CASE_SENSITIVE_ATTRIBUTES[attrName]; }
return attrName
}
/**
* Update on single tag expression
* @this Tag
* @param { Object } expr - expression logic
* @returns { undefined }
*/
function updateExpression(expr) {
if (this.root && getAttr(this.root,'virtualized')) { return }
var dom = expr.dom,
// remove the riot- prefix
attrName = normalizeAttrName(expr.attr),
isToggle = contains([SHOW_DIRECTIVE, HIDE_DIRECTIVE], attrName),
isVirtual = expr.root && expr.root.tagName === 'VIRTUAL',
parent = dom && (expr.parent || dom.parentNode),
// detect the style attributes
isStyleAttr = attrName === 'style',
isClassAttr = attrName === 'class',
isObj,
value;
// if it's a tag we could totally skip the rest
if (expr._riot_id) {
if (expr.isMounted) {
expr.update();
// if it hasn't been mounted yet, do that now.
} else {
expr.mount();
if (isVirtual) {
makeReplaceVirtual(expr, expr.root);
}
}
return
}
// if this expression has the update method it means it can handle the DOM changes by itself
if (expr.update) { return expr.update() }
// ...it seems to be a simple expression so we try to calculat its value
value = tmpl(expr.expr, this);
isObj = isObject(value);
// convert the style/class objects to strings
if (isObj) {
isObj = !isClassAttr && !isStyleAttr;
if (isClassAttr) {
value = tmpl(JSON.stringify(value), this);
} else if (isStyleAttr) {
value = styleObjectToString(value);
}
}
// for the boolean attributes we don't need the value
// we can convert it to checked=true to checked=checked
if (expr.bool) { value = value ? attrName : false; }
if (expr.isRtag) { return updateDataIs(expr, this, value) }
if (expr.wasParsedOnce && expr.value === value) { return }
// update the expression value
expr.value = value;
expr.wasParsedOnce = true;
// if the value is an object we can not do much more with it
if (isObj) { return }
// textarea and text nodes have no attribute name
if (!attrName) {
// about #815 w/o replace: the browser converts the value to a string,
// the comparison by "==" does too, but not in the server
value += '';
// test for parent avoids error with invalid assignment to nodeValue
if (parent) {
// cache the parent node because somehow it will become null on IE
// on the next iteration
expr.parent = parent;
if (parent.tagName === 'TEXTAREA') {
parent.value = value; // #1113
if (!IE_VERSION) { dom.nodeValue = value; } // #1625 IE throws here, nodeValue
} // will be available on 'updated'
else { dom.nodeValue = value; }
}
return
}
// remove original attribute
if (!expr.isAttrRemoved || !value) {
remAttr(dom, expr.attr);
expr.isAttrRemoved = true;
}
// event handler
if (isFunction(value)) {
setEventHandler(attrName, value, dom, this);
// show / hide
} else if (isToggle) {
toggleVisibility(dom, attrName === HIDE_DIRECTIVE ? !value : value);
// handle attributes
} else {
if (expr.bool) {
dom[attrName] = value;
}
if (attrName === 'value' && dom.value !== value) {
dom.value = value;
}
if (!isBlank(value) && value !== false) {
setAttr(dom, attrName, value);
}
// make sure that in case of style changes
// the element stays hidden
if (isStyleAttr && dom.hidden) { toggleVisibility(dom, false); }
}
}
/**
* Update all the expressions in a Tag instance
* @this Tag
* @param { Array } expressions - expression that must be re evaluated
*/
function updateAllExpressions(expressions) {
each(expressions, updateExpression.bind(this));
}
var IfExpr = {
init: function init(dom, tag, expr) {
remAttr(dom, CONDITIONAL_DIRECTIVE);
this.tag = tag;
this.expr = expr;
this.stub = document.createTextNode('');
this.pristine = dom;
var p = dom.parentNode;
p.insertBefore(this.stub, dom);
p.removeChild(dom);
return this
},
update: function update() {
this.value = tmpl(this.expr, this.tag);
if (this.value && !this.current) { // insert
this.current = this.pristine.cloneNode(true);
this.stub.parentNode.insertBefore(this.current, this.stub);
this.expressions = [];
parseExpressions.apply(this.tag, [this.current, this.expressions, true]);
} else if (!this.value && this.current) { // remove
unmountAll(this.expressions);
if (this.current._tag) {
this.current._tag.unmount();
} else if (this.current.parentNode)
{ this.current.parentNode.removeChild(this.current); }
this.current = null;
this.expressions = [];
}
if (this.value) { updateAllExpressions.call(this.tag, this.expressions); }
},
unmount: function unmount() {
unmountAll(this.expressions || []);
delete this.pristine;
delete this.parentNode;
delete this.stub;
}
};
var RefExpr = {
init: function init(dom, parent, attrName, attrValue) {
this.dom = dom;
this.attr = attrName;
this.rawValue = attrValue;
this.parent = parent;
this.hasExp = tmpl.hasExpr(attrValue);
return this
},
update: function update() {
var old = this.value;
var customParent = this.parent && getImmediateCustomParentTag(this.parent);
// if the referenced element is a custom tag, then we set the tag itself, rather than DOM
var tagOrDom = this.tag || this.dom;
this.value = this.hasExp ? tmpl(this.rawValue, this.parent) : this.rawValue;
// the name changed, so we need to remove it from the old key (if present)
if (!isBlank(old) && customParent) { arrayishRemove(customParent.refs, old, tagOrDom); }
if (isBlank(this.value)) {
// if the value is blank, we remove it
remAttr(this.dom, this.attr);
} else {
// add it to the refs of parent tag (this behavior was changed >=3.0)
if (customParent) { arrayishAdd(
customParent.refs,
this.value,
tagOrDom,
// use an array if it's a looped node and the ref is not an expression
null,
this.parent.__.index
); }
// set the actual DOM attr
setAttr(this.dom, this.attr, this.value);
}
},
unmount: function unmount() {
var tagOrDom = this.tag || this.dom;
var customParent = this.parent && getImmediateCustomParentTag(this.parent);
if (!isBlank(this.value) && customParent)
{ arrayishRemove(customParent.refs, this.value, tagOrDom); }
delete this.dom;
delete this.parent;
}
};
/**
* Convert the item looped into an object used to extend the child tag properties
* @param { Object } expr - object containing the keys used to extend the children tags
* @param { * } key - value to assign to the new object returned
* @param { * } val - value containing the position of the item in the array
* @param { Object } base - prototype object for the new item
* @returns { Object } - new object containing the values of the original item
*
* The variables 'key' and 'val' are arbitrary.
* They depend on the collection type looped (Array, Object)
* and on the expression used on the each tag
*
*/
function mkitem(expr, key, val, base) {
var item = base ? Object.create(base) : {};
item[expr.key] = key;
if (expr.pos) { item[expr.pos] = val; }
return item
}
/**
* Unmount the redundant tags
* @param { Array } items - array containing the current items to loop
* @param { Array } tags - array containing all the children tags
*/
function unmountRedundant(items, tags) {
var i = tags.length,
j = items.length;
while (i > j) {
i--;
remove.apply(tags[i], [tags, i]);
}
}
/**
* Remove a child tag
* @this Tag
* @param { Array } tags - tags collection
* @param { Number } i - index of the tag to remove
*/
function remove(tags, i) {
tags.splice(i, 1);
this.unmount();
arrayishRemove(this.parent, this, this.__.tagName, true);
}
/**
* Move the nested custom tags in non custom loop tags
* @this Tag
* @param { Number } i - current position of the loop tag
*/
function moveNestedTags(i) {
var this$1 = this;
each(Object.keys(this.tags), function (tagName) {
moveChildTag.apply(this$1.tags[tagName], [tagName, i]);
});
}
/**
* Move a child tag
* @this Tag
* @param { HTMLElement } root - dom node containing all the loop children
* @param { Tag } nextTag - instance of the next tag preceding the one we want to move
* @param { Boolean } isVirtual - is it a virtual tag?
*/
function move(root, nextTag, isVirtual) {
if (isVirtual)
{ moveVirtual.apply(this, [root, nextTag]); }
else
{ safeInsert(root, this.root, nextTag.root); }
}
/**
* Insert and mount a child tag
* @this Tag
* @param { HTMLElement } root - dom node containing all the loop children
* @param { Tag } nextTag - instance of the next tag preceding the one we want to insert
* @param { Boolean } isVirtual - is it a virtual tag?
*/
function insert(root, nextTag, isVirtual) {
if (isVirtual)
{ makeVirtual.apply(this, [root, nextTag]); }
else
{ safeInsert(root, this.root, nextTag.root); }
}
/**
* Append a new tag into the DOM
* @this Tag
* @param { HTMLElement } root - dom node containing all the loop children
* @param { Boolean } isVirtual - is it a virtual tag?
*/
function append(root, isVirtual) {
if (isVirtual)
{ makeVirtual.call(this, root); }
else
{ root.appendChild(this.root); }
}
/**
* Manage tags having the 'each'
* @param { HTMLElement } dom - DOM node we need to loop
* @param { Tag } parent - parent tag instance where the dom node is contained
* @param { String } expr - string contained in the 'each' attribute
* @returns { Object } expression object for this each loop
*/
function _each(dom, parent, expr) {
// remove the each property from the original tag
remAttr(dom, LOOP_DIRECTIVE);
var mustReorder = typeof getAttr(dom, LOOP_NO_REORDER_DIRECTIVE) !== T_STRING || remAttr(dom, LOOP_NO_REORDER_DIRECTIVE),
tagName = getTagName(dom),
impl = __TAG_IMPL[tagName],
parentNode = dom.parentNode,
placeholder = createDOMPlaceholder(),
child = getTag(dom),
ifExpr = getAttr(dom, CONDITIONAL_DIRECTIVE),
tags = [],
oldItems = [],
hasKeys,
isLoop = true,
isAnonymous = !__TAG_IMPL[tagName],
isVirtual = dom.tagName === 'VIRTUAL';
// parse the each expression
expr = tmpl.loopKeys(expr);
expr.isLoop = true;
if (ifExpr) { remAttr(dom, CONDITIONAL_DIRECTIVE); }
// insert a marked where the loop tags will be injected
parentNode.insertBefore(placeholder, dom);
parentNode.removeChild(dom);
expr.update = function updateEach() {
// get the new items collection
expr.value = tmpl(expr.val, parent);
var frag = createFrag(),
items = expr.value,
isObject$$1 = !isArray(items) && !isString(items),
root = placeholder.parentNode;
// object loop. any changes cause full redraw
if (isObject$$1) {
hasKeys = items || false;
items = hasKeys ?
Object.keys(items).map(function (key) {
return mkitem(expr, items[key], key)
}) : [];
} else {
hasKeys = false;
}
if (ifExpr) {
items = items.filter(function(item, i) {
if (expr.key && !isObject$$1)
{ return !!tmpl(ifExpr, mkitem(expr, item, i, parent)) }
return !!tmpl(ifExpr, extend(Object.create(parent), item))
});
}
// loop all the new items
each(items, function(item, i) {
// reorder only if the items are objects
var
doReorder = mustReorder && typeof item === T_OBJECT && !hasKeys,
oldPos = oldItems.indexOf(item),
isNew = oldPos === -1,
pos = !isNew && doReorder ? oldPos : i,
// does a tag exist in this position?
tag = tags[pos],
mustAppend = i >= oldItems.length,
mustCreate = doReorder && isNew || !doReorder && !tag;
item = !hasKeys && expr.key ? mkitem(expr, item, i) : item;
// new tag
if (mustCreate) {
tag = new Tag$1(impl, {
parent: parent,
isLoop: isLoop,
isAnonymous: isAnonymous,
tagName: tagName,
root: dom.cloneNode(isAnonymous),
item: item,
index: i,
}, dom.innerHTML);
// mount the tag
tag.mount();
if (mustAppend)
{ append.apply(tag, [frag || root, isVirtual]); }
else
{ insert.apply(tag, [root, tags[i], isVirtual]); }
if (!mustAppend) { oldItems.splice(i, 0, item); }
tags.splice(i, 0, tag);
if (child) { arrayishAdd(parent.tags, tagName, tag, true); }
} else if (pos !== i && doReorder) {
// move
if (contains(items, oldItems[pos])) {
move.apply(tag, [root, tags[i], isVirtual]);
// move the old tag instance
tags.splice(i, 0, tags.splice(pos, 1)[0]);
// move the old item
oldItems.splice(i, 0, oldItems.splice(pos, 1)[0]);
}
// update the position attribute if it exists
if (expr.pos) { tag[expr.pos] = i; }
// if the loop tags are not custom
// we need to move all their custom tags into the right position
if (!child && tag.tags) { moveNestedTags.call(tag, i); }
}
// cache the original item to use it in the events bound to this node
// and its children
tag.__.item = item;
tag.__.index = i;
tag.__.parent = parent;
if (!mustCreate) { tag.update(item); }
});
// remove the redundant tags
unmountRedundant(items, tags);
// clone the items array
oldItems = items.slice();
root.insertBefore(frag, placeholder);
};
expr.unmount = function() {
each(tags, function(t) { t.unmount(); });
};
return expr
}
/**
* Walk the tag DOM to detect the expressions to evaluate
* @this Tag
* @param { HTMLElement } root - root tag where we will start digging the expressions
* @param { Array } expressions - empty array where the expressions will be added
* @param { Boolean } mustIncludeRoot - flag to decide whether the root must be parsed as well
* @returns { Object } an object containing the root noode and the dom tree
*/
function parseExpressions(root, expressions, mustIncludeRoot) {
var this$1 = this;
var tree = {parent: {children: expressions}};
walkNodes(root, function (dom, ctx) {
var type = dom.nodeType, parent = ctx.parent, attr, expr, tagImpl;
if (!mustIncludeRoot && dom === root) { return {parent: parent} }
// text node
if (type === 3 && dom.parentNode.tagName !== 'STYLE' && tmpl.hasExpr(dom.nodeValue))
{ parent.children.push({dom: dom, expr: dom.nodeValue}); }
if (type !== 1) { return ctx } // not an element
var isVirtual = dom.tagName === 'VIRTUAL';
// loop. each does it's own thing (for now)
if (attr = getAttr(dom, LOOP_DIRECTIVE)) {
if(isVirtual) { setAttr(dom, 'loopVirtual', true); } // ignore here, handled in _each
parent.children.push(_each(dom, this$1, attr));
return false
}
// if-attrs become the new parent. Any following expressions (either on the current
// element, or below it) become children of this expression.
if (attr = getAttr(dom, CONDITIONAL_DIRECTIVE)) {
parent.children.push(Object.create(IfExpr).init(dom, this$1, attr));
return false
}
if (expr = getAttr(dom, IS_DIRECTIVE)) {
if (tmpl.hasExpr(expr)) {
parent.children.push({isRtag: true, expr: expr, dom: dom, attrs: [].slice.call(dom.attributes)});
return false
}
}
// if this is a tag, stop traversing here.
// we ignore the root, since parseExpressions is called while we're mounting that root
tagImpl = getTag(dom);
if(isVirtual) {
if(getAttr(dom, 'virtualized')) {dom.parentElement.removeChild(dom); } // tag created, remove from dom
if(!tagImpl && !getAttr(dom, 'virtualized') && !getAttr(dom, 'loopVirtual')) // ok to create virtual tag
{ tagImpl = { tmpl: dom.outerHTML }; }
}
if (tagImpl && (dom !== root || mustIncludeRoot)) {
if(isVirtual && !getAttr(dom, IS_DIRECTIVE)) { // handled in update
// can not remove attribute like directives
// so flag for removal after creation to prevent maximum stack error
setAttr(dom, 'virtualized', true);
var tag = new Tag$1({ tmpl: dom.outerHTML },
{root: dom, parent: this$1},
dom.innerHTML);
parent.children.push(tag); // no return, anonymous tag, keep parsing
} else {
var conf = {root: dom, parent: this$1, hasImpl: true};
parent.children.push(initChildTag(tagImpl, conf, dom.innerHTML, this$1));
return false
}
}
// attribute expressions
parseAttributes.apply(this$1, [dom, dom.attributes, function(attr, expr) {
if (!expr) { return }
parent.children.push(expr);
}]);
// whatever the parent is, all child elements get the same parent.
// If this element had an if-attr, that's the parent for all child elements
return {parent: parent}
}, tree);
return { tree: tree, root: root }
}
/**
* Calls `fn` for every attribute on an element. If that attr has an expression,
* it is also passed to fn.
* @this Tag
* @param { HTMLElement } dom - dom node to parse
* @param { Array } attrs - array of attributes
* @param { Function } fn - callback to exec on any iteration
*/
function parseAttributes(dom, attrs, fn) {
var this$1 = this;
each(attrs, function (attr) {
var name = attr.name, bool = isBoolAttr(name), expr;
if (contains(REF_DIRECTIVES, name)) {
expr = Object.create(RefExpr).init(dom, this$1, name, attr.value);
} else if (tmpl.hasExpr(attr.value)) {
expr = {dom: dom, expr: attr.value, attr: name, bool: bool};
}
fn(attr, expr);
});
}
/*
Includes hacks needed for the Internet Explorer version 9 and below
See: http://kangax.github.io/compat-table/es5/#ie8
http://codeplanet.io/dropping-ie8/
*/
var reHasYield = /<yield\b/i;
var reYieldAll = /<yield\s*(?:\/>|>([\S\s]*?)<\/yield\s*>|>)/ig;
var reYieldSrc = /<yield\s+to=['"]([^'">]*)['"]\s*>([\S\s]*?)<\/yield\s*>/ig;
var reYieldDest = /<yield\s+from=['"]?([-\w]+)['"]?\s*(?:\/>|>([\S\s]*?)<\/yield\s*>)/ig;
var rootEls = { tr: 'tbody', th: 'tr', td: 'tr', col: 'colgroup' };
var tblTags = IE_VERSION && IE_VERSION < 10 ? RE_SPECIAL_TAGS : RE_SPECIAL_TAGS_NO_OPTION;
var GENERIC = 'div';
/*
Creates the root element for table or select child elements:
tr/th/td/thead/tfoot/tbody/caption/col/colgroup/option/optgroup
*/
function specialTags(el, tmpl, tagName) {
var
select = tagName[0] === 'o',
parent = select ? 'select>' : 'table>';
// trim() is important here, this ensures we don't have artifacts,
// so we can check if we have only one element inside the parent
el.innerHTML = '<' + parent + tmpl.trim() + '</' + parent;
parent = el.firstChild;
// returns the immediate parent if tr/th/td/col is the only element, if not
// returns the whole tree, as this can include additional elements
/* istanbul ignore next */
if (select) {
parent.selectedIndex = -1; // for IE9, compatible w/current riot behavior
} else {
// avoids insertion of cointainer inside container (ex: tbody inside tbody)
var tname = rootEls[tagName];
if (tname && parent.childElementCount === 1) { parent = $(tname, parent); }
}
return parent
}
/*
Replace the yield tag from any tag template with the innerHTML of the
original tag in the page
*/
function replaceYield(tmpl, html) {
// do nothing if no yield
if (!reHasYield.test(tmpl)) { return tmpl }
// be careful with #1343 - string on the source having `$1`
var src = {};
html = html && html.replace(reYieldSrc, function (_, ref, text) {
src[ref] = src[ref] || text; // preserve first definition
return ''
}).trim();
return tmpl
.replace(reYieldDest, function (_, ref, def) { // yield with from - to attrs
return src[ref] || def || ''
})
.replace(reYieldAll, function (_, def) { // yield without any "from"
return html || def || ''
})
}
/**
* Creates a DOM element to wrap the given content. Normally an `DIV`, but can be
* also a `TABLE`, `SELECT`, `TBODY`, `TR`, or `COLGROUP` element.
*
* @param { String } tmpl - The template coming from the custom tag definition
* @param { String } html - HTML content that comes from the DOM element where you
* will mount the tag, mostly the original tag in the page
* @returns { HTMLElement } DOM element with _tmpl_ merged through `YIELD` with the _html_.
*/
function mkdom(tmpl, html) {
var match = tmpl && tmpl.match(/^\s*<([-\w]+)/),
tagName = match && match[1].toLowerCase(),
el = mkEl(GENERIC);
// replace all the yield tags with the tag inner html
tmpl = replaceYield(tmpl, html);
/* istanbul ignore next */
if (tblTags.test(tagName))
{ el = specialTags(el, tmpl, tagName); }
else
{ setInnerHTML(el, tmpl); }
return el
}
/**
* Another way to create a riot tag a bit more es6 friendly
* @param { HTMLElement } el - tag DOM selector or DOM node/s
* @param { Object } opts - tag logic
* @returns { Tag } new riot tag instance
*/
function Tag$2(el, opts) {
// get the tag properties from the class constructor
var ref = this;
var name = ref.name;
var tmpl = ref.tmpl;
var css = ref.css;
var attrs = ref.attrs;
var onCreate = ref.onCreate;
// register a new tag and cache the class prototype
if (!__TAG_IMPL[name]) {
tag$1(name, tmpl, css, attrs, onCreate);
// cache the class constructor
__TAG_IMPL[name].class = this.constructor;
}
// mount the tag using the class instance
mountTo(el, name, opts, this);
// inject the component css
if (css) { styleManager.inject(); }
return this
}
/**
* Create a new riot tag implementation
* @param { String } name - name/id of the new riot tag
* @param { String } tmpl - tag template
* @param { String } css - custom tag css
* @param { String } attrs - root tag attributes
* @param { Function } fn - user function
* @returns { String } name/id of the tag just created
*/
function tag$1(name, tmpl, css, attrs, fn) {
if (isFunction(attrs)) {
fn = attrs;
if (/^[\w\-]+\s?=/.test(css)) {
attrs = css;
css = '';
} else
{ attrs = ''; }
}
if (css) {
if (isFunction(css))
{ fn = css; }
else
{ styleManager.add(css); }
}
name = name.toLowerCase();
__TAG_IMPL[name] = { name: name, tmpl: tmpl, attrs: attrs, fn: fn };
return name
}
/**
* Create a new riot tag implementation (for use by the compiler)
* @param { String } name - name/id of the new riot tag
* @param { String } tmpl - tag template
* @param { String } css - custom tag css
* @param { String } attrs - root tag attributes
* @param { Function } fn - user function
* @returns { String } name/id of the tag just created
*/
function tag2$1(name, tmpl, css, attrs, fn) {
if (css) { styleManager.add(css, name); }
__TAG_IMPL[name] = { name: name, tmpl: tmpl, attrs: attrs, fn: fn };
return name
}
/**
* Mount a tag using a specific tag implementation
* @param { * } selector - tag DOM selector or DOM node/s
* @param { String } tagName - tag implementation name
* @param { Object } opts - tag logic
* @returns { Array } new tags instances
*/
function mount$1(selector, tagName, opts) {
var tags = [];
function pushTagsTo(root) {
if (root.tagName) {
var riotTag = getAttr(root, IS_DIRECTIVE);
// have tagName? force riot-tag to be the same
if (tagName && riotTag !== tagName) {
riotTag = tagName;
setAttr(root, IS_DIRECTIVE, tagName);
}
var tag = mountTo(root, riotTag || root.tagName.toLowerCase(), opts);
if (tag)
{ tags.push(tag); }
} else if (root.length)
{ each(root, pushTagsTo); } // assume nodeList
}
// inject styles into DOM
styleManager.inject();
if (isObject(tagName)) {
opts = tagName;
tagName = 0;
}
var elem;
var allTags;
// crawl the DOM to find the tag
if (isString(selector)) {
selector = selector === '*' ?
// select all registered tags
// & tags found with the riot-tag attribute set
allTags = selectTags() :
// or just the ones named like the selector
selector + selectTags(selector.split(/, */));
// make sure to pass always a selector
// to the querySelectorAll function
elem = selector ? $$(selector) : [];
}
else
// probably you have passed already a tag or a NodeList
{ elem = selector; }
// select all the registered and mount them inside their root elements
if (tagName === '*') {
// get all custom tags
tagName = allTags || selectTags();
// if the root els it's just a single tag
if (elem.tagName)
{ elem = $$(tagName, elem); }
else {
// select all the children for all the different root elements
var nodeList = [];
each(elem, function (_el) { return nodeList.push($$(tagName, _el)); });
elem = nodeList;
}
// get rid of the tagName
tagName = 0;
}
pushTagsTo(elem);
return tags
}
// Create a mixin that could be globally shared across all the tags
var mixins = {};
var globals = mixins[GLOBAL_MIXIN] = {};
var mixins_id = 0;
/**
* Create/Return a mixin by its name
* @param { String } name - mixin name (global mixin if object)
* @param { Object } mix - mixin logic
* @param { Boolean } g - is global?
* @returns { Object } the mixin logic
*/
function mixin$1(name, mix, g) {
// Unnamed global
if (isObject(name)) {
mixin$1(("__unnamed_" + (mixins_id++)), name, true);
return
}
var store = g ? globals : mixins;
// Getter
if (!mix) {
if (isUndefined(store[name]))
{ throw new Error('Unregistered mixin: ' + name) }
return store[name]
}
// Setter
store[name] = isFunction(mix) ?
extend(mix.prototype, store[name] || {}) && mix :
extend(store[name] || {}, mix);
}
/**
* Update all the tags instances created
* @returns { Array } all the tags instances
*/
function update$1() {
return each(__TAGS_CACHE, function (tag) { return tag.update(); })
}
function unregister$1(name) {
delete __TAG_IMPL[name];
}
var version$1 = 'v3.4.0';
var core = Object.freeze({
Tag: Tag$2,
tag: tag$1,
tag2: tag2$1,
mount: mount$1,
mixin: mixin$1,
update: update$1,
unregister: unregister$1,
version: version$1
});
// counter to give a unique id to all the Tag instances
var __uid = 0;
/**
* We need to update opts for this tag. That requires updating the expressions
* in any attributes on the tag, and then copying the result onto opts.
* @this Tag
* @param {Boolean} isLoop - is it a loop tag?
* @param { Tag } parent - parent tag node
* @param { Boolean } isAnonymous - is it a tag without any impl? (a tag not registered)
* @param { Object } opts - tag options
* @param { Array } instAttrs - tag attributes array
*/
function updateOpts(isLoop, parent, isAnonymous, opts, instAttrs) {
// isAnonymous `each` tags treat `dom` and `root` differently. In this case
// (and only this case) we don't need to do updateOpts, because the regular parse
// will update those attrs. Plus, isAnonymous tags don't need opts anyway
if (isLoop && isAnonymous) { return }
var ctx = !isAnonymous && isLoop ? this : parent || this;
each(instAttrs, function (attr) {
if (attr.expr) { updateAllExpressions.call(ctx, [attr.expr]); }
// normalize the attribute names
opts[toCamel(attr.name).replace(ATTRS_PREFIX, '')] = attr.expr ? attr.expr.value : attr.value;
});
}
/**
* Tag class
* @constructor
* @param { Object } impl - it contains the tag template, and logic
* @param { Object } conf - tag options
* @param { String } innerHTML - html that eventually we need to inject in the tag
*/
function Tag$1(impl, conf, innerHTML) {
if ( impl === void 0 ) impl = {};
if ( conf === void 0 ) conf = {};
var opts = extend({}, conf.opts),
parent = conf.parent,
isLoop = conf.isLoop,
isAnonymous = !!conf.isAnonymous,
skipAnonymous = settings$1.skipAnonymousTags && isAnonymous,
item = cleanUpData(conf.item),
index = conf.index, // available only for the looped nodes
instAttrs = [], // All attributes on the Tag when it's first parsed
implAttrs = [], // expressions on this type of Tag
expressions = [],
root = conf.root,
tagName = conf.tagName || getTagName(root),
isVirtual = tagName === 'virtual',
propsInSyncWithParent = [],
dom;
// make this tag observable
if (!skipAnonymous) { observable$1(this); }
// only call unmount if we have a valid __TAG_IMPL (has name property)
if (impl.name && root._tag) { root._tag.unmount(true); }
// not yet mounted
this.isMounted = false;
defineProperty(this, '__', {
isAnonymous: isAnonymous,
instAttrs: instAttrs,
innerHTML: innerHTML,
tagName: tagName,
index: index,
isLoop: isLoop,
// these vars will be needed only for the virtual tags
virts: [],
tail: null,
head: null,
parent: null,
item: null
});
// create a unique id to this tag
// it could be handy to use it also to improve the virtual dom rendering speed
defineProperty(this, '_riot_id', ++__uid); // base 1 allows test !t._riot_id
defineProperty(this, 'root', root);
extend(this, { opts: opts }, item);
// protect the "tags" and "refs" property from being overridden
defineProperty(this, 'parent', parent || null);
defineProperty(this, 'tags', {});
defineProperty(this, 'refs', {});
dom = isLoop && isAnonymous ? root : mkdom(impl.tmpl, innerHTML, isLoop);
/**
* Update the tag expressions and options
* @param { * } data - data we want to use to extend the tag properties
* @returns { Tag } the current tag instance
*/
defineProperty(this, 'update', function tagUpdate(data) {
var nextOpts = {},
canTrigger = this.isMounted && !skipAnonymous;
// make sure the data passed will not override
// the component core methods
data = cleanUpData(data);
extend(this, data);
updateOpts.apply(this, [isLoop, parent, isAnonymous, nextOpts, instAttrs]);
if (canTrigger && this.isMounted && isFunction(this.shouldUpdate) && !this.shouldUpdate(data, nextOpts)) {
return this
}
// inherit properties from the parent, but only for isAnonymous tags
if (isLoop && isAnonymous) { inheritFrom.apply(this, [this.parent, propsInSyncWithParent]); }
extend(opts, nextOpts);
if (canTrigger) { this.trigger('update', data); }
updateAllExpressions.call(this, expressions);
if (canTrigger) { this.trigger('updated'); }
return this
}.bind(this));
/**
* Add a mixin to this tag
* @returns { Tag } the current tag instance
*/
defineProperty(this, 'mixin', function tagMixin() {
var this$1 = this;
each(arguments, function (mix) {
var instance, obj;
var props = [];
// properties blacklisted and will not be bound to the tag instance
var propsBlacklist = ['init', '__proto__'];
mix = isString(mix) ? mixin$1(mix) : mix;
// check if the mixin is a function
if (isFunction(mix)) {
// create the new mixin instance
instance = new mix();
} else { instance = mix; }
var proto = Object.getPrototypeOf(instance);
// build multilevel prototype inheritance chain property list
do { props = props.concat(Object.getOwnPropertyNames(obj || instance)); }
while (obj = Object.getPrototypeOf(obj || instance))
// loop the keys in the function prototype or the all object keys
each(props, function (key) {
// bind methods to this
// allow mixins to override other properties/parent mixins
if (!contains(propsBlacklist, key)) {
// check for getters/setters
var descriptor = Object.getOwnPropertyDescriptor(instance, key) || Object.getOwnPropertyDescriptor(proto, key);
var hasGetterSetter = descriptor && (descriptor.get || descriptor.set);
// apply method only if it does not already exist on the instance
if (!this$1.hasOwnProperty(key) && hasGetterSetter) {
Object.defineProperty(this$1, key, descriptor);
} else {
this$1[key] = isFunction(instance[key]) ?
instance[key].bind(this$1) :
instance[key];
}
}
});
// init method will be called automatically
if (instance.init)
{ instance.init.bind(this$1)(); }
});
return this
}.bind(this));
/**
* Mount the current tag instance
* @returns { Tag } the current tag instance
*/
defineProperty(this, 'mount', function tagMount() {
var this$1 = this;
root._tag = this; // keep a reference to the tag just created
// Read all the attrs on this instance. This give us the info we need for updateOpts
parseAttributes.apply(parent, [root, root.attributes, function (attr, expr) {
if (!isAnonymous && RefExpr.isPrototypeOf(expr)) { expr.tag = this$1; }
attr.expr = expr;
instAttrs.push(attr);
}]);
// update the root adding custom attributes coming from the compiler
implAttrs = [];
walkAttrs(impl.attrs, function (k, v) { implAttrs.push({name: k, value: v}); });
parseAttributes.apply(this, [root, implAttrs, function (attr, expr) {
if (expr) { expressions.push(expr); }
else { setAttr(root, attr.name, attr.value); }
}]);
// initialiation
updateOpts.apply(this, [isLoop, parent, isAnonymous, opts, instAttrs]);
// add global mixins
var globalMixin = mixin$1(GLOBAL_MIXIN);
if (globalMixin && !skipAnonymous) {
for (var i in globalMixin) {
if (globalMixin.hasOwnProperty(i)) {
this$1.mixin(globalMixin[i]);
}
}
}
if (impl.fn) { impl.fn.call(this, opts); }
if (!skipAnonymous) { this.trigger('before-mount'); }
// parse layout after init. fn may calculate args for nested custom tags
parseExpressions.apply(this, [dom, expressions, isAnonymous]);
this.update(item);
if (!isAnonymous) {
while (dom.firstChild) { root.appendChild(dom.firstChild); }
}
defineProperty(this, 'root', root);
defineProperty(this, 'isMounted', true);
if (skipAnonymous) { return }
// if it's not a child tag we can trigger its mount event
if (!this.parent) {
this.trigger('mount');
}
// otherwise we need to wait that the parent "mount" or "updated" event gets triggered
else {
var p = getImmediateCustomParentTag(this.parent);
p.one(!p.isMounted ? 'mount' : 'updated', function () {
this$1.trigger('mount');
});
}
return this
}.bind(this));
/**
* Unmount the tag instance
* @param { Boolean } mustKeepRoot - if it's true the root node will not be removed
* @returns { Tag } the current tag instance
*/
defineProperty(this, 'unmount', function tagUnmount(mustKeepRoot) {
var this$1 = this;
var el = this.root,
p = el.parentNode,
ptag,
tagIndex = __TAGS_CACHE.indexOf(this);
if (!skipAnonymous) { this.trigger('before-unmount'); }
// clear all attributes coming from the mounted tag
walkAttrs(impl.attrs, function (name) {
if (startsWith(name, ATTRS_PREFIX))
{ name = name.slice(ATTRS_PREFIX.length); }
remAttr(root, name);
});
// remove this tag instance from the global virtualDom variable
if (tagIndex !== -1)
{ __TAGS_CACHE.splice(tagIndex, 1); }
if (p || isVirtual) {
if (parent) {
ptag = getImmediateCustomParentTag(parent);
if (isVirtual) {
Object.keys(this.tags).forEach(function (tagName) {
arrayishRemove(ptag.tags, tagName, this$1.tags[tagName]);
});
} else {
arrayishRemove(ptag.tags, tagName, this);
if(parent !== ptag) // remove from _parent too
{ arrayishRemove(parent.tags, tagName, this); }
}
} else {
while (el.firstChild) { el.removeChild(el.firstChild); }
}
if (p)
{ if (!mustKeepRoot) {
p.removeChild(el);
} else {
// the riot-tag and the data-is attributes aren't needed anymore, remove them
remAttr(p, IS_DIRECTIVE);
} }
}
if (this.__.virts) {
each(this.__.virts, function (v) {
if (v.parentNode) { v.parentNode.removeChild(v); }
});
}
// allow expressions to unmount themselves
unmountAll(expressions);
each(instAttrs, function (a) { return a.expr && a.expr.unmount && a.expr.unmount(); });
// custom internal unmount function to avoid relying on the observable
if (this.__.onUnmount) { this.__.onUnmount(); }
if (!skipAnonymous) {
this.trigger('unmount');
this.off('*');
}
defineProperty(this, 'isMounted', false);
delete this.root._tag;
return this
}.bind(this));
}
/**
* Detect the tag implementation by a DOM node
* @param { Object } dom - DOM node we need to parse to get its tag implementation
* @returns { Object } it returns an object containing the implementation of a custom tag (template and boot function)
*/
function getTag(dom) {
return dom.tagName && __TAG_IMPL[getAttr(dom, IS_DIRECTIVE) ||
getAttr(dom, IS_DIRECTIVE) || dom.tagName.toLowerCase()]
}
/**
* Inherit properties from a target tag instance
* @this Tag
* @param { Tag } target - tag where we will inherit properties
* @param { Array } propsInSyncWithParent - array of properties to sync with the target
*/
function inheritFrom(target, propsInSyncWithParent) {
var this$1 = this;
each(Object.keys(target), function (k) {
// some properties must be always in sync with the parent tag
var mustSync = !isReservedName(k) && contains(propsInSyncWithParent, k);
if (isUndefined(this$1[k]) || mustSync) {
// track the property to keep in sync
// so we can keep it updated
if (!mustSync) { propsInSyncWithParent.push(k); }
this$1[k] = target[k];
}
});
}
/**
* Move the position of a custom tag in its parent tag
* @this Tag
* @param { String } tagName - key where the tag was stored
* @param { Number } newPos - index where the new tag will be stored
*/
function moveChildTag(tagName, newPos) {
var parent = this.parent,
tags;
// no parent no move
if (!parent) { return }
tags = parent.tags[tagName];
if (isArray(tags))
{ tags.splice(newPos, 0, tags.splice(tags.indexOf(this), 1)[0]); }
else { arrayishAdd(parent.tags, tagName, this); }
}
/**
* Create a new child tag including it correctly into its parent
* @param { Object } child - child tag implementation
* @param { Object } opts - tag options containing the DOM node where the tag will be mounted
* @param { String } innerHTML - inner html of the child node
* @param { Object } parent - instance of the parent tag including the child custom tag
* @returns { Object } instance of the new child tag just created
*/
function initChildTag(child, opts, innerHTML, parent) {
var tag = new Tag$1(child, opts, innerHTML),
tagName = opts.tagName || getTagName(opts.root, true),
ptag = getImmediateCustomParentTag(parent);
// fix for the parent attribute in the looped elements
defineProperty(tag, 'parent', ptag);
// store the real parent tag
// in some cases this could be different from the custom parent tag
// for example in nested loops
tag.__.parent = parent;
// add this tag to the custom parent tag
arrayishAdd(ptag.tags, tagName, tag);
// and also to the real parent tag
if (ptag !== parent)
{ arrayishAdd(parent.tags, tagName, tag); }
// empty the child node once we got its template
// to avoid that its children get compiled multiple times
opts.root.innerHTML = '';
return tag
}
/**
* Loop backward all the parents tree to detect the first custom parent tag
* @param { Object } tag - a Tag instance
* @returns { Object } the instance of the first custom parent tag found
*/
function getImmediateCustomParentTag(tag) {
var ptag = tag;
while (ptag.__.isAnonymous) {
if (!ptag.parent) { break }
ptag = ptag.parent;
}
return ptag
}
/**
* Trigger the unmount method on all the expressions
* @param { Array } expressions - DOM expressions
*/
function unmountAll(expressions) {
each(expressions, function(expr) {
if (expr instanceof Tag$1) { expr.unmount(true); }
else if (expr.unmount) { expr.unmount(); }
});
}
/**
* Get the tag name of any DOM node
* @param { Object } dom - DOM node we want to parse
* @param { Boolean } skipDataIs - hack to ignore the data-is attribute when attaching to parent
* @returns { String } name to identify this dom node in riot
*/
function getTagName(dom, skipDataIs) {
var child = getTag(dom),
namedTag = !skipDataIs && getAttr(dom, IS_DIRECTIVE);
return namedTag && !tmpl.hasExpr(namedTag) ?
namedTag :
child ? child.name : dom.tagName.toLowerCase()
}
/**
* With this function we avoid that the internal Tag methods get overridden
* @param { Object } data - options we want to use to extend the tag instance
* @returns { Object } clean object without containing the riot internal reserved words
*/
function cleanUpData(data) {
if (!(data instanceof Tag$1) && !(data && isFunction(data.trigger)))
{ return data }
var o = {};
for (var key in data) {
if (!RE_RESERVED_NAMES.test(key)) { o[key] = data[key]; }
}
return o
}
/**
* Set the property of an object for a given key. If something already
* exists there, then it becomes an array containing both the old and new value.
* @param { Object } obj - object on which to set the property
* @param { String } key - property name
* @param { Object } value - the value of the property to be set
* @param { Boolean } ensureArray - ensure that the property remains an array
* @param { Number } index - add the new item in a certain array position
*/
function arrayishAdd(obj, key, value, ensureArray, index) {
var dest = obj[key];
var isArr = isArray(dest);
var hasIndex = !isUndefined(index);
if (dest && dest === value) { return }
// if the key was never set, set it once
if (!dest && ensureArray) { obj[key] = [value]; }
else if (!dest) { obj[key] = value; }
// if it was an array and not yet set
else {
if (isArr) {
var oldIndex = dest.indexOf(value);
// this item never changed its position
if (oldIndex === index) { return }
// remove the item from its old position
if (oldIndex !== -1) { dest.splice(oldIndex, 1); }
// move or add the item
if (hasIndex) {
dest.splice(index, 0, value);
} else {
dest.push(value);
}
} else { obj[key] = [dest, value]; }
}
}
/**
* Removes an item from an object at a given key. If the key points to an array,
* then the item is just removed from the array.
* @param { Object } obj - object on which to remove the property
* @param { String } key - property name
* @param { Object } value - the value of the property to be removed
* @param { Boolean } ensureArray - ensure that the property remains an array
*/
function arrayishRemove(obj, key, value, ensureArray) {
if (isArray(obj[key])) {
var index = obj[key].indexOf(value);
if (index !== -1) { obj[key].splice(index, 1); }
if (!obj[key].length) { delete obj[key]; }
else if (obj[key].length === 1 && !ensureArray) { obj[key] = obj[key][0]; }
} else
{ delete obj[key]; } // otherwise just delete the key
}
/**
* Mount a tag creating new Tag instance
* @param { Object } root - dom node where the tag will be mounted
* @param { String } tagName - name of the riot tag we want to mount
* @param { Object } opts - options to pass to the Tag instance
* @param { Object } ctx - optional context that will be used to extend an existing class ( used in riot.Tag )
* @returns { Tag } a new Tag instance
*/
function mountTo(root, tagName, opts, ctx) {
var impl = __TAG_IMPL[tagName],
implClass = __TAG_IMPL[tagName].class,
tag = ctx || (implClass ? Object.create(implClass.prototype) : {}),
// cache the inner HTML to fix #855
innerHTML = root._innerHTML = root._innerHTML || root.innerHTML;
// clear the inner html
root.innerHTML = '';
var conf = extend({ root: root, opts: opts }, { parent: opts ? opts.parent : null });
if (impl && root) { Tag$1.apply(tag, [impl, conf, innerHTML]); }
if (tag && tag.mount) {
tag.mount(true);
// add this tag to the virtualDom variable
if (!contains(__TAGS_CACHE, tag)) { __TAGS_CACHE.push(tag); }
}
return tag
}
/**
* makes a tag virtual and replaces a reference in the dom
* @this Tag
* @param { tag } the tag to make virtual
* @param { ref } the dom reference location
*/
function makeReplaceVirtual(tag, ref) {
var frag = createFrag();
makeVirtual.call(tag, frag);
ref.parentNode.replaceChild(frag, ref);
}
/**
* Adds the elements for a virtual tag
* @this Tag
* @param { Node } src - the node that will do the inserting or appending
* @param { Tag } target - only if inserting, insert before this tag's first child
*/
function makeVirtual(src, target) {
var this$1 = this;
var head = createDOMPlaceholder(),
tail = createDOMPlaceholder(),
frag = createFrag(),
sib, el;
this.root.insertBefore(head, this.root.firstChild);
this.root.appendChild(tail);
this.__.head = el = head;
this.__.tail = tail;
while (el) {
sib = el.nextSibling;
frag.appendChild(el);
this$1.__.virts.push(el); // hold for unmounting
el = sib;
}
if (target)
{ src.insertBefore(frag, target.__.head); }
else
{ src.appendChild(frag); }
}
/**
* Move virtual tag and all child nodes
* @this Tag
* @param { Node } src - the node that will do the inserting
* @param { Tag } target - insert before this tag's first child
*/
function moveVirtual(src, target) {
var this$1 = this;
var el = this.__.head,
frag = createFrag(),
sib;
while (el) {
sib = el.nextSibling;
frag.appendChild(el);
el = sib;
if (el === this$1.__.tail) {
frag.appendChild(el);
src.insertBefore(frag, target.__.head);
break
}
}
}
/**
* Get selectors for tags
* @param { Array } tags - tag names to select
* @returns { String } selector
*/
function selectTags(tags) {
// select all tags
if (!tags) {
var keys = Object.keys(__TAG_IMPL);
return keys + selectTags(keys)
}
return tags
.filter(function (t) { return !/[^-\w]/.test(t); })
.reduce(function (list, t) {
var name = t.trim().toLowerCase();
return list + ",[" + IS_DIRECTIVE + "=\"" + name + "\"]"
}, '')
}
var tags = Object.freeze({
getTag: getTag,
inheritFrom: inheritFrom,
moveChildTag: moveChildTag,
initChildTag: initChildTag,
getImmediateCustomParentTag: getImmediateCustomParentTag,
unmountAll: unmountAll,
getTagName: getTagName,
cleanUpData: cleanUpData,
arrayishAdd: arrayishAdd,
arrayishRemove: arrayishRemove,
mountTo: mountTo,
makeReplaceVirtual: makeReplaceVirtual,
makeVirtual: makeVirtual,
moveVirtual: moveVirtual,
selectTags: selectTags
});
/**
* Riot public api
*/
var settings = settings$1;
var util = {
tmpl: tmpl,
brackets: brackets,
styleManager: styleManager,
vdom: __TAGS_CACHE,
styleNode: styleManager.styleNode,
// export the riot internal utils as well
dom: dom,
check: check,
misc: misc,
tags: tags
};
// export the core props/methods
var Tag$$1 = Tag$2;
var tag$$1 = tag$1;
var tag2$$1 = tag2$1;
var mount$$1 = mount$1;
var mixin$$1 = mixin$1;
var update$$1 = update$1;
var unregister$$1 = unregister$1;
var version$$1 = version$1;
var observable = observable$1;
var riot$1 = extend({}, core, {
observable: observable$1,
settings: settings,
util: util,
});
exports.settings = settings;
exports.util = util;
exports.Tag = Tag$$1;
exports.tag = tag$$1;
exports.tag2 = tag2$$1;
exports.mount = mount$$1;
exports.mixin = mixin$$1;
exports.update = update$$1;
exports.unregister = unregister$$1;
exports.version = version$$1;
exports.observable = observable;
exports['default'] = riot$1;
Object.defineProperty(exports, '__esModule', { value: true });
})));
},{}]},{},[])
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsInJpb3QiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKiBSaW90IHYzLjQuMCwgQGxpY2Vuc2UgTUlUICovXG4oZnVuY3Rpb24gKGdsb2JhbCwgZmFjdG9yeSkge1xuXHR0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgPyBmYWN0b3J5KGV4cG9ydHMpIDpcblx0dHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kID8gZGVmaW5lKFsnZXhwb3J0cyddLCBmYWN0b3J5KSA6XG5cdChmYWN0b3J5KChnbG9iYWwucmlvdCA9IGdsb2JhbC5yaW90IHx8IHt9KSkpO1xufSh0aGlzLCAoZnVuY3Rpb24gKGV4cG9ydHMpIHsgJ3VzZSBzdHJpY3QnO1xuXG52YXIgX19UQUdTX0NBQ0hFID0gW107XG52YXIgX19UQUdfSU1QTCA9IHt9O1xudmFyIEdMT0JBTF9NSVhJTiA9ICdfX2dsb2JhbF9taXhpbic7XG52YXIgQVRUUlNfUFJFRklYID0gJ3Jpb3QtJztcbnZhciBSRUZfRElSRUNUSVZFUyA9IFsncmVmJywgJ2RhdGEtcmVmJ107XG52YXIgSVNfRElSRUNUSVZFID0gJ2RhdGEtaXMnO1xudmFyIENPTkRJVElPTkFMX0RJUkVDVElWRSA9ICdpZic7XG52YXIgTE9PUF9ESVJFQ1RJVkUgPSAnZWFjaCc7XG52YXIgTE9PUF9OT19SRU9SREVSX0RJUkVDVElWRSA9ICduby1yZW9yZGVyJztcbnZhciBTSE9XX0RJUkVDVElWRSA9ICdzaG93JztcbnZhciBISURFX0RJUkVDVElWRSA9ICdoaWRlJztcbnZhciBUX1NUUklORyA9ICdzdHJpbmcnO1xudmFyIFRfT0JKRUNUID0gJ29iamVjdCc7XG52YXIgVF9VTkRFRiAgPSAndW5kZWZpbmVkJztcbnZhciBUX0ZVTkNUSU9OID0gJ2Z1bmN0aW9uJztcbnZhciBYTElOS19OUyA9ICdodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rJztcbnZhciBYTElOS19SRUdFWCA9IC9eeGxpbms6KFxcdyspLztcbnZhciBXSU4gPSB0eXBlb2Ygd2luZG93ID09PSBUX1VOREVGID8gdW5kZWZpbmVkIDogd2luZG93O1xudmFyIFJFX1NQRUNJQUxfVEFHUyA9IC9eKD86dCg/OmJvZHl8aGVhZHxmb290fFtyaGRdKXxjYXB0aW9ufGNvbCg/Omdyb3VwKT98b3B0KD86aW9ufGdyb3VwKSkkLztcbnZhciBSRV9TUEVDSUFMX1RBR1NfTk9fT1BUSU9OID0gL14oPzp0KD86Ym9keXxoZWFkfGZvb3R8W3JoZF0pfGNhcHRpb258Y29sKD86Z3JvdXApPykkLztcbnZhciBSRV9SRVNFUlZFRF9OQU1FUyA9IC9eKD86Xyg/Oml0ZW18aWR8cGFyZW50KXx1cGRhdGV8cm9vdHwoPzp1bik/bW91bnR8bWl4aW58aXMoPzpNb3VudGVkfExvb3ApfHRhZ3N8cmVmc3xwYXJlbnR8b3B0c3x0cmlnZ2VyfG8oPzpufGZmfG5lKSkkLztcbnZhciBSRV9IVE1MX0FUVFJTID0gLyhbLVxcd10rKSA/PSA/KD86XCIoW15cIl0qKXwnKFteJ10qKXwoe1tefV0qfSkpL2c7XG52YXIgQ0FTRV9TRU5TSVRJVkVfQVRUUklCVVRFUyA9IHsgJ3ZpZXdib3gnOiAndmlld0JveCcgfTtcbnZhciBSRV9CT09MX0FUVFJTID0gL14oPzpkaXNhYmxlZHxjaGVja2VkfHJlYWRvbmx5fHJlcXVpcmVkfGFsbG93ZnVsbHNjcmVlbnxhdXRvKD86Zm9jdXN8cGxheSl8Y29tcGFjdHxjb250cm9sc3xkZWZhdWx0fGZvcm1ub3ZhbGlkYXRlfGhpZGRlbnxpc21hcHxpdGVtc2NvcGV8bG9vcHxtdWx0aXBsZXxtdXRlZHxubyg/OnJlc2l6ZXxzaGFkZXx2YWxpZGF0ZXx3cmFwKT98b3BlbnxyZXZlcnNlZHxzZWFtbGVzc3xzZWxlY3RlZHxzb3J0YWJsZXx0cnVlc3BlZWR8dHlwZW11c3RtYXRjaCkkLztcbnZhciBJRV9WRVJTSU9OID0gKFdJTiAmJiBXSU4uZG9jdW1lbnQgfHwge30pLmRvY3VtZW50TW9kZSB8IDA7XG5cbi8qKlxuICogQ2hlY2sgQ2hlY2sgaWYgdGhlIHBhc3NlZCBhcmd1bWVudCBpcyB1bmRlZmluZWRcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc0Jvb2xBdHRyKHZhbHVlKSB7XG4gIHJldHVybiBSRV9CT09MX0FUVFJTLnRlc3QodmFsdWUpXG59XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFzc2VkIGFyZ3VtZW50IGlzIGEgZnVuY3Rpb25cbiAqIEBwYXJhbSAgIHsgKiB9IHZhbHVlIC1cbiAqIEByZXR1cm5zIHsgQm9vbGVhbiB9IC1cbiAqL1xuZnVuY3Rpb24gaXNGdW5jdGlvbih2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBUX0ZVTkNUSU9OXG59XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFzc2VkIGFyZ3VtZW50IGlzIGFuIG9iamVjdCwgZXhjbHVkZSBudWxsXG4gKiBOT1RFOiB1c2UgaXNPYmplY3QoeCkgJiYgIWlzQXJyYXkoeCkgdG8gZXhjbHVkZXMgYXJyYXlzLlxuICogQHBhcmFtICAgeyAqIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc09iamVjdCh2YWx1ZSkge1xuICByZXR1cm4gdmFsdWUgJiYgdHlwZW9mIHZhbHVlID09PSBUX09CSkVDVCAvLyB0eXBlb2YgbnVsbCBpcyAnb2JqZWN0J1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhc3NlZCBhcmd1bWVudCBpcyB1bmRlZmluZWRcbiAqIEBwYXJhbSAgIHsgKiB9IHZhbHVlIC1cbiAqIEByZXR1cm5zIHsgQm9vbGVhbiB9IC1cbiAqL1xuZnVuY3Rpb24gaXNVbmRlZmluZWQodmFsdWUpIHtcbiAgcmV0dXJuIHR5cGVvZiB2YWx1ZSA9PT0gVF9VTkRFRlxufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhc3NlZCBhcmd1bWVudCBpcyBhIHN0cmluZ1xuICogQHBhcmFtICAgeyAqIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc1N0cmluZyh2YWx1ZSkge1xuICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBUX1NUUklOR1xufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhc3NlZCBhcmd1bWVudCBpcyBlbXB0eS4gRGlmZmVyZW50IGZyb20gZmFsc3ksIGJlY2F1c2Ugd2UgZG9udCBjb25zaWRlciAwIG9yIGZhbHNlIHRvIGJlIGJsYW5rXG4gKiBAcGFyYW0geyAqIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc0JsYW5rKHZhbHVlKSB7XG4gIHJldHVybiBpc1VuZGVmaW5lZCh2YWx1ZSkgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09ICcnXG59XG5cbi8qKlxuICogQ2hlY2sgaWYgcGFzc2VkIGFyZ3VtZW50IGlzIGEga2luZCBvZiBhcnJheVxuICogQHBhcmFtICAgeyAqIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc0FycmF5KHZhbHVlKSB7XG4gIHJldHVybiBBcnJheS5pc0FycmF5KHZhbHVlKSB8fCB2YWx1ZSBpbnN0YW5jZW9mIEFycmF5XG59XG5cbi8qKlxuICogQ2hlY2sgd2hldGhlciBvYmplY3QncyBwcm9wZXJ0eSBjb3VsZCBiZSBvdmVycmlkZGVuXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9ICBvYmogLSBzb3VyY2Ugb2JqZWN0XG4gKiBAcGFyYW0gICB7IFN0cmluZyB9ICBrZXkgLSBvYmplY3QgcHJvcGVydHlcbiAqIEByZXR1cm5zIHsgQm9vbGVhbiB9IC1cbiAqL1xuZnVuY3Rpb24gaXNXcml0YWJsZShvYmosIGtleSkge1xuICB2YXIgZGVzY3JpcHRvciA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iob2JqLCBrZXkpO1xuICByZXR1cm4gaXNVbmRlZmluZWQob2JqW2tleV0pIHx8IGRlc2NyaXB0b3IgJiYgZGVzY3JpcHRvci53cml0YWJsZVxufVxuXG4vKipcbiAqIENoZWNrIGlmIHBhc3NlZCBhcmd1bWVudCBpcyBhIHJlc2VydmVkIG5hbWVcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gdmFsdWUgLVxuICogQHJldHVybnMgeyBCb29sZWFuIH0gLVxuICovXG5mdW5jdGlvbiBpc1Jlc2VydmVkTmFtZSh2YWx1ZSkge1xuICByZXR1cm4gUkVfUkVTRVJWRURfTkFNRVMudGVzdCh2YWx1ZSlcbn1cblxudmFyIGNoZWNrID0gT2JqZWN0LmZyZWV6ZSh7XG5cdGlzQm9vbEF0dHI6IGlzQm9vbEF0dHIsXG5cdGlzRnVuY3Rpb246IGlzRnVuY3Rpb24sXG5cdGlzT2JqZWN0OiBpc09iamVjdCxcblx0aXNVbmRlZmluZWQ6IGlzVW5kZWZpbmVkLFxuXHRpc1N0cmluZzogaXNTdHJpbmcsXG5cdGlzQmxhbms6IGlzQmxhbmssXG5cdGlzQXJyYXk6IGlzQXJyYXksXG5cdGlzV3JpdGFibGU6IGlzV3JpdGFibGUsXG5cdGlzUmVzZXJ2ZWROYW1lOiBpc1Jlc2VydmVkTmFtZVxufSk7XG5cbi8qKlxuICogU2hvcnRlciBhbmQgZmFzdCB3YXkgdG8gc2VsZWN0IG11bHRpcGxlIG5vZGVzIGluIHRoZSBET01cbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gc2VsZWN0b3IgLSBET00gc2VsZWN0b3JcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gY3R4IC0gRE9NIG5vZGUgd2hlcmUgdGhlIHRhcmdldHMgb2Ygb3VyIHNlYXJjaCB3aWxsIGlzIGxvY2F0ZWRcbiAqIEByZXR1cm5zIHsgT2JqZWN0IH0gZG9tIG5vZGVzIGZvdW5kXG4gKi9cbmZ1bmN0aW9uICQkKHNlbGVjdG9yLCBjdHgpIHtcbiAgcmV0dXJuIChjdHggfHwgZG9jdW1lbnQpLnF1ZXJ5U2VsZWN0b3JBbGwoc2VsZWN0b3IpXG59XG5cbi8qKlxuICogU2hvcnRlciBhbmQgZmFzdCB3YXkgdG8gc2VsZWN0IGEgc2luZ2xlIG5vZGUgaW4gdGhlIERPTVxuICogQHBhcmFtICAgeyBTdHJpbmcgfSBzZWxlY3RvciAtIHVuaXF1ZSBkb20gc2VsZWN0b3JcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gY3R4IC0gRE9NIG5vZGUgd2hlcmUgdGhlIHRhcmdldCBvZiBvdXIgc2VhcmNoIHdpbGwgaXMgbG9jYXRlZFxuICogQHJldHVybnMgeyBPYmplY3QgfSBkb20gbm9kZSBmb3VuZFxuICovXG5mdW5jdGlvbiAkKHNlbGVjdG9yLCBjdHgpIHtcbiAgcmV0dXJuIChjdHggfHwgZG9jdW1lbnQpLnF1ZXJ5U2VsZWN0b3Ioc2VsZWN0b3IpXG59XG5cbi8qKlxuICogQ3JlYXRlIGEgZG9jdW1lbnQgZnJhZ21lbnRcbiAqIEByZXR1cm5zIHsgT2JqZWN0IH0gZG9jdW1lbnQgZnJhZ21lbnRcbiAqL1xuZnVuY3Rpb24gY3JlYXRlRnJhZygpIHtcbiAgcmV0dXJuIGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKVxufVxuXG4vKipcbiAqIENyZWF0ZSBhIGRvY3VtZW50IHRleHQgbm9kZVxuICogQHJldHVybnMgeyBPYmplY3QgfSBjcmVhdGUgYSB0ZXh0IG5vZGUgdG8gdXNlIGFzIHBsYWNlaG9sZGVyXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZURPTVBsYWNlaG9sZGVyKCkge1xuICByZXR1cm4gZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUoJycpXG59XG5cbi8qKlxuICogQ3JlYXRlIGEgZ2VuZXJpYyBET00gbm9kZVxuICogQHBhcmFtICAgeyBTdHJpbmcgfSBuYW1lIC0gbmFtZSBvZiB0aGUgRE9NIG5vZGUgd2Ugd2FudCB0byBjcmVhdGVcbiAqIEByZXR1cm5zIHsgT2JqZWN0IH0gRE9NIG5vZGUganVzdCBjcmVhdGVkXG4gKi9cbmZ1bmN0aW9uIG1rRWwobmFtZSkge1xuICByZXR1cm4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChuYW1lKVxufVxuXG4vKipcbiAqIFNldCB0aGUgaW5uZXIgaHRtbCBvZiBhbnkgRE9NIG5vZGUgU1ZHcyBpbmNsdWRlZFxuICogQHBhcmFtIHsgT2JqZWN0IH0gY29udGFpbmVyIC0gRE9NIG5vZGUgd2hlcmUgd2UnbGwgaW5qZWN0IG5ldyBodG1sXG4gKiBAcGFyYW0geyBTdHJpbmcgfSBodG1sIC0gaHRtbCB0byBpbmplY3RcbiAqL1xuLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbmZ1bmN0aW9uIHNldElubmVySFRNTChjb250YWluZXIsIGh0bWwpIHtcbiAgaWYgKCFpc1VuZGVmaW5lZChjb250YWluZXIuaW5uZXJIVE1MKSlcbiAgICB7IGNvbnRhaW5lci5pbm5lckhUTUwgPSBodG1sOyB9XG4gICAgLy8gc29tZSBicm93c2VycyBkbyBub3Qgc3VwcG9ydCBpbm5lckhUTUwgb24gdGhlIFNWR3MgdGFnc1xuICBlbHNlIHtcbiAgICB2YXIgZG9jID0gbmV3IERPTVBhcnNlcigpLnBhcnNlRnJvbVN0cmluZyhodG1sLCAnYXBwbGljYXRpb24veG1sJyk7XG4gICAgdmFyIG5vZGUgPSBjb250YWluZXIub3duZXJEb2N1bWVudC5pbXBvcnROb2RlKGRvYy5kb2N1bWVudEVsZW1lbnQsIHRydWUpO1xuICAgIGNvbnRhaW5lci5hcHBlbmRDaGlsZChub2RlKTtcbiAgfVxufVxuXG4vKipcbiAqIFRvZ2dsZSB0aGUgdmlzaWJpbGl0eSBvZiBhbnkgRE9NIG5vZGVcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gIGRvbSAtIERPTSBub2RlIHdlIHdhbnQgdG8gaGlkZVxuICogQHBhcmFtICAgeyBCb29sZWFuIH0gc2hvdyAtIGRvIHdlIHdhbnQgdG8gc2hvdyBpdD9cbiAqL1xuXG5mdW5jdGlvbiB0b2dnbGVWaXNpYmlsaXR5KGRvbSwgc2hvdykge1xuICBkb20uc3R5bGUuZGlzcGxheSA9IHNob3cgPyAnJyA6ICdub25lJztcbiAgZG9tWydoaWRkZW4nXSA9IHNob3cgPyBmYWxzZSA6IHRydWU7XG59XG5cbi8qKlxuICogUmVtb3ZlIGFueSBET00gYXR0cmlidXRlIGZyb20gYSBub2RlXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IGRvbSAtIERPTSBub2RlIHdlIHdhbnQgdG8gdXBkYXRlXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IG5hbWUgLSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB3ZSB3YW50IHRvIHJlbW92ZVxuICovXG5mdW5jdGlvbiByZW1BdHRyKGRvbSwgbmFtZSkge1xuICBkb20ucmVtb3ZlQXR0cmlidXRlKG5hbWUpO1xufVxuXG4vKipcbiAqIENvbnZlcnQgYSBzdHlsZSBvYmplY3QgdG8gYSBzdHJpbmdcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gc3R5bGUgLSBzdHlsZSBvYmplY3Qgd2UgbmVlZCB0byBwYXJzZVxuICogQHJldHVybnMgeyBTdHJpbmcgfSByZXN1bHRpbmcgY3NzIHN0cmluZ1xuICogQGV4YW1wbGVcbiAqIHN0eWxlT2JqZWN0VG9TdHJpbmcoeyBjb2xvcjogJ3JlZCcsIGhlaWdodDogJzEwcHgnfSkgLy8gPT4gJ2NvbG9yOiByZWQ7IGhlaWdodDogMTBweCdcbiAqL1xuZnVuY3Rpb24gc3R5bGVPYmplY3RUb1N0cmluZyhzdHlsZSkge1xuICByZXR1cm4gT2JqZWN0LmtleXMoc3R5bGUpLnJlZHVjZShmdW5jdGlvbiAoYWNjLCBwcm9wKSB7XG4gICAgcmV0dXJuIChhY2MgKyBcIiBcIiArIHByb3AgKyBcIjogXCIgKyAoc3R5bGVbcHJvcF0pICsgXCI7XCIpXG4gIH0sICcnKVxufVxuXG4vKipcbiAqIEdldCB0aGUgdmFsdWUgb2YgYW55IERPTSBhdHRyaWJ1dGUgb24gYSBub2RlXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IGRvbSAtIERPTSBub2RlIHdlIHdhbnQgdG8gcGFyc2VcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gbmFtZSAtIG5hbWUgb2YgdGhlIGF0dHJpYnV0ZSB3ZSB3YW50IHRvIGdldFxuICogQHJldHVybnMgeyBTdHJpbmcgfCB1bmRlZmluZWQgfSBuYW1lIG9mIHRoZSBub2RlIGF0dHJpYnV0ZSB3aGV0aGVyIGl0IGV4aXN0c1xuICovXG5mdW5jdGlvbiBnZXRBdHRyKGRvbSwgbmFtZSkge1xuICByZXR1cm4gZG9tLmdldEF0dHJpYnV0ZShuYW1lKVxufVxuXG4vKipcbiAqIFNldCBhbnkgRE9NIGF0dHJpYnV0ZVxuICogQHBhcmFtIHsgT2JqZWN0IH0gZG9tIC0gRE9NIG5vZGUgd2Ugd2FudCB0byB1cGRhdGVcbiAqIEBwYXJhbSB7IFN0cmluZyB9IG5hbWUgLSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB3ZSB3YW50IHRvIHNldFxuICogQHBhcmFtIHsgU3RyaW5nIH0gdmFsIC0gdmFsdWUgb2YgdGhlIHByb3BlcnR5IHdlIHdhbnQgdG8gc2V0XG4gKi9cbmZ1bmN0aW9uIHNldEF0dHIoZG9tLCBuYW1lLCB2YWwpIHtcbiAgdmFyIHhsaW5rID0gWExJTktfUkVHRVguZXhlYyhuYW1lKTtcbiAgaWYgKHhsaW5rICYmIHhsaW5rWzFdKVxuICAgIHsgZG9tLnNldEF0dHJpYnV0ZU5TKFhMSU5LX05TLCB4bGlua1sxXSwgdmFsKTsgfVxuICBlbHNlXG4gICAgeyBkb20uc2V0QXR0cmlidXRlKG5hbWUsIHZhbCk7IH1cbn1cblxuLyoqXG4gKiBJbnNlcnQgc2FmZWx5IGEgdGFnIHRvIGZpeCAjMTk2MiAjMTY0OVxuICogQHBhcmFtICAgeyBIVE1MRWxlbWVudCB9IHJvb3QgLSBjaGlsZHJlbiBjb250YWluZXJcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSBjdXJyIC0gbm9kZSB0byBpbnNlcnRcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSBuZXh0IC0gbm9kZSB0aGF0IHNob3VsZCBwcmVjZWVkIHRoZSBjdXJyZW50IG5vZGUgaW5zZXJ0ZWRcbiAqL1xuZnVuY3Rpb24gc2FmZUluc2VydChyb290LCBjdXJyLCBuZXh0KSB7XG4gIHJvb3QuaW5zZXJ0QmVmb3JlKGN1cnIsIG5leHQucGFyZW50Tm9kZSAmJiBuZXh0KTtcbn1cblxuLyoqXG4gKiBNaW5pbWl6ZSByaXNrOiBvbmx5IHplcm8gb3Igb25lIF9zcGFjZV8gYmV0d2VlbiBhdHRyICYgdmFsdWVcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gICBodG1sIC0gaHRtbCBzdHJpbmcgd2Ugd2FudCB0byBwYXJzZVxuICogQHBhcmFtICAgeyBGdW5jdGlvbiB9IGZuIC0gY2FsbGJhY2sgZnVuY3Rpb24gdG8gYXBwbHkgb24gYW55IGF0dHJpYnV0ZSBmb3VuZFxuICovXG5mdW5jdGlvbiB3YWxrQXR0cnMoaHRtbCwgZm4pIHtcbiAgaWYgKCFodG1sKVxuICAgIHsgcmV0dXJuIH1cbiAgdmFyIG07XG4gIHdoaWxlIChtID0gUkVfSFRNTF9BVFRSUy5leGVjKGh0bWwpKVxuICAgIHsgZm4obVsxXS50b0xvd2VyQ2FzZSgpLCBtWzJdIHx8IG1bM10gfHwgbVs0XSk7IH1cbn1cblxuLyoqXG4gKiBXYWxrIGRvd24gcmVjdXJzaXZlbHkgYWxsIHRoZSBjaGlsZHJlbiB0YWdzIHN0YXJ0aW5nIGRvbSBub2RlXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9ICAgZG9tIC0gc3RhcnRpbmcgbm9kZSB3aGVyZSB3ZSB3aWxsIHN0YXJ0IHRoZSByZWN1cnNpb25cbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSBmbiAtIGNhbGxiYWNrIHRvIHRyYW5zZm9ybSB0aGUgY2hpbGQgbm9kZSBqdXN0IGZvdW5kXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9ICAgY29udGV4dCAtIGZuIGNhbiBvcHRpb25hbGx5IHJldHVybiBhbiBvYmplY3QsIHdoaWNoIGlzIHBhc3NlZCB0byBjaGlsZHJlblxuICovXG5mdW5jdGlvbiB3YWxrTm9kZXMoZG9tLCBmbiwgY29udGV4dCkge1xuICBpZiAoZG9tKSB7XG4gICAgdmFyIHJlcyA9IGZuKGRvbSwgY29udGV4dCk7XG4gICAgdmFyIG5leHQ7XG4gICAgLy8gc3RvcCB0aGUgcmVjdXJzaW9uXG4gICAgaWYgKHJlcyA9PT0gZmFsc2UpIHsgcmV0dXJuIH1cblxuICAgIGRvbSA9IGRvbS5maXJzdENoaWxkO1xuXG4gICAgd2hpbGUgKGRvbSkge1xuICAgICAgbmV4dCA9IGRvbS5uZXh0U2libGluZztcbiAgICAgIHdhbGtOb2Rlcyhkb20sIGZuLCByZXMpO1xuICAgICAgZG9tID0gbmV4dDtcbiAgICB9XG4gIH1cbn1cblxudmFyIGRvbSA9IE9iamVjdC5mcmVlemUoe1xuXHQkJDogJCQsXG5cdCQ6ICQsXG5cdGNyZWF0ZUZyYWc6IGNyZWF0ZUZyYWcsXG5cdGNyZWF0ZURPTVBsYWNlaG9sZGVyOiBjcmVhdGVET01QbGFjZWhvbGRlcixcblx0bWtFbDogbWtFbCxcblx0c2V0SW5uZXJIVE1MOiBzZXRJbm5lckhUTUwsXG5cdHRvZ2dsZVZpc2liaWxpdHk6IHRvZ2dsZVZpc2liaWxpdHksXG5cdHJlbUF0dHI6IHJlbUF0dHIsXG5cdHN0eWxlT2JqZWN0VG9TdHJpbmc6IHN0eWxlT2JqZWN0VG9TdHJpbmcsXG5cdGdldEF0dHI6IGdldEF0dHIsXG5cdHNldEF0dHI6IHNldEF0dHIsXG5cdHNhZmVJbnNlcnQ6IHNhZmVJbnNlcnQsXG5cdHdhbGtBdHRyczogd2Fsa0F0dHJzLFxuXHR3YWxrTm9kZXM6IHdhbGtOb2Rlc1xufSk7XG5cbnZhciBzdHlsZU5vZGU7XG52YXIgY3NzVGV4dFByb3A7XG52YXIgYnlOYW1lID0ge307XG52YXIgcmVtYWluZGVyID0gW107XG52YXIgbmVlZHNJbmplY3QgPSBmYWxzZTtcblxuLy8gc2tpcCB0aGUgZm9sbG93aW5nIGNvZGUgb24gdGhlIHNlcnZlclxuaWYgKFdJTikge1xuICBzdHlsZU5vZGUgPSAoZnVuY3Rpb24gKCkge1xuICAgIC8vIGNyZWF0ZSBhIG5ldyBzdHlsZSBlbGVtZW50IHdpdGggdGhlIGNvcnJlY3QgdHlwZVxuICAgIHZhciBuZXdOb2RlID0gbWtFbCgnc3R5bGUnKTtcbiAgICBzZXRBdHRyKG5ld05vZGUsICd0eXBlJywgJ3RleHQvY3NzJyk7XG5cbiAgICAvLyByZXBsYWNlIGFueSB1c2VyIG5vZGUgb3IgaW5zZXJ0IHRoZSBuZXcgb25lIGludG8gdGhlIGhlYWRcbiAgICB2YXIgdXNlck5vZGUgPSAkKCdzdHlsZVt0eXBlPXJpb3RdJyk7XG4gICAgLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbiAgICBpZiAodXNlck5vZGUpIHtcbiAgICAgIGlmICh1c2VyTm9kZS5pZCkgeyBuZXdOb2RlLmlkID0gdXNlck5vZGUuaWQ7IH1cbiAgICAgIHVzZXJOb2RlLnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKG5ld05vZGUsIHVzZXJOb2RlKTtcbiAgICB9XG4gICAgZWxzZSB7IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF0uYXBwZW5kQ2hpbGQobmV3Tm9kZSk7IH1cblxuICAgIHJldHVybiBuZXdOb2RlXG4gIH0pKCk7XG4gIGNzc1RleHRQcm9wID0gc3R5bGVOb2RlLnN0eWxlU2hlZXQ7XG59XG5cbi8qKlxuICogT2JqZWN0IHRoYXQgd2lsbCBiZSB1c2VkIHRvIGluamVjdCBhbmQgbWFuYWdlIHRoZSBjc3Mgb2YgZXZlcnkgdGFnIGluc3RhbmNlXG4gKi9cbnZhciBzdHlsZU1hbmFnZXIgPSB7XG4gIHN0eWxlTm9kZTogc3R5bGVOb2RlLFxuICAvKipcbiAgICogU2F2ZSBhIHRhZyBzdHlsZSB0byBiZSBsYXRlciBpbmplY3RlZCBpbnRvIERPTVxuICAgKiBAcGFyYW0geyBTdHJpbmcgfSBjc3MgLSBjc3Mgc3RyaW5nXG4gICAqIEBwYXJhbSB7IFN0cmluZyB9IG5hbWUgLSBpZiBpdCdzIHBhc3NlZCB3ZSB3aWxsIG1hcCB0aGUgY3NzIHRvIGEgdGFnbmFtZVxuICAgKi9cbiAgYWRkOiBmdW5jdGlvbiBhZGQoY3NzLCBuYW1lKSB7XG4gICAgaWYgKG5hbWUpIHsgYnlOYW1lW25hbWVdID0gY3NzOyB9XG4gICAgZWxzZSB7IHJlbWFpbmRlci5wdXNoKGNzcyk7IH1cbiAgICBuZWVkc0luamVjdCA9IHRydWU7XG4gIH0sXG4gIC8qKlxuICAgKiBJbmplY3QgYWxsIHByZXZpb3VzbHkgc2F2ZWQgdGFnIHN0eWxlcyBpbnRvIERPTVxuICAgKiBpbm5lckhUTUwgc2VlbXMgc2xvdzogaHR0cDovL2pzcGVyZi5jb20vcmlvdC1pbnNlcnQtc3R5bGVcbiAgICovXG4gIGluamVjdDogZnVuY3Rpb24gaW5qZWN0KCkge1xuICAgIGlmICghV0lOIHx8ICFuZWVkc0luamVjdCkgeyByZXR1cm4gfVxuICAgIG5lZWRzSW5qZWN0ID0gZmFsc2U7XG4gICAgdmFyIHN0eWxlID0gT2JqZWN0LmtleXMoYnlOYW1lKVxuICAgICAgLm1hcChmdW5jdGlvbihrKSB7IHJldHVybiBieU5hbWVba10gfSlcbiAgICAgIC5jb25jYXQocmVtYWluZGVyKS5qb2luKCdcXG4nKTtcbiAgICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICAgIGlmIChjc3NUZXh0UHJvcCkgeyBjc3NUZXh0UHJvcC5jc3NUZXh0ID0gc3R5bGU7IH1cbiAgICBlbHNlIHsgc3R5bGVOb2RlLmlubmVySFRNTCA9IHN0eWxlOyB9XG4gIH1cbn07XG5cbi8qKlxuICogVGhlIHJpb3QgdGVtcGxhdGUgZW5naW5lXG4gKiBAdmVyc2lvbiB2My4wLjNcbiAqL1xuLyoqXG4gKiByaW90LnV0aWwuYnJhY2tldHNcbiAqXG4gKiAtIGBicmFja2V0cyAgICBgIC0gUmV0dXJucyBhIHN0cmluZyBvciByZWdleCBiYXNlZCBvbiBpdHMgcGFyYW1ldGVyXG4gKiAtIGBicmFja2V0cy5zZXRgIC0gQ2hhbmdlIHRoZSBjdXJyZW50IHJpb3QgYnJhY2tldHNcbiAqXG4gKiBAbW9kdWxlXG4gKi9cblxuLyogZ2xvYmFsIHJpb3QgKi9cblxuLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbnZhciBicmFja2V0cyA9IChmdW5jdGlvbiAoVU5ERUYpIHtcblxuICB2YXJcbiAgICBSRUdMT0IgPSAnZycsXG5cbiAgICBSX01MQ09NTVMgPSAvXFwvXFwqW14qXSpcXCorKD86W14qXFwvXVteKl0qXFwqKykqXFwvL2csXG5cbiAgICBSX1NUUklOR1MgPSAvXCJbXlwiXFxcXF0qKD86XFxcXFtcXFNcXHNdW15cIlxcXFxdKikqXCJ8J1teJ1xcXFxdKig/OlxcXFxbXFxTXFxzXVteJ1xcXFxdKikqJ3xgW15gXFxcXF0qKD86XFxcXFtcXFNcXHNdW15gXFxcXF0qKSpgL2csXG5cbiAgICBTX1FCTE9DS1MgPSBSX1NUUklOR1Muc291cmNlICsgJ3wnICtcbiAgICAgIC8oPzpcXGJyZXR1cm5cXHMrfCg/OlskXFx3XFwpXFxdXXxcXCtcXCt8LS0pXFxzKihcXC8pKD8hWypcXC9dKSkvLnNvdXJjZSArICd8JyArXG4gICAgICAvXFwvKD89W14qXFwvXSlbXltcXC9cXFxcXSooPzooPzpcXFsoPzpcXFxcLnxbXlxcXVxcXFxdKikqXFxdfFxcXFwuKVteW1xcL1xcXFxdKikqPyhcXC8pW2dpbV0qLy5zb3VyY2UsXG5cbiAgICBVTlNVUFBPUlRFRCA9IFJlZ0V4cCgnW1xcXFwnICsgJ3gwMC1cXFxceDFGPD5hLXpBLVowLTlcXCdcIiw7XFxcXFxcXFxdJyksXG5cbiAgICBORUVEX0VTQ0FQRSA9IC8oPz1bW1xcXSgpKis/Ll4kfF0pL2csXG5cbiAgICBGSU5EQlJBQ0VTID0ge1xuICAgICAgJygnOiBSZWdFeHAoJyhbKCldKXwnICAgKyBTX1FCTE9DS1MsIFJFR0xPQiksXG4gICAgICAnWyc6IFJlZ0V4cCgnKFtbXFxcXF1dKXwnICsgU19RQkxPQ0tTLCBSRUdMT0IpLFxuICAgICAgJ3snOiBSZWdFeHAoJyhbe31dKXwnICAgKyBTX1FCTE9DS1MsIFJFR0xPQilcbiAgICB9LFxuXG4gICAgREVGQVVMVCA9ICd7IH0nO1xuXG4gIHZhciBfcGFpcnMgPSBbXG4gICAgJ3snLCAnfScsXG4gICAgJ3snLCAnfScsXG4gICAgL3tbXn1dKn0vLFxuICAgIC9cXFxcKFt7fV0pL2csXG4gICAgL1xcXFwoeyl8ey9nLFxuICAgIFJlZ0V4cCgnXFxcXFxcXFwofSl8KFtbKHtdKXwofSl8JyArIFNfUUJMT0NLUywgUkVHTE9CKSxcbiAgICBERUZBVUxULFxuICAgIC9eXFxzKntcXF4/XFxzKihbJFxcd10rKSg/OlxccyosXFxzKihcXFMrKSk/XFxzK2luXFxzKyhcXFMuKilcXHMqfS8sXG4gICAgLyhefFteXFxcXF0pez1bXFxTXFxzXSo/fS9cbiAgXTtcblxuICB2YXJcbiAgICBjYWNoZWRCcmFja2V0cyA9IFVOREVGLFxuICAgIF9yZWdleCxcbiAgICBfY2FjaGUgPSBbXSxcbiAgICBfc2V0dGluZ3M7XG5cbiAgZnVuY3Rpb24gX2xvb3BiYWNrIChyZSkgeyByZXR1cm4gcmUgfVxuXG4gIGZ1bmN0aW9uIF9yZXdyaXRlIChyZSwgYnApIHtcbiAgICBpZiAoIWJwKSB7IGJwID0gX2NhY2hlOyB9XG4gICAgcmV0dXJuIG5ldyBSZWdFeHAoXG4gICAgICByZS5zb3VyY2UucmVwbGFjZSgvey9nLCBicFsyXSkucmVwbGFjZSgvfS9nLCBicFszXSksIHJlLmdsb2JhbCA/IFJFR0xPQiA6ICcnXG4gICAgKVxuICB9XG5cbiAgZnVuY3Rpb24gX2NyZWF0ZSAocGFpcikge1xuICAgIGlmIChwYWlyID09PSBERUZBVUxUKSB7IHJldHVybiBfcGFpcnMgfVxuXG4gICAgdmFyIGFyciA9IHBhaXIuc3BsaXQoJyAnKTtcblxuICAgIGlmIChhcnIubGVuZ3RoICE9PSAyIHx8IFVOU1VQUE9SVEVELnRlc3QocGFpcikpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignVW5zdXBwb3J0ZWQgYnJhY2tldHMgXCInICsgcGFpciArICdcIicpXG4gICAgfVxuICAgIGFyciA9IGFyci5jb25jYXQocGFpci5yZXBsYWNlKE5FRURfRVNDQVBFLCAnXFxcXCcpLnNwbGl0KCcgJykpO1xuXG4gICAgYXJyWzRdID0gX3Jld3JpdGUoYXJyWzFdLmxlbmd0aCA+IDEgPyAve1tcXFNcXHNdKj99LyA6IF9wYWlyc1s0XSwgYXJyKTtcbiAgICBhcnJbNV0gPSBfcmV3cml0ZShwYWlyLmxlbmd0aCA+IDMgPyAvXFxcXCh7fH0pL2cgOiBfcGFpcnNbNV0sIGFycik7XG4gICAgYXJyWzZdID0gX3Jld3JpdGUoX3BhaXJzWzZdLCBhcnIpO1xuICAgIGFycls3XSA9IFJlZ0V4cCgnXFxcXFxcXFwoJyArIGFyclszXSArICcpfChbWyh7XSl8KCcgKyBhcnJbM10gKyAnKXwnICsgU19RQkxPQ0tTLCBSRUdMT0IpO1xuICAgIGFycls4XSA9IHBhaXI7XG4gICAgcmV0dXJuIGFyclxuICB9XG5cbiAgZnVuY3Rpb24gX2JyYWNrZXRzIChyZU9ySWR4KSB7XG4gICAgcmV0dXJuIHJlT3JJZHggaW5zdGFuY2VvZiBSZWdFeHAgPyBfcmVnZXgocmVPcklkeCkgOiBfY2FjaGVbcmVPcklkeF1cbiAgfVxuXG4gIF9icmFja2V0cy5zcGxpdCA9IGZ1bmN0aW9uIHNwbGl0IChzdHIsIHRtcGwsIF9icCkge1xuICAgIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBfYnAgaXMgZm9yIHRoZSBjb21waWxlclxuICAgIGlmICghX2JwKSB7IF9icCA9IF9jYWNoZTsgfVxuXG4gICAgdmFyXG4gICAgICBwYXJ0cyA9IFtdLFxuICAgICAgbWF0Y2gsXG4gICAgICBpc2V4cHIsXG4gICAgICBzdGFydCxcbiAgICAgIHBvcyxcbiAgICAgIHJlID0gX2JwWzZdO1xuXG4gICAgaXNleHByID0gc3RhcnQgPSByZS5sYXN0SW5kZXggPSAwO1xuXG4gICAgd2hpbGUgKChtYXRjaCA9IHJlLmV4ZWMoc3RyKSkpIHtcblxuICAgICAgcG9zID0gbWF0Y2guaW5kZXg7XG5cbiAgICAgIGlmIChpc2V4cHIpIHtcblxuICAgICAgICBpZiAobWF0Y2hbMl0pIHtcbiAgICAgICAgICByZS5sYXN0SW5kZXggPSBza2lwQnJhY2VzKHN0ciwgbWF0Y2hbMl0sIHJlLmxhc3RJbmRleCk7XG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuICAgICAgICBpZiAoIW1hdGNoWzNdKSB7XG4gICAgICAgICAgY29udGludWVcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoIW1hdGNoWzFdKSB7XG4gICAgICAgIHVuZXNjYXBlU3RyKHN0ci5zbGljZShzdGFydCwgcG9zKSk7XG4gICAgICAgIHN0YXJ0ID0gcmUubGFzdEluZGV4O1xuICAgICAgICByZSA9IF9icFs2ICsgKGlzZXhwciBePSAxKV07XG4gICAgICAgIHJlLmxhc3RJbmRleCA9IHN0YXJ0O1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChzdHIgJiYgc3RhcnQgPCBzdHIubGVuZ3RoKSB7XG4gICAgICB1bmVzY2FwZVN0cihzdHIuc2xpY2Uoc3RhcnQpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFydHNcblxuICAgIGZ1bmN0aW9uIHVuZXNjYXBlU3RyIChzKSB7XG4gICAgICBpZiAodG1wbCB8fCBpc2V4cHIpIHtcbiAgICAgICAgcGFydHMucHVzaChzICYmIHMucmVwbGFjZShfYnBbNV0sICckMScpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHBhcnRzLnB1c2gocyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gc2tpcEJyYWNlcyAocywgY2gsIGl4KSB7XG4gICAgICB2YXJcbiAgICAgICAgbWF0Y2gsXG4gICAgICAgIHJlY2NoID0gRklOREJSQUNFU1tjaF07XG5cbiAgICAgIHJlY2NoLmxhc3RJbmRleCA9IGl4O1xuICAgICAgaXggPSAxO1xuICAgICAgd2hpbGUgKChtYXRjaCA9IHJlY2NoLmV4ZWMocykpKSB7XG4gICAgICAgIGlmIChtYXRjaFsxXSAmJlxuICAgICAgICAgICEobWF0Y2hbMV0gPT09IGNoID8gKytpeCA6IC0taXgpKSB7IGJyZWFrIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBpeCA/IHMubGVuZ3RoIDogcmVjY2gubGFzdEluZGV4XG4gICAgfVxuICB9O1xuXG4gIF9icmFja2V0cy5oYXNFeHByID0gZnVuY3Rpb24gaGFzRXhwciAoc3RyKSB7XG4gICAgcmV0dXJuIF9jYWNoZVs0XS50ZXN0KHN0cilcbiAgfTtcblxuICBfYnJhY2tldHMubG9vcEtleXMgPSBmdW5jdGlvbiBsb29wS2V5cyAoZXhwcikge1xuICAgIHZhciBtID0gZXhwci5tYXRjaChfY2FjaGVbOV0pO1xuXG4gICAgcmV0dXJuIG1cbiAgICAgID8geyBrZXk6IG1bMV0sIHBvczogbVsyXSwgdmFsOiBfY2FjaGVbMF0gKyBtWzNdLnRyaW0oKSArIF9jYWNoZVsxXSB9XG4gICAgICA6IHsgdmFsOiBleHByLnRyaW0oKSB9XG4gIH07XG5cbiAgX2JyYWNrZXRzLmFycmF5ID0gZnVuY3Rpb24gYXJyYXkgKHBhaXIpIHtcbiAgICByZXR1cm4gcGFpciA/IF9jcmVhdGUocGFpcikgOiBfY2FjaGVcbiAgfTtcblxuICBmdW5jdGlvbiBfcmVzZXQgKHBhaXIpIHtcbiAgICBpZiAoKHBhaXIgfHwgKHBhaXIgPSBERUZBVUxUKSkgIT09IF9jYWNoZVs4XSkge1xuICAgICAgX2NhY2hlID0gX2NyZWF0ZShwYWlyKTtcbiAgICAgIF9yZWdleCA9IHBhaXIgPT09IERFRkFVTFQgPyBfbG9vcGJhY2sgOiBfcmV3cml0ZTtcbiAgICAgIF9jYWNoZVs5XSA9IF9yZWdleChfcGFpcnNbOV0pO1xuICAgIH1cbiAgICBjYWNoZWRCcmFja2V0cyA9IHBhaXI7XG4gIH1cblxuICBmdW5jdGlvbiBfc2V0U2V0dGluZ3MgKG8pIHtcbiAgICB2YXIgYjtcblxuICAgIG8gPSBvIHx8IHt9O1xuICAgIGIgPSBvLmJyYWNrZXRzO1xuICAgIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShvLCAnYnJhY2tldHMnLCB7XG4gICAgICBzZXQ6IF9yZXNldCxcbiAgICAgIGdldDogZnVuY3Rpb24gKCkgeyByZXR1cm4gY2FjaGVkQnJhY2tldHMgfSxcbiAgICAgIGVudW1lcmFibGU6IHRydWVcbiAgICB9KTtcbiAgICBfc2V0dGluZ3MgPSBvO1xuICAgIF9yZXNldChiKTtcbiAgfVxuXG4gIE9iamVjdC5kZWZpbmVQcm9wZXJ0eShfYnJhY2tldHMsICdzZXR0aW5ncycsIHtcbiAgICBzZXQ6IF9zZXRTZXR0aW5ncyxcbiAgICBnZXQ6IGZ1bmN0aW9uICgpIHsgcmV0dXJuIF9zZXR0aW5ncyB9XG4gIH0pO1xuXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0OiBpbiB0aGUgYnJvd3NlciByaW90IGlzIGFsd2F5cyBpbiB0aGUgc2NvcGUgKi9cbiAgX2JyYWNrZXRzLnNldHRpbmdzID0gdHlwZW9mIHJpb3QgIT09ICd1bmRlZmluZWQnICYmIHJpb3Quc2V0dGluZ3MgfHwge307XG4gIF9icmFja2V0cy5zZXQgPSBfcmVzZXQ7XG5cbiAgX2JyYWNrZXRzLlJfU1RSSU5HUyA9IFJfU1RSSU5HUztcbiAgX2JyYWNrZXRzLlJfTUxDT01NUyA9IFJfTUxDT01NUztcbiAgX2JyYWNrZXRzLlNfUUJMT0NLUyA9IFNfUUJMT0NLUztcblxuICByZXR1cm4gX2JyYWNrZXRzXG5cbn0pKCk7XG5cbi8qKlxuICogQG1vZHVsZSB0bXBsXG4gKlxuICogdG1wbCAgICAgICAgICAtIFJvb3QgZnVuY3Rpb24sIHJldHVybnMgdGhlIHRlbXBsYXRlIHZhbHVlLCByZW5kZXIgd2l0aCBkYXRhXG4gKiB0bXBsLmhhc0V4cHIgIC0gVGVzdCB0aGUgZXhpc3RlbmNlIG9mIGEgZXhwcmVzc2lvbiBpbnNpZGUgYSBzdHJpbmdcbiAqIHRtcGwubG9vcEtleXMgLSBHZXQgdGhlIGtleXMgZm9yIGFuICdlYWNoJyBsb29wICh1c2VkIGJ5IGBfZWFjaGApXG4gKi9cblxuLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbnZhciB0bXBsID0gKGZ1bmN0aW9uICgpIHtcblxuICB2YXIgX2NhY2hlID0ge307XG5cbiAgZnVuY3Rpb24gX3RtcGwgKHN0ciwgZGF0YSkge1xuICAgIGlmICghc3RyKSB7IHJldHVybiBzdHIgfVxuXG4gICAgcmV0dXJuIChfY2FjaGVbc3RyXSB8fCAoX2NhY2hlW3N0cl0gPSBfY3JlYXRlKHN0cikpKS5jYWxsKGRhdGEsIF9sb2dFcnIpXG4gIH1cblxuICBfdG1wbC5oYXNFeHByID0gYnJhY2tldHMuaGFzRXhwcjtcblxuICBfdG1wbC5sb29wS2V5cyA9IGJyYWNrZXRzLmxvb3BLZXlzO1xuXG4gIC8vIGlzdGFuYnVsIGlnbm9yZSBuZXh0XG4gIF90bXBsLmNsZWFyQ2FjaGUgPSBmdW5jdGlvbiAoKSB7IF9jYWNoZSA9IHt9OyB9O1xuXG4gIF90bXBsLmVycm9ySGFuZGxlciA9IG51bGw7XG5cbiAgZnVuY3Rpb24gX2xvZ0VyciAoZXJyLCBjdHgpIHtcblxuICAgIGVyci5yaW90RGF0YSA9IHtcbiAgICAgIHRhZ05hbWU6IGN0eCAmJiBjdHguX18gJiYgY3R4Ll9fLnRhZ05hbWUsXG4gICAgICBfcmlvdF9pZDogY3R4ICYmIGN0eC5fcmlvdF9pZCAgLy9lc2xpbnQtZGlzYWJsZS1saW5lIGNhbWVsY2FzZVxuICAgIH07XG5cbiAgICBpZiAoX3RtcGwuZXJyb3JIYW5kbGVyKSB7IF90bXBsLmVycm9ySGFuZGxlcihlcnIpOyB9XG4gICAgZWxzZSBpZiAoXG4gICAgICB0eXBlb2YgY29uc29sZSAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIHR5cGVvZiBjb25zb2xlLmVycm9yID09PSAnZnVuY3Rpb24nXG4gICAgKSB7XG4gICAgICBpZiAoZXJyLnJpb3REYXRhLnRhZ05hbWUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignUmlvdCB0ZW1wbGF0ZSBlcnJvciB0aHJvd24gaW4gdGhlIDwlcz4gdGFnJywgZXJyLnJpb3REYXRhLnRhZ05hbWUpO1xuICAgICAgfVxuICAgICAgY29uc29sZS5lcnJvcihlcnIpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIF9jcmVhdGUgKHN0cikge1xuICAgIHZhciBleHByID0gX2dldFRtcGwoc3RyKTtcblxuICAgIGlmIChleHByLnNsaWNlKDAsIDExKSAhPT0gJ3RyeXtyZXR1cm4gJykgeyBleHByID0gJ3JldHVybiAnICsgZXhwcjsgfVxuXG4gICAgcmV0dXJuIG5ldyBGdW5jdGlvbignRScsIGV4cHIgKyAnOycpICAgIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tbmV3LWZ1bmNcbiAgfVxuXG4gIHZhclxuICAgIENIX0lERVhQUiA9IFN0cmluZy5mcm9tQ2hhckNvZGUoMHgyMDU3KSxcbiAgICBSRV9DU05BTUUgPSAvXig/OigtP1tfQS1aYS16XFx4QTAtXFx4RkZdWy1cXHdcXHhBMC1cXHhGRl0qKXxcXHUyMDU3KFxcZCspfik6LyxcbiAgICBSRV9RQkxPQ0sgPSBSZWdFeHAoYnJhY2tldHMuU19RQkxPQ0tTLCAnZycpLFxuICAgIFJFX0RRVU9URSA9IC9cXHUyMDU3L2csXG4gICAgUkVfUUJNQVJLID0gL1xcdTIwNTcoXFxkKyl+L2c7XG5cbiAgZnVuY3Rpb24gX2dldFRtcGwgKHN0cikge1xuICAgIHZhclxuICAgICAgcXN0ciA9IFtdLFxuICAgICAgZXhwcixcbiAgICAgIHBhcnRzID0gYnJhY2tldHMuc3BsaXQoc3RyLnJlcGxhY2UoUkVfRFFVT1RFLCAnXCInKSwgMSk7XG5cbiAgICBpZiAocGFydHMubGVuZ3RoID4gMiB8fCBwYXJ0c1swXSkge1xuICAgICAgdmFyIGksIGosIGxpc3QgPSBbXTtcblxuICAgICAgZm9yIChpID0gaiA9IDA7IGkgPCBwYXJ0cy5sZW5ndGg7ICsraSkge1xuXG4gICAgICAgIGV4cHIgPSBwYXJ0c1tpXTtcblxuICAgICAgICBpZiAoZXhwciAmJiAoZXhwciA9IGkgJiAxXG5cbiAgICAgICAgICAgID8gX3BhcnNlRXhwcihleHByLCAxLCBxc3RyKVxuXG4gICAgICAgICAgICA6ICdcIicgKyBleHByXG4gICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFwvZywgJ1xcXFxcXFxcJylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFxyXFxuP3xcXG4vZywgJ1xcXFxuJylcbiAgICAgICAgICAgICAgICAucmVwbGFjZSgvXCIvZywgJ1xcXFxcIicpICtcbiAgICAgICAgICAgICAgJ1wiJ1xuXG4gICAgICAgICAgKSkgeyBsaXN0W2orK10gPSBleHByOyB9XG5cbiAgICAgIH1cblxuICAgICAgZXhwciA9IGogPCAyID8gbGlzdFswXVxuICAgICAgICAgICA6ICdbJyArIGxpc3Quam9pbignLCcpICsgJ10uam9pbihcIlwiKSc7XG5cbiAgICB9IGVsc2Uge1xuXG4gICAgICBleHByID0gX3BhcnNlRXhwcihwYXJ0c1sxXSwgMCwgcXN0cik7XG4gICAgfVxuXG4gICAgaWYgKHFzdHJbMF0pIHtcbiAgICAgIGV4cHIgPSBleHByLnJlcGxhY2UoUkVfUUJNQVJLLCBmdW5jdGlvbiAoXywgcG9zKSB7XG4gICAgICAgIHJldHVybiBxc3RyW3Bvc11cbiAgICAgICAgICAucmVwbGFjZSgvXFxyL2csICdcXFxccicpXG4gICAgICAgICAgLnJlcGxhY2UoL1xcbi9nLCAnXFxcXG4nKVxuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBleHByXG4gIH1cblxuICB2YXJcbiAgICBSRV9CUkVORCA9IHtcbiAgICAgICcoJzogL1soKV0vZyxcbiAgICAgICdbJzogL1tbXFxdXS9nLFxuICAgICAgJ3snOiAvW3t9XS9nXG4gICAgfTtcblxuICBmdW5jdGlvbiBfcGFyc2VFeHByIChleHByLCBhc1RleHQsIHFzdHIpIHtcblxuICAgIGV4cHIgPSBleHByXG4gICAgICAgICAgLnJlcGxhY2UoUkVfUUJMT0NLLCBmdW5jdGlvbiAocywgZGl2KSB7XG4gICAgICAgICAgICByZXR1cm4gcy5sZW5ndGggPiAyICYmICFkaXYgPyBDSF9JREVYUFIgKyAocXN0ci5wdXNoKHMpIC0gMSkgKyAnficgOiBzXG4gICAgICAgICAgfSlcbiAgICAgICAgICAucmVwbGFjZSgvXFxzKy9nLCAnICcpLnRyaW0oKVxuICAgICAgICAgIC5yZXBsYWNlKC9cXCA/KFtbXFwoe30sP1xcLjpdKVxcID8vZywgJyQxJyk7XG5cbiAgICBpZiAoZXhwcikge1xuICAgICAgdmFyXG4gICAgICAgIGxpc3QgPSBbXSxcbiAgICAgICAgY250ID0gMCxcbiAgICAgICAgbWF0Y2g7XG5cbiAgICAgIHdoaWxlIChleHByICYmXG4gICAgICAgICAgICAobWF0Y2ggPSBleHByLm1hdGNoKFJFX0NTTkFNRSkpICYmXG4gICAgICAgICAgICAhbWF0Y2guaW5kZXhcbiAgICAgICAgKSB7XG4gICAgICAgIHZhclxuICAgICAgICAgIGtleSxcbiAgICAgICAgICBqc2IsXG4gICAgICAgICAgcmUgPSAvLHwoW1t7KF0pfCQvZztcblxuICAgICAgICBleHByID0gUmVnRXhwLnJpZ2h0Q29udGV4dDtcbiAgICAgICAga2V5ICA9IG1hdGNoWzJdID8gcXN0clttYXRjaFsyXV0uc2xpY2UoMSwgLTEpLnRyaW0oKS5yZXBsYWNlKC9cXHMrL2csICcgJykgOiBtYXRjaFsxXTtcblxuICAgICAgICB3aGlsZSAoanNiID0gKG1hdGNoID0gcmUuZXhlYyhleHByKSlbMV0pIHsgc2tpcEJyYWNlcyhqc2IsIHJlKTsgfVxuXG4gICAgICAgIGpzYiAgPSBleHByLnNsaWNlKDAsIG1hdGNoLmluZGV4KTtcbiAgICAgICAgZXhwciA9IFJlZ0V4cC5yaWdodENvbnRleHQ7XG5cbiAgICAgICAgbGlzdFtjbnQrK10gPSBfd3JhcEV4cHIoanNiLCAxLCBrZXkpO1xuICAgICAgfVxuXG4gICAgICBleHByID0gIWNudCA/IF93cmFwRXhwcihleHByLCBhc1RleHQpXG4gICAgICAgICAgIDogY250ID4gMSA/ICdbJyArIGxpc3Quam9pbignLCcpICsgJ10uam9pbihcIiBcIikudHJpbSgpJyA6IGxpc3RbMF07XG4gICAgfVxuICAgIHJldHVybiBleHByXG5cbiAgICBmdW5jdGlvbiBza2lwQnJhY2VzIChjaCwgcmUpIHtcbiAgICAgIHZhclxuICAgICAgICBtbSxcbiAgICAgICAgbHYgPSAxLFxuICAgICAgICBpciA9IFJFX0JSRU5EW2NoXTtcblxuICAgICAgaXIubGFzdEluZGV4ID0gcmUubGFzdEluZGV4O1xuICAgICAgd2hpbGUgKG1tID0gaXIuZXhlYyhleHByKSkge1xuICAgICAgICBpZiAobW1bMF0gPT09IGNoKSB7ICsrbHY7IH1cbiAgICAgICAgZWxzZSBpZiAoIS0tbHYpIHsgYnJlYWsgfVxuICAgICAgfVxuICAgICAgcmUubGFzdEluZGV4ID0gbHYgPyBleHByLmxlbmd0aCA6IGlyLmxhc3RJbmRleDtcbiAgICB9XG4gIH1cblxuICAvLyBpc3RhbmJ1bCBpZ25vcmUgbmV4dDogbm90IGJvdGhcbiAgdmFyIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBtYXgtbGVuXG4gICAgSlNfQ09OVEVYVCA9ICdcImluIHRoaXM/dGhpczonICsgKHR5cGVvZiB3aW5kb3cgIT09ICdvYmplY3QnID8gJ2dsb2JhbCcgOiAnd2luZG93JykgKyAnKS4nLFxuICAgIEpTX1ZBUk5BTUUgPSAvWyx7XVtcXCRcXHddKyg/PTopfCheICp8W14kXFx3XFwue10pKD8hKD86dHlwZW9mfHRydWV8ZmFsc2V8bnVsbHx1bmRlZmluZWR8aW58aW5zdGFuY2VvZnxpcyg/OkZpbml0ZXxOYU4pfHZvaWR8TmFOfG5ld3xEYXRlfFJlZ0V4cHxNYXRoKSg/IVskXFx3XSkpKFskX0EtWmEtel1bJFxcd10qKS9nLFxuICAgIEpTX05PUFJPUFMgPSAvXig/PShcXC5bJFxcd10rKSlcXDEoPzpbXi5bKF18JCkvO1xuXG4gIGZ1bmN0aW9uIF93cmFwRXhwciAoZXhwciwgYXNUZXh0LCBrZXkpIHtcbiAgICB2YXIgdGI7XG5cbiAgICBleHByID0gZXhwci5yZXBsYWNlKEpTX1ZBUk5BTUUsIGZ1bmN0aW9uIChtYXRjaCwgcCwgbXZhciwgcG9zLCBzKSB7XG4gICAgICBpZiAobXZhcikge1xuICAgICAgICBwb3MgPSB0YiA/IDAgOiBwb3MgKyBtYXRjaC5sZW5ndGg7XG5cbiAgICAgICAgaWYgKG12YXIgIT09ICd0aGlzJyAmJiBtdmFyICE9PSAnZ2xvYmFsJyAmJiBtdmFyICE9PSAnd2luZG93Jykge1xuICAgICAgICAgIG1hdGNoID0gcCArICcoXCInICsgbXZhciArIEpTX0NPTlRFWFQgKyBtdmFyO1xuICAgICAgICAgIGlmIChwb3MpIHsgdGIgPSAocyA9IHNbcG9zXSkgPT09ICcuJyB8fCBzID09PSAnKCcgfHwgcyA9PT0gJ1snOyB9XG4gICAgICAgIH0gZWxzZSBpZiAocG9zKSB7XG4gICAgICAgICAgdGIgPSAhSlNfTk9QUk9QUy50ZXN0KHMuc2xpY2UocG9zKSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBtYXRjaFxuICAgIH0pO1xuXG4gICAgaWYgKHRiKSB7XG4gICAgICBleHByID0gJ3RyeXtyZXR1cm4gJyArIGV4cHIgKyAnfWNhdGNoKGUpe0UoZSx0aGlzKX0nO1xuICAgIH1cblxuICAgIGlmIChrZXkpIHtcblxuICAgICAgZXhwciA9ICh0YlxuICAgICAgICAgID8gJ2Z1bmN0aW9uKCl7JyArIGV4cHIgKyAnfS5jYWxsKHRoaXMpJyA6ICcoJyArIGV4cHIgKyAnKSdcbiAgICAgICAgKSArICc/XCInICsga2V5ICsgJ1wiOlwiXCInO1xuXG4gICAgfSBlbHNlIGlmIChhc1RleHQpIHtcblxuICAgICAgZXhwciA9ICdmdW5jdGlvbih2KXsnICsgKHRiXG4gICAgICAgICAgPyBleHByLnJlcGxhY2UoJ3JldHVybiAnLCAndj0nKSA6ICd2PSgnICsgZXhwciArICcpJ1xuICAgICAgICApICsgJztyZXR1cm4gdnx8dj09PTA/djpcIlwifS5jYWxsKHRoaXMpJztcbiAgICB9XG5cbiAgICByZXR1cm4gZXhwclxuICB9XG5cbiAgX3RtcGwudmVyc2lvbiA9IGJyYWNrZXRzLnZlcnNpb24gPSAndjMuMC4zJztcblxuICByZXR1cm4gX3RtcGxcblxufSkoKTtcblxuLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cbnZhciBvYnNlcnZhYmxlJDEgPSBmdW5jdGlvbihlbCkge1xuXG4gIC8qKlxuICAgKiBFeHRlbmQgdGhlIG9yaWdpbmFsIG9iamVjdCBvciBjcmVhdGUgYSBuZXcgZW1wdHkgb25lXG4gICAqIEB0eXBlIHsgT2JqZWN0IH1cbiAgICovXG5cbiAgZWwgPSBlbCB8fCB7fTtcblxuICAvKipcbiAgICogUHJpdmF0ZSB2YXJpYWJsZXNcbiAgICovXG4gIHZhciBjYWxsYmFja3MgPSB7fSxcbiAgICBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcblxuICAvKipcbiAgICogUHVibGljIEFwaVxuICAgKi9cblxuICAvLyBleHRlbmQgdGhlIGVsIG9iamVjdCBhZGRpbmcgdGhlIG9ic2VydmFibGUgbWV0aG9kc1xuICBPYmplY3QuZGVmaW5lUHJvcGVydGllcyhlbCwge1xuICAgIC8qKlxuICAgICAqIExpc3RlbiB0byB0aGUgZ2l2ZW4gYGV2ZW50YCBhbmRzXG4gICAgICogZXhlY3V0ZSB0aGUgYGNhbGxiYWNrYCBlYWNoIHRpbWUgYW4gZXZlbnQgaXMgdHJpZ2dlcmVkLlxuICAgICAqIEBwYXJhbSAgeyBTdHJpbmcgfSBldmVudCAtIGV2ZW50IGlkXG4gICAgICogQHBhcmFtICB7IEZ1bmN0aW9uIH0gZm4gLSBjYWxsYmFjayBmdW5jdGlvblxuICAgICAqIEByZXR1cm5zIHsgT2JqZWN0IH0gZWxcbiAgICAgKi9cbiAgICBvbjoge1xuICAgICAgdmFsdWU6IGZ1bmN0aW9uKGV2ZW50LCBmbikge1xuICAgICAgICBpZiAodHlwZW9mIGZuID09ICdmdW5jdGlvbicpXG4gICAgICAgICAgeyAoY2FsbGJhY2tzW2V2ZW50XSA9IGNhbGxiYWNrc1tldmVudF0gfHwgW10pLnB1c2goZm4pOyB9XG4gICAgICAgIHJldHVybiBlbFxuICAgICAgfSxcbiAgICAgIGVudW1lcmFibGU6IGZhbHNlLFxuICAgICAgd3JpdGFibGU6IGZhbHNlLFxuICAgICAgY29uZmlndXJhYmxlOiBmYWxzZVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIHRoZSBnaXZlbiBgZXZlbnRgIGxpc3RlbmVyc1xuICAgICAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gZXZlbnQgLSBldmVudCBpZFxuICAgICAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSBmbiAtIGNhbGxiYWNrIGZ1bmN0aW9uXG4gICAgICogQHJldHVybnMgeyBPYmplY3QgfSBlbFxuICAgICAqL1xuICAgIG9mZjoge1xuICAgICAgdmFsdWU6IGZ1bmN0aW9uKGV2ZW50LCBmbikge1xuICAgICAgICBpZiAoZXZlbnQgPT0gJyonICYmICFmbikgeyBjYWxsYmFja3MgPSB7fTsgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICBpZiAoZm4pIHtcbiAgICAgICAgICAgIHZhciBhcnIgPSBjYWxsYmFja3NbZXZlbnRdO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGNiOyBjYiA9IGFyciAmJiBhcnJbaV07ICsraSkge1xuICAgICAgICAgICAgICBpZiAoY2IgPT0gZm4pIHsgYXJyLnNwbGljZShpLS0sIDEpOyB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHsgZGVsZXRlIGNhbGxiYWNrc1tldmVudF07IH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZWxcbiAgICAgIH0sXG4gICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogZmFsc2VcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogTGlzdGVuIHRvIHRoZSBnaXZlbiBgZXZlbnRgIGFuZFxuICAgICAqIGV4ZWN1dGUgdGhlIGBjYWxsYmFja2AgYXQgbW9zdCBvbmNlXG4gICAgICogQHBhcmFtICAgeyBTdHJpbmcgfSBldmVudCAtIGV2ZW50IGlkXG4gICAgICogQHBhcmFtICAgeyBGdW5jdGlvbiB9IGZuIC0gY2FsbGJhY2sgZnVuY3Rpb25cbiAgICAgKiBAcmV0dXJucyB7IE9iamVjdCB9IGVsXG4gICAgICovXG4gICAgb25lOiB7XG4gICAgICB2YWx1ZTogZnVuY3Rpb24oZXZlbnQsIGZuKSB7XG4gICAgICAgIGZ1bmN0aW9uIG9uKCkge1xuICAgICAgICAgIGVsLm9mZihldmVudCwgb24pO1xuICAgICAgICAgIGZuLmFwcGx5KGVsLCBhcmd1bWVudHMpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBlbC5vbihldmVudCwgb24pXG4gICAgICB9LFxuICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICB3cml0YWJsZTogZmFsc2UsXG4gICAgICBjb25maWd1cmFibGU6IGZhbHNlXG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEV4ZWN1dGUgYWxsIGNhbGxiYWNrIGZ1bmN0aW9ucyB0aGF0IGxpc3RlbiB0b1xuICAgICAqIHRoZSBnaXZlbiBgZXZlbnRgXG4gICAgICogQHBhcmFtICAgeyBTdHJpbmcgfSBldmVudCAtIGV2ZW50IGlkXG4gICAgICogQHJldHVybnMgeyBPYmplY3QgfSBlbFxuICAgICAqL1xuICAgIHRyaWdnZXI6IHtcbiAgICAgIHZhbHVlOiBmdW5jdGlvbihldmVudCkge1xuICAgICAgICB2YXIgYXJndW1lbnRzJDEgPSBhcmd1bWVudHM7XG5cblxuICAgICAgICAvLyBnZXR0aW5nIHRoZSBhcmd1bWVudHNcbiAgICAgICAgdmFyIGFyZ2xlbiA9IGFyZ3VtZW50cy5sZW5ndGggLSAxLFxuICAgICAgICAgIGFyZ3MgPSBuZXcgQXJyYXkoYXJnbGVuKSxcbiAgICAgICAgICBmbnMsXG4gICAgICAgICAgZm4sXG4gICAgICAgICAgaTtcblxuICAgICAgICBmb3IgKGkgPSAwOyBpIDwgYXJnbGVuOyBpKyspIHtcbiAgICAgICAgICBhcmdzW2ldID0gYXJndW1lbnRzJDFbaSArIDFdOyAvLyBza2lwIGZpcnN0IGFyZ3VtZW50XG4gICAgICAgIH1cblxuICAgICAgICBmbnMgPSBzbGljZS5jYWxsKGNhbGxiYWNrc1tldmVudF0gfHwgW10sIDApO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGZuID0gZm5zW2ldOyArK2kpIHtcbiAgICAgICAgICBmbi5hcHBseShlbCwgYXJncyk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoY2FsbGJhY2tzWycqJ10gJiYgZXZlbnQgIT0gJyonKVxuICAgICAgICAgIHsgZWwudHJpZ2dlci5hcHBseShlbCwgWycqJywgZXZlbnRdLmNvbmNhdChhcmdzKSk7IH1cblxuICAgICAgICByZXR1cm4gZWxcbiAgICAgIH0sXG4gICAgICBlbnVtZXJhYmxlOiBmYWxzZSxcbiAgICAgIHdyaXRhYmxlOiBmYWxzZSxcbiAgICAgIGNvbmZpZ3VyYWJsZTogZmFsc2VcbiAgICB9XG4gIH0pO1xuXG4gIHJldHVybiBlbFxuXG59O1xuXG4vKipcbiAqIFNwZWNpYWxpemVkIGZ1bmN0aW9uIGZvciBsb29waW5nIGFuIGFycmF5LWxpa2UgY29sbGVjdGlvbiB3aXRoIGBlYWNoPXt9YFxuICogQHBhcmFtICAgeyBBcnJheSB9IGxpc3QgLSBjb2xsZWN0aW9uIG9mIGl0ZW1zXG4gKiBAcGFyYW0gICB7RnVuY3Rpb259IGZuIC0gY2FsbGJhY2sgZnVuY3Rpb25cbiAqIEByZXR1cm5zIHsgQXJyYXkgfSB0aGUgYXJyYXkgbG9vcGVkXG4gKi9cbmZ1bmN0aW9uIGVhY2gobGlzdCwgZm4pIHtcbiAgdmFyIGxlbiA9IGxpc3QgPyBsaXN0Lmxlbmd0aCA6IDA7XG4gIHZhciBpID0gMDtcbiAgZm9yICg7IGkgPCBsZW47ICsraSkge1xuICAgIGZuKGxpc3RbaV0sIGkpO1xuICB9XG4gIHJldHVybiBsaXN0XG59XG5cbi8qKlxuICogQ2hlY2sgd2hldGhlciBhbiBhcnJheSBjb250YWlucyBhbiBpdGVtXG4gKiBAcGFyYW0gICB7IEFycmF5IH0gYXJyYXkgLSB0YXJnZXQgYXJyYXlcbiAqIEBwYXJhbSAgIHsgKiB9IGl0ZW0gLSBpdGVtIHRvIHRlc3RcbiAqIEByZXR1cm5zIHsgQm9vbGVhbiB9IC1cbiAqL1xuZnVuY3Rpb24gY29udGFpbnMoYXJyYXksIGl0ZW0pIHtcbiAgcmV0dXJuIGFycmF5LmluZGV4T2YoaXRlbSkgIT09IC0xXG59XG5cbi8qKlxuICogQ29udmVydCBhIHN0cmluZyBjb250YWluaW5nIGRhc2hlcyB0byBjYW1lbCBjYXNlXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IHN0ciAtIGlucHV0IHN0cmluZ1xuICogQHJldHVybnMgeyBTdHJpbmcgfSBteS1zdHJpbmcgLT4gbXlTdHJpbmdcbiAqL1xuZnVuY3Rpb24gdG9DYW1lbChzdHIpIHtcbiAgcmV0dXJuIHN0ci5yZXBsYWNlKC8tKFxcdykvZywgZnVuY3Rpb24gKF8sIGMpIHsgcmV0dXJuIGMudG9VcHBlckNhc2UoKTsgfSlcbn1cblxuLyoqXG4gKiBGYXN0ZXIgU3RyaW5nIHN0YXJ0c1dpdGggYWx0ZXJuYXRpdmVcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gc3RyIC0gc291cmNlIHN0cmluZ1xuICogQHBhcmFtICAgeyBTdHJpbmcgfSB2YWx1ZSAtIHRlc3Qgc3RyaW5nXG4gKiBAcmV0dXJucyB7IEJvb2xlYW4gfSAtXG4gKi9cbmZ1bmN0aW9uIHN0YXJ0c1dpdGgoc3RyLCB2YWx1ZSkge1xuICByZXR1cm4gc3RyLnNsaWNlKDAsIHZhbHVlLmxlbmd0aCkgPT09IHZhbHVlXG59XG5cbi8qKlxuICogSGVscGVyIGZ1bmN0aW9uIHRvIHNldCBhbiBpbW11dGFibGUgcHJvcGVydHlcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZWwgLSBvYmplY3Qgd2hlcmUgdGhlIG5ldyBwcm9wZXJ0eSB3aWxsIGJlIHNldFxuICogQHBhcmFtICAgeyBTdHJpbmcgfSBrZXkgLSBvYmplY3Qga2V5IHdoZXJlIHRoZSBuZXcgcHJvcGVydHkgd2lsbCBiZSBzdG9yZWRcbiAqIEBwYXJhbSAgIHsgKiB9IHZhbHVlIC0gdmFsdWUgb2YgdGhlIG5ldyBwcm9wZXJ0eVxuICogQHBhcmFtICAgeyBPYmplY3QgfSBvcHRpb25zIC0gc2V0IHRoZSBwcm9wZXJ5IG92ZXJyaWRpbmcgdGhlIGRlZmF1bHQgb3B0aW9uc1xuICogQHJldHVybnMgeyBPYmplY3QgfSAtIHRoZSBpbml0aWFsIG9iamVjdFxuICovXG5mdW5jdGlvbiBkZWZpbmVQcm9wZXJ0eShlbCwga2V5LCB2YWx1ZSwgb3B0aW9ucykge1xuICBPYmplY3QuZGVmaW5lUHJvcGVydHkoZWwsIGtleSwgZXh0ZW5kKHtcbiAgICB2YWx1ZTogdmFsdWUsXG4gICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgd3JpdGFibGU6IGZhbHNlLFxuICAgIGNvbmZpZ3VyYWJsZTogdHJ1ZVxuICB9LCBvcHRpb25zKSk7XG4gIHJldHVybiBlbFxufVxuXG4vKipcbiAqIEV4dGVuZCBhbnkgb2JqZWN0IHdpdGggb3RoZXIgcHJvcGVydGllc1xuICogQHBhcmFtICAgeyBPYmplY3QgfSBzcmMgLSBzb3VyY2Ugb2JqZWN0XG4gKiBAcmV0dXJucyB7IE9iamVjdCB9IHRoZSByZXN1bHRpbmcgZXh0ZW5kZWQgb2JqZWN0XG4gKlxuICogdmFyIG9iaiA9IHsgZm9vOiAnYmF6JyB9XG4gKiBleHRlbmQob2JqLCB7YmFyOiAnYmFyJywgZm9vOiAnYmFyJ30pXG4gKiBjb25zb2xlLmxvZyhvYmopID0+IHtiYXI6ICdiYXInLCBmb286ICdiYXInfVxuICpcbiAqL1xuZnVuY3Rpb24gZXh0ZW5kKHNyYykge1xuICB2YXIgb2JqLCBhcmdzID0gYXJndW1lbnRzO1xuICBmb3IgKHZhciBpID0gMTsgaSA8IGFyZ3MubGVuZ3RoOyArK2kpIHtcbiAgICBpZiAob2JqID0gYXJnc1tpXSkge1xuICAgICAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgICAgICAvLyBjaGVjayBpZiB0aGlzIHByb3BlcnR5IG9mIHRoZSBzb3VyY2Ugb2JqZWN0IGNvdWxkIGJlIG92ZXJyaWRkZW5cbiAgICAgICAgaWYgKGlzV3JpdGFibGUoc3JjLCBrZXkpKVxuICAgICAgICAgIHsgc3JjW2tleV0gPSBvYmpba2V5XTsgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gc3JjXG59XG5cbnZhciBtaXNjID0gT2JqZWN0LmZyZWV6ZSh7XG5cdGVhY2g6IGVhY2gsXG5cdGNvbnRhaW5zOiBjb250YWlucyxcblx0dG9DYW1lbDogdG9DYW1lbCxcblx0c3RhcnRzV2l0aDogc3RhcnRzV2l0aCxcblx0ZGVmaW5lUHJvcGVydHk6IGRlZmluZVByb3BlcnR5LFxuXHRleHRlbmQ6IGV4dGVuZFxufSk7XG5cbnZhciBzZXR0aW5ncyQxID0gZXh0ZW5kKE9iamVjdC5jcmVhdGUoYnJhY2tldHMuc2V0dGluZ3MpLCB7XG4gIHNraXBBbm9ueW1vdXNUYWdzOiB0cnVlXG59KTtcblxudmFyIEVWRU5UU19QUkVGSVhfUkVHRVggPSAvXm9uLztcblxuLyoqXG4gKiBUcmlnZ2VyIERPTSBldmVudHNcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSBkb20gLSBkb20gZWxlbWVudCB0YXJnZXQgb2YgdGhlIGV2ZW50XG4gKiBAcGFyYW0gICB7IEZ1bmN0aW9uIH0gaGFuZGxlciAtIHVzZXIgZnVuY3Rpb25cbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZSAtIGV2ZW50IG9iamVjdFxuICovXG5mdW5jdGlvbiBoYW5kbGVFdmVudChkb20sIGhhbmRsZXIsIGUpIHtcbiAgdmFyIHB0YWcgPSB0aGlzLl9fLnBhcmVudCxcbiAgICBpdGVtID0gdGhpcy5fXy5pdGVtO1xuXG4gIGlmICghaXRlbSlcbiAgICB7IHdoaWxlIChwdGFnICYmICFpdGVtKSB7XG4gICAgICBpdGVtID0gcHRhZy5fXy5pdGVtO1xuICAgICAgcHRhZyA9IHB0YWcuX18ucGFyZW50O1xuICAgIH0gfVxuXG4gIC8vIG92ZXJyaWRlIHRoZSBldmVudCBwcm9wZXJ0aWVzXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gIGlmIChpc1dyaXRhYmxlKGUsICdjdXJyZW50VGFyZ2V0JykpIHsgZS5jdXJyZW50VGFyZ2V0ID0gZG9tOyB9XG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gIGlmIChpc1dyaXRhYmxlKGUsICd0YXJnZXQnKSkgeyBlLnRhcmdldCA9IGUuc3JjRWxlbWVudDsgfVxuICAvKiBpc3RhbmJ1bCBpZ25vcmUgbmV4dCAqL1xuICBpZiAoaXNXcml0YWJsZShlLCAnd2hpY2gnKSkgeyBlLndoaWNoID0gZS5jaGFyQ29kZSB8fCBlLmtleUNvZGU7IH1cblxuICBlLml0ZW0gPSBpdGVtO1xuXG4gIGhhbmRsZXIuY2FsbCh0aGlzLCBlKTtcblxuICBpZiAoIWUucHJldmVudFVwZGF0ZSkge1xuICAgIHZhciBwID0gZ2V0SW1tZWRpYXRlQ3VzdG9tUGFyZW50VGFnKHRoaXMpO1xuICAgIC8vIGZpeGVzICMyMDgzXG4gICAgaWYgKHAuaXNNb3VudGVkKSB7IHAudXBkYXRlKCk7IH1cbiAgfVxufVxuXG4vKipcbiAqIEF0dGFjaCBhbiBldmVudCB0byBhIERPTSBub2RlXG4gKiBAcGFyYW0geyBTdHJpbmcgfSBuYW1lIC0gZXZlbnQgbmFtZVxuICogQHBhcmFtIHsgRnVuY3Rpb24gfSBoYW5kbGVyIC0gZXZlbnQgY2FsbGJhY2tcbiAqIEBwYXJhbSB7IE9iamVjdCB9IGRvbSAtIGRvbSBub2RlXG4gKiBAcGFyYW0geyBUYWcgfSB0YWcgLSB0YWcgaW5zdGFuY2VcbiAqL1xuZnVuY3Rpb24gc2V0RXZlbnRIYW5kbGVyKG5hbWUsIGhhbmRsZXIsIGRvbSwgdGFnKSB7XG4gIHZhciBldmVudE5hbWUsXG4gICAgY2IgPSBoYW5kbGVFdmVudC5iaW5kKHRhZywgZG9tLCBoYW5kbGVyKTtcblxuICAvLyBhdm9pZCB0byBiaW5kIHR3aWNlIHRoZSBzYW1lIGV2ZW50XG4gIGRvbVtuYW1lXSA9IG51bGw7XG5cbiAgLy8gbm9ybWFsaXplIGV2ZW50IG5hbWVcbiAgZXZlbnROYW1lID0gbmFtZS5yZXBsYWNlKEVWRU5UU19QUkVGSVhfUkVHRVgsICcnKTtcblxuICAvLyBjYWNoZSB0aGUgY2FsbGJhY2sgZGlyZWN0bHkgb24gdGhlIERPTSBub2RlXG4gIGlmICghZG9tLl9yaW90RXZlbnRzKSB7IGRvbS5fcmlvdEV2ZW50cyA9IHt9OyB9XG5cbiAgaWYgKGRvbS5fcmlvdEV2ZW50c1tuYW1lXSlcbiAgICB7IGRvbS5yZW1vdmVFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZG9tLl9yaW90RXZlbnRzW25hbWVdKTsgfVxuXG4gIGRvbS5fcmlvdEV2ZW50c1tuYW1lXSA9IGNiO1xuICBkb20uYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUsIGNiLCBmYWxzZSk7XG59XG5cbi8qKlxuICogVXBkYXRlIGR5bmFtaWNhbGx5IGNyZWF0ZWQgZGF0YS1pcyB0YWdzIHdpdGggY2hhbmdpbmcgZXhwcmVzc2lvbnNcbiAqIEBwYXJhbSB7IE9iamVjdCB9IGV4cHIgLSBleHByZXNzaW9uIHRhZyBhbmQgZXhwcmVzc2lvbiBpbmZvXG4gKiBAcGFyYW0geyBUYWcgfSAgICBwYXJlbnQgLSBwYXJlbnQgZm9yIHRhZyBjcmVhdGlvblxuICogQHBhcmFtIHsgU3RyaW5nIH0gdGFnTmFtZSAtIHRhZyBpbXBsZW1lbnRhdGlvbiB3ZSB3YW50IHRvIHVzZVxuICovXG5mdW5jdGlvbiB1cGRhdGVEYXRhSXMoZXhwciwgcGFyZW50LCB0YWdOYW1lKSB7XG4gIHZhciBjb25mLCBpc1ZpcnR1YWwsIGhlYWQsIHJlZjtcblxuICBpZiAoZXhwci50YWcgJiYgZXhwci50YWdOYW1lID09PSB0YWdOYW1lKSB7XG4gICAgZXhwci50YWcudXBkYXRlKCk7XG4gICAgcmV0dXJuXG4gIH1cblxuICBpc1ZpcnR1YWwgPSBleHByLmRvbS50YWdOYW1lID09PSAnVklSVFVBTCc7XG4gIC8vIHN5bmMgX3BhcmVudCB0byBhY2NvbW1vZGF0ZSBjaGFuZ2luZyB0YWduYW1lc1xuICBpZiAoZXhwci50YWcpIHtcblxuICAgIC8vIG5lZWQgcGxhY2Vob2xkZXIgYmVmb3JlIHVubW91bnRcbiAgICBpZihpc1ZpcnR1YWwpIHtcbiAgICAgIGhlYWQgPSBleHByLnRhZy5fXy5oZWFkO1xuICAgICAgcmVmID0gY3JlYXRlRE9NUGxhY2Vob2xkZXIoKTtcbiAgICAgIGhlYWQucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocmVmLCBoZWFkKTtcbiAgICB9XG5cbiAgICBleHByLnRhZy51bm1vdW50KHRydWUpO1xuICB9XG5cbiAgZXhwci5pbXBsID0gX19UQUdfSU1QTFt0YWdOYW1lXTtcbiAgY29uZiA9IHtyb290OiBleHByLmRvbSwgcGFyZW50OiBwYXJlbnQsIGhhc0ltcGw6IHRydWUsIHRhZ05hbWU6IHRhZ05hbWV9O1xuICBleHByLnRhZyA9IGluaXRDaGlsZFRhZyhleHByLmltcGwsIGNvbmYsIGV4cHIuZG9tLmlubmVySFRNTCwgcGFyZW50KTtcbiAgZWFjaChleHByLmF0dHJzLCBmdW5jdGlvbiAoYSkgeyByZXR1cm4gc2V0QXR0cihleHByLnRhZy5yb290LCBhLm5hbWUsIGEudmFsdWUpOyB9KTtcbiAgZXhwci50YWdOYW1lID0gdGFnTmFtZTtcbiAgZXhwci50YWcubW91bnQoKTtcbiAgaWYgKGlzVmlydHVhbClcbiAgICB7IG1ha2VSZXBsYWNlVmlydHVhbChleHByLnRhZywgcmVmIHx8IGV4cHIudGFnLnJvb3QpOyB9IC8vIHJvb3QgZXhpc3QgZmlyc3QgdGltZSwgYWZ0ZXIgdXNlIHBsYWNlaG9sZGVyXG5cbiAgLy8gcGFyZW50IGlzIHRoZSBwbGFjZWhvbGRlciB0YWcsIG5vdCB0aGUgZHluYW1pYyB0YWcgc28gY2xlYW4gdXBcbiAgcGFyZW50Ll9fLm9uVW5tb3VudCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBkZWxOYW1lID0gZXhwci50YWcub3B0cy5kYXRhSXMsXG4gICAgICB0YWdzID0gZXhwci50YWcucGFyZW50LnRhZ3MsXG4gICAgICBfdGFncyA9IGV4cHIudGFnLl9fLnBhcmVudC50YWdzO1xuICAgIGFycmF5aXNoUmVtb3ZlKHRhZ3MsIGRlbE5hbWUsIGV4cHIudGFnKTtcbiAgICBhcnJheWlzaFJlbW92ZShfdGFncywgZGVsTmFtZSwgZXhwci50YWcpO1xuICAgIGV4cHIudGFnLnVubW91bnQoKTtcbiAgfTtcbn1cblxuLyoqXG4gKiBOb21hbGl6ZSBhbnkgYXR0cmlidXRlIHJlbW92aW5nIHRoZSBcInJpb3QtXCIgcHJlZml4XG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IGF0dHJOYW1lIC0gb3JpZ2luYWwgYXR0cmlidXRlIG5hbWVcbiAqIEByZXR1cm5zIHsgU3RyaW5nIH0gdmFsaWQgaHRtbCBhdHRyaWJ1dGUgbmFtZVxuICovXG5mdW5jdGlvbiBub3JtYWxpemVBdHRyTmFtZShhdHRyTmFtZSkge1xuICBpZiAoIWF0dHJOYW1lKSB7IHJldHVybiBudWxsIH1cbiAgYXR0ck5hbWUgPSBhdHRyTmFtZS5yZXBsYWNlKEFUVFJTX1BSRUZJWCwgJycpO1xuICBpZiAoQ0FTRV9TRU5TSVRJVkVfQVRUUklCVVRFU1thdHRyTmFtZV0pIHsgYXR0ck5hbWUgPSBDQVNFX1NFTlNJVElWRV9BVFRSSUJVVEVTW2F0dHJOYW1lXTsgfVxuICByZXR1cm4gYXR0ck5hbWVcbn1cblxuLyoqXG4gKiBVcGRhdGUgb24gc2luZ2xlIHRhZyBleHByZXNzaW9uXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSB7IE9iamVjdCB9IGV4cHIgLSBleHByZXNzaW9uIGxvZ2ljXG4gKiBAcmV0dXJucyB7IHVuZGVmaW5lZCB9XG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZUV4cHJlc3Npb24oZXhwcikge1xuICBpZiAodGhpcy5yb290ICYmIGdldEF0dHIodGhpcy5yb290LCd2aXJ0dWFsaXplZCcpKSB7IHJldHVybiB9XG5cbiAgdmFyIGRvbSA9IGV4cHIuZG9tLFxuICAgIC8vIHJlbW92ZSB0aGUgcmlvdC0gcHJlZml4XG4gICAgYXR0ck5hbWUgPSBub3JtYWxpemVBdHRyTmFtZShleHByLmF0dHIpLFxuICAgIGlzVG9nZ2xlID0gY29udGFpbnMoW1NIT1dfRElSRUNUSVZFLCBISURFX0RJUkVDVElWRV0sIGF0dHJOYW1lKSxcbiAgICBpc1ZpcnR1YWwgPSBleHByLnJvb3QgJiYgZXhwci5yb290LnRhZ05hbWUgPT09ICdWSVJUVUFMJyxcbiAgICBwYXJlbnQgPSBkb20gJiYgKGV4cHIucGFyZW50IHx8IGRvbS5wYXJlbnROb2RlKSxcbiAgICAvLyBkZXRlY3QgdGhlIHN0eWxlIGF0dHJpYnV0ZXNcbiAgICBpc1N0eWxlQXR0ciA9IGF0dHJOYW1lID09PSAnc3R5bGUnLFxuICAgIGlzQ2xhc3NBdHRyID0gYXR0ck5hbWUgPT09ICdjbGFzcycsXG4gICAgaXNPYmosXG4gICAgdmFsdWU7XG5cbiAgLy8gaWYgaXQncyBhIHRhZyB3ZSBjb3VsZCB0b3RhbGx5IHNraXAgdGhlIHJlc3RcbiAgaWYgKGV4cHIuX3Jpb3RfaWQpIHtcbiAgICBpZiAoZXhwci5pc01vdW50ZWQpIHtcbiAgICAgIGV4cHIudXBkYXRlKCk7XG4gICAgLy8gaWYgaXQgaGFzbid0IGJlZW4gbW91bnRlZCB5ZXQsIGRvIHRoYXQgbm93LlxuICAgIH0gZWxzZSB7XG4gICAgICBleHByLm1vdW50KCk7XG4gICAgICBpZiAoaXNWaXJ0dWFsKSB7XG4gICAgICAgIG1ha2VSZXBsYWNlVmlydHVhbChleHByLCBleHByLnJvb3QpO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm5cbiAgfVxuICAvLyBpZiB0aGlzIGV4cHJlc3Npb24gaGFzIHRoZSB1cGRhdGUgbWV0aG9kIGl0IG1lYW5zIGl0IGNhbiBoYW5kbGUgdGhlIERPTSBjaGFuZ2VzIGJ5IGl0c2VsZlxuICBpZiAoZXhwci51cGRhdGUpIHsgcmV0dXJuIGV4cHIudXBkYXRlKCkgfVxuXG4gIC8vIC4uLml0IHNlZW1zIHRvIGJlIGEgc2ltcGxlIGV4cHJlc3Npb24gc28gd2UgdHJ5IHRvIGNhbGN1bGF0IGl0cyB2YWx1ZVxuICB2YWx1ZSA9IHRtcGwoZXhwci5leHByLCB0aGlzKTtcbiAgaXNPYmogPSBpc09iamVjdCh2YWx1ZSk7XG5cbiAgLy8gY29udmVydCB0aGUgc3R5bGUvY2xhc3Mgb2JqZWN0cyB0byBzdHJpbmdzXG4gIGlmIChpc09iaikge1xuICAgIGlzT2JqID0gIWlzQ2xhc3NBdHRyICYmICFpc1N0eWxlQXR0cjtcbiAgICBpZiAoaXNDbGFzc0F0dHIpIHtcbiAgICAgIHZhbHVlID0gdG1wbChKU09OLnN0cmluZ2lmeSh2YWx1ZSksIHRoaXMpO1xuICAgIH0gZWxzZSBpZiAoaXNTdHlsZUF0dHIpIHtcbiAgICAgIHZhbHVlID0gc3R5bGVPYmplY3RUb1N0cmluZyh2YWx1ZSk7XG4gICAgfVxuICB9XG5cbiAgLy8gZm9yIHRoZSBib29sZWFuIGF0dHJpYnV0ZXMgd2UgZG9uJ3QgbmVlZCB0aGUgdmFsdWVcbiAgLy8gd2UgY2FuIGNvbnZlcnQgaXQgdG8gY2hlY2tlZD10cnVlIHRvIGNoZWNrZWQ9Y2hlY2tlZFxuICBpZiAoZXhwci5ib29sKSB7IHZhbHVlID0gdmFsdWUgPyBhdHRyTmFtZSA6IGZhbHNlOyB9XG4gIGlmIChleHByLmlzUnRhZykgeyByZXR1cm4gdXBkYXRlRGF0YUlzKGV4cHIsIHRoaXMsIHZhbHVlKSB9XG4gIGlmIChleHByLndhc1BhcnNlZE9uY2UgJiYgZXhwci52YWx1ZSA9PT0gdmFsdWUpIHsgcmV0dXJuIH1cblxuICAvLyB1cGRhdGUgdGhlIGV4cHJlc3Npb24gdmFsdWVcbiAgZXhwci52YWx1ZSA9IHZhbHVlO1xuICBleHByLndhc1BhcnNlZE9uY2UgPSB0cnVlO1xuXG4gIC8vIGlmIHRoZSB2YWx1ZSBpcyBhbiBvYmplY3Qgd2UgY2FuIG5vdCBkbyBtdWNoIG1vcmUgd2l0aCBpdFxuICBpZiAoaXNPYmopIHsgcmV0dXJuIH1cblxuICAvLyB0ZXh0YXJlYSBhbmQgdGV4dCBub2RlcyBoYXZlIG5vIGF0dHJpYnV0ZSBuYW1lXG4gIGlmICghYXR0ck5hbWUpIHtcbiAgICAvLyBhYm91dCAjODE1IHcvbyByZXBsYWNlOiB0aGUgYnJvd3NlciBjb252ZXJ0cyB0aGUgdmFsdWUgdG8gYSBzdHJpbmcsXG4gICAgLy8gdGhlIGNvbXBhcmlzb24gYnkgXCI9PVwiIGRvZXMgdG9vLCBidXQgbm90IGluIHRoZSBzZXJ2ZXJcbiAgICB2YWx1ZSArPSAnJztcbiAgICAvLyB0ZXN0IGZvciBwYXJlbnQgYXZvaWRzIGVycm9yIHdpdGggaW52YWxpZCBhc3NpZ25tZW50IHRvIG5vZGVWYWx1ZVxuICAgIGlmIChwYXJlbnQpIHtcbiAgICAgIC8vIGNhY2hlIHRoZSBwYXJlbnQgbm9kZSBiZWNhdXNlIHNvbWVob3cgaXQgd2lsbCBiZWNvbWUgbnVsbCBvbiBJRVxuICAgICAgLy8gb24gdGhlIG5leHQgaXRlcmF0aW9uXG4gICAgICBleHByLnBhcmVudCA9IHBhcmVudDtcbiAgICAgIGlmIChwYXJlbnQudGFnTmFtZSA9PT0gJ1RFWFRBUkVBJykge1xuICAgICAgICBwYXJlbnQudmFsdWUgPSB2YWx1ZTsgICAgICAgICAgICAgICAgICAgIC8vICMxMTEzXG4gICAgICAgIGlmICghSUVfVkVSU0lPTikgeyBkb20ubm9kZVZhbHVlID0gdmFsdWU7IH0gIC8vICMxNjI1IElFIHRocm93cyBoZXJlLCBub2RlVmFsdWVcbiAgICAgIH0gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdpbGwgYmUgYXZhaWxhYmxlIG9uICd1cGRhdGVkJ1xuICAgICAgZWxzZSB7IGRvbS5ub2RlVmFsdWUgPSB2YWx1ZTsgfVxuICAgIH1cbiAgICByZXR1cm5cbiAgfVxuXG4gIC8vIHJlbW92ZSBvcmlnaW5hbCBhdHRyaWJ1dGVcbiAgaWYgKCFleHByLmlzQXR0clJlbW92ZWQgfHwgIXZhbHVlKSB7XG4gICAgcmVtQXR0cihkb20sIGV4cHIuYXR0cik7XG4gICAgZXhwci5pc0F0dHJSZW1vdmVkID0gdHJ1ZTtcbiAgfVxuXG4gIC8vIGV2ZW50IGhhbmRsZXJcbiAgaWYgKGlzRnVuY3Rpb24odmFsdWUpKSB7XG4gICAgc2V0RXZlbnRIYW5kbGVyKGF0dHJOYW1lLCB2YWx1ZSwgZG9tLCB0aGlzKTtcbiAgLy8gc2hvdyAvIGhpZGVcbiAgfSBlbHNlIGlmIChpc1RvZ2dsZSkge1xuICAgIHRvZ2dsZVZpc2liaWxpdHkoZG9tLCBhdHRyTmFtZSA9PT0gSElERV9ESVJFQ1RJVkUgPyAhdmFsdWUgOiB2YWx1ZSk7XG4gIC8vIGhhbmRsZSBhdHRyaWJ1dGVzXG4gIH0gZWxzZSB7XG4gICAgaWYgKGV4cHIuYm9vbCkge1xuICAgICAgZG9tW2F0dHJOYW1lXSA9IHZhbHVlO1xuICAgIH1cblxuICAgIGlmIChhdHRyTmFtZSA9PT0gJ3ZhbHVlJyAmJiBkb20udmFsdWUgIT09IHZhbHVlKSB7XG4gICAgICBkb20udmFsdWUgPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBpZiAoIWlzQmxhbmsodmFsdWUpICYmIHZhbHVlICE9PSBmYWxzZSkge1xuICAgICAgc2V0QXR0cihkb20sIGF0dHJOYW1lLCB2YWx1ZSk7XG4gICAgfVxuXG4gICAgLy8gbWFrZSBzdXJlIHRoYXQgaW4gY2FzZSBvZiBzdHlsZSBjaGFuZ2VzXG4gICAgLy8gdGhlIGVsZW1lbnQgc3RheXMgaGlkZGVuXG4gICAgaWYgKGlzU3R5bGVBdHRyICYmIGRvbS5oaWRkZW4pIHsgdG9nZ2xlVmlzaWJpbGl0eShkb20sIGZhbHNlKTsgfVxuICB9XG59XG5cbi8qKlxuICogVXBkYXRlIGFsbCB0aGUgZXhwcmVzc2lvbnMgaW4gYSBUYWcgaW5zdGFuY2VcbiAqIEB0aGlzIFRhZ1xuICogQHBhcmFtIHsgQXJyYXkgfSBleHByZXNzaW9ucyAtIGV4cHJlc3Npb24gdGhhdCBtdXN0IGJlIHJlIGV2YWx1YXRlZFxuICovXG5mdW5jdGlvbiB1cGRhdGVBbGxFeHByZXNzaW9ucyhleHByZXNzaW9ucykge1xuICBlYWNoKGV4cHJlc3Npb25zLCB1cGRhdGVFeHByZXNzaW9uLmJpbmQodGhpcykpO1xufVxuXG52YXIgSWZFeHByID0ge1xuICBpbml0OiBmdW5jdGlvbiBpbml0KGRvbSwgdGFnLCBleHByKSB7XG4gICAgcmVtQXR0cihkb20sIENPTkRJVElPTkFMX0RJUkVDVElWRSk7XG4gICAgdGhpcy50YWcgPSB0YWc7XG4gICAgdGhpcy5leHByID0gZXhwcjtcbiAgICB0aGlzLnN0dWIgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnJyk7XG4gICAgdGhpcy5wcmlzdGluZSA9IGRvbTtcblxuICAgIHZhciBwID0gZG9tLnBhcmVudE5vZGU7XG4gICAgcC5pbnNlcnRCZWZvcmUodGhpcy5zdHViLCBkb20pO1xuICAgIHAucmVtb3ZlQ2hpbGQoZG9tKTtcblxuICAgIHJldHVybiB0aGlzXG4gIH0sXG4gIHVwZGF0ZTogZnVuY3Rpb24gdXBkYXRlKCkge1xuICAgIHRoaXMudmFsdWUgPSB0bXBsKHRoaXMuZXhwciwgdGhpcy50YWcpO1xuXG4gICAgaWYgKHRoaXMudmFsdWUgJiYgIXRoaXMuY3VycmVudCkgeyAvLyBpbnNlcnRcbiAgICAgIHRoaXMuY3VycmVudCA9IHRoaXMucHJpc3RpbmUuY2xvbmVOb2RlKHRydWUpO1xuICAgICAgdGhpcy5zdHViLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKHRoaXMuY3VycmVudCwgdGhpcy5zdHViKTtcbiAgICAgIHRoaXMuZXhwcmVzc2lvbnMgPSBbXTtcbiAgICAgIHBhcnNlRXhwcmVzc2lvbnMuYXBwbHkodGhpcy50YWcsIFt0aGlzLmN1cnJlbnQsIHRoaXMuZXhwcmVzc2lvbnMsIHRydWVdKTtcbiAgICB9IGVsc2UgaWYgKCF0aGlzLnZhbHVlICYmIHRoaXMuY3VycmVudCkgeyAvLyByZW1vdmVcbiAgICAgIHVubW91bnRBbGwodGhpcy5leHByZXNzaW9ucyk7XG4gICAgICBpZiAodGhpcy5jdXJyZW50Ll90YWcpIHtcbiAgICAgICAgdGhpcy5jdXJyZW50Ll90YWcudW5tb3VudCgpO1xuICAgICAgfSBlbHNlIGlmICh0aGlzLmN1cnJlbnQucGFyZW50Tm9kZSlcbiAgICAgICAgeyB0aGlzLmN1cnJlbnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLmN1cnJlbnQpOyB9XG4gICAgICB0aGlzLmN1cnJlbnQgPSBudWxsO1xuICAgICAgdGhpcy5leHByZXNzaW9ucyA9IFtdO1xuICAgIH1cblxuICAgIGlmICh0aGlzLnZhbHVlKSB7IHVwZGF0ZUFsbEV4cHJlc3Npb25zLmNhbGwodGhpcy50YWcsIHRoaXMuZXhwcmVzc2lvbnMpOyB9XG4gIH0sXG4gIHVubW91bnQ6IGZ1bmN0aW9uIHVubW91bnQoKSB7XG4gICAgdW5tb3VudEFsbCh0aGlzLmV4cHJlc3Npb25zIHx8IFtdKTtcbiAgICBkZWxldGUgdGhpcy5wcmlzdGluZTtcbiAgICBkZWxldGUgdGhpcy5wYXJlbnROb2RlO1xuICAgIGRlbGV0ZSB0aGlzLnN0dWI7XG4gIH1cbn07XG5cbnZhciBSZWZFeHByID0ge1xuICBpbml0OiBmdW5jdGlvbiBpbml0KGRvbSwgcGFyZW50LCBhdHRyTmFtZSwgYXR0clZhbHVlKSB7XG4gICAgdGhpcy5kb20gPSBkb207XG4gICAgdGhpcy5hdHRyID0gYXR0ck5hbWU7XG4gICAgdGhpcy5yYXdWYWx1ZSA9IGF0dHJWYWx1ZTtcbiAgICB0aGlzLnBhcmVudCA9IHBhcmVudDtcbiAgICB0aGlzLmhhc0V4cCA9IHRtcGwuaGFzRXhwcihhdHRyVmFsdWUpO1xuICAgIHJldHVybiB0aGlzXG4gIH0sXG4gIHVwZGF0ZTogZnVuY3Rpb24gdXBkYXRlKCkge1xuICAgIHZhciBvbGQgPSB0aGlzLnZhbHVlO1xuICAgIHZhciBjdXN0b21QYXJlbnQgPSB0aGlzLnBhcmVudCAmJiBnZXRJbW1lZGlhdGVDdXN0b21QYXJlbnRUYWcodGhpcy5wYXJlbnQpO1xuICAgIC8vIGlmIHRoZSByZWZlcmVuY2VkIGVsZW1lbnQgaXMgYSBjdXN0b20gdGFnLCB0aGVuIHdlIHNldCB0aGUgdGFnIGl0c2VsZiwgcmF0aGVyIHRoYW4gRE9NXG4gICAgdmFyIHRhZ09yRG9tID0gdGhpcy50YWcgfHwgdGhpcy5kb207XG5cbiAgICB0aGlzLnZhbHVlID0gdGhpcy5oYXNFeHAgPyB0bXBsKHRoaXMucmF3VmFsdWUsIHRoaXMucGFyZW50KSA6IHRoaXMucmF3VmFsdWU7XG5cbiAgICAvLyB0aGUgbmFtZSBjaGFuZ2VkLCBzbyB3ZSBuZWVkIHRvIHJlbW92ZSBpdCBmcm9tIHRoZSBvbGQga2V5IChpZiBwcmVzZW50KVxuICAgIGlmICghaXNCbGFuayhvbGQpICYmIGN1c3RvbVBhcmVudCkgeyBhcnJheWlzaFJlbW92ZShjdXN0b21QYXJlbnQucmVmcywgb2xkLCB0YWdPckRvbSk7IH1cblxuICAgIGlmIChpc0JsYW5rKHRoaXMudmFsdWUpKSB7XG4gICAgICAvLyBpZiB0aGUgdmFsdWUgaXMgYmxhbmssIHdlIHJlbW92ZSBpdFxuICAgICAgcmVtQXR0cih0aGlzLmRvbSwgdGhpcy5hdHRyKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gYWRkIGl0IHRvIHRoZSByZWZzIG9mIHBhcmVudCB0YWcgKHRoaXMgYmVoYXZpb3Igd2FzIGNoYW5nZWQgPj0zLjApXG4gICAgICBpZiAoY3VzdG9tUGFyZW50KSB7IGFycmF5aXNoQWRkKFxuICAgICAgICBjdXN0b21QYXJlbnQucmVmcyxcbiAgICAgICAgdGhpcy52YWx1ZSxcbiAgICAgICAgdGFnT3JEb20sXG4gICAgICAgIC8vIHVzZSBhbiBhcnJheSBpZiBpdCdzIGEgbG9vcGVkIG5vZGUgYW5kIHRoZSByZWYgaXMgbm90IGFuIGV4cHJlc3Npb25cbiAgICAgICAgbnVsbCxcbiAgICAgICAgdGhpcy5wYXJlbnQuX18uaW5kZXhcbiAgICAgICk7IH1cbiAgICAgIC8vIHNldCB0aGUgYWN0dWFsIERPTSBhdHRyXG4gICAgICBzZXRBdHRyKHRoaXMuZG9tLCB0aGlzLmF0dHIsIHRoaXMudmFsdWUpO1xuICAgIH1cbiAgfSxcbiAgdW5tb3VudDogZnVuY3Rpb24gdW5tb3VudCgpIHtcbiAgICB2YXIgdGFnT3JEb20gPSB0aGlzLnRhZyB8fCB0aGlzLmRvbTtcbiAgICB2YXIgY3VzdG9tUGFyZW50ID0gdGhpcy5wYXJlbnQgJiYgZ2V0SW1tZWRpYXRlQ3VzdG9tUGFyZW50VGFnKHRoaXMucGFyZW50KTtcbiAgICBpZiAoIWlzQmxhbmsodGhpcy52YWx1ZSkgJiYgY3VzdG9tUGFyZW50KVxuICAgICAgeyBhcnJheWlzaFJlbW92ZShjdXN0b21QYXJlbnQucmVmcywgdGhpcy52YWx1ZSwgdGFnT3JEb20pOyB9XG4gICAgZGVsZXRlIHRoaXMuZG9tO1xuICAgIGRlbGV0ZSB0aGlzLnBhcmVudDtcbiAgfVxufTtcblxuLyoqXG4gKiBDb252ZXJ0IHRoZSBpdGVtIGxvb3BlZCBpbnRvIGFuIG9iamVjdCB1c2VkIHRvIGV4dGVuZCB0aGUgY2hpbGQgdGFnIHByb3BlcnRpZXNcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZXhwciAtIG9iamVjdCBjb250YWluaW5nIHRoZSBrZXlzIHVzZWQgdG8gZXh0ZW5kIHRoZSBjaGlsZHJlbiB0YWdzXG4gKiBAcGFyYW0gICB7ICogfSBrZXkgLSB2YWx1ZSB0byBhc3NpZ24gdG8gdGhlIG5ldyBvYmplY3QgcmV0dXJuZWRcbiAqIEBwYXJhbSAgIHsgKiB9IHZhbCAtIHZhbHVlIGNvbnRhaW5pbmcgdGhlIHBvc2l0aW9uIG9mIHRoZSBpdGVtIGluIHRoZSBhcnJheVxuICogQHBhcmFtICAgeyBPYmplY3QgfSBiYXNlIC0gcHJvdG90eXBlIG9iamVjdCBmb3IgdGhlIG5ldyBpdGVtXG4gKiBAcmV0dXJucyB7IE9iamVjdCB9IC0gbmV3IG9iamVjdCBjb250YWluaW5nIHRoZSB2YWx1ZXMgb2YgdGhlIG9yaWdpbmFsIGl0ZW1cbiAqXG4gKiBUaGUgdmFyaWFibGVzICdrZXknIGFuZCAndmFsJyBhcmUgYXJiaXRyYXJ5LlxuICogVGhleSBkZXBlbmQgb24gdGhlIGNvbGxlY3Rpb24gdHlwZSBsb29wZWQgKEFycmF5LCBPYmplY3QpXG4gKiBhbmQgb24gdGhlIGV4cHJlc3Npb24gdXNlZCBvbiB0aGUgZWFjaCB0YWdcbiAqXG4gKi9cbmZ1bmN0aW9uIG1raXRlbShleHByLCBrZXksIHZhbCwgYmFzZSkge1xuICB2YXIgaXRlbSA9IGJhc2UgPyBPYmplY3QuY3JlYXRlKGJhc2UpIDoge307XG4gIGl0ZW1bZXhwci5rZXldID0ga2V5O1xuICBpZiAoZXhwci5wb3MpIHsgaXRlbVtleHByLnBvc10gPSB2YWw7IH1cbiAgcmV0dXJuIGl0ZW1cbn1cblxuLyoqXG4gKiBVbm1vdW50IHRoZSByZWR1bmRhbnQgdGFnc1xuICogQHBhcmFtICAgeyBBcnJheSB9IGl0ZW1zIC0gYXJyYXkgY29udGFpbmluZyB0aGUgY3VycmVudCBpdGVtcyB0byBsb29wXG4gKiBAcGFyYW0gICB7IEFycmF5IH0gdGFncyAtIGFycmF5IGNvbnRhaW5pbmcgYWxsIHRoZSBjaGlsZHJlbiB0YWdzXG4gKi9cbmZ1bmN0aW9uIHVubW91bnRSZWR1bmRhbnQoaXRlbXMsIHRhZ3MpIHtcbiAgdmFyIGkgPSB0YWdzLmxlbmd0aCxcbiAgICBqID0gaXRlbXMubGVuZ3RoO1xuXG4gIHdoaWxlIChpID4gaikge1xuICAgIGktLTtcbiAgICByZW1vdmUuYXBwbHkodGFnc1tpXSwgW3RhZ3MsIGldKTtcbiAgfVxufVxuXG5cbi8qKlxuICogUmVtb3ZlIGEgY2hpbGQgdGFnXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHsgQXJyYXkgfSB0YWdzIC0gdGFncyBjb2xsZWN0aW9uXG4gKiBAcGFyYW0gICB7IE51bWJlciB9IGkgLSBpbmRleCBvZiB0aGUgdGFnIHRvIHJlbW92ZVxuICovXG5mdW5jdGlvbiByZW1vdmUodGFncywgaSkge1xuICB0YWdzLnNwbGljZShpLCAxKTtcbiAgdGhpcy51bm1vdW50KCk7XG4gIGFycmF5aXNoUmVtb3ZlKHRoaXMucGFyZW50LCB0aGlzLCB0aGlzLl9fLnRhZ05hbWUsIHRydWUpO1xufVxuXG4vKipcbiAqIE1vdmUgdGhlIG5lc3RlZCBjdXN0b20gdGFncyBpbiBub24gY3VzdG9tIGxvb3AgdGFnc1xuICogQHRoaXMgVGFnXG4gKiBAcGFyYW0gICB7IE51bWJlciB9IGkgLSBjdXJyZW50IHBvc2l0aW9uIG9mIHRoZSBsb29wIHRhZ1xuICovXG5mdW5jdGlvbiBtb3ZlTmVzdGVkVGFncyhpKSB7XG4gIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gIGVhY2goT2JqZWN0LmtleXModGhpcy50YWdzKSwgZnVuY3Rpb24gKHRhZ05hbWUpIHtcbiAgICBtb3ZlQ2hpbGRUYWcuYXBwbHkodGhpcyQxLnRhZ3NbdGFnTmFtZV0sIFt0YWdOYW1lLCBpXSk7XG4gIH0pO1xufVxuXG4vKipcbiAqIE1vdmUgYSBjaGlsZCB0YWdcbiAqIEB0aGlzIFRhZ1xuICogQHBhcmFtICAgeyBIVE1MRWxlbWVudCB9IHJvb3QgLSBkb20gbm9kZSBjb250YWluaW5nIGFsbCB0aGUgbG9vcCBjaGlsZHJlblxuICogQHBhcmFtICAgeyBUYWcgfSBuZXh0VGFnIC0gaW5zdGFuY2Ugb2YgdGhlIG5leHQgdGFnIHByZWNlZGluZyB0aGUgb25lIHdlIHdhbnQgdG8gbW92ZVxuICogQHBhcmFtICAgeyBCb29sZWFuIH0gaXNWaXJ0dWFsIC0gaXMgaXQgYSB2aXJ0dWFsIHRhZz9cbiAqL1xuZnVuY3Rpb24gbW92ZShyb290LCBuZXh0VGFnLCBpc1ZpcnR1YWwpIHtcbiAgaWYgKGlzVmlydHVhbClcbiAgICB7IG1vdmVWaXJ0dWFsLmFwcGx5KHRoaXMsIFtyb290LCBuZXh0VGFnXSk7IH1cbiAgZWxzZVxuICAgIHsgc2FmZUluc2VydChyb290LCB0aGlzLnJvb3QsIG5leHRUYWcucm9vdCk7IH1cbn1cblxuLyoqXG4gKiBJbnNlcnQgYW5kIG1vdW50IGEgY2hpbGQgdGFnXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSByb290IC0gZG9tIG5vZGUgY29udGFpbmluZyBhbGwgdGhlIGxvb3AgY2hpbGRyZW5cbiAqIEBwYXJhbSAgIHsgVGFnIH0gbmV4dFRhZyAtIGluc3RhbmNlIG9mIHRoZSBuZXh0IHRhZyBwcmVjZWRpbmcgdGhlIG9uZSB3ZSB3YW50IHRvIGluc2VydFxuICogQHBhcmFtICAgeyBCb29sZWFuIH0gaXNWaXJ0dWFsIC0gaXMgaXQgYSB2aXJ0dWFsIHRhZz9cbiAqL1xuZnVuY3Rpb24gaW5zZXJ0KHJvb3QsIG5leHRUYWcsIGlzVmlydHVhbCkge1xuICBpZiAoaXNWaXJ0dWFsKVxuICAgIHsgbWFrZVZpcnR1YWwuYXBwbHkodGhpcywgW3Jvb3QsIG5leHRUYWddKTsgfVxuICBlbHNlXG4gICAgeyBzYWZlSW5zZXJ0KHJvb3QsIHRoaXMucm9vdCwgbmV4dFRhZy5yb290KTsgfVxufVxuXG4vKipcbiAqIEFwcGVuZCBhIG5ldyB0YWcgaW50byB0aGUgRE9NXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSByb290IC0gZG9tIG5vZGUgY29udGFpbmluZyBhbGwgdGhlIGxvb3AgY2hpbGRyZW5cbiAqIEBwYXJhbSAgIHsgQm9vbGVhbiB9IGlzVmlydHVhbCAtIGlzIGl0IGEgdmlydHVhbCB0YWc/XG4gKi9cbmZ1bmN0aW9uIGFwcGVuZChyb290LCBpc1ZpcnR1YWwpIHtcbiAgaWYgKGlzVmlydHVhbClcbiAgICB7IG1ha2VWaXJ0dWFsLmNhbGwodGhpcywgcm9vdCk7IH1cbiAgZWxzZVxuICAgIHsgcm9vdC5hcHBlbmRDaGlsZCh0aGlzLnJvb3QpOyB9XG59XG5cbi8qKlxuICogTWFuYWdlIHRhZ3MgaGF2aW5nIHRoZSAnZWFjaCdcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSBkb20gLSBET00gbm9kZSB3ZSBuZWVkIHRvIGxvb3BcbiAqIEBwYXJhbSAgIHsgVGFnIH0gcGFyZW50IC0gcGFyZW50IHRhZyBpbnN0YW5jZSB3aGVyZSB0aGUgZG9tIG5vZGUgaXMgY29udGFpbmVkXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IGV4cHIgLSBzdHJpbmcgY29udGFpbmVkIGluIHRoZSAnZWFjaCcgYXR0cmlidXRlXG4gKiBAcmV0dXJucyB7IE9iamVjdCB9IGV4cHJlc3Npb24gb2JqZWN0IGZvciB0aGlzIGVhY2ggbG9vcFxuICovXG5mdW5jdGlvbiBfZWFjaChkb20sIHBhcmVudCwgZXhwcikge1xuXG4gIC8vIHJlbW92ZSB0aGUgZWFjaCBwcm9wZXJ0eSBmcm9tIHRoZSBvcmlnaW5hbCB0YWdcbiAgcmVtQXR0cihkb20sIExPT1BfRElSRUNUSVZFKTtcblxuICB2YXIgbXVzdFJlb3JkZXIgPSB0eXBlb2YgZ2V0QXR0cihkb20sIExPT1BfTk9fUkVPUkRFUl9ESVJFQ1RJVkUpICE9PSBUX1NUUklORyB8fCByZW1BdHRyKGRvbSwgTE9PUF9OT19SRU9SREVSX0RJUkVDVElWRSksXG4gICAgdGFnTmFtZSA9IGdldFRhZ05hbWUoZG9tKSxcbiAgICBpbXBsID0gX19UQUdfSU1QTFt0YWdOYW1lXSxcbiAgICBwYXJlbnROb2RlID0gZG9tLnBhcmVudE5vZGUsXG4gICAgcGxhY2Vob2xkZXIgPSBjcmVhdGVET01QbGFjZWhvbGRlcigpLFxuICAgIGNoaWxkID0gZ2V0VGFnKGRvbSksXG4gICAgaWZFeHByID0gZ2V0QXR0cihkb20sIENPTkRJVElPTkFMX0RJUkVDVElWRSksXG4gICAgdGFncyA9IFtdLFxuICAgIG9sZEl0ZW1zID0gW10sXG4gICAgaGFzS2V5cyxcbiAgICBpc0xvb3AgPSB0cnVlLFxuICAgIGlzQW5vbnltb3VzID0gIV9fVEFHX0lNUExbdGFnTmFtZV0sXG4gICAgaXNWaXJ0dWFsID0gZG9tLnRhZ05hbWUgPT09ICdWSVJUVUFMJztcblxuICAvLyBwYXJzZSB0aGUgZWFjaCBleHByZXNzaW9uXG4gIGV4cHIgPSB0bXBsLmxvb3BLZXlzKGV4cHIpO1xuICBleHByLmlzTG9vcCA9IHRydWU7XG5cbiAgaWYgKGlmRXhwcikgeyByZW1BdHRyKGRvbSwgQ09ORElUSU9OQUxfRElSRUNUSVZFKTsgfVxuXG4gIC8vIGluc2VydCBhIG1hcmtlZCB3aGVyZSB0aGUgbG9vcCB0YWdzIHdpbGwgYmUgaW5qZWN0ZWRcbiAgcGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUocGxhY2Vob2xkZXIsIGRvbSk7XG4gIHBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZG9tKTtcblxuICBleHByLnVwZGF0ZSA9IGZ1bmN0aW9uIHVwZGF0ZUVhY2goKSB7XG4gICAgLy8gZ2V0IHRoZSBuZXcgaXRlbXMgY29sbGVjdGlvblxuICAgIGV4cHIudmFsdWUgPSB0bXBsKGV4cHIudmFsLCBwYXJlbnQpO1xuXG4gICAgdmFyIGZyYWcgPSBjcmVhdGVGcmFnKCksXG4gICAgICBpdGVtcyA9IGV4cHIudmFsdWUsXG4gICAgICBpc09iamVjdCQkMSA9ICFpc0FycmF5KGl0ZW1zKSAmJiAhaXNTdHJpbmcoaXRlbXMpLFxuICAgICAgcm9vdCA9IHBsYWNlaG9sZGVyLnBhcmVudE5vZGU7XG5cbiAgICAvLyBvYmplY3QgbG9vcC4gYW55IGNoYW5nZXMgY2F1c2UgZnVsbCByZWRyYXdcbiAgICBpZiAoaXNPYmplY3QkJDEpIHtcbiAgICAgIGhhc0tleXMgPSBpdGVtcyB8fCBmYWxzZTtcbiAgICAgIGl0ZW1zID0gaGFzS2V5cyA/XG4gICAgICAgIE9iamVjdC5rZXlzKGl0ZW1zKS5tYXAoZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgIHJldHVybiBta2l0ZW0oZXhwciwgaXRlbXNba2V5XSwga2V5KVxuICAgICAgICB9KSA6IFtdO1xuICAgIH0gZWxzZSB7XG4gICAgICBoYXNLZXlzID0gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKGlmRXhwcikge1xuICAgICAgaXRlbXMgPSBpdGVtcy5maWx0ZXIoZnVuY3Rpb24oaXRlbSwgaSkge1xuICAgICAgICBpZiAoZXhwci5rZXkgJiYgIWlzT2JqZWN0JCQxKVxuICAgICAgICAgIHsgcmV0dXJuICEhdG1wbChpZkV4cHIsIG1raXRlbShleHByLCBpdGVtLCBpLCBwYXJlbnQpKSB9XG5cbiAgICAgICAgcmV0dXJuICEhdG1wbChpZkV4cHIsIGV4dGVuZChPYmplY3QuY3JlYXRlKHBhcmVudCksIGl0ZW0pKVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgLy8gbG9vcCBhbGwgdGhlIG5ldyBpdGVtc1xuICAgIGVhY2goaXRlbXMsIGZ1bmN0aW9uKGl0ZW0sIGkpIHtcbiAgICAgIC8vIHJlb3JkZXIgb25seSBpZiB0aGUgaXRlbXMgYXJlIG9iamVjdHNcbiAgICAgIHZhclxuICAgICAgICBkb1Jlb3JkZXIgPSBtdXN0UmVvcmRlciAmJiB0eXBlb2YgaXRlbSA9PT0gVF9PQkpFQ1QgJiYgIWhhc0tleXMsXG4gICAgICAgIG9sZFBvcyA9IG9sZEl0ZW1zLmluZGV4T2YoaXRlbSksXG4gICAgICAgIGlzTmV3ID0gb2xkUG9zID09PSAtMSxcbiAgICAgICAgcG9zID0gIWlzTmV3ICYmIGRvUmVvcmRlciA/IG9sZFBvcyA6IGksXG4gICAgICAgIC8vIGRvZXMgYSB0YWcgZXhpc3QgaW4gdGhpcyBwb3NpdGlvbj9cbiAgICAgICAgdGFnID0gdGFnc1twb3NdLFxuICAgICAgICBtdXN0QXBwZW5kID0gaSA+PSBvbGRJdGVtcy5sZW5ndGgsXG4gICAgICAgIG11c3RDcmVhdGUgPSAgZG9SZW9yZGVyICYmIGlzTmV3IHx8ICFkb1Jlb3JkZXIgJiYgIXRhZztcblxuICAgICAgaXRlbSA9ICFoYXNLZXlzICYmIGV4cHIua2V5ID8gbWtpdGVtKGV4cHIsIGl0ZW0sIGkpIDogaXRlbTtcblxuICAgICAgLy8gbmV3IHRhZ1xuICAgICAgaWYgKG11c3RDcmVhdGUpIHtcbiAgICAgICAgdGFnID0gbmV3IFRhZyQxKGltcGwsIHtcbiAgICAgICAgICBwYXJlbnQ6IHBhcmVudCxcbiAgICAgICAgICBpc0xvb3A6IGlzTG9vcCxcbiAgICAgICAgICBpc0Fub255bW91czogaXNBbm9ueW1vdXMsXG4gICAgICAgICAgdGFnTmFtZTogdGFnTmFtZSxcbiAgICAgICAgICByb290OiBkb20uY2xvbmVOb2RlKGlzQW5vbnltb3VzKSxcbiAgICAgICAgICBpdGVtOiBpdGVtLFxuICAgICAgICAgIGluZGV4OiBpLFxuICAgICAgICB9LCBkb20uaW5uZXJIVE1MKTtcblxuICAgICAgICAvLyBtb3VudCB0aGUgdGFnXG4gICAgICAgIHRhZy5tb3VudCgpO1xuXG4gICAgICAgIGlmIChtdXN0QXBwZW5kKVxuICAgICAgICAgIHsgYXBwZW5kLmFwcGx5KHRhZywgW2ZyYWcgfHwgcm9vdCwgaXNWaXJ0dWFsXSk7IH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgIHsgaW5zZXJ0LmFwcGx5KHRhZywgW3Jvb3QsIHRhZ3NbaV0sIGlzVmlydHVhbF0pOyB9XG5cbiAgICAgICAgaWYgKCFtdXN0QXBwZW5kKSB7IG9sZEl0ZW1zLnNwbGljZShpLCAwLCBpdGVtKTsgfVxuICAgICAgICB0YWdzLnNwbGljZShpLCAwLCB0YWcpO1xuICAgICAgICBpZiAoY2hpbGQpIHsgYXJyYXlpc2hBZGQocGFyZW50LnRhZ3MsIHRhZ05hbWUsIHRhZywgdHJ1ZSk7IH1cbiAgICAgIH0gZWxzZSBpZiAocG9zICE9PSBpICYmIGRvUmVvcmRlcikge1xuICAgICAgICAvLyBtb3ZlXG4gICAgICAgIGlmIChjb250YWlucyhpdGVtcywgb2xkSXRlbXNbcG9zXSkpIHtcbiAgICAgICAgICBtb3ZlLmFwcGx5KHRhZywgW3Jvb3QsIHRhZ3NbaV0sIGlzVmlydHVhbF0pO1xuICAgICAgICAgIC8vIG1vdmUgdGhlIG9sZCB0YWcgaW5zdGFuY2VcbiAgICAgICAgICB0YWdzLnNwbGljZShpLCAwLCB0YWdzLnNwbGljZShwb3MsIDEpWzBdKTtcbiAgICAgICAgICAvLyBtb3ZlIHRoZSBvbGQgaXRlbVxuICAgICAgICAgIG9sZEl0ZW1zLnNwbGljZShpLCAwLCBvbGRJdGVtcy5zcGxpY2UocG9zLCAxKVswXSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyB1cGRhdGUgdGhlIHBvc2l0aW9uIGF0dHJpYnV0ZSBpZiBpdCBleGlzdHNcbiAgICAgICAgaWYgKGV4cHIucG9zKSB7IHRhZ1tleHByLnBvc10gPSBpOyB9XG5cbiAgICAgICAgLy8gaWYgdGhlIGxvb3AgdGFncyBhcmUgbm90IGN1c3RvbVxuICAgICAgICAvLyB3ZSBuZWVkIHRvIG1vdmUgYWxsIHRoZWlyIGN1c3RvbSB0YWdzIGludG8gdGhlIHJpZ2h0IHBvc2l0aW9uXG4gICAgICAgIGlmICghY2hpbGQgJiYgdGFnLnRhZ3MpIHsgbW92ZU5lc3RlZFRhZ3MuY2FsbCh0YWcsIGkpOyB9XG4gICAgICB9XG5cbiAgICAgIC8vIGNhY2hlIHRoZSBvcmlnaW5hbCBpdGVtIHRvIHVzZSBpdCBpbiB0aGUgZXZlbnRzIGJvdW5kIHRvIHRoaXMgbm9kZVxuICAgICAgLy8gYW5kIGl0cyBjaGlsZHJlblxuICAgICAgdGFnLl9fLml0ZW0gPSBpdGVtO1xuICAgICAgdGFnLl9fLmluZGV4ID0gaTtcbiAgICAgIHRhZy5fXy5wYXJlbnQgPSBwYXJlbnQ7XG5cbiAgICAgIGlmICghbXVzdENyZWF0ZSkgeyB0YWcudXBkYXRlKGl0ZW0pOyB9XG4gICAgfSk7XG5cbiAgICAvLyByZW1vdmUgdGhlIHJlZHVuZGFudCB0YWdzXG4gICAgdW5tb3VudFJlZHVuZGFudChpdGVtcywgdGFncyk7XG5cbiAgICAvLyBjbG9uZSB0aGUgaXRlbXMgYXJyYXlcbiAgICBvbGRJdGVtcyA9IGl0ZW1zLnNsaWNlKCk7XG5cbiAgICByb290Lmluc2VydEJlZm9yZShmcmFnLCBwbGFjZWhvbGRlcik7XG4gIH07XG5cbiAgZXhwci51bm1vdW50ID0gZnVuY3Rpb24oKSB7XG4gICAgZWFjaCh0YWdzLCBmdW5jdGlvbih0KSB7IHQudW5tb3VudCgpOyB9KTtcbiAgfTtcblxuICByZXR1cm4gZXhwclxufVxuXG4vKipcbiAqIFdhbGsgdGhlIHRhZyBET00gdG8gZGV0ZWN0IHRoZSBleHByZXNzaW9ucyB0byBldmFsdWF0ZVxuICogQHRoaXMgVGFnXG4gKiBAcGFyYW0gICB7IEhUTUxFbGVtZW50IH0gcm9vdCAtIHJvb3QgdGFnIHdoZXJlIHdlIHdpbGwgc3RhcnQgZGlnZ2luZyB0aGUgZXhwcmVzc2lvbnNcbiAqIEBwYXJhbSAgIHsgQXJyYXkgfSBleHByZXNzaW9ucyAtIGVtcHR5IGFycmF5IHdoZXJlIHRoZSBleHByZXNzaW9ucyB3aWxsIGJlIGFkZGVkXG4gKiBAcGFyYW0gICB7IEJvb2xlYW4gfSBtdXN0SW5jbHVkZVJvb3QgLSBmbGFnIHRvIGRlY2lkZSB3aGV0aGVyIHRoZSByb290IG11c3QgYmUgcGFyc2VkIGFzIHdlbGxcbiAqIEByZXR1cm5zIHsgT2JqZWN0IH0gYW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHJvb3Qgbm9vZGUgYW5kIHRoZSBkb20gdHJlZVxuICovXG5mdW5jdGlvbiBwYXJzZUV4cHJlc3Npb25zKHJvb3QsIGV4cHJlc3Npb25zLCBtdXN0SW5jbHVkZVJvb3QpIHtcbiAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgdmFyIHRyZWUgPSB7cGFyZW50OiB7Y2hpbGRyZW46IGV4cHJlc3Npb25zfX07XG5cbiAgd2Fsa05vZGVzKHJvb3QsIGZ1bmN0aW9uIChkb20sIGN0eCkge1xuICAgIHZhciB0eXBlID0gZG9tLm5vZGVUeXBlLCBwYXJlbnQgPSBjdHgucGFyZW50LCBhdHRyLCBleHByLCB0YWdJbXBsO1xuICAgIGlmICghbXVzdEluY2x1ZGVSb290ICYmIGRvbSA9PT0gcm9vdCkgeyByZXR1cm4ge3BhcmVudDogcGFyZW50fSB9XG5cbiAgICAvLyB0ZXh0IG5vZGVcbiAgICBpZiAodHlwZSA9PT0gMyAmJiBkb20ucGFyZW50Tm9kZS50YWdOYW1lICE9PSAnU1RZTEUnICYmIHRtcGwuaGFzRXhwcihkb20ubm9kZVZhbHVlKSlcbiAgICAgIHsgcGFyZW50LmNoaWxkcmVuLnB1c2goe2RvbTogZG9tLCBleHByOiBkb20ubm9kZVZhbHVlfSk7IH1cblxuICAgIGlmICh0eXBlICE9PSAxKSB7IHJldHVybiBjdHggfSAvLyBub3QgYW4gZWxlbWVudFxuXG4gICAgdmFyIGlzVmlydHVhbCA9IGRvbS50YWdOYW1lID09PSAnVklSVFVBTCc7XG5cbiAgICAvLyBsb29wLiBlYWNoIGRvZXMgaXQncyBvd24gdGhpbmcgKGZvciBub3cpXG4gICAgaWYgKGF0dHIgPSBnZXRBdHRyKGRvbSwgTE9PUF9ESVJFQ1RJVkUpKSB7XG4gICAgICBpZihpc1ZpcnR1YWwpIHsgc2V0QXR0cihkb20sICdsb29wVmlydHVhbCcsIHRydWUpOyB9IC8vIGlnbm9yZSBoZXJlLCBoYW5kbGVkIGluIF9lYWNoXG4gICAgICBwYXJlbnQuY2hpbGRyZW4ucHVzaChfZWFjaChkb20sIHRoaXMkMSwgYXR0cikpO1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuXG4gICAgLy8gaWYtYXR0cnMgYmVjb21lIHRoZSBuZXcgcGFyZW50LiBBbnkgZm9sbG93aW5nIGV4cHJlc3Npb25zIChlaXRoZXIgb24gdGhlIGN1cnJlbnRcbiAgICAvLyBlbGVtZW50LCBvciBiZWxvdyBpdCkgYmVjb21lIGNoaWxkcmVuIG9mIHRoaXMgZXhwcmVzc2lvbi5cbiAgICBpZiAoYXR0ciA9IGdldEF0dHIoZG9tLCBDT05ESVRJT05BTF9ESVJFQ1RJVkUpKSB7XG4gICAgICBwYXJlbnQuY2hpbGRyZW4ucHVzaChPYmplY3QuY3JlYXRlKElmRXhwcikuaW5pdChkb20sIHRoaXMkMSwgYXR0cikpO1xuICAgICAgcmV0dXJuIGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKGV4cHIgPSBnZXRBdHRyKGRvbSwgSVNfRElSRUNUSVZFKSkge1xuICAgICAgaWYgKHRtcGwuaGFzRXhwcihleHByKSkge1xuICAgICAgICBwYXJlbnQuY2hpbGRyZW4ucHVzaCh7aXNSdGFnOiB0cnVlLCBleHByOiBleHByLCBkb206IGRvbSwgYXR0cnM6IFtdLnNsaWNlLmNhbGwoZG9tLmF0dHJpYnV0ZXMpfSk7XG4gICAgICAgIHJldHVybiBmYWxzZVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIGlmIHRoaXMgaXMgYSB0YWcsIHN0b3AgdHJhdmVyc2luZyBoZXJlLlxuICAgIC8vIHdlIGlnbm9yZSB0aGUgcm9vdCwgc2luY2UgcGFyc2VFeHByZXNzaW9ucyBpcyBjYWxsZWQgd2hpbGUgd2UncmUgbW91bnRpbmcgdGhhdCByb290XG4gICAgdGFnSW1wbCA9IGdldFRhZyhkb20pO1xuICAgIGlmKGlzVmlydHVhbCkge1xuICAgICAgaWYoZ2V0QXR0cihkb20sICd2aXJ0dWFsaXplZCcpKSB7ZG9tLnBhcmVudEVsZW1lbnQucmVtb3ZlQ2hpbGQoZG9tKTsgfSAvLyB0YWcgY3JlYXRlZCwgcmVtb3ZlIGZyb20gZG9tXG4gICAgICBpZighdGFnSW1wbCAmJiAhZ2V0QXR0cihkb20sICd2aXJ0dWFsaXplZCcpICYmICFnZXRBdHRyKGRvbSwgJ2xvb3BWaXJ0dWFsJykpICAvLyBvayB0byBjcmVhdGUgdmlydHVhbCB0YWdcbiAgICAgICAgeyB0YWdJbXBsID0geyB0bXBsOiBkb20ub3V0ZXJIVE1MIH07IH1cbiAgICB9XG5cbiAgICBpZiAodGFnSW1wbCAmJiAoZG9tICE9PSByb290IHx8IG11c3RJbmNsdWRlUm9vdCkpIHtcbiAgICAgIGlmKGlzVmlydHVhbCAmJiAhZ2V0QXR0cihkb20sIElTX0RJUkVDVElWRSkpIHsgLy8gaGFuZGxlZCBpbiB1cGRhdGVcbiAgICAgICAgLy8gY2FuIG5vdCByZW1vdmUgYXR0cmlidXRlIGxpa2UgZGlyZWN0aXZlc1xuICAgICAgICAvLyBzbyBmbGFnIGZvciByZW1vdmFsIGFmdGVyIGNyZWF0aW9uIHRvIHByZXZlbnQgbWF4aW11bSBzdGFjayBlcnJvclxuICAgICAgICBzZXRBdHRyKGRvbSwgJ3ZpcnR1YWxpemVkJywgdHJ1ZSk7XG5cbiAgICAgICAgdmFyIHRhZyA9IG5ldyBUYWckMSh7IHRtcGw6IGRvbS5vdXRlckhUTUwgfSxcbiAgICAgICAgICB7cm9vdDogZG9tLCBwYXJlbnQ6IHRoaXMkMX0sXG4gICAgICAgICAgZG9tLmlubmVySFRNTCk7XG4gICAgICAgIHBhcmVudC5jaGlsZHJlbi5wdXNoKHRhZyk7IC8vIG5vIHJldHVybiwgYW5vbnltb3VzIHRhZywga2VlcCBwYXJzaW5nXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgY29uZiA9IHtyb290OiBkb20sIHBhcmVudDogdGhpcyQxLCBoYXNJbXBsOiB0cnVlfTtcbiAgICAgICAgcGFyZW50LmNoaWxkcmVuLnB1c2goaW5pdENoaWxkVGFnKHRhZ0ltcGwsIGNvbmYsIGRvbS5pbm5lckhUTUwsIHRoaXMkMSkpO1xuICAgICAgICByZXR1cm4gZmFsc2VcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBhdHRyaWJ1dGUgZXhwcmVzc2lvbnNcbiAgICBwYXJzZUF0dHJpYnV0ZXMuYXBwbHkodGhpcyQxLCBbZG9tLCBkb20uYXR0cmlidXRlcywgZnVuY3Rpb24oYXR0ciwgZXhwcikge1xuICAgICAgaWYgKCFleHByKSB7IHJldHVybiB9XG4gICAgICBwYXJlbnQuY2hpbGRyZW4ucHVzaChleHByKTtcbiAgICB9XSk7XG5cbiAgICAvLyB3aGF0ZXZlciB0aGUgcGFyZW50IGlzLCBhbGwgY2hpbGQgZWxlbWVudHMgZ2V0IHRoZSBzYW1lIHBhcmVudC5cbiAgICAvLyBJZiB0aGlzIGVsZW1lbnQgaGFkIGFuIGlmLWF0dHIsIHRoYXQncyB0aGUgcGFyZW50IGZvciBhbGwgY2hpbGQgZWxlbWVudHNcbiAgICByZXR1cm4ge3BhcmVudDogcGFyZW50fVxuICB9LCB0cmVlKTtcblxuICByZXR1cm4geyB0cmVlOiB0cmVlLCByb290OiByb290IH1cbn1cblxuLyoqXG4gKiBDYWxscyBgZm5gIGZvciBldmVyeSBhdHRyaWJ1dGUgb24gYW4gZWxlbWVudC4gSWYgdGhhdCBhdHRyIGhhcyBhbiBleHByZXNzaW9uLFxuICogaXQgaXMgYWxzbyBwYXNzZWQgdG8gZm4uXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHsgSFRNTEVsZW1lbnQgfSBkb20gLSBkb20gbm9kZSB0byBwYXJzZVxuICogQHBhcmFtICAgeyBBcnJheSB9IGF0dHJzIC0gYXJyYXkgb2YgYXR0cmlidXRlc1xuICogQHBhcmFtICAgeyBGdW5jdGlvbiB9IGZuIC0gY2FsbGJhY2sgdG8gZXhlYyBvbiBhbnkgaXRlcmF0aW9uXG4gKi9cbmZ1bmN0aW9uIHBhcnNlQXR0cmlidXRlcyhkb20sIGF0dHJzLCBmbikge1xuICB2YXIgdGhpcyQxID0gdGhpcztcblxuICBlYWNoKGF0dHJzLCBmdW5jdGlvbiAoYXR0cikge1xuICAgIHZhciBuYW1lID0gYXR0ci5uYW1lLCBib29sID0gaXNCb29sQXR0cihuYW1lKSwgZXhwcjtcblxuICAgIGlmIChjb250YWlucyhSRUZfRElSRUNUSVZFUywgbmFtZSkpIHtcbiAgICAgIGV4cHIgPSAgT2JqZWN0LmNyZWF0ZShSZWZFeHByKS5pbml0KGRvbSwgdGhpcyQxLCBuYW1lLCBhdHRyLnZhbHVlKTtcbiAgICB9IGVsc2UgaWYgKHRtcGwuaGFzRXhwcihhdHRyLnZhbHVlKSkge1xuICAgICAgZXhwciA9IHtkb206IGRvbSwgZXhwcjogYXR0ci52YWx1ZSwgYXR0cjogbmFtZSwgYm9vbDogYm9vbH07XG4gICAgfVxuXG4gICAgZm4oYXR0ciwgZXhwcik7XG4gIH0pO1xufVxuXG4vKlxuICBJbmNsdWRlcyBoYWNrcyBuZWVkZWQgZm9yIHRoZSBJbnRlcm5ldCBFeHBsb3JlciB2ZXJzaW9uIDkgYW5kIGJlbG93XG4gIFNlZTogaHR0cDovL2thbmdheC5naXRodWIuaW8vY29tcGF0LXRhYmxlL2VzNS8jaWU4XG4gICAgICAgaHR0cDovL2NvZGVwbGFuZXQuaW8vZHJvcHBpbmctaWU4L1xuKi9cblxudmFyIHJlSGFzWWllbGQgID0gLzx5aWVsZFxcYi9pO1xudmFyIHJlWWllbGRBbGwgID0gLzx5aWVsZFxccyooPzpcXC8+fD4oW1xcU1xcc10qPyk8XFwveWllbGRcXHMqPnw+KS9pZztcbnZhciByZVlpZWxkU3JjICA9IC88eWllbGRcXHMrdG89WydcIl0oW14nXCI+XSopWydcIl1cXHMqPihbXFxTXFxzXSo/KTxcXC95aWVsZFxccyo+L2lnO1xudmFyIHJlWWllbGREZXN0ID0gLzx5aWVsZFxccytmcm9tPVsnXCJdPyhbLVxcd10rKVsnXCJdP1xccyooPzpcXC8+fD4oW1xcU1xcc10qPyk8XFwveWllbGRcXHMqPikvaWc7XG52YXIgcm9vdEVscyA9IHsgdHI6ICd0Ym9keScsIHRoOiAndHInLCB0ZDogJ3RyJywgY29sOiAnY29sZ3JvdXAnIH07XG52YXIgdGJsVGFncyA9IElFX1ZFUlNJT04gJiYgSUVfVkVSU0lPTiA8IDEwID8gUkVfU1BFQ0lBTF9UQUdTIDogUkVfU1BFQ0lBTF9UQUdTX05PX09QVElPTjtcbnZhciBHRU5FUklDID0gJ2Rpdic7XG5cblxuLypcbiAgQ3JlYXRlcyB0aGUgcm9vdCBlbGVtZW50IGZvciB0YWJsZSBvciBzZWxlY3QgY2hpbGQgZWxlbWVudHM6XG4gIHRyL3RoL3RkL3RoZWFkL3Rmb290L3Rib2R5L2NhcHRpb24vY29sL2NvbGdyb3VwL29wdGlvbi9vcHRncm91cFxuKi9cbmZ1bmN0aW9uIHNwZWNpYWxUYWdzKGVsLCB0bXBsLCB0YWdOYW1lKSB7XG5cbiAgdmFyXG4gICAgc2VsZWN0ID0gdGFnTmFtZVswXSA9PT0gJ28nLFxuICAgIHBhcmVudCA9IHNlbGVjdCA/ICdzZWxlY3Q+JyA6ICd0YWJsZT4nO1xuXG4gIC8vIHRyaW0oKSBpcyBpbXBvcnRhbnQgaGVyZSwgdGhpcyBlbnN1cmVzIHdlIGRvbid0IGhhdmUgYXJ0aWZhY3RzLFxuICAvLyBzbyB3ZSBjYW4gY2hlY2sgaWYgd2UgaGF2ZSBvbmx5IG9uZSBlbGVtZW50IGluc2lkZSB0aGUgcGFyZW50XG4gIGVsLmlubmVySFRNTCA9ICc8JyArIHBhcmVudCArIHRtcGwudHJpbSgpICsgJzwvJyArIHBhcmVudDtcbiAgcGFyZW50ID0gZWwuZmlyc3RDaGlsZDtcblxuICAvLyByZXR1cm5zIHRoZSBpbW1lZGlhdGUgcGFyZW50IGlmIHRyL3RoL3RkL2NvbCBpcyB0aGUgb25seSBlbGVtZW50LCBpZiBub3RcbiAgLy8gcmV0dXJucyB0aGUgd2hvbGUgdHJlZSwgYXMgdGhpcyBjYW4gaW5jbHVkZSBhZGRpdGlvbmFsIGVsZW1lbnRzXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gIGlmIChzZWxlY3QpIHtcbiAgICBwYXJlbnQuc2VsZWN0ZWRJbmRleCA9IC0xOyAgLy8gZm9yIElFOSwgY29tcGF0aWJsZSB3L2N1cnJlbnQgcmlvdCBiZWhhdmlvclxuICB9IGVsc2Uge1xuICAgIC8vIGF2b2lkcyBpbnNlcnRpb24gb2YgY29pbnRhaW5lciBpbnNpZGUgY29udGFpbmVyIChleDogdGJvZHkgaW5zaWRlIHRib2R5KVxuICAgIHZhciB0bmFtZSA9IHJvb3RFbHNbdGFnTmFtZV07XG4gICAgaWYgKHRuYW1lICYmIHBhcmVudC5jaGlsZEVsZW1lbnRDb3VudCA9PT0gMSkgeyBwYXJlbnQgPSAkKHRuYW1lLCBwYXJlbnQpOyB9XG4gIH1cbiAgcmV0dXJuIHBhcmVudFxufVxuXG4vKlxuICBSZXBsYWNlIHRoZSB5aWVsZCB0YWcgZnJvbSBhbnkgdGFnIHRlbXBsYXRlIHdpdGggdGhlIGlubmVySFRNTCBvZiB0aGVcbiAgb3JpZ2luYWwgdGFnIGluIHRoZSBwYWdlXG4qL1xuZnVuY3Rpb24gcmVwbGFjZVlpZWxkKHRtcGwsIGh0bWwpIHtcbiAgLy8gZG8gbm90aGluZyBpZiBubyB5aWVsZFxuICBpZiAoIXJlSGFzWWllbGQudGVzdCh0bXBsKSkgeyByZXR1cm4gdG1wbCB9XG5cbiAgLy8gYmUgY2FyZWZ1bCB3aXRoICMxMzQzIC0gc3RyaW5nIG9uIHRoZSBzb3VyY2UgaGF2aW5nIGAkMWBcbiAgdmFyIHNyYyA9IHt9O1xuXG4gIGh0bWwgPSBodG1sICYmIGh0bWwucmVwbGFjZShyZVlpZWxkU3JjLCBmdW5jdGlvbiAoXywgcmVmLCB0ZXh0KSB7XG4gICAgc3JjW3JlZl0gPSBzcmNbcmVmXSB8fCB0ZXh0OyAgIC8vIHByZXNlcnZlIGZpcnN0IGRlZmluaXRpb25cbiAgICByZXR1cm4gJydcbiAgfSkudHJpbSgpO1xuXG4gIHJldHVybiB0bXBsXG4gICAgLnJlcGxhY2UocmVZaWVsZERlc3QsIGZ1bmN0aW9uIChfLCByZWYsIGRlZikgeyAgLy8geWllbGQgd2l0aCBmcm9tIC0gdG8gYXR0cnNcbiAgICAgIHJldHVybiBzcmNbcmVmXSB8fCBkZWYgfHwgJydcbiAgICB9KVxuICAgIC5yZXBsYWNlKHJlWWllbGRBbGwsIGZ1bmN0aW9uIChfLCBkZWYpIHsgICAgICAgIC8vIHlpZWxkIHdpdGhvdXQgYW55IFwiZnJvbVwiXG4gICAgICByZXR1cm4gaHRtbCB8fCBkZWYgfHwgJydcbiAgICB9KVxufVxuXG4vKipcbiAqIENyZWF0ZXMgYSBET00gZWxlbWVudCB0byB3cmFwIHRoZSBnaXZlbiBjb250ZW50LiBOb3JtYWxseSBhbiBgRElWYCwgYnV0IGNhbiBiZVxuICogYWxzbyBhIGBUQUJMRWAsIGBTRUxFQ1RgLCBgVEJPRFlgLCBgVFJgLCBvciBgQ09MR1JPVVBgIGVsZW1lbnQuXG4gKlxuICogQHBhcmFtICAgeyBTdHJpbmcgfSB0bXBsICAtIFRoZSB0ZW1wbGF0ZSBjb21pbmcgZnJvbSB0aGUgY3VzdG9tIHRhZyBkZWZpbml0aW9uXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IGh0bWwgLSBIVE1MIGNvbnRlbnQgdGhhdCBjb21lcyBmcm9tIHRoZSBET00gZWxlbWVudCB3aGVyZSB5b3VcbiAqICAgICAgICAgICB3aWxsIG1vdW50IHRoZSB0YWcsIG1vc3RseSB0aGUgb3JpZ2luYWwgdGFnIGluIHRoZSBwYWdlXG4gKiBAcmV0dXJucyB7IEhUTUxFbGVtZW50IH0gRE9NIGVsZW1lbnQgd2l0aCBfdG1wbF8gbWVyZ2VkIHRocm91Z2ggYFlJRUxEYCB3aXRoIHRoZSBfaHRtbF8uXG4gKi9cbmZ1bmN0aW9uIG1rZG9tKHRtcGwsIGh0bWwpIHtcbiAgdmFyIG1hdGNoICAgPSB0bXBsICYmIHRtcGwubWF0Y2goL15cXHMqPChbLVxcd10rKS8pLFxuICAgIHRhZ05hbWUgPSBtYXRjaCAmJiBtYXRjaFsxXS50b0xvd2VyQ2FzZSgpLFxuICAgIGVsID0gbWtFbChHRU5FUklDKTtcblxuICAvLyByZXBsYWNlIGFsbCB0aGUgeWllbGQgdGFncyB3aXRoIHRoZSB0YWcgaW5uZXIgaHRtbFxuICB0bXBsID0gcmVwbGFjZVlpZWxkKHRtcGwsIGh0bWwpO1xuXG4gIC8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXG4gIGlmICh0YmxUYWdzLnRlc3QodGFnTmFtZSkpXG4gICAgeyBlbCA9IHNwZWNpYWxUYWdzKGVsLCB0bXBsLCB0YWdOYW1lKTsgfVxuICBlbHNlXG4gICAgeyBzZXRJbm5lckhUTUwoZWwsIHRtcGwpOyB9XG5cbiAgcmV0dXJuIGVsXG59XG5cbi8qKlxuICogQW5vdGhlciB3YXkgdG8gY3JlYXRlIGEgcmlvdCB0YWcgYSBiaXQgbW9yZSBlczYgZnJpZW5kbHlcbiAqIEBwYXJhbSB7IEhUTUxFbGVtZW50IH0gZWwgLSB0YWcgRE9NIHNlbGVjdG9yIG9yIERPTSBub2RlL3NcbiAqIEBwYXJhbSB7IE9iamVjdCB9IG9wdHMgLSB0YWcgbG9naWNcbiAqIEByZXR1cm5zIHsgVGFnIH0gbmV3IHJpb3QgdGFnIGluc3RhbmNlXG4gKi9cbmZ1bmN0aW9uIFRhZyQyKGVsLCBvcHRzKSB7XG4gIC8vIGdldCB0aGUgdGFnIHByb3BlcnRpZXMgZnJvbSB0aGUgY2xhc3MgY29uc3RydWN0b3JcbiAgdmFyIHJlZiA9IHRoaXM7XG4gIHZhciBuYW1lID0gcmVmLm5hbWU7XG4gIHZhciB0bXBsID0gcmVmLnRtcGw7XG4gIHZhciBjc3MgPSByZWYuY3NzO1xuICB2YXIgYXR0cnMgPSByZWYuYXR0cnM7XG4gIHZhciBvbkNyZWF0ZSA9IHJlZi5vbkNyZWF0ZTtcbiAgLy8gcmVnaXN0ZXIgYSBuZXcgdGFnIGFuZCBjYWNoZSB0aGUgY2xhc3MgcHJvdG90eXBlXG4gIGlmICghX19UQUdfSU1QTFtuYW1lXSkge1xuICAgIHRhZyQxKG5hbWUsIHRtcGwsIGNzcywgYXR0cnMsIG9uQ3JlYXRlKTtcbiAgICAvLyBjYWNoZSB0aGUgY2xhc3MgY29uc3RydWN0b3JcbiAgICBfX1RBR19JTVBMW25hbWVdLmNsYXNzID0gdGhpcy5jb25zdHJ1Y3RvcjtcbiAgfVxuXG4gIC8vIG1vdW50IHRoZSB0YWcgdXNpbmcgdGhlIGNsYXNzIGluc3RhbmNlXG4gIG1vdW50VG8oZWwsIG5hbWUsIG9wdHMsIHRoaXMpO1xuICAvLyBpbmplY3QgdGhlIGNvbXBvbmVudCBjc3NcbiAgaWYgKGNzcykgeyBzdHlsZU1hbmFnZXIuaW5qZWN0KCk7IH1cblxuICByZXR1cm4gdGhpc1xufVxuXG4vKipcbiAqIENyZWF0ZSBhIG5ldyByaW90IHRhZyBpbXBsZW1lbnRhdGlvblxuICogQHBhcmFtICAgeyBTdHJpbmcgfSAgIG5hbWUgLSBuYW1lL2lkIG9mIHRoZSBuZXcgcmlvdCB0YWdcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gICB0bXBsIC0gdGFnIHRlbXBsYXRlXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9ICAgY3NzIC0gY3VzdG9tIHRhZyBjc3NcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gICBhdHRycyAtIHJvb3QgdGFnIGF0dHJpYnV0ZXNcbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSBmbiAtIHVzZXIgZnVuY3Rpb25cbiAqIEByZXR1cm5zIHsgU3RyaW5nIH0gbmFtZS9pZCBvZiB0aGUgdGFnIGp1c3QgY3JlYXRlZFxuICovXG5mdW5jdGlvbiB0YWckMShuYW1lLCB0bXBsLCBjc3MsIGF0dHJzLCBmbikge1xuICBpZiAoaXNGdW5jdGlvbihhdHRycykpIHtcbiAgICBmbiA9IGF0dHJzO1xuXG4gICAgaWYgKC9eW1xcd1xcLV0rXFxzPz0vLnRlc3QoY3NzKSkge1xuICAgICAgYXR0cnMgPSBjc3M7XG4gICAgICBjc3MgPSAnJztcbiAgICB9IGVsc2VcbiAgICAgIHsgYXR0cnMgPSAnJzsgfVxuICB9XG5cbiAgaWYgKGNzcykge1xuICAgIGlmIChpc0Z1bmN0aW9uKGNzcykpXG4gICAgICB7IGZuID0gY3NzOyB9XG4gICAgZWxzZVxuICAgICAgeyBzdHlsZU1hbmFnZXIuYWRkKGNzcyk7IH1cbiAgfVxuXG4gIG5hbWUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7XG4gIF9fVEFHX0lNUExbbmFtZV0gPSB7IG5hbWU6IG5hbWUsIHRtcGw6IHRtcGwsIGF0dHJzOiBhdHRycywgZm46IGZuIH07XG5cbiAgcmV0dXJuIG5hbWVcbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgcmlvdCB0YWcgaW1wbGVtZW50YXRpb24gKGZvciB1c2UgYnkgdGhlIGNvbXBpbGVyKVxuICogQHBhcmFtICAgeyBTdHJpbmcgfSAgIG5hbWUgLSBuYW1lL2lkIG9mIHRoZSBuZXcgcmlvdCB0YWdcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gICB0bXBsIC0gdGFnIHRlbXBsYXRlXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9ICAgY3NzIC0gY3VzdG9tIHRhZyBjc3NcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gICBhdHRycyAtIHJvb3QgdGFnIGF0dHJpYnV0ZXNcbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSBmbiAtIHVzZXIgZnVuY3Rpb25cbiAqIEByZXR1cm5zIHsgU3RyaW5nIH0gbmFtZS9pZCBvZiB0aGUgdGFnIGp1c3QgY3JlYXRlZFxuICovXG5mdW5jdGlvbiB0YWcyJDEobmFtZSwgdG1wbCwgY3NzLCBhdHRycywgZm4pIHtcbiAgaWYgKGNzcykgeyBzdHlsZU1hbmFnZXIuYWRkKGNzcywgbmFtZSk7IH1cblxuICBfX1RBR19JTVBMW25hbWVdID0geyBuYW1lOiBuYW1lLCB0bXBsOiB0bXBsLCBhdHRyczogYXR0cnMsIGZuOiBmbiB9O1xuXG4gIHJldHVybiBuYW1lXG59XG5cbi8qKlxuICogTW91bnQgYSB0YWcgdXNpbmcgYSBzcGVjaWZpYyB0YWcgaW1wbGVtZW50YXRpb25cbiAqIEBwYXJhbSAgIHsgKiB9IHNlbGVjdG9yIC0gdGFnIERPTSBzZWxlY3RvciBvciBET00gbm9kZS9zXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IHRhZ05hbWUgLSB0YWcgaW1wbGVtZW50YXRpb24gbmFtZVxuICogQHBhcmFtICAgeyBPYmplY3QgfSBvcHRzIC0gdGFnIGxvZ2ljXG4gKiBAcmV0dXJucyB7IEFycmF5IH0gbmV3IHRhZ3MgaW5zdGFuY2VzXG4gKi9cbmZ1bmN0aW9uIG1vdW50JDEoc2VsZWN0b3IsIHRhZ05hbWUsIG9wdHMpIHtcbiAgdmFyIHRhZ3MgPSBbXTtcblxuICBmdW5jdGlvbiBwdXNoVGFnc1RvKHJvb3QpIHtcbiAgICBpZiAocm9vdC50YWdOYW1lKSB7XG4gICAgICB2YXIgcmlvdFRhZyA9IGdldEF0dHIocm9vdCwgSVNfRElSRUNUSVZFKTtcblxuICAgICAgLy8gaGF2ZSB0YWdOYW1lPyBmb3JjZSByaW90LXRhZyB0byBiZSB0aGUgc2FtZVxuICAgICAgaWYgKHRhZ05hbWUgJiYgcmlvdFRhZyAhPT0gdGFnTmFtZSkge1xuICAgICAgICByaW90VGFnID0gdGFnTmFtZTtcbiAgICAgICAgc2V0QXR0cihyb290LCBJU19ESVJFQ1RJVkUsIHRhZ05hbWUpO1xuICAgICAgfVxuXG4gICAgICB2YXIgdGFnID0gbW91bnRUbyhyb290LCByaW90VGFnIHx8IHJvb3QudGFnTmFtZS50b0xvd2VyQ2FzZSgpLCBvcHRzKTtcblxuICAgICAgaWYgKHRhZylcbiAgICAgICAgeyB0YWdzLnB1c2godGFnKTsgfVxuICAgIH0gZWxzZSBpZiAocm9vdC5sZW5ndGgpXG4gICAgICB7IGVhY2gocm9vdCwgcHVzaFRhZ3NUbyk7IH0gLy8gYXNzdW1lIG5vZGVMaXN0XG4gIH1cblxuICAvLyBpbmplY3Qgc3R5bGVzIGludG8gRE9NXG4gIHN0eWxlTWFuYWdlci5pbmplY3QoKTtcblxuICBpZiAoaXNPYmplY3QodGFnTmFtZSkpIHtcbiAgICBvcHRzID0gdGFnTmFtZTtcbiAgICB0YWdOYW1lID0gMDtcbiAgfVxuXG4gIHZhciBlbGVtO1xuICB2YXIgYWxsVGFncztcblxuICAvLyBjcmF3bCB0aGUgRE9NIHRvIGZpbmQgdGhlIHRhZ1xuICBpZiAoaXNTdHJpbmcoc2VsZWN0b3IpKSB7XG4gICAgc2VsZWN0b3IgPSBzZWxlY3RvciA9PT0gJyonID9cbiAgICAgIC8vIHNlbGVjdCBhbGwgcmVnaXN0ZXJlZCB0YWdzXG4gICAgICAvLyAmIHRhZ3MgZm91bmQgd2l0aCB0aGUgcmlvdC10YWcgYXR0cmlidXRlIHNldFxuICAgICAgYWxsVGFncyA9IHNlbGVjdFRhZ3MoKSA6XG4gICAgICAvLyBvciBqdXN0IHRoZSBvbmVzIG5hbWVkIGxpa2UgdGhlIHNlbGVjdG9yXG4gICAgICBzZWxlY3RvciArIHNlbGVjdFRhZ3Moc2VsZWN0b3Iuc3BsaXQoLywgKi8pKTtcblxuICAgIC8vIG1ha2Ugc3VyZSB0byBwYXNzIGFsd2F5cyBhIHNlbGVjdG9yXG4gICAgLy8gdG8gdGhlIHF1ZXJ5U2VsZWN0b3JBbGwgZnVuY3Rpb25cbiAgICBlbGVtID0gc2VsZWN0b3IgPyAkJChzZWxlY3RvcikgOiBbXTtcbiAgfVxuICBlbHNlXG4gICAgLy8gcHJvYmFibHkgeW91IGhhdmUgcGFzc2VkIGFscmVhZHkgYSB0YWcgb3IgYSBOb2RlTGlzdFxuICAgIHsgZWxlbSA9IHNlbGVjdG9yOyB9XG5cbiAgLy8gc2VsZWN0IGFsbCB0aGUgcmVnaXN0ZXJlZCBhbmQgbW91bnQgdGhlbSBpbnNpZGUgdGhlaXIgcm9vdCBlbGVtZW50c1xuICBpZiAodGFnTmFtZSA9PT0gJyonKSB7XG4gICAgLy8gZ2V0IGFsbCBjdXN0b20gdGFnc1xuICAgIHRhZ05hbWUgPSBhbGxUYWdzIHx8IHNlbGVjdFRhZ3MoKTtcbiAgICAvLyBpZiB0aGUgcm9vdCBlbHMgaXQncyBqdXN0IGEgc2luZ2xlIHRhZ1xuICAgIGlmIChlbGVtLnRhZ05hbWUpXG4gICAgICB7IGVsZW0gPSAkJCh0YWdOYW1lLCBlbGVtKTsgfVxuICAgIGVsc2Uge1xuICAgICAgLy8gc2VsZWN0IGFsbCB0aGUgY2hpbGRyZW4gZm9yIGFsbCB0aGUgZGlmZmVyZW50IHJvb3QgZWxlbWVudHNcbiAgICAgIHZhciBub2RlTGlzdCA9IFtdO1xuXG4gICAgICBlYWNoKGVsZW0sIGZ1bmN0aW9uIChfZWwpIHsgcmV0dXJuIG5vZGVMaXN0LnB1c2goJCQodGFnTmFtZSwgX2VsKSk7IH0pO1xuXG4gICAgICBlbGVtID0gbm9kZUxpc3Q7XG4gICAgfVxuICAgIC8vIGdldCByaWQgb2YgdGhlIHRhZ05hbWVcbiAgICB0YWdOYW1lID0gMDtcbiAgfVxuXG4gIHB1c2hUYWdzVG8oZWxlbSk7XG5cbiAgcmV0dXJuIHRhZ3Ncbn1cblxuLy8gQ3JlYXRlIGEgbWl4aW4gdGhhdCBjb3VsZCBiZSBnbG9iYWxseSBzaGFyZWQgYWNyb3NzIGFsbCB0aGUgdGFnc1xudmFyIG1peGlucyA9IHt9O1xudmFyIGdsb2JhbHMgPSBtaXhpbnNbR0xPQkFMX01JWElOXSA9IHt9O1xudmFyIG1peGluc19pZCA9IDA7XG5cbi8qKlxuICogQ3JlYXRlL1JldHVybiBhIG1peGluIGJ5IGl0cyBuYW1lXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9ICBuYW1lIC0gbWl4aW4gbmFtZSAoZ2xvYmFsIG1peGluIGlmIG9iamVjdClcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gIG1peCAtIG1peGluIGxvZ2ljXG4gKiBAcGFyYW0gICB7IEJvb2xlYW4gfSBnIC0gaXMgZ2xvYmFsP1xuICogQHJldHVybnMgeyBPYmplY3QgfSAgdGhlIG1peGluIGxvZ2ljXG4gKi9cbmZ1bmN0aW9uIG1peGluJDEobmFtZSwgbWl4LCBnKSB7XG4gIC8vIFVubmFtZWQgZ2xvYmFsXG4gIGlmIChpc09iamVjdChuYW1lKSkge1xuICAgIG1peGluJDEoKFwiX191bm5hbWVkX1wiICsgKG1peGluc19pZCsrKSksIG5hbWUsIHRydWUpO1xuICAgIHJldHVyblxuICB9XG5cbiAgdmFyIHN0b3JlID0gZyA/IGdsb2JhbHMgOiBtaXhpbnM7XG5cbiAgLy8gR2V0dGVyXG4gIGlmICghbWl4KSB7XG4gICAgaWYgKGlzVW5kZWZpbmVkKHN0b3JlW25hbWVdKSlcbiAgICAgIHsgdGhyb3cgbmV3IEVycm9yKCdVbnJlZ2lzdGVyZWQgbWl4aW46ICcgKyBuYW1lKSB9XG5cbiAgICByZXR1cm4gc3RvcmVbbmFtZV1cbiAgfVxuXG4gIC8vIFNldHRlclxuICBzdG9yZVtuYW1lXSA9IGlzRnVuY3Rpb24obWl4KSA/XG4gICAgZXh0ZW5kKG1peC5wcm90b3R5cGUsIHN0b3JlW25hbWVdIHx8IHt9KSAmJiBtaXggOlxuICAgIGV4dGVuZChzdG9yZVtuYW1lXSB8fCB7fSwgbWl4KTtcbn1cblxuLyoqXG4gKiBVcGRhdGUgYWxsIHRoZSB0YWdzIGluc3RhbmNlcyBjcmVhdGVkXG4gKiBAcmV0dXJucyB7IEFycmF5IH0gYWxsIHRoZSB0YWdzIGluc3RhbmNlc1xuICovXG5mdW5jdGlvbiB1cGRhdGUkMSgpIHtcbiAgcmV0dXJuIGVhY2goX19UQUdTX0NBQ0hFLCBmdW5jdGlvbiAodGFnKSB7IHJldHVybiB0YWcudXBkYXRlKCk7IH0pXG59XG5cbmZ1bmN0aW9uIHVucmVnaXN0ZXIkMShuYW1lKSB7XG4gIGRlbGV0ZSBfX1RBR19JTVBMW25hbWVdO1xufVxuXG52YXIgdmVyc2lvbiQxID0gJ3YzLjQuMCc7XG5cblxudmFyIGNvcmUgPSBPYmplY3QuZnJlZXplKHtcblx0VGFnOiBUYWckMixcblx0dGFnOiB0YWckMSxcblx0dGFnMjogdGFnMiQxLFxuXHRtb3VudDogbW91bnQkMSxcblx0bWl4aW46IG1peGluJDEsXG5cdHVwZGF0ZTogdXBkYXRlJDEsXG5cdHVucmVnaXN0ZXI6IHVucmVnaXN0ZXIkMSxcblx0dmVyc2lvbjogdmVyc2lvbiQxXG59KTtcblxuLy8gY291bnRlciB0byBnaXZlIGEgdW5pcXVlIGlkIHRvIGFsbCB0aGUgVGFnIGluc3RhbmNlc1xudmFyIF9fdWlkID0gMDtcblxuLyoqXG4gKiBXZSBuZWVkIHRvIHVwZGF0ZSBvcHRzIGZvciB0aGlzIHRhZy4gVGhhdCByZXF1aXJlcyB1cGRhdGluZyB0aGUgZXhwcmVzc2lvbnNcbiAqIGluIGFueSBhdHRyaWJ1dGVzIG9uIHRoZSB0YWcsIGFuZCB0aGVuIGNvcHlpbmcgdGhlIHJlc3VsdCBvbnRvIG9wdHMuXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHtCb29sZWFufSBpc0xvb3AgLSBpcyBpdCBhIGxvb3AgdGFnP1xuICogQHBhcmFtICAgeyBUYWcgfSAgcGFyZW50IC0gcGFyZW50IHRhZyBub2RlXG4gKiBAcGFyYW0gICB7IEJvb2xlYW4gfSAgaXNBbm9ueW1vdXMgLSBpcyBpdCBhIHRhZyB3aXRob3V0IGFueSBpbXBsPyAoYSB0YWcgbm90IHJlZ2lzdGVyZWQpXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9ICBvcHRzIC0gdGFnIG9wdGlvbnNcbiAqIEBwYXJhbSAgIHsgQXJyYXkgfSAgaW5zdEF0dHJzIC0gdGFnIGF0dHJpYnV0ZXMgYXJyYXlcbiAqL1xuZnVuY3Rpb24gdXBkYXRlT3B0cyhpc0xvb3AsIHBhcmVudCwgaXNBbm9ueW1vdXMsIG9wdHMsIGluc3RBdHRycykge1xuICAvLyBpc0Fub255bW91cyBgZWFjaGAgdGFncyB0cmVhdCBgZG9tYCBhbmQgYHJvb3RgIGRpZmZlcmVudGx5LiBJbiB0aGlzIGNhc2VcbiAgLy8gKGFuZCBvbmx5IHRoaXMgY2FzZSkgd2UgZG9uJ3QgbmVlZCB0byBkbyB1cGRhdGVPcHRzLCBiZWNhdXNlIHRoZSByZWd1bGFyIHBhcnNlXG4gIC8vIHdpbGwgdXBkYXRlIHRob3NlIGF0dHJzLiBQbHVzLCBpc0Fub255bW91cyB0YWdzIGRvbid0IG5lZWQgb3B0cyBhbnl3YXlcbiAgaWYgKGlzTG9vcCAmJiBpc0Fub255bW91cykgeyByZXR1cm4gfVxuXG4gIHZhciBjdHggPSAhaXNBbm9ueW1vdXMgJiYgaXNMb29wID8gdGhpcyA6IHBhcmVudCB8fCB0aGlzO1xuICBlYWNoKGluc3RBdHRycywgZnVuY3Rpb24gKGF0dHIpIHtcbiAgICBpZiAoYXR0ci5leHByKSB7IHVwZGF0ZUFsbEV4cHJlc3Npb25zLmNhbGwoY3R4LCBbYXR0ci5leHByXSk7IH1cbiAgICAvLyBub3JtYWxpemUgdGhlIGF0dHJpYnV0ZSBuYW1lc1xuICAgIG9wdHNbdG9DYW1lbChhdHRyLm5hbWUpLnJlcGxhY2UoQVRUUlNfUFJFRklYLCAnJyldID0gYXR0ci5leHByID8gYXR0ci5leHByLnZhbHVlIDogYXR0ci52YWx1ZTtcbiAgfSk7XG59XG5cblxuLyoqXG4gKiBUYWcgY2xhc3NcbiAqIEBjb25zdHJ1Y3RvclxuICogQHBhcmFtIHsgT2JqZWN0IH0gaW1wbCAtIGl0IGNvbnRhaW5zIHRoZSB0YWcgdGVtcGxhdGUsIGFuZCBsb2dpY1xuICogQHBhcmFtIHsgT2JqZWN0IH0gY29uZiAtIHRhZyBvcHRpb25zXG4gKiBAcGFyYW0geyBTdHJpbmcgfSBpbm5lckhUTUwgLSBodG1sIHRoYXQgZXZlbnR1YWxseSB3ZSBuZWVkIHRvIGluamVjdCBpbiB0aGUgdGFnXG4gKi9cbmZ1bmN0aW9uIFRhZyQxKGltcGwsIGNvbmYsIGlubmVySFRNTCkge1xuICBpZiAoIGltcGwgPT09IHZvaWQgMCApIGltcGwgPSB7fTtcbiAgaWYgKCBjb25mID09PSB2b2lkIDAgKSBjb25mID0ge307XG5cblxuICB2YXIgb3B0cyA9IGV4dGVuZCh7fSwgY29uZi5vcHRzKSxcbiAgICBwYXJlbnQgPSBjb25mLnBhcmVudCxcbiAgICBpc0xvb3AgPSBjb25mLmlzTG9vcCxcbiAgICBpc0Fub255bW91cyA9ICEhY29uZi5pc0Fub255bW91cyxcbiAgICBza2lwQW5vbnltb3VzID0gc2V0dGluZ3MkMS5za2lwQW5vbnltb3VzVGFncyAmJiBpc0Fub255bW91cyxcbiAgICBpdGVtID0gY2xlYW5VcERhdGEoY29uZi5pdGVtKSxcbiAgICBpbmRleCA9IGNvbmYuaW5kZXgsIC8vIGF2YWlsYWJsZSBvbmx5IGZvciB0aGUgbG9vcGVkIG5vZGVzXG4gICAgaW5zdEF0dHJzID0gW10sIC8vIEFsbCBhdHRyaWJ1dGVzIG9uIHRoZSBUYWcgd2hlbiBpdCdzIGZpcnN0IHBhcnNlZFxuICAgIGltcGxBdHRycyA9IFtdLCAvLyBleHByZXNzaW9ucyBvbiB0aGlzIHR5cGUgb2YgVGFnXG4gICAgZXhwcmVzc2lvbnMgPSBbXSxcbiAgICByb290ID0gY29uZi5yb290LFxuICAgIHRhZ05hbWUgPSBjb25mLnRhZ05hbWUgfHwgZ2V0VGFnTmFtZShyb290KSxcbiAgICBpc1ZpcnR1YWwgPSB0YWdOYW1lID09PSAndmlydHVhbCcsXG4gICAgcHJvcHNJblN5bmNXaXRoUGFyZW50ID0gW10sXG4gICAgZG9tO1xuXG4gIC8vIG1ha2UgdGhpcyB0YWcgb2JzZXJ2YWJsZVxuICBpZiAoIXNraXBBbm9ueW1vdXMpIHsgb2JzZXJ2YWJsZSQxKHRoaXMpOyB9XG4gIC8vIG9ubHkgY2FsbCB1bm1vdW50IGlmIHdlIGhhdmUgYSB2YWxpZCBfX1RBR19JTVBMIChoYXMgbmFtZSBwcm9wZXJ0eSlcbiAgaWYgKGltcGwubmFtZSAmJiByb290Ll90YWcpIHsgcm9vdC5fdGFnLnVubW91bnQodHJ1ZSk7IH1cblxuICAvLyBub3QgeWV0IG1vdW50ZWRcbiAgdGhpcy5pc01vdW50ZWQgPSBmYWxzZTtcblxuICBkZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX18nLCB7XG4gICAgaXNBbm9ueW1vdXM6IGlzQW5vbnltb3VzLFxuICAgIGluc3RBdHRyczogaW5zdEF0dHJzLFxuICAgIGlubmVySFRNTDogaW5uZXJIVE1MLFxuICAgIHRhZ05hbWU6IHRhZ05hbWUsXG4gICAgaW5kZXg6IGluZGV4LFxuICAgIGlzTG9vcDogaXNMb29wLFxuICAgIC8vIHRoZXNlIHZhcnMgd2lsbCBiZSBuZWVkZWQgb25seSBmb3IgdGhlIHZpcnR1YWwgdGFnc1xuICAgIHZpcnRzOiBbXSxcbiAgICB0YWlsOiBudWxsLFxuICAgIGhlYWQ6IG51bGwsXG4gICAgcGFyZW50OiBudWxsLFxuICAgIGl0ZW06IG51bGxcbiAgfSk7XG5cbiAgLy8gY3JlYXRlIGEgdW5pcXVlIGlkIHRvIHRoaXMgdGFnXG4gIC8vIGl0IGNvdWxkIGJlIGhhbmR5IHRvIHVzZSBpdCBhbHNvIHRvIGltcHJvdmUgdGhlIHZpcnR1YWwgZG9tIHJlbmRlcmluZyBzcGVlZFxuICBkZWZpbmVQcm9wZXJ0eSh0aGlzLCAnX3Jpb3RfaWQnLCArK19fdWlkKTsgLy8gYmFzZSAxIGFsbG93cyB0ZXN0ICF0Ll9yaW90X2lkXG4gIGRlZmluZVByb3BlcnR5KHRoaXMsICdyb290Jywgcm9vdCk7XG4gIGV4dGVuZCh0aGlzLCB7IG9wdHM6IG9wdHMgfSwgaXRlbSk7XG4gIC8vIHByb3RlY3QgdGhlIFwidGFnc1wiIGFuZCBcInJlZnNcIiBwcm9wZXJ0eSBmcm9tIGJlaW5nIG92ZXJyaWRkZW5cbiAgZGVmaW5lUHJvcGVydHkodGhpcywgJ3BhcmVudCcsIHBhcmVudCB8fCBudWxsKTtcbiAgZGVmaW5lUHJvcGVydHkodGhpcywgJ3RhZ3MnLCB7fSk7XG4gIGRlZmluZVByb3BlcnR5KHRoaXMsICdyZWZzJywge30pO1xuXG4gIGRvbSA9IGlzTG9vcCAmJiBpc0Fub255bW91cyA/IHJvb3QgOiBta2RvbShpbXBsLnRtcGwsIGlubmVySFRNTCwgaXNMb29wKTtcblxuICAvKipcbiAgICogVXBkYXRlIHRoZSB0YWcgZXhwcmVzc2lvbnMgYW5kIG9wdGlvbnNcbiAgICogQHBhcmFtICAgeyAqIH0gIGRhdGEgLSBkYXRhIHdlIHdhbnQgdG8gdXNlIHRvIGV4dGVuZCB0aGUgdGFnIHByb3BlcnRpZXNcbiAgICogQHJldHVybnMgeyBUYWcgfSB0aGUgY3VycmVudCB0YWcgaW5zdGFuY2VcbiAgICovXG4gIGRlZmluZVByb3BlcnR5KHRoaXMsICd1cGRhdGUnLCBmdW5jdGlvbiB0YWdVcGRhdGUoZGF0YSkge1xuICAgIHZhciBuZXh0T3B0cyA9IHt9LFxuICAgICAgY2FuVHJpZ2dlciA9IHRoaXMuaXNNb3VudGVkICYmICFza2lwQW5vbnltb3VzO1xuXG4gICAgLy8gbWFrZSBzdXJlIHRoZSBkYXRhIHBhc3NlZCB3aWxsIG5vdCBvdmVycmlkZVxuICAgIC8vIHRoZSBjb21wb25lbnQgY29yZSBtZXRob2RzXG4gICAgZGF0YSA9IGNsZWFuVXBEYXRhKGRhdGEpO1xuICAgIGV4dGVuZCh0aGlzLCBkYXRhKTtcbiAgICB1cGRhdGVPcHRzLmFwcGx5KHRoaXMsIFtpc0xvb3AsIHBhcmVudCwgaXNBbm9ueW1vdXMsIG5leHRPcHRzLCBpbnN0QXR0cnNdKTtcblxuICAgIGlmIChjYW5UcmlnZ2VyICYmIHRoaXMuaXNNb3VudGVkICYmIGlzRnVuY3Rpb24odGhpcy5zaG91bGRVcGRhdGUpICYmICF0aGlzLnNob3VsZFVwZGF0ZShkYXRhLCBuZXh0T3B0cykpIHtcbiAgICAgIHJldHVybiB0aGlzXG4gICAgfVxuXG4gICAgLy8gaW5oZXJpdCBwcm9wZXJ0aWVzIGZyb20gdGhlIHBhcmVudCwgYnV0IG9ubHkgZm9yIGlzQW5vbnltb3VzIHRhZ3NcbiAgICBpZiAoaXNMb29wICYmIGlzQW5vbnltb3VzKSB7IGluaGVyaXRGcm9tLmFwcGx5KHRoaXMsIFt0aGlzLnBhcmVudCwgcHJvcHNJblN5bmNXaXRoUGFyZW50XSk7IH1cbiAgICBleHRlbmQob3B0cywgbmV4dE9wdHMpO1xuICAgIGlmIChjYW5UcmlnZ2VyKSB7IHRoaXMudHJpZ2dlcigndXBkYXRlJywgZGF0YSk7IH1cbiAgICB1cGRhdGVBbGxFeHByZXNzaW9ucy5jYWxsKHRoaXMsIGV4cHJlc3Npb25zKTtcbiAgICBpZiAoY2FuVHJpZ2dlcikgeyB0aGlzLnRyaWdnZXIoJ3VwZGF0ZWQnKTsgfVxuXG4gICAgcmV0dXJuIHRoaXNcblxuICB9LmJpbmQodGhpcykpO1xuXG4gIC8qKlxuICAgKiBBZGQgYSBtaXhpbiB0byB0aGlzIHRhZ1xuICAgKiBAcmV0dXJucyB7IFRhZyB9IHRoZSBjdXJyZW50IHRhZyBpbnN0YW5jZVxuICAgKi9cbiAgZGVmaW5lUHJvcGVydHkodGhpcywgJ21peGluJywgZnVuY3Rpb24gdGFnTWl4aW4oKSB7XG4gICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBlYWNoKGFyZ3VtZW50cywgZnVuY3Rpb24gKG1peCkge1xuICAgICAgdmFyIGluc3RhbmNlLCBvYmo7XG4gICAgICB2YXIgcHJvcHMgPSBbXTtcblxuICAgICAgLy8gcHJvcGVydGllcyBibGFja2xpc3RlZCBhbmQgd2lsbCBub3QgYmUgYm91bmQgdG8gdGhlIHRhZyBpbnN0YW5jZVxuICAgICAgdmFyIHByb3BzQmxhY2tsaXN0ID0gWydpbml0JywgJ19fcHJvdG9fXyddO1xuXG4gICAgICBtaXggPSBpc1N0cmluZyhtaXgpID8gbWl4aW4kMShtaXgpIDogbWl4O1xuXG4gICAgICAvLyBjaGVjayBpZiB0aGUgbWl4aW4gaXMgYSBmdW5jdGlvblxuICAgICAgaWYgKGlzRnVuY3Rpb24obWl4KSkge1xuICAgICAgICAvLyBjcmVhdGUgdGhlIG5ldyBtaXhpbiBpbnN0YW5jZVxuICAgICAgICBpbnN0YW5jZSA9IG5ldyBtaXgoKTtcbiAgICAgIH0gZWxzZSB7IGluc3RhbmNlID0gbWl4OyB9XG5cbiAgICAgIHZhciBwcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZihpbnN0YW5jZSk7XG5cbiAgICAgIC8vIGJ1aWxkIG11bHRpbGV2ZWwgcHJvdG90eXBlIGluaGVyaXRhbmNlIGNoYWluIHByb3BlcnR5IGxpc3RcbiAgICAgIGRvIHsgcHJvcHMgPSBwcm9wcy5jb25jYXQoT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXMob2JqIHx8IGluc3RhbmNlKSk7IH1cbiAgICAgIHdoaWxlIChvYmogPSBPYmplY3QuZ2V0UHJvdG90eXBlT2Yob2JqIHx8IGluc3RhbmNlKSlcblxuICAgICAgLy8gbG9vcCB0aGUga2V5cyBpbiB0aGUgZnVuY3Rpb24gcHJvdG90eXBlIG9yIHRoZSBhbGwgb2JqZWN0IGtleXNcbiAgICAgIGVhY2gocHJvcHMsIGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgLy8gYmluZCBtZXRob2RzIHRvIHRoaXNcbiAgICAgICAgLy8gYWxsb3cgbWl4aW5zIHRvIG92ZXJyaWRlIG90aGVyIHByb3BlcnRpZXMvcGFyZW50IG1peGluc1xuICAgICAgICBpZiAoIWNvbnRhaW5zKHByb3BzQmxhY2tsaXN0LCBrZXkpKSB7XG4gICAgICAgICAgLy8gY2hlY2sgZm9yIGdldHRlcnMvc2V0dGVyc1xuICAgICAgICAgIHZhciBkZXNjcmlwdG9yID0gT2JqZWN0LmdldE93blByb3BlcnR5RGVzY3JpcHRvcihpbnN0YW5jZSwga2V5KSB8fCBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHByb3RvLCBrZXkpO1xuICAgICAgICAgIHZhciBoYXNHZXR0ZXJTZXR0ZXIgPSBkZXNjcmlwdG9yICYmIChkZXNjcmlwdG9yLmdldCB8fCBkZXNjcmlwdG9yLnNldCk7XG5cbiAgICAgICAgICAvLyBhcHBseSBtZXRob2Qgb25seSBpZiBpdCBkb2VzIG5vdCBhbHJlYWR5IGV4aXN0IG9uIHRoZSBpbnN0YW5jZVxuICAgICAgICAgIGlmICghdGhpcyQxLmhhc093blByb3BlcnR5KGtleSkgJiYgaGFzR2V0dGVyU2V0dGVyKSB7XG4gICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkodGhpcyQxLCBrZXksIGRlc2NyaXB0b3IpO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aGlzJDFba2V5XSA9IGlzRnVuY3Rpb24oaW5zdGFuY2Vba2V5XSkgP1xuICAgICAgICAgICAgICBpbnN0YW5jZVtrZXldLmJpbmQodGhpcyQxKSA6XG4gICAgICAgICAgICAgIGluc3RhbmNlW2tleV07XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgICAgLy8gaW5pdCBtZXRob2Qgd2lsbCBiZSBjYWxsZWQgYXV0b21hdGljYWxseVxuICAgICAgaWYgKGluc3RhbmNlLmluaXQpXG4gICAgICAgIHsgaW5zdGFuY2UuaW5pdC5iaW5kKHRoaXMkMSkoKTsgfVxuICAgIH0pO1xuICAgIHJldHVybiB0aGlzXG4gIH0uYmluZCh0aGlzKSk7XG5cbiAgLyoqXG4gICAqIE1vdW50IHRoZSBjdXJyZW50IHRhZyBpbnN0YW5jZVxuICAgKiBAcmV0dXJucyB7IFRhZyB9IHRoZSBjdXJyZW50IHRhZyBpbnN0YW5jZVxuICAgKi9cbiAgZGVmaW5lUHJvcGVydHkodGhpcywgJ21vdW50JywgZnVuY3Rpb24gdGFnTW91bnQoKSB7XG4gICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICByb290Ll90YWcgPSB0aGlzOyAvLyBrZWVwIGEgcmVmZXJlbmNlIHRvIHRoZSB0YWcganVzdCBjcmVhdGVkXG5cbiAgICAvLyBSZWFkIGFsbCB0aGUgYXR0cnMgb24gdGhpcyBpbnN0YW5jZS4gVGhpcyBnaXZlIHVzIHRoZSBpbmZvIHdlIG5lZWQgZm9yIHVwZGF0ZU9wdHNcbiAgICBwYXJzZUF0dHJpYnV0ZXMuYXBwbHkocGFyZW50LCBbcm9vdCwgcm9vdC5hdHRyaWJ1dGVzLCBmdW5jdGlvbiAoYXR0ciwgZXhwcikge1xuICAgICAgaWYgKCFpc0Fub255bW91cyAmJiBSZWZFeHByLmlzUHJvdG90eXBlT2YoZXhwcikpIHsgZXhwci50YWcgPSB0aGlzJDE7IH1cbiAgICAgIGF0dHIuZXhwciA9IGV4cHI7XG4gICAgICBpbnN0QXR0cnMucHVzaChhdHRyKTtcbiAgICB9XSk7XG5cbiAgICAvLyB1cGRhdGUgdGhlIHJvb3QgYWRkaW5nIGN1c3RvbSBhdHRyaWJ1dGVzIGNvbWluZyBmcm9tIHRoZSBjb21waWxlclxuICAgIGltcGxBdHRycyA9IFtdO1xuICAgIHdhbGtBdHRycyhpbXBsLmF0dHJzLCBmdW5jdGlvbiAoaywgdikgeyBpbXBsQXR0cnMucHVzaCh7bmFtZTogaywgdmFsdWU6IHZ9KTsgfSk7XG4gICAgcGFyc2VBdHRyaWJ1dGVzLmFwcGx5KHRoaXMsIFtyb290LCBpbXBsQXR0cnMsIGZ1bmN0aW9uIChhdHRyLCBleHByKSB7XG4gICAgICBpZiAoZXhwcikgeyBleHByZXNzaW9ucy5wdXNoKGV4cHIpOyB9XG4gICAgICBlbHNlIHsgc2V0QXR0cihyb290LCBhdHRyLm5hbWUsIGF0dHIudmFsdWUpOyB9XG4gICAgfV0pO1xuXG4gICAgLy8gaW5pdGlhbGlhdGlvblxuICAgIHVwZGF0ZU9wdHMuYXBwbHkodGhpcywgW2lzTG9vcCwgcGFyZW50LCBpc0Fub255bW91cywgb3B0cywgaW5zdEF0dHJzXSk7XG5cbiAgICAvLyBhZGQgZ2xvYmFsIG1peGluc1xuICAgIHZhciBnbG9iYWxNaXhpbiA9IG1peGluJDEoR0xPQkFMX01JWElOKTtcblxuICAgIGlmIChnbG9iYWxNaXhpbiAmJiAhc2tpcEFub255bW91cykge1xuICAgICAgZm9yICh2YXIgaSBpbiBnbG9iYWxNaXhpbikge1xuICAgICAgICBpZiAoZ2xvYmFsTWl4aW4uaGFzT3duUHJvcGVydHkoaSkpIHtcbiAgICAgICAgICB0aGlzJDEubWl4aW4oZ2xvYmFsTWl4aW5baV0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKGltcGwuZm4pIHsgaW1wbC5mbi5jYWxsKHRoaXMsIG9wdHMpOyB9XG5cbiAgICBpZiAoIXNraXBBbm9ueW1vdXMpIHsgdGhpcy50cmlnZ2VyKCdiZWZvcmUtbW91bnQnKTsgfVxuXG4gICAgLy8gcGFyc2UgbGF5b3V0IGFmdGVyIGluaXQuIGZuIG1heSBjYWxjdWxhdGUgYXJncyBmb3IgbmVzdGVkIGN1c3RvbSB0YWdzXG4gICAgcGFyc2VFeHByZXNzaW9ucy5hcHBseSh0aGlzLCBbZG9tLCBleHByZXNzaW9ucywgaXNBbm9ueW1vdXNdKTtcblxuICAgIHRoaXMudXBkYXRlKGl0ZW0pO1xuXG4gICAgaWYgKCFpc0Fub255bW91cykge1xuICAgICAgd2hpbGUgKGRvbS5maXJzdENoaWxkKSB7IHJvb3QuYXBwZW5kQ2hpbGQoZG9tLmZpcnN0Q2hpbGQpOyB9XG4gICAgfVxuXG4gICAgZGVmaW5lUHJvcGVydHkodGhpcywgJ3Jvb3QnLCByb290KTtcbiAgICBkZWZpbmVQcm9wZXJ0eSh0aGlzLCAnaXNNb3VudGVkJywgdHJ1ZSk7XG5cbiAgICBpZiAoc2tpcEFub255bW91cykgeyByZXR1cm4gfVxuXG4gICAgLy8gaWYgaXQncyBub3QgYSBjaGlsZCB0YWcgd2UgY2FuIHRyaWdnZXIgaXRzIG1vdW50IGV2ZW50XG4gICAgaWYgKCF0aGlzLnBhcmVudCkge1xuICAgICAgdGhpcy50cmlnZ2VyKCdtb3VudCcpO1xuICAgIH1cbiAgICAvLyBvdGhlcndpc2Ugd2UgbmVlZCB0byB3YWl0IHRoYXQgdGhlIHBhcmVudCBcIm1vdW50XCIgb3IgXCJ1cGRhdGVkXCIgZXZlbnQgZ2V0cyB0cmlnZ2VyZWRcbiAgICBlbHNlIHtcbiAgICAgIHZhciBwID0gZ2V0SW1tZWRpYXRlQ3VzdG9tUGFyZW50VGFnKHRoaXMucGFyZW50KTtcbiAgICAgIHAub25lKCFwLmlzTW91bnRlZCA/ICdtb3VudCcgOiAndXBkYXRlZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcyQxLnRyaWdnZXIoJ21vdW50Jyk7XG4gICAgICB9KTtcbiAgICB9XG5cbiAgICByZXR1cm4gdGhpc1xuXG4gIH0uYmluZCh0aGlzKSk7XG5cbiAgLyoqXG4gICAqIFVubW91bnQgdGhlIHRhZyBpbnN0YW5jZVxuICAgKiBAcGFyYW0geyBCb29sZWFuIH0gbXVzdEtlZXBSb290IC0gaWYgaXQncyB0cnVlIHRoZSByb290IG5vZGUgd2lsbCBub3QgYmUgcmVtb3ZlZFxuICAgKiBAcmV0dXJucyB7IFRhZyB9IHRoZSBjdXJyZW50IHRhZyBpbnN0YW5jZVxuICAgKi9cbiAgZGVmaW5lUHJvcGVydHkodGhpcywgJ3VubW91bnQnLCBmdW5jdGlvbiB0YWdVbm1vdW50KG11c3RLZWVwUm9vdCkge1xuICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgdmFyIGVsID0gdGhpcy5yb290LFxuICAgICAgcCA9IGVsLnBhcmVudE5vZGUsXG4gICAgICBwdGFnLFxuICAgICAgdGFnSW5kZXggPSBfX1RBR1NfQ0FDSEUuaW5kZXhPZih0aGlzKTtcblxuICAgIGlmICghc2tpcEFub255bW91cykgeyB0aGlzLnRyaWdnZXIoJ2JlZm9yZS11bm1vdW50Jyk7IH1cblxuICAgIC8vIGNsZWFyIGFsbCBhdHRyaWJ1dGVzIGNvbWluZyBmcm9tIHRoZSBtb3VudGVkIHRhZ1xuICAgIHdhbGtBdHRycyhpbXBsLmF0dHJzLCBmdW5jdGlvbiAobmFtZSkge1xuICAgICAgaWYgKHN0YXJ0c1dpdGgobmFtZSwgQVRUUlNfUFJFRklYKSlcbiAgICAgICAgeyBuYW1lID0gbmFtZS5zbGljZShBVFRSU19QUkVGSVgubGVuZ3RoKTsgfVxuICAgICAgcmVtQXR0cihyb290LCBuYW1lKTtcbiAgICB9KTtcblxuICAgIC8vIHJlbW92ZSB0aGlzIHRhZyBpbnN0YW5jZSBmcm9tIHRoZSBnbG9iYWwgdmlydHVhbERvbSB2YXJpYWJsZVxuICAgIGlmICh0YWdJbmRleCAhPT0gLTEpXG4gICAgICB7IF9fVEFHU19DQUNIRS5zcGxpY2UodGFnSW5kZXgsIDEpOyB9XG5cbiAgICBpZiAocCB8fCBpc1ZpcnR1YWwpIHtcbiAgICAgIGlmIChwYXJlbnQpIHtcbiAgICAgICAgcHRhZyA9IGdldEltbWVkaWF0ZUN1c3RvbVBhcmVudFRhZyhwYXJlbnQpO1xuXG4gICAgICAgIGlmIChpc1ZpcnR1YWwpIHtcbiAgICAgICAgICBPYmplY3Qua2V5cyh0aGlzLnRhZ3MpLmZvckVhY2goZnVuY3Rpb24gKHRhZ05hbWUpIHtcbiAgICAgICAgICAgIGFycmF5aXNoUmVtb3ZlKHB0YWcudGFncywgdGFnTmFtZSwgdGhpcyQxLnRhZ3NbdGFnTmFtZV0pO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGFycmF5aXNoUmVtb3ZlKHB0YWcudGFncywgdGFnTmFtZSwgdGhpcyk7XG4gICAgICAgICAgaWYocGFyZW50ICE9PSBwdGFnKSAvLyByZW1vdmUgZnJvbSBfcGFyZW50IHRvb1xuICAgICAgICAgICAgeyBhcnJheWlzaFJlbW92ZShwYXJlbnQudGFncywgdGFnTmFtZSwgdGhpcyk7IH1cbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgd2hpbGUgKGVsLmZpcnN0Q2hpbGQpIHsgZWwucmVtb3ZlQ2hpbGQoZWwuZmlyc3RDaGlsZCk7IH1cbiAgICAgIH1cblxuICAgICAgaWYgKHApXG4gICAgICAgIHsgaWYgKCFtdXN0S2VlcFJvb3QpIHtcbiAgICAgICAgICBwLnJlbW92ZUNoaWxkKGVsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAvLyB0aGUgcmlvdC10YWcgYW5kIHRoZSBkYXRhLWlzIGF0dHJpYnV0ZXMgYXJlbid0IG5lZWRlZCBhbnltb3JlLCByZW1vdmUgdGhlbVxuICAgICAgICAgIHJlbUF0dHIocCwgSVNfRElSRUNUSVZFKTtcbiAgICAgICAgfSB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX18udmlydHMpIHtcbiAgICAgIGVhY2godGhpcy5fXy52aXJ0cywgZnVuY3Rpb24gKHYpIHtcbiAgICAgICAgaWYgKHYucGFyZW50Tm9kZSkgeyB2LnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQodik7IH1cbiAgICAgIH0pO1xuICAgIH1cblxuICAgIC8vIGFsbG93IGV4cHJlc3Npb25zIHRvIHVubW91bnQgdGhlbXNlbHZlc1xuICAgIHVubW91bnRBbGwoZXhwcmVzc2lvbnMpO1xuICAgIGVhY2goaW5zdEF0dHJzLCBmdW5jdGlvbiAoYSkgeyByZXR1cm4gYS5leHByICYmIGEuZXhwci51bm1vdW50ICYmIGEuZXhwci51bm1vdW50KCk7IH0pO1xuXG4gICAgLy8gY3VzdG9tIGludGVybmFsIHVubW91bnQgZnVuY3Rpb24gdG8gYXZvaWQgcmVseWluZyBvbiB0aGUgb2JzZXJ2YWJsZVxuICAgIGlmICh0aGlzLl9fLm9uVW5tb3VudCkgeyB0aGlzLl9fLm9uVW5tb3VudCgpOyB9XG5cbiAgICBpZiAoIXNraXBBbm9ueW1vdXMpIHtcbiAgICAgIHRoaXMudHJpZ2dlcigndW5tb3VudCcpO1xuICAgICAgdGhpcy5vZmYoJyonKTtcbiAgICB9XG5cbiAgICBkZWZpbmVQcm9wZXJ0eSh0aGlzLCAnaXNNb3VudGVkJywgZmFsc2UpO1xuXG4gICAgZGVsZXRlIHRoaXMucm9vdC5fdGFnO1xuXG4gICAgcmV0dXJuIHRoaXNcblxuICB9LmJpbmQodGhpcykpO1xufVxuXG4vKipcbiAqIERldGVjdCB0aGUgdGFnIGltcGxlbWVudGF0aW9uIGJ5IGEgRE9NIG5vZGVcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZG9tIC0gRE9NIG5vZGUgd2UgbmVlZCB0byBwYXJzZSB0byBnZXQgaXRzIHRhZyBpbXBsZW1lbnRhdGlvblxuICogQHJldHVybnMgeyBPYmplY3QgfSBpdCByZXR1cm5zIGFuIG9iamVjdCBjb250YWluaW5nIHRoZSBpbXBsZW1lbnRhdGlvbiBvZiBhIGN1c3RvbSB0YWcgKHRlbXBsYXRlIGFuZCBib290IGZ1bmN0aW9uKVxuICovXG5mdW5jdGlvbiBnZXRUYWcoZG9tKSB7XG4gIHJldHVybiBkb20udGFnTmFtZSAmJiBfX1RBR19JTVBMW2dldEF0dHIoZG9tLCBJU19ESVJFQ1RJVkUpIHx8XG4gICAgZ2V0QXR0cihkb20sIElTX0RJUkVDVElWRSkgfHwgZG9tLnRhZ05hbWUudG9Mb3dlckNhc2UoKV1cbn1cblxuLyoqXG4gKiBJbmhlcml0IHByb3BlcnRpZXMgZnJvbSBhIHRhcmdldCB0YWcgaW5zdGFuY2VcbiAqIEB0aGlzIFRhZ1xuICogQHBhcmFtICAgeyBUYWcgfSB0YXJnZXQgLSB0YWcgd2hlcmUgd2Ugd2lsbCBpbmhlcml0IHByb3BlcnRpZXNcbiAqIEBwYXJhbSAgIHsgQXJyYXkgfSBwcm9wc0luU3luY1dpdGhQYXJlbnQgLSBhcnJheSBvZiBwcm9wZXJ0aWVzIHRvIHN5bmMgd2l0aCB0aGUgdGFyZ2V0XG4gKi9cbmZ1bmN0aW9uIGluaGVyaXRGcm9tKHRhcmdldCwgcHJvcHNJblN5bmNXaXRoUGFyZW50KSB7XG4gIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gIGVhY2goT2JqZWN0LmtleXModGFyZ2V0KSwgZnVuY3Rpb24gKGspIHtcbiAgICAvLyBzb21lIHByb3BlcnRpZXMgbXVzdCBiZSBhbHdheXMgaW4gc3luYyB3aXRoIHRoZSBwYXJlbnQgdGFnXG4gICAgdmFyIG11c3RTeW5jID0gIWlzUmVzZXJ2ZWROYW1lKGspICYmIGNvbnRhaW5zKHByb3BzSW5TeW5jV2l0aFBhcmVudCwgayk7XG5cbiAgICBpZiAoaXNVbmRlZmluZWQodGhpcyQxW2tdKSB8fCBtdXN0U3luYykge1xuICAgICAgLy8gdHJhY2sgdGhlIHByb3BlcnR5IHRvIGtlZXAgaW4gc3luY1xuICAgICAgLy8gc28gd2UgY2FuIGtlZXAgaXQgdXBkYXRlZFxuICAgICAgaWYgKCFtdXN0U3luYykgeyBwcm9wc0luU3luY1dpdGhQYXJlbnQucHVzaChrKTsgfVxuICAgICAgdGhpcyQxW2tdID0gdGFyZ2V0W2tdO1xuICAgIH1cbiAgfSk7XG59XG5cbi8qKlxuICogTW92ZSB0aGUgcG9zaXRpb24gb2YgYSBjdXN0b20gdGFnIGluIGl0cyBwYXJlbnQgdGFnXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSAgIHsgU3RyaW5nIH0gdGFnTmFtZSAtIGtleSB3aGVyZSB0aGUgdGFnIHdhcyBzdG9yZWRcbiAqIEBwYXJhbSAgIHsgTnVtYmVyIH0gbmV3UG9zIC0gaW5kZXggd2hlcmUgdGhlIG5ldyB0YWcgd2lsbCBiZSBzdG9yZWRcbiAqL1xuZnVuY3Rpb24gbW92ZUNoaWxkVGFnKHRhZ05hbWUsIG5ld1Bvcykge1xuICB2YXIgcGFyZW50ID0gdGhpcy5wYXJlbnQsXG4gICAgdGFncztcbiAgLy8gbm8gcGFyZW50IG5vIG1vdmVcbiAgaWYgKCFwYXJlbnQpIHsgcmV0dXJuIH1cblxuICB0YWdzID0gcGFyZW50LnRhZ3NbdGFnTmFtZV07XG5cbiAgaWYgKGlzQXJyYXkodGFncykpXG4gICAgeyB0YWdzLnNwbGljZShuZXdQb3MsIDAsIHRhZ3Muc3BsaWNlKHRhZ3MuaW5kZXhPZih0aGlzKSwgMSlbMF0pOyB9XG4gIGVsc2UgeyBhcnJheWlzaEFkZChwYXJlbnQudGFncywgdGFnTmFtZSwgdGhpcyk7IH1cbn1cblxuLyoqXG4gKiBDcmVhdGUgYSBuZXcgY2hpbGQgdGFnIGluY2x1ZGluZyBpdCBjb3JyZWN0bHkgaW50byBpdHMgcGFyZW50XG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IGNoaWxkIC0gY2hpbGQgdGFnIGltcGxlbWVudGF0aW9uXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IG9wdHMgLSB0YWcgb3B0aW9ucyBjb250YWluaW5nIHRoZSBET00gbm9kZSB3aGVyZSB0aGUgdGFnIHdpbGwgYmUgbW91bnRlZFxuICogQHBhcmFtICAgeyBTdHJpbmcgfSBpbm5lckhUTUwgLSBpbm5lciBodG1sIG9mIHRoZSBjaGlsZCBub2RlXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IHBhcmVudCAtIGluc3RhbmNlIG9mIHRoZSBwYXJlbnQgdGFnIGluY2x1ZGluZyB0aGUgY2hpbGQgY3VzdG9tIHRhZ1xuICogQHJldHVybnMgeyBPYmplY3QgfSBpbnN0YW5jZSBvZiB0aGUgbmV3IGNoaWxkIHRhZyBqdXN0IGNyZWF0ZWRcbiAqL1xuZnVuY3Rpb24gaW5pdENoaWxkVGFnKGNoaWxkLCBvcHRzLCBpbm5lckhUTUwsIHBhcmVudCkge1xuICB2YXIgdGFnID0gbmV3IFRhZyQxKGNoaWxkLCBvcHRzLCBpbm5lckhUTUwpLFxuICAgIHRhZ05hbWUgPSBvcHRzLnRhZ05hbWUgfHwgZ2V0VGFnTmFtZShvcHRzLnJvb3QsIHRydWUpLFxuICAgIHB0YWcgPSBnZXRJbW1lZGlhdGVDdXN0b21QYXJlbnRUYWcocGFyZW50KTtcbiAgLy8gZml4IGZvciB0aGUgcGFyZW50IGF0dHJpYnV0ZSBpbiB0aGUgbG9vcGVkIGVsZW1lbnRzXG4gIGRlZmluZVByb3BlcnR5KHRhZywgJ3BhcmVudCcsIHB0YWcpO1xuICAvLyBzdG9yZSB0aGUgcmVhbCBwYXJlbnQgdGFnXG4gIC8vIGluIHNvbWUgY2FzZXMgdGhpcyBjb3VsZCBiZSBkaWZmZXJlbnQgZnJvbSB0aGUgY3VzdG9tIHBhcmVudCB0YWdcbiAgLy8gZm9yIGV4YW1wbGUgaW4gbmVzdGVkIGxvb3BzXG4gIHRhZy5fXy5wYXJlbnQgPSBwYXJlbnQ7XG5cbiAgLy8gYWRkIHRoaXMgdGFnIHRvIHRoZSBjdXN0b20gcGFyZW50IHRhZ1xuICBhcnJheWlzaEFkZChwdGFnLnRhZ3MsIHRhZ05hbWUsIHRhZyk7XG5cbiAgLy8gYW5kIGFsc28gdG8gdGhlIHJlYWwgcGFyZW50IHRhZ1xuICBpZiAocHRhZyAhPT0gcGFyZW50KVxuICAgIHsgYXJyYXlpc2hBZGQocGFyZW50LnRhZ3MsIHRhZ05hbWUsIHRhZyk7IH1cblxuICAvLyBlbXB0eSB0aGUgY2hpbGQgbm9kZSBvbmNlIHdlIGdvdCBpdHMgdGVtcGxhdGVcbiAgLy8gdG8gYXZvaWQgdGhhdCBpdHMgY2hpbGRyZW4gZ2V0IGNvbXBpbGVkIG11bHRpcGxlIHRpbWVzXG4gIG9wdHMucm9vdC5pbm5lckhUTUwgPSAnJztcblxuICByZXR1cm4gdGFnXG59XG5cbi8qKlxuICogTG9vcCBiYWNrd2FyZCBhbGwgdGhlIHBhcmVudHMgdHJlZSB0byBkZXRlY3QgdGhlIGZpcnN0IGN1c3RvbSBwYXJlbnQgdGFnXG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IHRhZyAtIGEgVGFnIGluc3RhbmNlXG4gKiBAcmV0dXJucyB7IE9iamVjdCB9IHRoZSBpbnN0YW5jZSBvZiB0aGUgZmlyc3QgY3VzdG9tIHBhcmVudCB0YWcgZm91bmRcbiAqL1xuZnVuY3Rpb24gZ2V0SW1tZWRpYXRlQ3VzdG9tUGFyZW50VGFnKHRhZykge1xuICB2YXIgcHRhZyA9IHRhZztcbiAgd2hpbGUgKHB0YWcuX18uaXNBbm9ueW1vdXMpIHtcbiAgICBpZiAoIXB0YWcucGFyZW50KSB7IGJyZWFrIH1cbiAgICBwdGFnID0gcHRhZy5wYXJlbnQ7XG4gIH1cbiAgcmV0dXJuIHB0YWdcbn1cblxuLyoqXG4gKiBUcmlnZ2VyIHRoZSB1bm1vdW50IG1ldGhvZCBvbiBhbGwgdGhlIGV4cHJlc3Npb25zXG4gKiBAcGFyYW0gICB7IEFycmF5IH0gZXhwcmVzc2lvbnMgLSBET00gZXhwcmVzc2lvbnNcbiAqL1xuZnVuY3Rpb24gdW5tb3VudEFsbChleHByZXNzaW9ucykge1xuICBlYWNoKGV4cHJlc3Npb25zLCBmdW5jdGlvbihleHByKSB7XG4gICAgaWYgKGV4cHIgaW5zdGFuY2VvZiBUYWckMSkgeyBleHByLnVubW91bnQodHJ1ZSk7IH1cbiAgICBlbHNlIGlmIChleHByLnVubW91bnQpIHsgZXhwci51bm1vdW50KCk7IH1cbiAgfSk7XG59XG5cbi8qKlxuICogR2V0IHRoZSB0YWcgbmFtZSBvZiBhbnkgRE9NIG5vZGVcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZG9tIC0gRE9NIG5vZGUgd2Ugd2FudCB0byBwYXJzZVxuICogQHBhcmFtICAgeyBCb29sZWFuIH0gc2tpcERhdGFJcyAtIGhhY2sgdG8gaWdub3JlIHRoZSBkYXRhLWlzIGF0dHJpYnV0ZSB3aGVuIGF0dGFjaGluZyB0byBwYXJlbnRcbiAqIEByZXR1cm5zIHsgU3RyaW5nIH0gbmFtZSB0byBpZGVudGlmeSB0aGlzIGRvbSBub2RlIGluIHJpb3RcbiAqL1xuZnVuY3Rpb24gZ2V0VGFnTmFtZShkb20sIHNraXBEYXRhSXMpIHtcbiAgdmFyIGNoaWxkID0gZ2V0VGFnKGRvbSksXG4gICAgbmFtZWRUYWcgPSAhc2tpcERhdGFJcyAmJiBnZXRBdHRyKGRvbSwgSVNfRElSRUNUSVZFKTtcbiAgcmV0dXJuIG5hbWVkVGFnICYmICF0bXBsLmhhc0V4cHIobmFtZWRUYWcpID9cbiAgICAgICAgICAgICAgICBuYW1lZFRhZyA6XG4gICAgICAgICAgICAgIGNoaWxkID8gY2hpbGQubmFtZSA6IGRvbS50YWdOYW1lLnRvTG93ZXJDYXNlKClcbn1cblxuLyoqXG4gKiBXaXRoIHRoaXMgZnVuY3Rpb24gd2UgYXZvaWQgdGhhdCB0aGUgaW50ZXJuYWwgVGFnIG1ldGhvZHMgZ2V0IG92ZXJyaWRkZW5cbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gZGF0YSAtIG9wdGlvbnMgd2Ugd2FudCB0byB1c2UgdG8gZXh0ZW5kIHRoZSB0YWcgaW5zdGFuY2VcbiAqIEByZXR1cm5zIHsgT2JqZWN0IH0gY2xlYW4gb2JqZWN0IHdpdGhvdXQgY29udGFpbmluZyB0aGUgcmlvdCBpbnRlcm5hbCByZXNlcnZlZCB3b3Jkc1xuICovXG5mdW5jdGlvbiBjbGVhblVwRGF0YShkYXRhKSB7XG4gIGlmICghKGRhdGEgaW5zdGFuY2VvZiBUYWckMSkgJiYgIShkYXRhICYmIGlzRnVuY3Rpb24oZGF0YS50cmlnZ2VyKSkpXG4gICAgeyByZXR1cm4gZGF0YSB9XG5cbiAgdmFyIG8gPSB7fTtcbiAgZm9yICh2YXIga2V5IGluIGRhdGEpIHtcbiAgICBpZiAoIVJFX1JFU0VSVkVEX05BTUVTLnRlc3Qoa2V5KSkgeyBvW2tleV0gPSBkYXRhW2tleV07IH1cbiAgfVxuICByZXR1cm4gb1xufVxuXG4vKipcbiAqIFNldCB0aGUgcHJvcGVydHkgb2YgYW4gb2JqZWN0IGZvciBhIGdpdmVuIGtleS4gSWYgc29tZXRoaW5nIGFscmVhZHlcbiAqIGV4aXN0cyB0aGVyZSwgdGhlbiBpdCBiZWNvbWVzIGFuIGFycmF5IGNvbnRhaW5pbmcgYm90aCB0aGUgb2xkIGFuZCBuZXcgdmFsdWUuXG4gKiBAcGFyYW0geyBPYmplY3QgfSBvYmogLSBvYmplY3Qgb24gd2hpY2ggdG8gc2V0IHRoZSBwcm9wZXJ0eVxuICogQHBhcmFtIHsgU3RyaW5nIH0ga2V5IC0gcHJvcGVydHkgbmFtZVxuICogQHBhcmFtIHsgT2JqZWN0IH0gdmFsdWUgLSB0aGUgdmFsdWUgb2YgdGhlIHByb3BlcnR5IHRvIGJlIHNldFxuICogQHBhcmFtIHsgQm9vbGVhbiB9IGVuc3VyZUFycmF5IC0gZW5zdXJlIHRoYXQgdGhlIHByb3BlcnR5IHJlbWFpbnMgYW4gYXJyYXlcbiAqIEBwYXJhbSB7IE51bWJlciB9IGluZGV4IC0gYWRkIHRoZSBuZXcgaXRlbSBpbiBhIGNlcnRhaW4gYXJyYXkgcG9zaXRpb25cbiAqL1xuZnVuY3Rpb24gYXJyYXlpc2hBZGQob2JqLCBrZXksIHZhbHVlLCBlbnN1cmVBcnJheSwgaW5kZXgpIHtcbiAgdmFyIGRlc3QgPSBvYmpba2V5XTtcbiAgdmFyIGlzQXJyID0gaXNBcnJheShkZXN0KTtcbiAgdmFyIGhhc0luZGV4ID0gIWlzVW5kZWZpbmVkKGluZGV4KTtcblxuICBpZiAoZGVzdCAmJiBkZXN0ID09PSB2YWx1ZSkgeyByZXR1cm4gfVxuXG4gIC8vIGlmIHRoZSBrZXkgd2FzIG5ldmVyIHNldCwgc2V0IGl0IG9uY2VcbiAgaWYgKCFkZXN0ICYmIGVuc3VyZUFycmF5KSB7IG9ialtrZXldID0gW3ZhbHVlXTsgfVxuICBlbHNlIGlmICghZGVzdCkgeyBvYmpba2V5XSA9IHZhbHVlOyB9XG4gIC8vIGlmIGl0IHdhcyBhbiBhcnJheSBhbmQgbm90IHlldCBzZXRcbiAgZWxzZSB7XG4gICAgaWYgKGlzQXJyKSB7XG4gICAgICB2YXIgb2xkSW5kZXggPSBkZXN0LmluZGV4T2YodmFsdWUpO1xuICAgICAgLy8gdGhpcyBpdGVtIG5ldmVyIGNoYW5nZWQgaXRzIHBvc2l0aW9uXG4gICAgICBpZiAob2xkSW5kZXggPT09IGluZGV4KSB7IHJldHVybiB9XG4gICAgICAvLyByZW1vdmUgdGhlIGl0ZW0gZnJvbSBpdHMgb2xkIHBvc2l0aW9uXG4gICAgICBpZiAob2xkSW5kZXggIT09IC0xKSB7IGRlc3Quc3BsaWNlKG9sZEluZGV4LCAxKTsgfVxuICAgICAgLy8gbW92ZSBvciBhZGQgdGhlIGl0ZW1cbiAgICAgIGlmIChoYXNJbmRleCkge1xuICAgICAgICBkZXN0LnNwbGljZShpbmRleCwgMCwgdmFsdWUpO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGVzdC5wdXNoKHZhbHVlKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgeyBvYmpba2V5XSA9IFtkZXN0LCB2YWx1ZV07IH1cbiAgfVxufVxuXG4vKipcbiAqIFJlbW92ZXMgYW4gaXRlbSBmcm9tIGFuIG9iamVjdCBhdCBhIGdpdmVuIGtleS4gSWYgdGhlIGtleSBwb2ludHMgdG8gYW4gYXJyYXksXG4gKiB0aGVuIHRoZSBpdGVtIGlzIGp1c3QgcmVtb3ZlZCBmcm9tIHRoZSBhcnJheS5cbiAqIEBwYXJhbSB7IE9iamVjdCB9IG9iaiAtIG9iamVjdCBvbiB3aGljaCB0byByZW1vdmUgdGhlIHByb3BlcnR5XG4gKiBAcGFyYW0geyBTdHJpbmcgfSBrZXkgLSBwcm9wZXJ0eSBuYW1lXG4gKiBAcGFyYW0geyBPYmplY3QgfSB2YWx1ZSAtIHRoZSB2YWx1ZSBvZiB0aGUgcHJvcGVydHkgdG8gYmUgcmVtb3ZlZFxuICogQHBhcmFtIHsgQm9vbGVhbiB9IGVuc3VyZUFycmF5IC0gZW5zdXJlIHRoYXQgdGhlIHByb3BlcnR5IHJlbWFpbnMgYW4gYXJyYXlcbiovXG5mdW5jdGlvbiBhcnJheWlzaFJlbW92ZShvYmosIGtleSwgdmFsdWUsIGVuc3VyZUFycmF5KSB7XG4gIGlmIChpc0FycmF5KG9ialtrZXldKSkge1xuICAgIHZhciBpbmRleCA9IG9ialtrZXldLmluZGV4T2YodmFsdWUpO1xuICAgIGlmIChpbmRleCAhPT0gLTEpIHsgb2JqW2tleV0uc3BsaWNlKGluZGV4LCAxKTsgfVxuICAgIGlmICghb2JqW2tleV0ubGVuZ3RoKSB7IGRlbGV0ZSBvYmpba2V5XTsgfVxuICAgIGVsc2UgaWYgKG9ialtrZXldLmxlbmd0aCA9PT0gMSAmJiAhZW5zdXJlQXJyYXkpIHsgb2JqW2tleV0gPSBvYmpba2V5XVswXTsgfVxuICB9IGVsc2VcbiAgICB7IGRlbGV0ZSBvYmpba2V5XTsgfSAvLyBvdGhlcndpc2UganVzdCBkZWxldGUgdGhlIGtleVxufVxuXG4vKipcbiAqIE1vdW50IGEgdGFnIGNyZWF0aW5nIG5ldyBUYWcgaW5zdGFuY2VcbiAqIEBwYXJhbSAgIHsgT2JqZWN0IH0gcm9vdCAtIGRvbSBub2RlIHdoZXJlIHRoZSB0YWcgd2lsbCBiZSBtb3VudGVkXG4gKiBAcGFyYW0gICB7IFN0cmluZyB9IHRhZ05hbWUgLSBuYW1lIG9mIHRoZSByaW90IHRhZyB3ZSB3YW50IHRvIG1vdW50XG4gKiBAcGFyYW0gICB7IE9iamVjdCB9IG9wdHMgLSBvcHRpb25zIHRvIHBhc3MgdG8gdGhlIFRhZyBpbnN0YW5jZVxuICogQHBhcmFtICAgeyBPYmplY3QgfSBjdHggLSBvcHRpb25hbCBjb250ZXh0IHRoYXQgd2lsbCBiZSB1c2VkIHRvIGV4dGVuZCBhbiBleGlzdGluZyBjbGFzcyAoIHVzZWQgaW4gcmlvdC5UYWcgKVxuICogQHJldHVybnMgeyBUYWcgfSBhIG5ldyBUYWcgaW5zdGFuY2VcbiAqL1xuZnVuY3Rpb24gbW91bnRUbyhyb290LCB0YWdOYW1lLCBvcHRzLCBjdHgpIHtcbiAgdmFyIGltcGwgPSBfX1RBR19JTVBMW3RhZ05hbWVdLFxuICAgIGltcGxDbGFzcyA9IF9fVEFHX0lNUExbdGFnTmFtZV0uY2xhc3MsXG4gICAgdGFnID0gY3R4IHx8IChpbXBsQ2xhc3MgPyBPYmplY3QuY3JlYXRlKGltcGxDbGFzcy5wcm90b3R5cGUpIDoge30pLFxuICAgIC8vIGNhY2hlIHRoZSBpbm5lciBIVE1MIHRvIGZpeCAjODU1XG4gICAgaW5uZXJIVE1MID0gcm9vdC5faW5uZXJIVE1MID0gcm9vdC5faW5uZXJIVE1MIHx8IHJvb3QuaW5uZXJIVE1MO1xuXG4gIC8vIGNsZWFyIHRoZSBpbm5lciBodG1sXG4gIHJvb3QuaW5uZXJIVE1MID0gJyc7XG5cbiAgdmFyIGNvbmYgPSBleHRlbmQoeyByb290OiByb290LCBvcHRzOiBvcHRzIH0sIHsgcGFyZW50OiBvcHRzID8gb3B0cy5wYXJlbnQgOiBudWxsIH0pO1xuXG4gIGlmIChpbXBsICYmIHJvb3QpIHsgVGFnJDEuYXBwbHkodGFnLCBbaW1wbCwgY29uZiwgaW5uZXJIVE1MXSk7IH1cblxuICBpZiAodGFnICYmIHRhZy5tb3VudCkge1xuICAgIHRhZy5tb3VudCh0cnVlKTtcbiAgICAvLyBhZGQgdGhpcyB0YWcgdG8gdGhlIHZpcnR1YWxEb20gdmFyaWFibGVcbiAgICBpZiAoIWNvbnRhaW5zKF9fVEFHU19DQUNIRSwgdGFnKSkgeyBfX1RBR1NfQ0FDSEUucHVzaCh0YWcpOyB9XG4gIH1cblxuICByZXR1cm4gdGFnXG59XG5cbi8qKlxuICogbWFrZXMgYSB0YWcgdmlydHVhbCBhbmQgcmVwbGFjZXMgYSByZWZlcmVuY2UgaW4gdGhlIGRvbVxuICogQHRoaXMgVGFnXG4gKiBAcGFyYW0geyB0YWcgfSB0aGUgdGFnIHRvIG1ha2UgdmlydHVhbFxuICogQHBhcmFtIHsgcmVmIH0gdGhlIGRvbSByZWZlcmVuY2UgbG9jYXRpb25cbiAqL1xuZnVuY3Rpb24gbWFrZVJlcGxhY2VWaXJ0dWFsKHRhZywgcmVmKSB7XG4gIHZhciBmcmFnID0gY3JlYXRlRnJhZygpO1xuICBtYWtlVmlydHVhbC5jYWxsKHRhZywgZnJhZyk7XG4gIHJlZi5wYXJlbnROb2RlLnJlcGxhY2VDaGlsZChmcmFnLCByZWYpO1xufVxuXG4vKipcbiAqIEFkZHMgdGhlIGVsZW1lbnRzIGZvciBhIHZpcnR1YWwgdGFnXG4gKiBAdGhpcyBUYWdcbiAqIEBwYXJhbSB7IE5vZGUgfSBzcmMgLSB0aGUgbm9kZSB0aGF0IHdpbGwgZG8gdGhlIGluc2VydGluZyBvciBhcHBlbmRpbmdcbiAqIEBwYXJhbSB7IFRhZyB9IHRhcmdldCAtIG9ubHkgaWYgaW5zZXJ0aW5nLCBpbnNlcnQgYmVmb3JlIHRoaXMgdGFnJ3MgZmlyc3QgY2hpbGRcbiAqL1xuZnVuY3Rpb24gbWFrZVZpcnR1YWwoc3JjLCB0YXJnZXQpIHtcbiAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgdmFyIGhlYWQgPSBjcmVhdGVET01QbGFjZWhvbGRlcigpLFxuICAgIHRhaWwgPSBjcmVhdGVET01QbGFjZWhvbGRlcigpLFxuICAgIGZyYWcgPSBjcmVhdGVGcmFnKCksXG4gICAgc2liLCBlbDtcblxuICB0aGlzLnJvb3QuaW5zZXJ0QmVmb3JlKGhlYWQsIHRoaXMucm9vdC5maXJzdENoaWxkKTtcbiAgdGhpcy5yb290LmFwcGVuZENoaWxkKHRhaWwpO1xuXG4gIHRoaXMuX18uaGVhZCA9IGVsID0gaGVhZDtcbiAgdGhpcy5fXy50YWlsID0gdGFpbDtcblxuICB3aGlsZSAoZWwpIHtcbiAgICBzaWIgPSBlbC5uZXh0U2libGluZztcbiAgICBmcmFnLmFwcGVuZENoaWxkKGVsKTtcbiAgICB0aGlzJDEuX18udmlydHMucHVzaChlbCk7IC8vIGhvbGQgZm9yIHVubW91bnRpbmdcbiAgICBlbCA9IHNpYjtcbiAgfVxuXG4gIGlmICh0YXJnZXQpXG4gICAgeyBzcmMuaW5zZXJ0QmVmb3JlKGZyYWcsIHRhcmdldC5fXy5oZWFkKTsgfVxuICBlbHNlXG4gICAgeyBzcmMuYXBwZW5kQ2hpbGQoZnJhZyk7IH1cbn1cblxuLyoqXG4gKiBNb3ZlIHZpcnR1YWwgdGFnIGFuZCBhbGwgY2hpbGQgbm9kZXNcbiAqIEB0aGlzIFRhZ1xuICogQHBhcmFtIHsgTm9kZSB9IHNyYyAgLSB0aGUgbm9kZSB0aGF0IHdpbGwgZG8gdGhlIGluc2VydGluZ1xuICogQHBhcmFtIHsgVGFnIH0gdGFyZ2V0IC0gaW5zZXJ0IGJlZm9yZSB0aGlzIHRhZydzIGZpcnN0IGNoaWxkXG4gKi9cbmZ1bmN0aW9uIG1vdmVWaXJ0dWFsKHNyYywgdGFyZ2V0KSB7XG4gIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gIHZhciBlbCA9IHRoaXMuX18uaGVhZCxcbiAgICBmcmFnID0gY3JlYXRlRnJhZygpLFxuICAgIHNpYjtcblxuICB3aGlsZSAoZWwpIHtcbiAgICBzaWIgPSBlbC5uZXh0U2libGluZztcbiAgICBmcmFnLmFwcGVuZENoaWxkKGVsKTtcbiAgICBlbCA9IHNpYjtcbiAgICBpZiAoZWwgPT09IHRoaXMkMS5fXy50YWlsKSB7XG4gICAgICBmcmFnLmFwcGVuZENoaWxkKGVsKTtcbiAgICAgIHNyYy5pbnNlcnRCZWZvcmUoZnJhZywgdGFyZ2V0Ll9fLmhlYWQpO1xuICAgICAgYnJlYWtcbiAgICB9XG4gIH1cbn1cblxuLyoqXG4gKiBHZXQgc2VsZWN0b3JzIGZvciB0YWdzXG4gKiBAcGFyYW0gICB7IEFycmF5IH0gdGFncyAtIHRhZyBuYW1lcyB0byBzZWxlY3RcbiAqIEByZXR1cm5zIHsgU3RyaW5nIH0gc2VsZWN0b3JcbiAqL1xuZnVuY3Rpb24gc2VsZWN0VGFncyh0YWdzKSB7XG4gIC8vIHNlbGVjdCBhbGwgdGFnc1xuICBpZiAoIXRhZ3MpIHtcbiAgICB2YXIga2V5cyA9IE9iamVjdC5rZXlzKF9fVEFHX0lNUEwpO1xuICAgIHJldHVybiBrZXlzICsgc2VsZWN0VGFncyhrZXlzKVxuICB9XG5cbiAgcmV0dXJuIHRhZ3NcbiAgICAuZmlsdGVyKGZ1bmN0aW9uICh0KSB7IHJldHVybiAhL1teLVxcd10vLnRlc3QodCk7IH0pXG4gICAgLnJlZHVjZShmdW5jdGlvbiAobGlzdCwgdCkge1xuICAgICAgdmFyIG5hbWUgPSB0LnRyaW0oKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgcmV0dXJuIGxpc3QgKyBcIixbXCIgKyBJU19ESVJFQ1RJVkUgKyBcIj1cXFwiXCIgKyBuYW1lICsgXCJcXFwiXVwiXG4gICAgfSwgJycpXG59XG5cblxudmFyIHRhZ3MgPSBPYmplY3QuZnJlZXplKHtcblx0Z2V0VGFnOiBnZXRUYWcsXG5cdGluaGVyaXRGcm9tOiBpbmhlcml0RnJvbSxcblx0bW92ZUNoaWxkVGFnOiBtb3ZlQ2hpbGRUYWcsXG5cdGluaXRDaGlsZFRhZzogaW5pdENoaWxkVGFnLFxuXHRnZXRJbW1lZGlhdGVDdXN0b21QYXJlbnRUYWc6IGdldEltbWVkaWF0ZUN1c3RvbVBhcmVudFRhZyxcblx0dW5tb3VudEFsbDogdW5tb3VudEFsbCxcblx0Z2V0VGFnTmFtZTogZ2V0VGFnTmFtZSxcblx0Y2xlYW5VcERhdGE6IGNsZWFuVXBEYXRhLFxuXHRhcnJheWlzaEFkZDogYXJyYXlpc2hBZGQsXG5cdGFycmF5aXNoUmVtb3ZlOiBhcnJheWlzaFJlbW92ZSxcblx0bW91bnRUbzogbW91bnRUbyxcblx0bWFrZVJlcGxhY2VWaXJ0dWFsOiBtYWtlUmVwbGFjZVZpcnR1YWwsXG5cdG1ha2VWaXJ0dWFsOiBtYWtlVmlydHVhbCxcblx0bW92ZVZpcnR1YWw6IG1vdmVWaXJ0dWFsLFxuXHRzZWxlY3RUYWdzOiBzZWxlY3RUYWdzXG59KTtcblxuLyoqXG4gKiBSaW90IHB1YmxpYyBhcGlcbiAqL1xudmFyIHNldHRpbmdzID0gc2V0dGluZ3MkMTtcbnZhciB1dGlsID0ge1xuICB0bXBsOiB0bXBsLFxuICBicmFja2V0czogYnJhY2tldHMsXG4gIHN0eWxlTWFuYWdlcjogc3R5bGVNYW5hZ2VyLFxuICB2ZG9tOiBfX1RBR1NfQ0FDSEUsXG4gIHN0eWxlTm9kZTogc3R5bGVNYW5hZ2VyLnN0eWxlTm9kZSxcbiAgLy8gZXhwb3J0IHRoZSByaW90IGludGVybmFsIHV0aWxzIGFzIHdlbGxcbiAgZG9tOiBkb20sXG4gIGNoZWNrOiBjaGVjayxcbiAgbWlzYzogbWlzYyxcbiAgdGFnczogdGFnc1xufTtcblxuLy8gZXhwb3J0IHRoZSBjb3JlIHByb3BzL21ldGhvZHNcbnZhciBUYWckJDEgPSBUYWckMjtcbnZhciB0YWckJDEgPSB0YWckMTtcbnZhciB0YWcyJCQxID0gdGFnMiQxO1xudmFyIG1vdW50JCQxID0gbW91bnQkMTtcbnZhciBtaXhpbiQkMSA9IG1peGluJDE7XG52YXIgdXBkYXRlJCQxID0gdXBkYXRlJDE7XG52YXIgdW5yZWdpc3RlciQkMSA9IHVucmVnaXN0ZXIkMTtcbnZhciB2ZXJzaW9uJCQxID0gdmVyc2lvbiQxO1xudmFyIG9ic2VydmFibGUgPSBvYnNlcnZhYmxlJDE7XG5cbnZhciByaW90JDEgPSBleHRlbmQoe30sIGNvcmUsIHtcbiAgb2JzZXJ2YWJsZTogb2JzZXJ2YWJsZSQxLFxuICBzZXR0aW5nczogc2V0dGluZ3MsXG4gIHV0aWw6IHV0aWwsXG59KTtcblxuZXhwb3J0cy5zZXR0aW5ncyA9IHNldHRpbmdzO1xuZXhwb3J0cy51dGlsID0gdXRpbDtcbmV4cG9ydHMuVGFnID0gVGFnJCQxO1xuZXhwb3J0cy50YWcgPSB0YWckJDE7XG5leHBvcnRzLnRhZzIgPSB0YWcyJCQxO1xuZXhwb3J0cy5tb3VudCA9IG1vdW50JCQxO1xuZXhwb3J0cy5taXhpbiA9IG1peGluJCQxO1xuZXhwb3J0cy51cGRhdGUgPSB1cGRhdGUkJDE7XG5leHBvcnRzLnVucmVnaXN0ZXIgPSB1bnJlZ2lzdGVyJCQxO1xuZXhwb3J0cy52ZXJzaW9uID0gdmVyc2lvbiQkMTtcbmV4cG9ydHMub2JzZXJ2YWJsZSA9IG9ic2VydmFibGU7XG5leHBvcnRzWydkZWZhdWx0J10gPSByaW90JDE7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG5cbn0pKSk7XG4iXX0=
const hyperHTML = require('hyperhtml')
const component = require('hypercomponent')
riot = {}
const _riot = require('riot')
function toRiot (name, component, riot) {
riot.tag(name, '', function (opts) {
var tag = this
var instance = null
tag.one('mount', function onMount () {
if (instance === null) {
instance = component(opts)
tag.root.appendChild(instance.render(tag.opts))
}
})
tag.on('update', function onUpdate () {
if (instance !== null) instance.render(tag.opts)
})
tag.on('unmount', function onUnmount () {
if (instance) element = null
})
})
}
const Button = component((render, data) => render`
<button>
${data.text}
</button>
`)
function List () {
var cache = []
return component((render, data) => {
if (cache.length > data.children.length) cache.splice(data.children.length)
return render`
<ul>${
data.children.map((child, i) =>
hyperHTML.wire(cache[i] || (cache[i] = {}))`<li>${child}</li>`)
}</ul>
`
})()
}
;(function (riot) {
toRiot('c-button', Button, riot)
toRiot('c-list', List, riot)
riot.tag('app', '<div><c-list children="{children}"></c-list><c-button text="{text}"></c-button><c-button text="Hello There!"></c-button></div>', function app (opts) {
var tag = this
var buttons = opts.data.map(Button)
tag.children = opts.data.map((data, i) => buttons[i].render({ text: data }))
tag.text = opts.text
tag.on('update', function onUpdate () {
if (buttons.length > tag.data.length) buttons.splice(tag.data.length)
tag.children = tag.data.map((data, i) => (buttons[i] || Button()).render({ text: data }))
})
})
var app = riot.mount(document.body, 'app', { text: 'Hey there', data: ['test', 'test1', 'test2'] })[0]
setTimeout(() => app.update({ text: 'Hey there, again', data: ['test1', 'test2'] }), 2000)
setTimeout(() => app.update({ text: 'Hey there, and again', data: ['test11', 'test2', 'test3'] }), 5000)
})(_riot)
;}, 0)
{
"name": "requirebin-sketch",
"version": "1.0.0",
"dependencies": {
"hypercomponent": "2.0.1",
"hyperhtml": "0.8.6",
"riot": "3.4.0"
}
}
<!-- contents of this file will be placed inside the <body> -->
<!-- contents of this file will be placed inside the <head> -->
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment