made with requirebin
Created
May 4, 2017 01:17
-
-
Save joshgillies/7e9b5fee912239103707bb7b8082095e to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({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 = { | |
'&': '&', | |
'<': '<', | |
'>': '>', | |
"'": ''', | |
'"': '"' | |
}, | |
oUnescape = { | |
'&': '&', | |
'&': '&', | |
'<': '<', | |
'<': '<', | |
'>': '>', | |
'>': '>', | |
''': "'", | |
''': "'", | |
'"': '"', | |
'"': '"' | |
}, | |
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) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "requirebin-sketch", | |
"version": "1.0.0", | |
"dependencies": { | |
"hypercomponent": "2.0.1", | |
"hyperhtml": "0.8.6", | |
"riot": "3.4.0" | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <body> --> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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