made with requirebin
Last active
May 17, 2017 17:05
-
-
Save sevastos/d580df5617513b164f1e7e186e20c861 to your computer and use it in GitHub Desktop.
requirebin sketch
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Trend { | |
constructor(database) { | |
this.database = database; | |
} | |
create() { | |
console.log('create', this.database); | |
this.database.query(); | |
} | |
} | |
var sinon = require('sinon'); | |
var Database = {query:function(){}}; | |
var database_mock = sinon.mock(Database); | |
database_mock.expects("query").once(); | |
var trend = new Trend(Database); | |
trend.create(); | |
database_mock.verify(); | |
database_mock.restore(); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
setTimeout(function(){ | |
;require=(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){ | |
// shim for using process in browser | |
var process = module.exports = {}; | |
// cached from whatever global is present so that test runners that stub it | |
// don't break things. But we need to wrap it in a try catch in case it is | |
// wrapped in strict mode code which doesn't define any globals. It's inside a | |
// function because try/catches deoptimize in certain engines. | |
var cachedSetTimeout; | |
var cachedClearTimeout; | |
function defaultSetTimout() { | |
throw new Error('setTimeout has not been defined'); | |
} | |
function defaultClearTimeout () { | |
throw new Error('clearTimeout has not been defined'); | |
} | |
(function () { | |
try { | |
if (typeof setTimeout === 'function') { | |
cachedSetTimeout = setTimeout; | |
} else { | |
cachedSetTimeout = defaultSetTimout; | |
} | |
} catch (e) { | |
cachedSetTimeout = defaultSetTimout; | |
} | |
try { | |
if (typeof clearTimeout === 'function') { | |
cachedClearTimeout = clearTimeout; | |
} else { | |
cachedClearTimeout = defaultClearTimeout; | |
} | |
} catch (e) { | |
cachedClearTimeout = defaultClearTimeout; | |
} | |
} ()) | |
function runTimeout(fun) { | |
if (cachedSetTimeout === setTimeout) { | |
//normal enviroments in sane situations | |
return setTimeout(fun, 0); | |
} | |
// if setTimeout wasn't available but was latter defined | |
if ((cachedSetTimeout === defaultSetTimout || !cachedSetTimeout) && setTimeout) { | |
cachedSetTimeout = setTimeout; | |
return setTimeout(fun, 0); | |
} | |
try { | |
// when when somebody has screwed with setTimeout but no I.E. maddness | |
return cachedSetTimeout(fun, 0); | |
} catch(e){ | |
try { | |
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
return cachedSetTimeout.call(null, fun, 0); | |
} catch(e){ | |
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error | |
return cachedSetTimeout.call(this, fun, 0); | |
} | |
} | |
} | |
function runClearTimeout(marker) { | |
if (cachedClearTimeout === clearTimeout) { | |
//normal enviroments in sane situations | |
return clearTimeout(marker); | |
} | |
// if clearTimeout wasn't available but was latter defined | |
if ((cachedClearTimeout === defaultClearTimeout || !cachedClearTimeout) && clearTimeout) { | |
cachedClearTimeout = clearTimeout; | |
return clearTimeout(marker); | |
} | |
try { | |
// when when somebody has screwed with setTimeout but no I.E. maddness | |
return cachedClearTimeout(marker); | |
} catch (e){ | |
try { | |
// When we are in I.E. but the script has been evaled so I.E. doesn't trust the global object when called normally | |
return cachedClearTimeout.call(null, marker); | |
} catch (e){ | |
// same as above but when it's a version of I.E. that must have the global object for 'this', hopfully our context correct otherwise it will throw a global error. | |
// Some versions of I.E. have different rules for clearTimeout vs setTimeout | |
return cachedClearTimeout.call(this, marker); | |
} | |
} | |
} | |
var queue = []; | |
var draining = false; | |
var currentQueue; | |
var queueIndex = -1; | |
function cleanUpNextTick() { | |
if (!draining || !currentQueue) { | |
return; | |
} | |
draining = false; | |
if (currentQueue.length) { | |
queue = currentQueue.concat(queue); | |
} else { | |
queueIndex = -1; | |
} | |
if (queue.length) { | |
drainQueue(); | |
} | |
} | |
function drainQueue() { | |
if (draining) { | |
return; | |
} | |
var timeout = runTimeout(cleanUpNextTick); | |
draining = true; | |
var len = queue.length; | |
while(len) { | |
currentQueue = queue; | |
queue = []; | |
while (++queueIndex < len) { | |
if (currentQueue) { | |
currentQueue[queueIndex].run(); | |
} | |
} | |
queueIndex = -1; | |
len = queue.length; | |
} | |
currentQueue = null; | |
draining = false; | |
runClearTimeout(timeout); | |
} | |
process.nextTick = function (fun) { | |
var args = new Array(arguments.length - 1); | |
if (arguments.length > 1) { | |
for (var i = 1; i < arguments.length; i++) { | |
args[i - 1] = arguments[i]; | |
} | |
} | |
queue.push(new Item(fun, args)); | |
if (queue.length === 1 && !draining) { | |
runTimeout(drainQueue); | |
} | |
}; | |
// v8 likes predictible objects | |
function Item(fun, array) { | |
this.fun = fun; | |
this.array = array; | |
} | |
Item.prototype.run = function () { | |
this.fun.apply(null, this.array); | |
}; | |
process.title = 'browser'; | |
process.browser = true; | |
process.env = {}; | |
process.argv = []; | |
process.version = ''; // empty string to avoid regexp issues | |
process.versions = {}; | |
function noop() {} | |
process.on = noop; | |
process.addListener = noop; | |
process.once = noop; | |
process.off = noop; | |
process.removeListener = noop; | |
process.removeAllListeners = noop; | |
process.emit = noop; | |
process.binding = function (name) { | |
throw new Error('process.binding is not supported'); | |
}; | |
process.cwd = function () { return '/' }; | |
process.chdir = function (dir) { | |
throw new Error('process.chdir is not supported'); | |
}; | |
process.umask = function() { return 0; }; | |
},{}],2:[function(require,module,exports){ | |
if (typeof Object.create === 'function') { | |
// implementation from standard node.js 'util' module | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
ctor.prototype = Object.create(superCtor.prototype, { | |
constructor: { | |
value: ctor, | |
enumerable: false, | |
writable: true, | |
configurable: true | |
} | |
}); | |
}; | |
} else { | |
// old school shim for old browsers | |
module.exports = function inherits(ctor, superCtor) { | |
ctor.super_ = superCtor | |
var TempCtor = function () {} | |
TempCtor.prototype = superCtor.prototype | |
ctor.prototype = new TempCtor() | |
ctor.prototype.constructor = ctor | |
} | |
} | |
},{}],3:[function(require,module,exports){ | |
module.exports = function isBuffer(arg) { | |
return arg && typeof arg === 'object' | |
&& typeof arg.copy === 'function' | |
&& typeof arg.fill === 'function' | |
&& typeof arg.readUInt8 === 'function'; | |
} | |
},{}],4:[function(require,module,exports){ | |
(function (process,global){ | |
// Copyright Joyent, Inc. and other Node contributors. | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a | |
// copy of this software and associated documentation files (the | |
// "Software"), to deal in the Software without restriction, including | |
// without limitation the rights to use, copy, modify, merge, publish, | |
// distribute, sublicense, and/or sell copies of the Software, and to permit | |
// persons to whom the Software is furnished to do so, subject to the | |
// following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included | |
// in all copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS | |
// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN | |
// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | |
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR | |
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE | |
// USE OR OTHER DEALINGS IN THE SOFTWARE. | |
var formatRegExp = /%[sdj%]/g; | |
exports.format = function(f) { | |
if (!isString(f)) { | |
var objects = []; | |
for (var i = 0; i < arguments.length; i++) { | |
objects.push(inspect(arguments[i])); | |
} | |
return objects.join(' '); | |
} | |
var i = 1; | |
var args = arguments; | |
var len = args.length; | |
var str = String(f).replace(formatRegExp, function(x) { | |
if (x === '%%') return '%'; | |
if (i >= len) return x; | |
switch (x) { | |
case '%s': return String(args[i++]); | |
case '%d': return Number(args[i++]); | |
case '%j': | |
try { | |
return JSON.stringify(args[i++]); | |
} catch (_) { | |
return '[Circular]'; | |
} | |
default: | |
return x; | |
} | |
}); | |
for (var x = args[i]; i < len; x = args[++i]) { | |
if (isNull(x) || !isObject(x)) { | |
str += ' ' + x; | |
} else { | |
str += ' ' + inspect(x); | |
} | |
} | |
return str; | |
}; | |
// Mark that a method should not be used. | |
// Returns a modified function which warns once by default. | |
// If --no-deprecation is set, then it is a no-op. | |
exports.deprecate = function(fn, msg) { | |
// Allow for deprecating things in the process of starting up. | |
if (isUndefined(global.process)) { | |
return function() { | |
return exports.deprecate(fn, msg).apply(this, arguments); | |
}; | |
} | |
if (process.noDeprecation === true) { | |
return fn; | |
} | |
var warned = false; | |
function deprecated() { | |
if (!warned) { | |
if (process.throwDeprecation) { | |
throw new Error(msg); | |
} else if (process.traceDeprecation) { | |
console.trace(msg); | |
} else { | |
console.error(msg); | |
} | |
warned = true; | |
} | |
return fn.apply(this, arguments); | |
} | |
return deprecated; | |
}; | |
var debugs = {}; | |
var debugEnviron; | |
exports.debuglog = function(set) { | |
if (isUndefined(debugEnviron)) | |
debugEnviron = process.env.NODE_DEBUG || ''; | |
set = set.toUpperCase(); | |
if (!debugs[set]) { | |
if (new RegExp('\\b' + set + '\\b', 'i').test(debugEnviron)) { | |
var pid = process.pid; | |
debugs[set] = function() { | |
var msg = exports.format.apply(exports, arguments); | |
console.error('%s %d: %s', set, pid, msg); | |
}; | |
} else { | |
debugs[set] = function() {}; | |
} | |
} | |
return debugs[set]; | |
}; | |
/** | |
* Echos the value of a value. Trys to print the value out | |
* in the best way possible given the different types. | |
* | |
* @param {Object} obj The object to print out. | |
* @param {Object} opts Optional options object that alters the output. | |
*/ | |
/* legacy: obj, showHidden, depth, colors*/ | |
function inspect(obj, opts) { | |
// default options | |
var ctx = { | |
seen: [], | |
stylize: stylizeNoColor | |
}; | |
// legacy... | |
if (arguments.length >= 3) ctx.depth = arguments[2]; | |
if (arguments.length >= 4) ctx.colors = arguments[3]; | |
if (isBoolean(opts)) { | |
// legacy... | |
ctx.showHidden = opts; | |
} else if (opts) { | |
// got an "options" object | |
exports._extend(ctx, opts); | |
} | |
// set default options | |
if (isUndefined(ctx.showHidden)) ctx.showHidden = false; | |
if (isUndefined(ctx.depth)) ctx.depth = 2; | |
if (isUndefined(ctx.colors)) ctx.colors = false; | |
if (isUndefined(ctx.customInspect)) ctx.customInspect = true; | |
if (ctx.colors) ctx.stylize = stylizeWithColor; | |
return formatValue(ctx, obj, ctx.depth); | |
} | |
exports.inspect = inspect; | |
// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics | |
inspect.colors = { | |
'bold' : [1, 22], | |
'italic' : [3, 23], | |
'underline' : [4, 24], | |
'inverse' : [7, 27], | |
'white' : [37, 39], | |
'grey' : [90, 39], | |
'black' : [30, 39], | |
'blue' : [34, 39], | |
'cyan' : [36, 39], | |
'green' : [32, 39], | |
'magenta' : [35, 39], | |
'red' : [31, 39], | |
'yellow' : [33, 39] | |
}; | |
// Don't use 'blue' not visible on cmd.exe | |
inspect.styles = { | |
'special': 'cyan', | |
'number': 'yellow', | |
'boolean': 'yellow', | |
'undefined': 'grey', | |
'null': 'bold', | |
'string': 'green', | |
'date': 'magenta', | |
// "name": intentionally not styling | |
'regexp': 'red' | |
}; | |
function stylizeWithColor(str, styleType) { | |
var style = inspect.styles[styleType]; | |
if (style) { | |
return '\u001b[' + inspect.colors[style][0] + 'm' + str + | |
'\u001b[' + inspect.colors[style][1] + 'm'; | |
} else { | |
return str; | |
} | |
} | |
function stylizeNoColor(str, styleType) { | |
return str; | |
} | |
function arrayToHash(array) { | |
var hash = {}; | |
array.forEach(function(val, idx) { | |
hash[val] = true; | |
}); | |
return hash; | |
} | |
function formatValue(ctx, value, recurseTimes) { | |
// Provide a hook for user-specified inspect functions. | |
// Check that value is an object with an inspect function on it | |
if (ctx.customInspect && | |
value && | |
isFunction(value.inspect) && | |
// Filter out the util module, it's inspect function is special | |
value.inspect !== exports.inspect && | |
// Also filter out any prototype objects using the circular check. | |
!(value.constructor && value.constructor.prototype === value)) { | |
var ret = value.inspect(recurseTimes, ctx); | |
if (!isString(ret)) { | |
ret = formatValue(ctx, ret, recurseTimes); | |
} | |
return ret; | |
} | |
// Primitive types cannot have properties | |
var primitive = formatPrimitive(ctx, value); | |
if (primitive) { | |
return primitive; | |
} | |
// Look up the keys of the object. | |
var keys = Object.keys(value); | |
var visibleKeys = arrayToHash(keys); | |
if (ctx.showHidden) { | |
keys = Object.getOwnPropertyNames(value); | |
} | |
// IE doesn't make error fields non-enumerable | |
// http://msdn.microsoft.com/en-us/library/ie/dww52sbt(v=vs.94).aspx | |
if (isError(value) | |
&& (keys.indexOf('message') >= 0 || keys.indexOf('description') >= 0)) { | |
return formatError(value); | |
} | |
// Some type of object without properties can be shortcutted. | |
if (keys.length === 0) { | |
if (isFunction(value)) { | |
var name = value.name ? ': ' + value.name : ''; | |
return ctx.stylize('[Function' + name + ']', 'special'); | |
} | |
if (isRegExp(value)) { | |
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); | |
} | |
if (isDate(value)) { | |
return ctx.stylize(Date.prototype.toString.call(value), 'date'); | |
} | |
if (isError(value)) { | |
return formatError(value); | |
} | |
} | |
var base = '', array = false, braces = ['{', '}']; | |
// Make Array say that they are Array | |
if (isArray(value)) { | |
array = true; | |
braces = ['[', ']']; | |
} | |
// Make functions say that they are functions | |
if (isFunction(value)) { | |
var n = value.name ? ': ' + value.name : ''; | |
base = ' [Function' + n + ']'; | |
} | |
// Make RegExps say that they are RegExps | |
if (isRegExp(value)) { | |
base = ' ' + RegExp.prototype.toString.call(value); | |
} | |
// Make dates with properties first say the date | |
if (isDate(value)) { | |
base = ' ' + Date.prototype.toUTCString.call(value); | |
} | |
// Make error with message first say the error | |
if (isError(value)) { | |
base = ' ' + formatError(value); | |
} | |
if (keys.length === 0 && (!array || value.length == 0)) { | |
return braces[0] + base + braces[1]; | |
} | |
if (recurseTimes < 0) { | |
if (isRegExp(value)) { | |
return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); | |
} else { | |
return ctx.stylize('[Object]', 'special'); | |
} | |
} | |
ctx.seen.push(value); | |
var output; | |
if (array) { | |
output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); | |
} else { | |
output = keys.map(function(key) { | |
return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); | |
}); | |
} | |
ctx.seen.pop(); | |
return reduceToSingleString(output, base, braces); | |
} | |
function formatPrimitive(ctx, value) { | |
if (isUndefined(value)) | |
return ctx.stylize('undefined', 'undefined'); | |
if (isString(value)) { | |
var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') | |
.replace(/'/g, "\\'") | |
.replace(/\\"/g, '"') + '\''; | |
return ctx.stylize(simple, 'string'); | |
} | |
if (isNumber(value)) | |
return ctx.stylize('' + value, 'number'); | |
if (isBoolean(value)) | |
return ctx.stylize('' + value, 'boolean'); | |
// For some reason typeof null is "object", so special case here. | |
if (isNull(value)) | |
return ctx.stylize('null', 'null'); | |
} | |
function formatError(value) { | |
return '[' + Error.prototype.toString.call(value) + ']'; | |
} | |
function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { | |
var output = []; | |
for (var i = 0, l = value.length; i < l; ++i) { | |
if (hasOwnProperty(value, String(i))) { | |
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, | |
String(i), true)); | |
} else { | |
output.push(''); | |
} | |
} | |
keys.forEach(function(key) { | |
if (!key.match(/^\d+$/)) { | |
output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, | |
key, true)); | |
} | |
}); | |
return output; | |
} | |
function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { | |
var name, str, desc; | |
desc = Object.getOwnPropertyDescriptor(value, key) || { value: value[key] }; | |
if (desc.get) { | |
if (desc.set) { | |
str = ctx.stylize('[Getter/Setter]', 'special'); | |
} else { | |
str = ctx.stylize('[Getter]', 'special'); | |
} | |
} else { | |
if (desc.set) { | |
str = ctx.stylize('[Setter]', 'special'); | |
} | |
} | |
if (!hasOwnProperty(visibleKeys, key)) { | |
name = '[' + key + ']'; | |
} | |
if (!str) { | |
if (ctx.seen.indexOf(desc.value) < 0) { | |
if (isNull(recurseTimes)) { | |
str = formatValue(ctx, desc.value, null); | |
} else { | |
str = formatValue(ctx, desc.value, recurseTimes - 1); | |
} | |
if (str.indexOf('\n') > -1) { | |
if (array) { | |
str = str.split('\n').map(function(line) { | |
return ' ' + line; | |
}).join('\n').substr(2); | |
} else { | |
str = '\n' + str.split('\n').map(function(line) { | |
return ' ' + line; | |
}).join('\n'); | |
} | |
} | |
} else { | |
str = ctx.stylize('[Circular]', 'special'); | |
} | |
} | |
if (isUndefined(name)) { | |
if (array && key.match(/^\d+$/)) { | |
return str; | |
} | |
name = JSON.stringify('' + key); | |
if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { | |
name = name.substr(1, name.length - 2); | |
name = ctx.stylize(name, 'name'); | |
} else { | |
name = name.replace(/'/g, "\\'") | |
.replace(/\\"/g, '"') | |
.replace(/(^"|"$)/g, "'"); | |
name = ctx.stylize(name, 'string'); | |
} | |
} | |
return name + ': ' + str; | |
} | |
function reduceToSingleString(output, base, braces) { | |
var numLinesEst = 0; | |
var length = output.reduce(function(prev, cur) { | |
numLinesEst++; | |
if (cur.indexOf('\n') >= 0) numLinesEst++; | |
return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1; | |
}, 0); | |
if (length > 60) { | |
return braces[0] + | |
(base === '' ? '' : base + '\n ') + | |
' ' + | |
output.join(',\n ') + | |
' ' + | |
braces[1]; | |
} | |
return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; | |
} | |
// NOTE: These type checking functions intentionally don't use `instanceof` | |
// because it is fragile and can be easily faked with `Object.create()`. | |
function isArray(ar) { | |
return Array.isArray(ar); | |
} | |
exports.isArray = isArray; | |
function isBoolean(arg) { | |
return typeof arg === 'boolean'; | |
} | |
exports.isBoolean = isBoolean; | |
function isNull(arg) { | |
return arg === null; | |
} | |
exports.isNull = isNull; | |
function isNullOrUndefined(arg) { | |
return arg == null; | |
} | |
exports.isNullOrUndefined = isNullOrUndefined; | |
function isNumber(arg) { | |
return typeof arg === 'number'; | |
} | |
exports.isNumber = isNumber; | |
function isString(arg) { | |
return typeof arg === 'string'; | |
} | |
exports.isString = isString; | |
function isSymbol(arg) { | |
return typeof arg === 'symbol'; | |
} | |
exports.isSymbol = isSymbol; | |
function isUndefined(arg) { | |
return arg === void 0; | |
} | |
exports.isUndefined = isUndefined; | |
function isRegExp(re) { | |
return isObject(re) && objectToString(re) === '[object RegExp]'; | |
} | |
exports.isRegExp = isRegExp; | |
function isObject(arg) { | |
return typeof arg === 'object' && arg !== null; | |
} | |
exports.isObject = isObject; | |
function isDate(d) { | |
return isObject(d) && objectToString(d) === '[object Date]'; | |
} | |
exports.isDate = isDate; | |
function isError(e) { | |
return isObject(e) && | |
(objectToString(e) === '[object Error]' || e instanceof Error); | |
} | |
exports.isError = isError; | |
function isFunction(arg) { | |
return typeof arg === 'function'; | |
} | |
exports.isFunction = isFunction; | |
function isPrimitive(arg) { | |
return arg === null || | |
typeof arg === 'boolean' || | |
typeof arg === 'number' || | |
typeof arg === 'string' || | |
typeof arg === 'symbol' || // ES6 symbol | |
typeof arg === 'undefined'; | |
} | |
exports.isPrimitive = isPrimitive; | |
exports.isBuffer = require('./support/isBuffer'); | |
function objectToString(o) { | |
return Object.prototype.toString.call(o); | |
} | |
function pad(n) { | |
return n < 10 ? '0' + n.toString(10) : n.toString(10); | |
} | |
var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', | |
'Oct', 'Nov', 'Dec']; | |
// 26 Feb 16:19:34 | |
function timestamp() { | |
var d = new Date(); | |
var time = [pad(d.getHours()), | |
pad(d.getMinutes()), | |
pad(d.getSeconds())].join(':'); | |
return [d.getDate(), months[d.getMonth()], time].join(' '); | |
} | |
// log is just a thin wrapper to console.log that prepends a timestamp | |
exports.log = function() { | |
console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments)); | |
}; | |
/** | |
* Inherit the prototype methods from one constructor into another. | |
* | |
* The Function.prototype.inherits from lang.js rewritten as a standalone | |
* function (not on Function.prototype). NOTE: If this file is to be loaded | |
* during bootstrapping this function needs to be rewritten using some native | |
* functions as prototype setup using normal JavaScript does not work as | |
* expected during bootstrapping (see mirror.js in r114903). | |
* | |
* @param {function} ctor Constructor function which needs to inherit the | |
* prototype. | |
* @param {function} superCtor Constructor function to inherit prototype from. | |
*/ | |
exports.inherits = require('inherits'); | |
exports._extend = function(origin, add) { | |
// Don't do anything if add isn't an object | |
if (!add || !isObject(add)) return origin; | |
var keys = Object.keys(add); | |
var i = keys.length; | |
while (i--) { | |
origin[keys[i]] = add[keys[i]]; | |
} | |
return origin; | |
}; | |
function hasOwnProperty(obj, prop) { | |
return Object.prototype.hasOwnProperty.call(obj, prop); | |
} | |
}).call(this,require('_process'),typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"./support/isBuffer":3,"_process":1,"inherits":2}],5:[function(require,module,exports){ | |
(function (global){ | |
/** | |
* @depend times_in_words.js | |
* @depend util/core.js | |
* @depend match.js | |
* @depend format.js | |
*/ | |
/** | |
* Assertions matching the test spy retrieval interface. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal, global) { | |
"use strict"; | |
var slice = Array.prototype.slice; | |
function makeApi(sinon) { | |
var assert; | |
function verifyIsStub() { | |
var method; | |
for (var i = 0, l = arguments.length; i < l; ++i) { | |
method = arguments[i]; | |
if (!method) { | |
assert.fail("fake is not a spy"); | |
} | |
if (method.proxy && method.proxy.isSinonProxy) { | |
verifyIsStub(method.proxy); | |
} else { | |
if (typeof method !== "function") { | |
assert.fail(method + " is not a function"); | |
} | |
if (typeof method.getCall !== "function") { | |
assert.fail(method + " is not stubbed"); | |
} | |
} | |
} | |
} | |
function verifyIsValidAssertion(assertionMethod, assertionArgs) { | |
switch (assertionMethod) { | |
case "notCalled": | |
case "called": | |
case "calledOnce": | |
case "calledTwice": | |
case "calledThrice": | |
if (assertionArgs.length !== 0) { | |
assert.fail(assertionMethod + | |
" takes 1 argument but was called with " + | |
(assertionArgs.length + 1) + " arguments"); | |
} | |
break; | |
default: | |
break; | |
} | |
} | |
function failAssertion(object, msg) { | |
object = object || global; | |
var failMethod = object.fail || assert.fail; | |
failMethod.call(object, msg); | |
} | |
function mirrorPropAsAssertion(name, method, message) { | |
if (arguments.length === 2) { | |
message = method; | |
method = name; | |
} | |
assert[name] = function (fake) { | |
verifyIsStub(fake); | |
var args = slice.call(arguments, 1); | |
verifyIsValidAssertion(name, args); | |
var failed = false; | |
if (typeof method === "function") { | |
failed = !method(fake); | |
} else { | |
failed = typeof fake[method] === "function" ? | |
!fake[method].apply(fake, args) : !fake[method]; | |
} | |
if (failed) { | |
failAssertion(this, (fake.printf || fake.proxy.printf).apply(fake, [message].concat(args))); | |
} else { | |
assert.pass(name); | |
} | |
}; | |
} | |
function exposedName(prefix, prop) { | |
return !prefix || /^fail/.test(prop) ? prop : | |
prefix + prop.slice(0, 1).toUpperCase() + prop.slice(1); | |
} | |
assert = { | |
failException: "AssertError", | |
fail: function fail(message) { | |
var error = new Error(message); | |
error.name = this.failException || assert.failException; | |
throw error; | |
}, | |
pass: function pass() {}, | |
callOrder: function assertCallOrder() { | |
verifyIsStub.apply(null, arguments); | |
var expected = ""; | |
var actual = ""; | |
if (!sinon.calledInOrder(arguments)) { | |
try { | |
expected = [].join.call(arguments, ", "); | |
var calls = slice.call(arguments); | |
var i = calls.length; | |
while (i) { | |
if (!calls[--i].called) { | |
calls.splice(i, 1); | |
} | |
} | |
actual = sinon.orderByFirstCall(calls).join(", "); | |
} catch (e) { | |
// If this fails, we'll just fall back to the blank string | |
} | |
failAssertion(this, "expected " + expected + " to be " + | |
"called in order but were called as " + actual); | |
} else { | |
assert.pass("callOrder"); | |
} | |
}, | |
callCount: function assertCallCount(method, count) { | |
verifyIsStub(method); | |
if (method.callCount !== count) { | |
var msg = "expected %n to be called " + sinon.timesInWords(count) + | |
" but was called %c%C"; | |
failAssertion(this, method.printf(msg)); | |
} else { | |
assert.pass("callCount"); | |
} | |
}, | |
expose: function expose(target, options) { | |
if (!target) { | |
throw new TypeError("target is null or undefined"); | |
} | |
var o = options || {}; | |
var prefix = typeof o.prefix === "undefined" && "assert" || o.prefix; | |
var includeFail = typeof o.includeFail === "undefined" || !!o.includeFail; | |
for (var method in this) { | |
if (method !== "expose" && (includeFail || !/^(fail)/.test(method))) { | |
target[exposedName(prefix, method)] = this[method]; | |
} | |
} | |
return target; | |
}, | |
match: function match(actual, expectation) { | |
var matcher = sinon.match(expectation); | |
if (matcher.test(actual)) { | |
assert.pass("match"); | |
} else { | |
var formatted = [ | |
"expected value to match", | |
" expected = " + sinon.format(expectation), | |
" actual = " + sinon.format(actual) | |
]; | |
failAssertion(this, formatted.join("\n")); | |
} | |
} | |
}; | |
mirrorPropAsAssertion("called", "expected %n to have been called at least once but was never called"); | |
mirrorPropAsAssertion("notCalled", function (spy) { | |
return !spy.called; | |
}, "expected %n to not have been called but was called %c%C"); | |
mirrorPropAsAssertion("calledOnce", "expected %n to be called once but was called %c%C"); | |
mirrorPropAsAssertion("calledTwice", "expected %n to be called twice but was called %c%C"); | |
mirrorPropAsAssertion("calledThrice", "expected %n to be called thrice but was called %c%C"); | |
mirrorPropAsAssertion("calledOn", "expected %n to be called with %1 as this but was called with %t"); | |
mirrorPropAsAssertion( | |
"alwaysCalledOn", | |
"expected %n to always be called with %1 as this but was called with %t" | |
); | |
mirrorPropAsAssertion("calledWithNew", "expected %n to be called with new"); | |
mirrorPropAsAssertion("alwaysCalledWithNew", "expected %n to always be called with new"); | |
mirrorPropAsAssertion("calledWith", "expected %n to be called with arguments %*%C"); | |
mirrorPropAsAssertion("calledWithMatch", "expected %n to be called with match %*%C"); | |
mirrorPropAsAssertion("alwaysCalledWith", "expected %n to always be called with arguments %*%C"); | |
mirrorPropAsAssertion("alwaysCalledWithMatch", "expected %n to always be called with match %*%C"); | |
mirrorPropAsAssertion("calledWithExactly", "expected %n to be called with exact arguments %*%C"); | |
mirrorPropAsAssertion("alwaysCalledWithExactly", "expected %n to always be called with exact arguments %*%C"); | |
mirrorPropAsAssertion("neverCalledWith", "expected %n to never be called with arguments %*%C"); | |
mirrorPropAsAssertion("neverCalledWithMatch", "expected %n to never be called with match %*%C"); | |
mirrorPropAsAssertion("threw", "%n did not throw exception%C"); | |
mirrorPropAsAssertion("alwaysThrew", "%n did not always throw exception%C"); | |
sinon.assert = assert; | |
return assert; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./match"); | |
require("./format"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon, // eslint-disable-line no-undef | |
typeof global !== "undefined" ? global : self | |
)); | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"./format":10,"./match":12,"./util/core":21}],6:[function(require,module,exports){ | |
(function (process){ | |
/** | |
* @depend util/core.js | |
* @depend extend.js | |
*/ | |
/** | |
* Stub behavior | |
* | |
* @author Christian Johansen ([email protected]) | |
* @author Tim Fischbach ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
var slice = Array.prototype.slice; | |
var join = Array.prototype.join; | |
var useLeftMostCallback = -1; | |
var useRightMostCallback = -2; | |
var nextTick = (function () { | |
if (typeof process === "object" && typeof process.nextTick === "function") { | |
return process.nextTick; | |
} | |
if (typeof setImmediate === "function") { | |
return setImmediate; | |
} | |
return function (callback) { | |
setTimeout(callback, 0); | |
}; | |
})(); | |
function throwsException(error, message) { | |
if (typeof error === "string") { | |
this.exception = new Error(message || ""); | |
this.exception.name = error; | |
} else if (!error) { | |
this.exception = new Error("Error"); | |
} else { | |
this.exception = error; | |
} | |
return this; | |
} | |
function getCallback(behavior, args) { | |
var callArgAt = behavior.callArgAt; | |
if (callArgAt >= 0) { | |
return args[callArgAt]; | |
} | |
var argumentList; | |
if (callArgAt === useLeftMostCallback) { | |
argumentList = args; | |
} | |
if (callArgAt === useRightMostCallback) { | |
argumentList = slice.call(args).reverse(); | |
} | |
var callArgProp = behavior.callArgProp; | |
for (var i = 0, l = argumentList.length; i < l; ++i) { | |
if (!callArgProp && typeof argumentList[i] === "function") { | |
return argumentList[i]; | |
} | |
if (callArgProp && argumentList[i] && | |
typeof argumentList[i][callArgProp] === "function") { | |
return argumentList[i][callArgProp]; | |
} | |
} | |
return null; | |
} | |
function makeApi(sinon) { | |
function getCallbackError(behavior, func, args) { | |
if (behavior.callArgAt < 0) { | |
var msg; | |
if (behavior.callArgProp) { | |
msg = sinon.functionName(behavior.stub) + | |
" expected to yield to '" + behavior.callArgProp + | |
"', but no object with such a property was passed."; | |
} else { | |
msg = sinon.functionName(behavior.stub) + | |
" expected to yield, but no callback was passed."; | |
} | |
if (args.length > 0) { | |
msg += " Received [" + join.call(args, ", ") + "]"; | |
} | |
return msg; | |
} | |
return "argument at index " + behavior.callArgAt + " is not a function: " + func; | |
} | |
function callCallback(behavior, args) { | |
if (typeof behavior.callArgAt === "number") { | |
var func = getCallback(behavior, args); | |
if (typeof func !== "function") { | |
throw new TypeError(getCallbackError(behavior, func, args)); | |
} | |
if (behavior.callbackAsync) { | |
nextTick(function () { | |
func.apply(behavior.callbackContext, behavior.callbackArguments); | |
}); | |
} else { | |
func.apply(behavior.callbackContext, behavior.callbackArguments); | |
} | |
} | |
} | |
var proto = { | |
create: function create(stub) { | |
var behavior = sinon.extend({}, sinon.behavior); | |
delete behavior.create; | |
behavior.stub = stub; | |
return behavior; | |
}, | |
isPresent: function isPresent() { | |
return (typeof this.callArgAt === "number" || | |
this.exception || | |
typeof this.returnArgAt === "number" || | |
this.returnThis || | |
this.returnValueDefined); | |
}, | |
invoke: function invoke(context, args) { | |
callCallback(this, args); | |
if (this.exception) { | |
throw this.exception; | |
} else if (typeof this.returnArgAt === "number") { | |
return args[this.returnArgAt]; | |
} else if (this.returnThis) { | |
return context; | |
} | |
return this.returnValue; | |
}, | |
onCall: function onCall(index) { | |
return this.stub.onCall(index); | |
}, | |
onFirstCall: function onFirstCall() { | |
return this.stub.onFirstCall(); | |
}, | |
onSecondCall: function onSecondCall() { | |
return this.stub.onSecondCall(); | |
}, | |
onThirdCall: function onThirdCall() { | |
return this.stub.onThirdCall(); | |
}, | |
withArgs: function withArgs(/* arguments */) { | |
throw new Error( | |
"Defining a stub by invoking \"stub.onCall(...).withArgs(...)\" " + | |
"is not supported. Use \"stub.withArgs(...).onCall(...)\" " + | |
"to define sequential behavior for calls with certain arguments." | |
); | |
}, | |
callsArg: function callsArg(pos) { | |
if (typeof pos !== "number") { | |
throw new TypeError("argument index is not number"); | |
} | |
this.callArgAt = pos; | |
this.callbackArguments = []; | |
this.callbackContext = undefined; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
callsArgOn: function callsArgOn(pos, context) { | |
if (typeof pos !== "number") { | |
throw new TypeError("argument index is not number"); | |
} | |
if (typeof context !== "object") { | |
throw new TypeError("argument context is not an object"); | |
} | |
this.callArgAt = pos; | |
this.callbackArguments = []; | |
this.callbackContext = context; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
callsArgWith: function callsArgWith(pos) { | |
if (typeof pos !== "number") { | |
throw new TypeError("argument index is not number"); | |
} | |
this.callArgAt = pos; | |
this.callbackArguments = slice.call(arguments, 1); | |
this.callbackContext = undefined; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
callsArgOnWith: function callsArgWith(pos, context) { | |
if (typeof pos !== "number") { | |
throw new TypeError("argument index is not number"); | |
} | |
if (typeof context !== "object") { | |
throw new TypeError("argument context is not an object"); | |
} | |
this.callArgAt = pos; | |
this.callbackArguments = slice.call(arguments, 2); | |
this.callbackContext = context; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
yields: function () { | |
this.callArgAt = useLeftMostCallback; | |
this.callbackArguments = slice.call(arguments, 0); | |
this.callbackContext = undefined; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
yieldsRight: function () { | |
this.callArgAt = useRightMostCallback; | |
this.callbackArguments = slice.call(arguments, 0); | |
this.callbackContext = undefined; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
yieldsOn: function (context) { | |
if (typeof context !== "object") { | |
throw new TypeError("argument context is not an object"); | |
} | |
this.callArgAt = useLeftMostCallback; | |
this.callbackArguments = slice.call(arguments, 1); | |
this.callbackContext = context; | |
this.callArgProp = undefined; | |
this.callbackAsync = false; | |
return this; | |
}, | |
yieldsTo: function (prop) { | |
this.callArgAt = useLeftMostCallback; | |
this.callbackArguments = slice.call(arguments, 1); | |
this.callbackContext = undefined; | |
this.callArgProp = prop; | |
this.callbackAsync = false; | |
return this; | |
}, | |
yieldsToOn: function (prop, context) { | |
if (typeof context !== "object") { | |
throw new TypeError("argument context is not an object"); | |
} | |
this.callArgAt = useLeftMostCallback; | |
this.callbackArguments = slice.call(arguments, 2); | |
this.callbackContext = context; | |
this.callArgProp = prop; | |
this.callbackAsync = false; | |
return this; | |
}, | |
throws: throwsException, | |
throwsException: throwsException, | |
returns: function returns(value) { | |
this.returnValue = value; | |
this.returnValueDefined = true; | |
this.exception = undefined; | |
return this; | |
}, | |
returnsArg: function returnsArg(pos) { | |
if (typeof pos !== "number") { | |
throw new TypeError("argument index is not number"); | |
} | |
this.returnArgAt = pos; | |
return this; | |
}, | |
returnsThis: function returnsThis() { | |
this.returnThis = true; | |
return this; | |
} | |
}; | |
function createAsyncVersion(syncFnName) { | |
return function () { | |
var result = this[syncFnName].apply(this, arguments); | |
this.callbackAsync = true; | |
return result; | |
}; | |
} | |
// create asynchronous versions of callsArg* and yields* methods | |
for (var method in proto) { | |
// need to avoid creating anotherasync versions of the newly added async methods | |
if (proto.hasOwnProperty(method) && method.match(/^(callsArg|yields)/) && !method.match(/Async/)) { | |
proto[method + "Async"] = createAsyncVersion(method); | |
} | |
} | |
sinon.behavior = proto; | |
return proto; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./extend"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
}).call(this,require('_process')) | |
},{"./extend":9,"./util/core":21,"_process":1}],7:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend match.js | |
* @depend format.js | |
*/ | |
/** | |
* Spy calls | |
* | |
* @author Christian Johansen ([email protected]) | |
* @author Maximilian Antoni ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
* Copyright (c) 2013 Maximilian Antoni | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
var slice = Array.prototype.slice; | |
function makeApi(sinon) { | |
function throwYieldError(proxy, text, args) { | |
var msg = sinon.functionName(proxy) + text; | |
if (args.length) { | |
msg += " Received [" + slice.call(args).join(", ") + "]"; | |
} | |
throw new Error(msg); | |
} | |
var callProto = { | |
calledOn: function calledOn(thisValue) { | |
if (sinon.match && sinon.match.isMatcher(thisValue)) { | |
return thisValue.test(this.thisValue); | |
} | |
return this.thisValue === thisValue; | |
}, | |
calledWith: function calledWith() { | |
var l = arguments.length; | |
if (l > this.args.length) { | |
return false; | |
} | |
for (var i = 0; i < l; i += 1) { | |
if (!sinon.deepEqual(arguments[i], this.args[i])) { | |
return false; | |
} | |
} | |
return true; | |
}, | |
calledWithMatch: function calledWithMatch() { | |
var l = arguments.length; | |
if (l > this.args.length) { | |
return false; | |
} | |
for (var i = 0; i < l; i += 1) { | |
var actual = this.args[i]; | |
var expectation = arguments[i]; | |
if (!sinon.match || !sinon.match(expectation).test(actual)) { | |
return false; | |
} | |
} | |
return true; | |
}, | |
calledWithExactly: function calledWithExactly() { | |
return arguments.length === this.args.length && | |
this.calledWith.apply(this, arguments); | |
}, | |
notCalledWith: function notCalledWith() { | |
return !this.calledWith.apply(this, arguments); | |
}, | |
notCalledWithMatch: function notCalledWithMatch() { | |
return !this.calledWithMatch.apply(this, arguments); | |
}, | |
returned: function returned(value) { | |
return sinon.deepEqual(value, this.returnValue); | |
}, | |
threw: function threw(error) { | |
if (typeof error === "undefined" || !this.exception) { | |
return !!this.exception; | |
} | |
return this.exception === error || this.exception.name === error; | |
}, | |
calledWithNew: function calledWithNew() { | |
return this.proxy.prototype && this.thisValue instanceof this.proxy; | |
}, | |
calledBefore: function (other) { | |
return this.callId < other.callId; | |
}, | |
calledAfter: function (other) { | |
return this.callId > other.callId; | |
}, | |
callArg: function (pos) { | |
this.args[pos](); | |
}, | |
callArgOn: function (pos, thisValue) { | |
this.args[pos].apply(thisValue); | |
}, | |
callArgWith: function (pos) { | |
this.callArgOnWith.apply(this, [pos, null].concat(slice.call(arguments, 1))); | |
}, | |
callArgOnWith: function (pos, thisValue) { | |
var args = slice.call(arguments, 2); | |
this.args[pos].apply(thisValue, args); | |
}, | |
"yield": function () { | |
this.yieldOn.apply(this, [null].concat(slice.call(arguments, 0))); | |
}, | |
yieldOn: function (thisValue) { | |
var args = this.args; | |
for (var i = 0, l = args.length; i < l; ++i) { | |
if (typeof args[i] === "function") { | |
args[i].apply(thisValue, slice.call(arguments, 1)); | |
return; | |
} | |
} | |
throwYieldError(this.proxy, " cannot yield since no callback was passed.", args); | |
}, | |
yieldTo: function (prop) { | |
this.yieldToOn.apply(this, [prop, null].concat(slice.call(arguments, 1))); | |
}, | |
yieldToOn: function (prop, thisValue) { | |
var args = this.args; | |
for (var i = 0, l = args.length; i < l; ++i) { | |
if (args[i] && typeof args[i][prop] === "function") { | |
args[i][prop].apply(thisValue, slice.call(arguments, 2)); | |
return; | |
} | |
} | |
throwYieldError(this.proxy, " cannot yield to '" + prop + | |
"' since no callback was passed.", args); | |
}, | |
getStackFrames: function () { | |
// Omit the error message and the two top stack frames in sinon itself: | |
return this.stack && this.stack.split("\n").slice(3); | |
}, | |
toString: function () { | |
var callStr = this.proxy ? this.proxy.toString() + "(" : ""; | |
var args = []; | |
if (!this.args) { | |
return ":("; | |
} | |
for (var i = 0, l = this.args.length; i < l; ++i) { | |
args.push(sinon.format(this.args[i])); | |
} | |
callStr = callStr + args.join(", ") + ")"; | |
if (typeof this.returnValue !== "undefined") { | |
callStr += " => " + sinon.format(this.returnValue); | |
} | |
if (this.exception) { | |
callStr += " !" + this.exception.name; | |
if (this.exception.message) { | |
callStr += "(" + this.exception.message + ")"; | |
} | |
} | |
if (this.stack) { | |
callStr += this.getStackFrames()[0].replace(/^\s*(?:at\s+|@)?/, " at "); | |
} | |
return callStr; | |
} | |
}; | |
callProto.invokeCallback = callProto.yield; | |
function createSpyCall(spy, thisValue, args, returnValue, exception, id, stack) { | |
if (typeof id !== "number") { | |
throw new TypeError("Call id is not a number"); | |
} | |
var proxyCall = sinon.create(callProto); | |
proxyCall.proxy = spy; | |
proxyCall.thisValue = thisValue; | |
proxyCall.args = args; | |
proxyCall.returnValue = returnValue; | |
proxyCall.exception = exception; | |
proxyCall.callId = id; | |
proxyCall.stack = stack; | |
return proxyCall; | |
} | |
createSpyCall.toString = callProto.toString; // used by mocks | |
sinon.spyCall = createSpyCall; | |
return createSpyCall; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./match"); | |
require("./format"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./format":10,"./match":12,"./util/core":21}],8:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend spy.js | |
* @depend stub.js | |
* @depend mock.js | |
*/ | |
/** | |
* Collections of stubs, spies and mocks. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
var push = [].push; | |
var hasOwnProperty = Object.prototype.hasOwnProperty; | |
function getFakes(fakeCollection) { | |
if (!fakeCollection.fakes) { | |
fakeCollection.fakes = []; | |
} | |
return fakeCollection.fakes; | |
} | |
function each(fakeCollection, method) { | |
var fakes = getFakes(fakeCollection); | |
for (var i = 0, l = fakes.length; i < l; i += 1) { | |
if (typeof fakes[i][method] === "function") { | |
fakes[i][method](); | |
} | |
} | |
} | |
function compact(fakeCollection) { | |
var fakes = getFakes(fakeCollection); | |
var i = 0; | |
while (i < fakes.length) { | |
fakes.splice(i, 1); | |
} | |
} | |
function makeApi(sinon) { | |
var collection = { | |
verify: function resolve() { | |
each(this, "verify"); | |
}, | |
restore: function restore() { | |
each(this, "restore"); | |
compact(this); | |
}, | |
reset: function restore() { | |
each(this, "reset"); | |
}, | |
verifyAndRestore: function verifyAndRestore() { | |
var exception; | |
try { | |
this.verify(); | |
} catch (e) { | |
exception = e; | |
} | |
this.restore(); | |
if (exception) { | |
throw exception; | |
} | |
}, | |
add: function add(fake) { | |
push.call(getFakes(this), fake); | |
return fake; | |
}, | |
spy: function spy() { | |
return this.add(sinon.spy.apply(sinon, arguments)); | |
}, | |
stub: function stub(object, property, value) { | |
if (property) { | |
var original = object[property]; | |
if (typeof original !== "function") { | |
if (!hasOwnProperty.call(object, property)) { | |
throw new TypeError("Cannot stub non-existent own property " + property); | |
} | |
object[property] = value; | |
return this.add({ | |
restore: function () { | |
object[property] = original; | |
} | |
}); | |
} | |
} | |
if (!property && !!object && typeof object === "object") { | |
var stubbedObj = sinon.stub.apply(sinon, arguments); | |
for (var prop in stubbedObj) { | |
if (typeof stubbedObj[prop] === "function") { | |
this.add(stubbedObj[prop]); | |
} | |
} | |
return stubbedObj; | |
} | |
return this.add(sinon.stub.apply(sinon, arguments)); | |
}, | |
mock: function mock() { | |
return this.add(sinon.mock.apply(sinon, arguments)); | |
}, | |
inject: function inject(obj) { | |
var col = this; | |
obj.spy = function () { | |
return col.spy.apply(col, arguments); | |
}; | |
obj.stub = function () { | |
return col.stub.apply(col, arguments); | |
}; | |
obj.mock = function () { | |
return col.mock.apply(col, arguments); | |
}; | |
return obj; | |
} | |
}; | |
sinon.collection = collection; | |
return collection; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./mock"); | |
require("./spy"); | |
require("./stub"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./mock":13,"./spy":15,"./stub":16,"./util/core":21}],9:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
// Adapted from https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug | |
var hasDontEnumBug = (function () { | |
var obj = { | |
constructor: function () { | |
return "0"; | |
}, | |
toString: function () { | |
return "1"; | |
}, | |
valueOf: function () { | |
return "2"; | |
}, | |
toLocaleString: function () { | |
return "3"; | |
}, | |
prototype: function () { | |
return "4"; | |
}, | |
isPrototypeOf: function () { | |
return "5"; | |
}, | |
propertyIsEnumerable: function () { | |
return "6"; | |
}, | |
hasOwnProperty: function () { | |
return "7"; | |
}, | |
length: function () { | |
return "8"; | |
}, | |
unique: function () { | |
return "9"; | |
} | |
}; | |
var result = []; | |
for (var prop in obj) { | |
if (obj.hasOwnProperty(prop)) { | |
result.push(obj[prop]()); | |
} | |
} | |
return result.join("") !== "0123456789"; | |
})(); | |
/* Public: Extend target in place with all (own) properties from sources in-order. Thus, last source will | |
* override properties in previous sources. | |
* | |
* target - The Object to extend | |
* sources - Objects to copy properties from. | |
* | |
* Returns the extended target | |
*/ | |
function extend(target /*, sources */) { | |
var sources = Array.prototype.slice.call(arguments, 1); | |
var source, i, prop; | |
for (i = 0; i < sources.length; i++) { | |
source = sources[i]; | |
for (prop in source) { | |
if (source.hasOwnProperty(prop)) { | |
target[prop] = source[prop]; | |
} | |
} | |
// Make sure we copy (own) toString method even when in JScript with DontEnum bug | |
// See https://developer.mozilla.org/en/docs/ECMAScript_DontEnum_attribute#JScript_DontEnum_Bug | |
if (hasDontEnumBug && source.hasOwnProperty("toString") && source.toString !== target.toString) { | |
target.toString = source.toString; | |
} | |
} | |
return target; | |
} | |
sinon.extend = extend; | |
return sinon.extend; | |
} | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
module.exports = makeApi(sinon); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21}],10:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
/** | |
* Format functions | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2014 Christian Johansen | |
*/ | |
(function (sinonGlobal, formatio) { | |
"use strict"; | |
function makeApi(sinon) { | |
function valueFormatter(value) { | |
return "" + value; | |
} | |
function getFormatioFormatter() { | |
var formatter = formatio.configure({ | |
quoteStrings: false, | |
limitChildrenCount: 250 | |
}); | |
function format() { | |
return formatter.ascii.apply(formatter, arguments); | |
} | |
return format; | |
} | |
function getNodeFormatter() { | |
try { | |
var util = require("util"); | |
} catch (e) { | |
/* Node, but no util module - would be very old, but better safe than sorry */ | |
} | |
function format(v) { | |
var isObjectWithNativeToString = typeof v === "object" && v.toString === Object.prototype.toString; | |
return isObjectWithNativeToString ? util.inspect(v) : v; | |
} | |
return util ? format : valueFormatter; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var formatter; | |
if (isNode) { | |
try { | |
formatio = require("formatio"); | |
} | |
catch (e) {} // eslint-disable-line no-empty | |
} | |
if (formatio) { | |
formatter = getFormatioFormatter(); | |
} else if (isNode) { | |
formatter = getNodeFormatter(); | |
} else { | |
formatter = valueFormatter; | |
} | |
sinon.format = formatter; | |
return sinon.format; | |
} | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
module.exports = makeApi(sinon); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon, // eslint-disable-line no-undef | |
typeof formatio === "object" && formatio // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21,"formatio":29,"util":4}],11:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
/** | |
* Logs errors | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2014 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
// cache a reference to setTimeout, so that our reference won't be stubbed out | |
// when using fake timers and errors will still get logged | |
// https://github.com/cjohansen/Sinon.JS/issues/381 | |
var realSetTimeout = setTimeout; | |
function makeApi(sinon) { | |
function log() {} | |
function logError(label, err) { | |
var msg = label + " threw exception: "; | |
function throwLoggedError() { | |
err.message = msg + err.message; | |
throw err; | |
} | |
sinon.log(msg + "[" + err.name + "] " + err.message); | |
if (err.stack) { | |
sinon.log(err.stack); | |
} | |
if (logError.useImmediateExceptions) { | |
throwLoggedError(); | |
} else { | |
logError.setTimeout(throwLoggedError, 0); | |
} | |
} | |
// When set to true, any errors logged will be thrown immediately; | |
// If set to false, the errors will be thrown in separate execution frame. | |
logError.useImmediateExceptions = false; | |
// wrap realSetTimeout with something we can stub in tests | |
logError.setTimeout = function (func, timeout) { | |
realSetTimeout(func, timeout); | |
}; | |
var exports = {}; | |
exports.log = sinon.log = log; | |
exports.logError = sinon.logError = logError; | |
return exports; | |
} | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
module.exports = makeApi(sinon); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21}],12:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend typeOf.js | |
*/ | |
/*jslint eqeqeq: false, onevar: false, plusplus: false*/ | |
/*global module, require, sinon*/ | |
/** | |
* Match functions | |
* | |
* @author Maximilian Antoni ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2012 Maximilian Antoni | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
function assertType(value, type, name) { | |
var actual = sinon.typeOf(value); | |
if (actual !== type) { | |
throw new TypeError("Expected type of " + name + " to be " + | |
type + ", but was " + actual); | |
} | |
} | |
var matcher = { | |
toString: function () { | |
return this.message; | |
} | |
}; | |
function isMatcher(object) { | |
return matcher.isPrototypeOf(object); | |
} | |
function matchObject(expectation, actual) { | |
if (actual === null || actual === undefined) { | |
return false; | |
} | |
for (var key in expectation) { | |
if (expectation.hasOwnProperty(key)) { | |
var exp = expectation[key]; | |
var act = actual[key]; | |
if (isMatcher(exp)) { | |
if (!exp.test(act)) { | |
return false; | |
} | |
} else if (sinon.typeOf(exp) === "object") { | |
if (!matchObject(exp, act)) { | |
return false; | |
} | |
} else if (!sinon.deepEqual(exp, act)) { | |
return false; | |
} | |
} | |
} | |
return true; | |
} | |
function match(expectation, message) { | |
var m = sinon.create(matcher); | |
var type = sinon.typeOf(expectation); | |
switch (type) { | |
case "object": | |
if (typeof expectation.test === "function") { | |
m.test = function (actual) { | |
return expectation.test(actual) === true; | |
}; | |
m.message = "match(" + sinon.functionName(expectation.test) + ")"; | |
return m; | |
} | |
var str = []; | |
for (var key in expectation) { | |
if (expectation.hasOwnProperty(key)) { | |
str.push(key + ": " + expectation[key]); | |
} | |
} | |
m.test = function (actual) { | |
return matchObject(expectation, actual); | |
}; | |
m.message = "match(" + str.join(", ") + ")"; | |
break; | |
case "number": | |
m.test = function (actual) { | |
// we need type coercion here | |
return expectation == actual; // eslint-disable-line eqeqeq | |
}; | |
break; | |
case "string": | |
m.test = function (actual) { | |
if (typeof actual !== "string") { | |
return false; | |
} | |
return actual.indexOf(expectation) !== -1; | |
}; | |
m.message = "match(\"" + expectation + "\")"; | |
break; | |
case "regexp": | |
m.test = function (actual) { | |
if (typeof actual !== "string") { | |
return false; | |
} | |
return expectation.test(actual); | |
}; | |
break; | |
case "function": | |
m.test = expectation; | |
if (message) { | |
m.message = message; | |
} else { | |
m.message = "match(" + sinon.functionName(expectation) + ")"; | |
} | |
break; | |
default: | |
m.test = function (actual) { | |
return sinon.deepEqual(expectation, actual); | |
}; | |
} | |
if (!m.message) { | |
m.message = "match(" + expectation + ")"; | |
} | |
return m; | |
} | |
matcher.or = function (m2) { | |
if (!arguments.length) { | |
throw new TypeError("Matcher expected"); | |
} else if (!isMatcher(m2)) { | |
m2 = match(m2); | |
} | |
var m1 = this; | |
var or = sinon.create(matcher); | |
or.test = function (actual) { | |
return m1.test(actual) || m2.test(actual); | |
}; | |
or.message = m1.message + ".or(" + m2.message + ")"; | |
return or; | |
}; | |
matcher.and = function (m2) { | |
if (!arguments.length) { | |
throw new TypeError("Matcher expected"); | |
} else if (!isMatcher(m2)) { | |
m2 = match(m2); | |
} | |
var m1 = this; | |
var and = sinon.create(matcher); | |
and.test = function (actual) { | |
return m1.test(actual) && m2.test(actual); | |
}; | |
and.message = m1.message + ".and(" + m2.message + ")"; | |
return and; | |
}; | |
match.isMatcher = isMatcher; | |
match.any = match(function () { | |
return true; | |
}, "any"); | |
match.defined = match(function (actual) { | |
return actual !== null && actual !== undefined; | |
}, "defined"); | |
match.truthy = match(function (actual) { | |
return !!actual; | |
}, "truthy"); | |
match.falsy = match(function (actual) { | |
return !actual; | |
}, "falsy"); | |
match.same = function (expectation) { | |
return match(function (actual) { | |
return expectation === actual; | |
}, "same(" + expectation + ")"); | |
}; | |
match.typeOf = function (type) { | |
assertType(type, "string", "type"); | |
return match(function (actual) { | |
return sinon.typeOf(actual) === type; | |
}, "typeOf(\"" + type + "\")"); | |
}; | |
match.instanceOf = function (type) { | |
assertType(type, "function", "type"); | |
return match(function (actual) { | |
return actual instanceof type; | |
}, "instanceOf(" + sinon.functionName(type) + ")"); | |
}; | |
function createPropertyMatcher(propertyTest, messagePrefix) { | |
return function (property, value) { | |
assertType(property, "string", "property"); | |
var onlyProperty = arguments.length === 1; | |
var message = messagePrefix + "(\"" + property + "\""; | |
if (!onlyProperty) { | |
message += ", " + value; | |
} | |
message += ")"; | |
return match(function (actual) { | |
if (actual === undefined || actual === null || | |
!propertyTest(actual, property)) { | |
return false; | |
} | |
return onlyProperty || sinon.deepEqual(value, actual[property]); | |
}, message); | |
}; | |
} | |
match.has = createPropertyMatcher(function (actual, property) { | |
if (typeof actual === "object") { | |
return property in actual; | |
} | |
return actual[property] !== undefined; | |
}, "has"); | |
match.hasOwn = createPropertyMatcher(function (actual, property) { | |
return actual.hasOwnProperty(property); | |
}, "hasOwn"); | |
match.bool = match.typeOf("boolean"); | |
match.number = match.typeOf("number"); | |
match.string = match.typeOf("string"); | |
match.object = match.typeOf("object"); | |
match.func = match.typeOf("function"); | |
match.array = match.typeOf("array"); | |
match.regexp = match.typeOf("regexp"); | |
match.date = match.typeOf("date"); | |
sinon.match = match; | |
return match; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./typeOf"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./typeOf":20,"./util/core":21}],13:[function(require,module,exports){ | |
/** | |
* @depend times_in_words.js | |
* @depend util/core.js | |
* @depend call.js | |
* @depend extend.js | |
* @depend match.js | |
* @depend spy.js | |
* @depend stub.js | |
* @depend format.js | |
*/ | |
/** | |
* Mock functions. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
var push = [].push; | |
var match = sinon.match; | |
function mock(object) { | |
// if (typeof console !== undefined && console.warn) { | |
// console.warn("mock will be removed from Sinon.JS v2.0"); | |
// } | |
if (!object) { | |
return sinon.expectation.create("Anonymous mock"); | |
} | |
return mock.create(object); | |
} | |
function each(collection, callback) { | |
if (!collection) { | |
return; | |
} | |
for (var i = 0, l = collection.length; i < l; i += 1) { | |
callback(collection[i]); | |
} | |
} | |
function arrayEquals(arr1, arr2, compareLength) { | |
if (compareLength && (arr1.length !== arr2.length)) { | |
return false; | |
} | |
for (var i = 0, l = arr1.length; i < l; i++) { | |
if (!sinon.deepEqual(arr1[i], arr2[i])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
sinon.extend(mock, { | |
create: function create(object) { | |
if (!object) { | |
throw new TypeError("object is null"); | |
} | |
var mockObject = sinon.extend({}, mock); | |
mockObject.object = object; | |
delete mockObject.create; | |
return mockObject; | |
}, | |
expects: function expects(method) { | |
if (!method) { | |
throw new TypeError("method is falsy"); | |
} | |
if (!this.expectations) { | |
this.expectations = {}; | |
this.proxies = []; | |
} | |
if (!this.expectations[method]) { | |
this.expectations[method] = []; | |
var mockObject = this; | |
sinon.wrapMethod(this.object, method, function () { | |
return mockObject.invokeMethod(method, this, arguments); | |
}); | |
push.call(this.proxies, method); | |
} | |
var expectation = sinon.expectation.create(method); | |
push.call(this.expectations[method], expectation); | |
return expectation; | |
}, | |
restore: function restore() { | |
var object = this.object; | |
each(this.proxies, function (proxy) { | |
if (typeof object[proxy].restore === "function") { | |
object[proxy].restore(); | |
} | |
}); | |
}, | |
verify: function verify() { | |
var expectations = this.expectations || {}; | |
var messages = []; | |
var met = []; | |
each(this.proxies, function (proxy) { | |
each(expectations[proxy], function (expectation) { | |
if (!expectation.met()) { | |
push.call(messages, expectation.toString()); | |
} else { | |
push.call(met, expectation.toString()); | |
} | |
}); | |
}); | |
this.restore(); | |
if (messages.length > 0) { | |
sinon.expectation.fail(messages.concat(met).join("\n")); | |
} else if (met.length > 0) { | |
sinon.expectation.pass(messages.concat(met).join("\n")); | |
} | |
return true; | |
}, | |
invokeMethod: function invokeMethod(method, thisValue, args) { | |
var expectations = this.expectations && this.expectations[method] ? this.expectations[method] : []; | |
var expectationsWithMatchingArgs = []; | |
var currentArgs = args || []; | |
var i, available; | |
for (i = 0; i < expectations.length; i += 1) { | |
var expectedArgs = expectations[i].expectedArguments || []; | |
if (arrayEquals(expectedArgs, currentArgs, expectations[i].expectsExactArgCount)) { | |
expectationsWithMatchingArgs.push(expectations[i]); | |
} | |
} | |
for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { | |
if (!expectationsWithMatchingArgs[i].met() && | |
expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { | |
return expectationsWithMatchingArgs[i].apply(thisValue, args); | |
} | |
} | |
var messages = []; | |
var exhausted = 0; | |
for (i = 0; i < expectationsWithMatchingArgs.length; i += 1) { | |
if (expectationsWithMatchingArgs[i].allowsCall(thisValue, args)) { | |
available = available || expectationsWithMatchingArgs[i]; | |
} else { | |
exhausted += 1; | |
} | |
} | |
if (available && exhausted === 0) { | |
return available.apply(thisValue, args); | |
} | |
for (i = 0; i < expectations.length; i += 1) { | |
push.call(messages, " " + expectations[i].toString()); | |
} | |
messages.unshift("Unexpected call: " + sinon.spyCall.toString.call({ | |
proxy: method, | |
args: args | |
})); | |
sinon.expectation.fail(messages.join("\n")); | |
} | |
}); | |
var times = sinon.timesInWords; | |
var slice = Array.prototype.slice; | |
function callCountInWords(callCount) { | |
if (callCount === 0) { | |
return "never called"; | |
} | |
return "called " + times(callCount); | |
} | |
function expectedCallCountInWords(expectation) { | |
var min = expectation.minCalls; | |
var max = expectation.maxCalls; | |
if (typeof min === "number" && typeof max === "number") { | |
var str = times(min); | |
if (min !== max) { | |
str = "at least " + str + " and at most " + times(max); | |
} | |
return str; | |
} | |
if (typeof min === "number") { | |
return "at least " + times(min); | |
} | |
return "at most " + times(max); | |
} | |
function receivedMinCalls(expectation) { | |
var hasMinLimit = typeof expectation.minCalls === "number"; | |
return !hasMinLimit || expectation.callCount >= expectation.minCalls; | |
} | |
function receivedMaxCalls(expectation) { | |
if (typeof expectation.maxCalls !== "number") { | |
return false; | |
} | |
return expectation.callCount === expectation.maxCalls; | |
} | |
function verifyMatcher(possibleMatcher, arg) { | |
var isMatcher = match && match.isMatcher(possibleMatcher); | |
return isMatcher && possibleMatcher.test(arg) || true; | |
} | |
sinon.expectation = { | |
minCalls: 1, | |
maxCalls: 1, | |
create: function create(methodName) { | |
var expectation = sinon.extend(sinon.stub.create(), sinon.expectation); | |
delete expectation.create; | |
expectation.method = methodName; | |
return expectation; | |
}, | |
invoke: function invoke(func, thisValue, args) { | |
this.verifyCallAllowed(thisValue, args); | |
return sinon.spy.invoke.apply(this, arguments); | |
}, | |
atLeast: function atLeast(num) { | |
if (typeof num !== "number") { | |
throw new TypeError("'" + num + "' is not number"); | |
} | |
if (!this.limitsSet) { | |
this.maxCalls = null; | |
this.limitsSet = true; | |
} | |
this.minCalls = num; | |
return this; | |
}, | |
atMost: function atMost(num) { | |
if (typeof num !== "number") { | |
throw new TypeError("'" + num + "' is not number"); | |
} | |
if (!this.limitsSet) { | |
this.minCalls = null; | |
this.limitsSet = true; | |
} | |
this.maxCalls = num; | |
return this; | |
}, | |
never: function never() { | |
return this.exactly(0); | |
}, | |
once: function once() { | |
return this.exactly(1); | |
}, | |
twice: function twice() { | |
return this.exactly(2); | |
}, | |
thrice: function thrice() { | |
return this.exactly(3); | |
}, | |
exactly: function exactly(num) { | |
if (typeof num !== "number") { | |
throw new TypeError("'" + num + "' is not a number"); | |
} | |
this.atLeast(num); | |
return this.atMost(num); | |
}, | |
met: function met() { | |
return !this.failed && receivedMinCalls(this); | |
}, | |
verifyCallAllowed: function verifyCallAllowed(thisValue, args) { | |
if (receivedMaxCalls(this)) { | |
this.failed = true; | |
sinon.expectation.fail(this.method + " already called " + times(this.maxCalls)); | |
} | |
if ("expectedThis" in this && this.expectedThis !== thisValue) { | |
sinon.expectation.fail(this.method + " called with " + thisValue + " as thisValue, expected " + | |
this.expectedThis); | |
} | |
if (!("expectedArguments" in this)) { | |
return; | |
} | |
if (!args) { | |
sinon.expectation.fail(this.method + " received no arguments, expected " + | |
sinon.format(this.expectedArguments)); | |
} | |
if (args.length < this.expectedArguments.length) { | |
sinon.expectation.fail(this.method + " received too few arguments (" + sinon.format(args) + | |
"), expected " + sinon.format(this.expectedArguments)); | |
} | |
if (this.expectsExactArgCount && | |
args.length !== this.expectedArguments.length) { | |
sinon.expectation.fail(this.method + " received too many arguments (" + sinon.format(args) + | |
"), expected " + sinon.format(this.expectedArguments)); | |
} | |
for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { | |
if (!verifyMatcher(this.expectedArguments[i], args[i])) { | |
sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + | |
", didn't match " + this.expectedArguments.toString()); | |
} | |
if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { | |
sinon.expectation.fail(this.method + " received wrong arguments " + sinon.format(args) + | |
", expected " + sinon.format(this.expectedArguments)); | |
} | |
} | |
}, | |
allowsCall: function allowsCall(thisValue, args) { | |
if (this.met() && receivedMaxCalls(this)) { | |
return false; | |
} | |
if ("expectedThis" in this && this.expectedThis !== thisValue) { | |
return false; | |
} | |
if (!("expectedArguments" in this)) { | |
return true; | |
} | |
args = args || []; | |
if (args.length < this.expectedArguments.length) { | |
return false; | |
} | |
if (this.expectsExactArgCount && | |
args.length !== this.expectedArguments.length) { | |
return false; | |
} | |
for (var i = 0, l = this.expectedArguments.length; i < l; i += 1) { | |
if (!verifyMatcher(this.expectedArguments[i], args[i])) { | |
return false; | |
} | |
if (!sinon.deepEqual(this.expectedArguments[i], args[i])) { | |
return false; | |
} | |
} | |
return true; | |
}, | |
withArgs: function withArgs() { | |
this.expectedArguments = slice.call(arguments); | |
return this; | |
}, | |
withExactArgs: function withExactArgs() { | |
this.withArgs.apply(this, arguments); | |
this.expectsExactArgCount = true; | |
return this; | |
}, | |
on: function on(thisValue) { | |
this.expectedThis = thisValue; | |
return this; | |
}, | |
toString: function () { | |
var args = (this.expectedArguments || []).slice(); | |
if (!this.expectsExactArgCount) { | |
push.call(args, "[...]"); | |
} | |
var callStr = sinon.spyCall.toString.call({ | |
proxy: this.method || "anonymous mock expectation", | |
args: args | |
}); | |
var message = callStr.replace(", [...", "[, ...") + " " + | |
expectedCallCountInWords(this); | |
if (this.met()) { | |
return "Expectation met: " + message; | |
} | |
return "Expected " + message + " (" + | |
callCountInWords(this.callCount) + ")"; | |
}, | |
verify: function verify() { | |
if (!this.met()) { | |
sinon.expectation.fail(this.toString()); | |
} else { | |
sinon.expectation.pass(this.toString()); | |
} | |
return true; | |
}, | |
pass: function pass(message) { | |
sinon.assert.pass(message); | |
}, | |
fail: function fail(message) { | |
var exception = new Error(message); | |
exception.name = "ExpectationError"; | |
throw exception; | |
} | |
}; | |
sinon.mock = mock; | |
return mock; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./times_in_words"); | |
require("./call"); | |
require("./extend"); | |
require("./match"); | |
require("./spy"); | |
require("./stub"); | |
require("./format"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./call":7,"./extend":9,"./format":10,"./match":12,"./spy":15,"./stub":16,"./times_in_words":19,"./util/core":21}],14:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend extend.js | |
* @depend collection.js | |
* @depend util/fake_timers.js | |
* @depend util/fake_server_with_clock.js | |
*/ | |
/** | |
* Manages fake collections as well as fake utilities such as Sinon's | |
* timers and fake XHR implementation in one convenient object. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
var push = [].push; | |
function exposeValue(sandbox, config, key, value) { | |
if (!value) { | |
return; | |
} | |
if (config.injectInto && !(key in config.injectInto)) { | |
config.injectInto[key] = value; | |
sandbox.injectedKeys.push(key); | |
} else { | |
push.call(sandbox.args, value); | |
} | |
} | |
function prepareSandboxFromConfig(config) { | |
var sandbox = sinon.create(sinon.sandbox); | |
if (config.useFakeServer) { | |
if (typeof config.useFakeServer === "object") { | |
sandbox.serverPrototype = config.useFakeServer; | |
} | |
sandbox.useFakeServer(); | |
} | |
if (config.useFakeTimers) { | |
if (typeof config.useFakeTimers === "object") { | |
sandbox.useFakeTimers.apply(sandbox, config.useFakeTimers); | |
} else { | |
sandbox.useFakeTimers(); | |
} | |
} | |
return sandbox; | |
} | |
sinon.sandbox = sinon.extend(sinon.create(sinon.collection), { | |
useFakeTimers: function useFakeTimers() { | |
this.clock = sinon.useFakeTimers.apply(sinon, arguments); | |
return this.add(this.clock); | |
}, | |
serverPrototype: sinon.fakeServer, | |
useFakeServer: function useFakeServer() { | |
var proto = this.serverPrototype || sinon.fakeServer; | |
if (!proto || !proto.create) { | |
return null; | |
} | |
this.server = proto.create(); | |
return this.add(this.server); | |
}, | |
inject: function (obj) { | |
sinon.collection.inject.call(this, obj); | |
if (this.clock) { | |
obj.clock = this.clock; | |
} | |
if (this.server) { | |
obj.server = this.server; | |
obj.requests = this.server.requests; | |
} | |
obj.match = sinon.match; | |
return obj; | |
}, | |
restore: function () { | |
if (arguments.length) { | |
throw new Error("sandbox.restore() does not take any parameters. Perhaps you meant stub.restore()"); | |
} | |
sinon.collection.restore.apply(this, arguments); | |
this.restoreContext(); | |
}, | |
restoreContext: function () { | |
if (this.injectedKeys) { | |
for (var i = 0, j = this.injectedKeys.length; i < j; i++) { | |
delete this.injectInto[this.injectedKeys[i]]; | |
} | |
this.injectedKeys = []; | |
} | |
}, | |
create: function (config) { | |
if (!config) { | |
return sinon.create(sinon.sandbox); | |
} | |
var sandbox = prepareSandboxFromConfig(config); | |
sandbox.args = sandbox.args || []; | |
sandbox.injectedKeys = []; | |
sandbox.injectInto = config.injectInto; | |
var prop, | |
value; | |
var exposed = sandbox.inject({}); | |
if (config.properties) { | |
for (var i = 0, l = config.properties.length; i < l; i++) { | |
prop = config.properties[i]; | |
value = exposed[prop] || prop === "sandbox" && sandbox; | |
exposeValue(sandbox, config, prop, value); | |
} | |
} else { | |
exposeValue(sandbox, config, "sandbox", value); | |
} | |
return sandbox; | |
}, | |
match: sinon.match | |
}); | |
sinon.sandbox.useFakeXMLHttpRequest = sinon.sandbox.useFakeServer; | |
return sinon.sandbox; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
require("./extend"); | |
require("./util/fake_server_with_clock"); | |
require("./util/fake_timers"); | |
require("./collection"); | |
module.exports = makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./collection":8,"./extend":9,"./util/core":21,"./util/fake_server_with_clock":24,"./util/fake_timers":25}],15:[function(require,module,exports){ | |
/** | |
* @depend times_in_words.js | |
* @depend util/core.js | |
* @depend extend.js | |
* @depend call.js | |
* @depend format.js | |
*/ | |
/** | |
* Spy functions | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
var push = Array.prototype.push; | |
var slice = Array.prototype.slice; | |
var callId = 0; | |
function spy(object, property, types) { | |
if (!property && typeof object === "function") { | |
return spy.create(object); | |
} | |
if (!object && !property) { | |
return spy.create(function () { }); | |
} | |
if (types) { | |
// A new descriptor is needed here because we can only wrap functions | |
// By passing the original descriptor we would end up trying to spy non-function properties | |
var descriptor = {}; | |
var methodDesc = sinon.getPropertyDescriptor(object, property); | |
for (var i = 0; i < types.length; i++) { | |
descriptor[types[i]] = spy.create(methodDesc[types[i]]); | |
} | |
return sinon.wrapMethod(object, property, descriptor); | |
} | |
return sinon.wrapMethod(object, property, spy.create(object[property])); | |
} | |
function matchingFake(fakes, args, strict) { | |
if (!fakes) { | |
return undefined; | |
} | |
for (var i = 0, l = fakes.length; i < l; i++) { | |
if (fakes[i].matches(args, strict)) { | |
return fakes[i]; | |
} | |
} | |
} | |
function incrementCallCount() { | |
this.called = true; | |
this.callCount += 1; | |
this.notCalled = false; | |
this.calledOnce = this.callCount === 1; | |
this.calledTwice = this.callCount === 2; | |
this.calledThrice = this.callCount === 3; | |
} | |
function createCallProperties() { | |
this.firstCall = this.getCall(0); | |
this.secondCall = this.getCall(1); | |
this.thirdCall = this.getCall(2); | |
this.lastCall = this.getCall(this.callCount - 1); | |
} | |
var vars = "a,b,c,d,e,f,g,h,i,j,k,l"; | |
function createProxy(func, proxyLength) { | |
// Retain the function length: | |
var p; | |
if (proxyLength) { | |
eval("p = (function proxy(" + vars.substring(0, proxyLength * 2 - 1) + // eslint-disable-line no-eval | |
") { return p.invoke(func, this, slice.call(arguments)); });"); | |
} else { | |
p = function proxy() { | |
return p.invoke(func, this, slice.call(arguments)); | |
}; | |
} | |
p.isSinonProxy = true; | |
return p; | |
} | |
var uuid = 0; | |
// Public API | |
var spyApi = { | |
reset: function () { | |
if (this.invoking) { | |
var err = new Error("Cannot reset Sinon function while invoking it. " + | |
"Move the call to .reset outside of the callback."); | |
err.name = "InvalidResetException"; | |
throw err; | |
} | |
this.called = false; | |
this.notCalled = true; | |
this.calledOnce = false; | |
this.calledTwice = false; | |
this.calledThrice = false; | |
this.callCount = 0; | |
this.firstCall = null; | |
this.secondCall = null; | |
this.thirdCall = null; | |
this.lastCall = null; | |
this.args = []; | |
this.returnValues = []; | |
this.thisValues = []; | |
this.exceptions = []; | |
this.callIds = []; | |
this.stacks = []; | |
if (this.fakes) { | |
for (var i = 0; i < this.fakes.length; i++) { | |
this.fakes[i].reset(); | |
} | |
} | |
return this; | |
}, | |
create: function create(func, spyLength) { | |
var name; | |
if (typeof func !== "function") { | |
func = function () { }; | |
} else { | |
name = sinon.functionName(func); | |
} | |
if (!spyLength) { | |
spyLength = func.length; | |
} | |
var proxy = createProxy(func, spyLength); | |
sinon.extend(proxy, spy); | |
delete proxy.create; | |
sinon.extend(proxy, func); | |
proxy.reset(); | |
proxy.prototype = func.prototype; | |
proxy.displayName = name || "spy"; | |
proxy.toString = sinon.functionToString; | |
proxy.instantiateFake = sinon.spy.create; | |
proxy.id = "spy#" + uuid++; | |
return proxy; | |
}, | |
invoke: function invoke(func, thisValue, args) { | |
var matching = matchingFake(this.fakes, args); | |
var exception, returnValue; | |
incrementCallCount.call(this); | |
push.call(this.thisValues, thisValue); | |
push.call(this.args, args); | |
push.call(this.callIds, callId++); | |
// Make call properties available from within the spied function: | |
createCallProperties.call(this); | |
try { | |
this.invoking = true; | |
if (matching) { | |
returnValue = matching.invoke(func, thisValue, args); | |
} else { | |
returnValue = (this.func || func).apply(thisValue, args); | |
} | |
var thisCall = this.getCall(this.callCount - 1); | |
if (thisCall.calledWithNew() && typeof returnValue !== "object") { | |
returnValue = thisValue; | |
} | |
} catch (e) { | |
exception = e; | |
} finally { | |
delete this.invoking; | |
} | |
push.call(this.exceptions, exception); | |
push.call(this.returnValues, returnValue); | |
push.call(this.stacks, new Error().stack); | |
// Make return value and exception available in the calls: | |
createCallProperties.call(this); | |
if (exception !== undefined) { | |
throw exception; | |
} | |
return returnValue; | |
}, | |
named: function named(name) { | |
this.displayName = name; | |
return this; | |
}, | |
getCall: function getCall(i) { | |
if (i < 0 || i >= this.callCount) { | |
return null; | |
} | |
return sinon.spyCall(this, this.thisValues[i], this.args[i], | |
this.returnValues[i], this.exceptions[i], | |
this.callIds[i], this.stacks[i]); | |
}, | |
getCalls: function () { | |
var calls = []; | |
var i; | |
for (i = 0; i < this.callCount; i++) { | |
calls.push(this.getCall(i)); | |
} | |
return calls; | |
}, | |
calledBefore: function calledBefore(spyFn) { | |
if (!this.called) { | |
return false; | |
} | |
if (!spyFn.called) { | |
return true; | |
} | |
return this.callIds[0] < spyFn.callIds[spyFn.callIds.length - 1]; | |
}, | |
calledAfter: function calledAfter(spyFn) { | |
if (!this.called || !spyFn.called) { | |
return false; | |
} | |
return this.callIds[this.callCount - 1] > spyFn.callIds[spyFn.callCount - 1]; | |
}, | |
withArgs: function () { | |
var args = slice.call(arguments); | |
if (this.fakes) { | |
var match = matchingFake(this.fakes, args, true); | |
if (match) { | |
return match; | |
} | |
} else { | |
this.fakes = []; | |
} | |
var original = this; | |
var fake = this.instantiateFake(); | |
fake.matchingAguments = args; | |
fake.parent = this; | |
push.call(this.fakes, fake); | |
fake.withArgs = function () { | |
return original.withArgs.apply(original, arguments); | |
}; | |
for (var i = 0; i < this.args.length; i++) { | |
if (fake.matches(this.args[i])) { | |
incrementCallCount.call(fake); | |
push.call(fake.thisValues, this.thisValues[i]); | |
push.call(fake.args, this.args[i]); | |
push.call(fake.returnValues, this.returnValues[i]); | |
push.call(fake.exceptions, this.exceptions[i]); | |
push.call(fake.callIds, this.callIds[i]); | |
} | |
} | |
createCallProperties.call(fake); | |
return fake; | |
}, | |
matches: function (args, strict) { | |
var margs = this.matchingAguments; | |
if (margs.length <= args.length && | |
sinon.deepEqual(margs, args.slice(0, margs.length))) { | |
return !strict || margs.length === args.length; | |
} | |
}, | |
printf: function (format) { | |
var spyInstance = this; | |
var args = slice.call(arguments, 1); | |
var formatter; | |
return (format || "").replace(/%(.)/g, function (match, specifyer) { | |
formatter = spyApi.formatters[specifyer]; | |
if (typeof formatter === "function") { | |
return formatter.call(null, spyInstance, args); | |
} else if (!isNaN(parseInt(specifyer, 10))) { | |
return sinon.format(args[specifyer - 1]); | |
} | |
return "%" + specifyer; | |
}); | |
} | |
}; | |
function delegateToCalls(method, matchAny, actual, notCalled) { | |
spyApi[method] = function () { | |
if (!this.called) { | |
if (notCalled) { | |
return notCalled.apply(this, arguments); | |
} | |
return false; | |
} | |
var currentCall; | |
var matches = 0; | |
for (var i = 0, l = this.callCount; i < l; i += 1) { | |
currentCall = this.getCall(i); | |
if (currentCall[actual || method].apply(currentCall, arguments)) { | |
matches += 1; | |
if (matchAny) { | |
return true; | |
} | |
} | |
} | |
return matches === this.callCount; | |
}; | |
} | |
delegateToCalls("calledOn", true); | |
delegateToCalls("alwaysCalledOn", false, "calledOn"); | |
delegateToCalls("calledWith", true); | |
delegateToCalls("calledWithMatch", true); | |
delegateToCalls("alwaysCalledWith", false, "calledWith"); | |
delegateToCalls("alwaysCalledWithMatch", false, "calledWithMatch"); | |
delegateToCalls("calledWithExactly", true); | |
delegateToCalls("alwaysCalledWithExactly", false, "calledWithExactly"); | |
delegateToCalls("neverCalledWith", false, "notCalledWith", function () { | |
return true; | |
}); | |
delegateToCalls("neverCalledWithMatch", false, "notCalledWithMatch", function () { | |
return true; | |
}); | |
delegateToCalls("threw", true); | |
delegateToCalls("alwaysThrew", false, "threw"); | |
delegateToCalls("returned", true); | |
delegateToCalls("alwaysReturned", false, "returned"); | |
delegateToCalls("calledWithNew", true); | |
delegateToCalls("alwaysCalledWithNew", false, "calledWithNew"); | |
delegateToCalls("callArg", false, "callArgWith", function () { | |
throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); | |
}); | |
spyApi.callArgWith = spyApi.callArg; | |
delegateToCalls("callArgOn", false, "callArgOnWith", function () { | |
throw new Error(this.toString() + " cannot call arg since it was not yet invoked."); | |
}); | |
spyApi.callArgOnWith = spyApi.callArgOn; | |
delegateToCalls("yield", false, "yield", function () { | |
throw new Error(this.toString() + " cannot yield since it was not yet invoked."); | |
}); | |
// "invokeCallback" is an alias for "yield" since "yield" is invalid in strict mode. | |
spyApi.invokeCallback = spyApi.yield; | |
delegateToCalls("yieldOn", false, "yieldOn", function () { | |
throw new Error(this.toString() + " cannot yield since it was not yet invoked."); | |
}); | |
delegateToCalls("yieldTo", false, "yieldTo", function (property) { | |
throw new Error(this.toString() + " cannot yield to '" + property + | |
"' since it was not yet invoked."); | |
}); | |
delegateToCalls("yieldToOn", false, "yieldToOn", function (property) { | |
throw new Error(this.toString() + " cannot yield to '" + property + | |
"' since it was not yet invoked."); | |
}); | |
spyApi.formatters = { | |
c: function (spyInstance) { | |
return sinon.timesInWords(spyInstance.callCount); | |
}, | |
n: function (spyInstance) { | |
return spyInstance.toString(); | |
}, | |
C: function (spyInstance) { | |
var calls = []; | |
for (var i = 0, l = spyInstance.callCount; i < l; ++i) { | |
var stringifiedCall = " " + spyInstance.getCall(i).toString(); | |
if (/\n/.test(calls[i - 1])) { | |
stringifiedCall = "\n" + stringifiedCall; | |
} | |
push.call(calls, stringifiedCall); | |
} | |
return calls.length > 0 ? "\n" + calls.join("\n") : ""; | |
}, | |
t: function (spyInstance) { | |
var objects = []; | |
for (var i = 0, l = spyInstance.callCount; i < l; ++i) { | |
push.call(objects, sinon.format(spyInstance.thisValues[i])); | |
} | |
return objects.join(", "); | |
}, | |
"*": function (spyInstance, args) { | |
var formatted = []; | |
for (var i = 0, l = args.length; i < l; ++i) { | |
push.call(formatted, sinon.format(args[i])); | |
} | |
return formatted.join(", "); | |
} | |
}; | |
sinon.extend(spy, spyApi); | |
spy.spyCall = sinon.spyCall; | |
sinon.spy = spy; | |
return spy; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
require("./call"); | |
require("./extend"); | |
require("./times_in_words"); | |
require("./format"); | |
module.exports = makeApi(core); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./call":7,"./extend":9,"./format":10,"./times_in_words":19,"./util/core":21}],16:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend extend.js | |
* @depend spy.js | |
* @depend behavior.js | |
* @depend walk.js | |
*/ | |
/** | |
* Stub functions | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
function stub(object, property, func) { | |
if (!!func && typeof func !== "function" && typeof func !== "object") { | |
throw new TypeError("Custom stub should be a function or a property descriptor"); | |
} | |
var wrapper; | |
if (func) { | |
if (typeof func === "function") { | |
wrapper = sinon.spy && sinon.spy.create ? sinon.spy.create(func) : func; | |
} else { | |
wrapper = func; | |
if (sinon.spy && sinon.spy.create) { | |
var types = sinon.objectKeys(wrapper); | |
for (var i = 0; i < types.length; i++) { | |
wrapper[types[i]] = sinon.spy.create(wrapper[types[i]]); | |
} | |
} | |
} | |
} else { | |
var stubLength = 0; | |
if (typeof object === "object" && typeof object[property] === "function") { | |
stubLength = object[property].length; | |
} | |
wrapper = stub.create(stubLength); | |
} | |
if (!object && typeof property === "undefined") { | |
return sinon.stub.create(); | |
} | |
if (typeof property === "undefined" && typeof object === "object") { | |
sinon.walk(object || {}, function (value, prop, propOwner) { | |
// we don't want to stub things like toString(), valueOf(), etc. so we only stub if the object | |
// is not Object.prototype | |
if ( | |
propOwner !== Object.prototype && | |
prop !== "constructor" && | |
typeof sinon.getPropertyDescriptor(propOwner, prop).value === "function" | |
) { | |
stub(object, prop); | |
} | |
}); | |
return object; | |
} | |
return sinon.wrapMethod(object, property, wrapper); | |
} | |
/*eslint-disable no-use-before-define*/ | |
function getParentBehaviour(stubInstance) { | |
return (stubInstance.parent && getCurrentBehavior(stubInstance.parent)); | |
} | |
function getDefaultBehavior(stubInstance) { | |
return stubInstance.defaultBehavior || | |
getParentBehaviour(stubInstance) || | |
sinon.behavior.create(stubInstance); | |
} | |
function getCurrentBehavior(stubInstance) { | |
var behavior = stubInstance.behaviors[stubInstance.callCount - 1]; | |
return behavior && behavior.isPresent() ? behavior : getDefaultBehavior(stubInstance); | |
} | |
/*eslint-enable no-use-before-define*/ | |
var uuid = 0; | |
var proto = { | |
create: function create(stubLength) { | |
var functionStub = function () { | |
return getCurrentBehavior(functionStub).invoke(this, arguments); | |
}; | |
functionStub.id = "stub#" + uuid++; | |
var orig = functionStub; | |
functionStub = sinon.spy.create(functionStub, stubLength); | |
functionStub.func = orig; | |
sinon.extend(functionStub, stub); | |
functionStub.instantiateFake = sinon.stub.create; | |
functionStub.displayName = "stub"; | |
functionStub.toString = sinon.functionToString; | |
functionStub.defaultBehavior = null; | |
functionStub.behaviors = []; | |
return functionStub; | |
}, | |
resetBehavior: function () { | |
var i; | |
this.defaultBehavior = null; | |
this.behaviors = []; | |
delete this.returnValue; | |
delete this.returnArgAt; | |
this.returnThis = false; | |
if (this.fakes) { | |
for (i = 0; i < this.fakes.length; i++) { | |
this.fakes[i].resetBehavior(); | |
} | |
} | |
}, | |
onCall: function onCall(index) { | |
if (!this.behaviors[index]) { | |
this.behaviors[index] = sinon.behavior.create(this); | |
} | |
return this.behaviors[index]; | |
}, | |
onFirstCall: function onFirstCall() { | |
return this.onCall(0); | |
}, | |
onSecondCall: function onSecondCall() { | |
return this.onCall(1); | |
}, | |
onThirdCall: function onThirdCall() { | |
return this.onCall(2); | |
} | |
}; | |
function createBehavior(behaviorMethod) { | |
return function () { | |
this.defaultBehavior = this.defaultBehavior || sinon.behavior.create(this); | |
this.defaultBehavior[behaviorMethod].apply(this.defaultBehavior, arguments); | |
return this; | |
}; | |
} | |
for (var method in sinon.behavior) { | |
if (sinon.behavior.hasOwnProperty(method) && | |
!proto.hasOwnProperty(method) && | |
method !== "create" && | |
method !== "withArgs" && | |
method !== "invoke") { | |
proto[method] = createBehavior(method); | |
} | |
} | |
sinon.extend(stub, proto); | |
sinon.stub = stub; | |
return stub; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
require("./behavior"); | |
require("./spy"); | |
require("./extend"); | |
module.exports = makeApi(core); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./behavior":6,"./extend":9,"./spy":15,"./util/core":21}],17:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend sandbox.js | |
*/ | |
/** | |
* Test function, sandboxes fakes | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
var slice = Array.prototype.slice; | |
function test(callback) { | |
var type = typeof callback; | |
if (type !== "function") { | |
throw new TypeError("sinon.test needs to wrap a test function, got " + type); | |
} | |
function sinonSandboxedTest() { | |
var config = sinon.getConfig(sinon.config); | |
config.injectInto = config.injectIntoThis && this || config.injectInto; | |
var sandbox = sinon.sandbox.create(config); | |
var args = slice.call(arguments); | |
var oldDone = args.length && args[args.length - 1]; | |
var exception, result; | |
if (typeof oldDone === "function") { | |
args[args.length - 1] = function sinonDone(res) { | |
if (res) { | |
sandbox.restore(); | |
} else { | |
sandbox.verifyAndRestore(); | |
} | |
oldDone(res); | |
}; | |
} | |
try { | |
result = callback.apply(this, args.concat(sandbox.args)); | |
} catch (e) { | |
exception = e; | |
} | |
if (typeof exception !== "undefined") { | |
sandbox.restore(); | |
throw exception; | |
} else if (typeof oldDone !== "function") { | |
sandbox.verifyAndRestore(); | |
} | |
return result; | |
} | |
if (callback.length) { | |
return function sinonAsyncSandboxedTest(done) { // eslint-disable-line no-unused-vars | |
return sinonSandboxedTest.apply(this, arguments); | |
}; | |
} | |
return sinonSandboxedTest; | |
} | |
test.config = { | |
injectIntoThis: true, | |
injectInto: null, | |
properties: ["spy", "stub", "mock", "clock", "server", "requests"], | |
useFakeTimers: true, | |
useFakeServer: true | |
}; | |
sinon.test = test; | |
return test; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
require("./sandbox"); | |
module.exports = makeApi(core); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require, module.exports, module); | |
} else if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}(typeof sinon === "object" && sinon || null)); // eslint-disable-line no-undef | |
},{"./sandbox":14,"./util/core":21}],18:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
* @depend test.js | |
*/ | |
/** | |
* Test case, sandboxes all test functions | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function createTest(property, setUp, tearDown) { | |
return function () { | |
if (setUp) { | |
setUp.apply(this, arguments); | |
} | |
var exception, result; | |
try { | |
result = property.apply(this, arguments); | |
} catch (e) { | |
exception = e; | |
} | |
if (tearDown) { | |
tearDown.apply(this, arguments); | |
} | |
if (exception) { | |
throw exception; | |
} | |
return result; | |
}; | |
} | |
function makeApi(sinon) { | |
function testCase(tests, prefix) { | |
if (!tests || typeof tests !== "object") { | |
throw new TypeError("sinon.testCase needs an object with test functions"); | |
} | |
prefix = prefix || "test"; | |
var rPrefix = new RegExp("^" + prefix); | |
var methods = {}; | |
var setUp = tests.setUp; | |
var tearDown = tests.tearDown; | |
var testName, | |
property, | |
method; | |
for (testName in tests) { | |
if (tests.hasOwnProperty(testName) && !/^(setUp|tearDown)$/.test(testName)) { | |
property = tests[testName]; | |
if (typeof property === "function" && rPrefix.test(testName)) { | |
method = property; | |
if (setUp || tearDown) { | |
method = createTest(property, setUp, tearDown); | |
} | |
methods[testName] = sinon.test(method); | |
} else { | |
methods[testName] = tests[testName]; | |
} | |
} | |
} | |
return methods; | |
} | |
sinon.testCase = testCase; | |
return testCase; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
require("./test"); | |
module.exports = makeApi(core); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./test":17,"./util/core":21}],19:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
function timesInWords(count) { | |
switch (count) { | |
case 1: | |
return "once"; | |
case 2: | |
return "twice"; | |
case 3: | |
return "thrice"; | |
default: | |
return (count || 0) + " times"; | |
} | |
} | |
sinon.timesInWords = timesInWords; | |
return sinon.timesInWords; | |
} | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
module.exports = makeApi(core); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21}],20:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
/** | |
* Format functions | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2014 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
function typeOf(value) { | |
if (value === null) { | |
return "null"; | |
} else if (value === undefined) { | |
return "undefined"; | |
} | |
var string = Object.prototype.toString.call(value); | |
return string.substring(8, string.length - 1).toLowerCase(); | |
} | |
sinon.typeOf = typeOf; | |
return sinon.typeOf; | |
} | |
function loadDependencies(require, exports, module) { | |
var core = require("./util/core"); | |
module.exports = makeApi(core); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21}],21:[function(require,module,exports){ | |
/** | |
* @depend ../../sinon.js | |
*/ | |
/** | |
* Sinon core utilities. For internal use only. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
var div = typeof document !== "undefined" && document.createElement("div"); | |
var hasOwn = Object.prototype.hasOwnProperty; | |
function isDOMNode(obj) { | |
var success = false; | |
try { | |
obj.appendChild(div); | |
success = div.parentNode === obj; | |
} catch (e) { | |
return false; | |
} finally { | |
try { | |
obj.removeChild(div); | |
} catch (e) { | |
// Remove failed, not much we can do about that | |
} | |
} | |
return success; | |
} | |
function isElement(obj) { | |
return div && obj && obj.nodeType === 1 && isDOMNode(obj); | |
} | |
function isFunction(obj) { | |
return typeof obj === "function" || !!(obj && obj.constructor && obj.call && obj.apply); | |
} | |
function isReallyNaN(val) { | |
return typeof val === "number" && isNaN(val); | |
} | |
function mirrorProperties(target, source) { | |
for (var prop in source) { | |
if (!hasOwn.call(target, prop)) { | |
target[prop] = source[prop]; | |
} | |
} | |
} | |
function isRestorable(obj) { | |
return typeof obj === "function" && typeof obj.restore === "function" && obj.restore.sinon; | |
} | |
// Cheap way to detect if we have ES5 support. | |
var hasES5Support = "keys" in Object; | |
function makeApi(sinon) { | |
sinon.wrapMethod = function wrapMethod(object, property, method) { | |
if (!object) { | |
throw new TypeError("Should wrap property of object"); | |
} | |
if (typeof method !== "function" && typeof method !== "object") { | |
throw new TypeError("Method wrapper should be a function or a property descriptor"); | |
} | |
function checkWrappedMethod(wrappedMethod) { | |
var error; | |
if (!isFunction(wrappedMethod)) { | |
error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + | |
property + " as function"); | |
} else if (wrappedMethod.restore && wrappedMethod.restore.sinon) { | |
error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); | |
} else if (wrappedMethod.calledBefore) { | |
var verb = wrappedMethod.returns ? "stubbed" : "spied on"; | |
error = new TypeError("Attempted to wrap " + property + " which is already " + verb); | |
} | |
if (error) { | |
if (wrappedMethod && wrappedMethod.stackTrace) { | |
error.stack += "\n--------------\n" + wrappedMethod.stackTrace; | |
} | |
throw error; | |
} | |
} | |
var error, wrappedMethod, i; | |
function simplePropertyAssignment() { | |
wrappedMethod = object[property]; | |
checkWrappedMethod(wrappedMethod); | |
object[property] = method; | |
method.displayName = property; | |
} | |
// IE 8 does not support hasOwnProperty on the window object and Firefox has a problem | |
// when using hasOwn.call on objects from other frames. | |
var owned = (object.hasOwnProperty && object.hasOwnProperty === hasOwn) ? | |
object.hasOwnProperty(property) : hasOwn.call(object, property); | |
if (hasES5Support) { | |
var methodDesc = (typeof method === "function") ? {value: method} : method; | |
var wrappedMethodDesc = sinon.getPropertyDescriptor(object, property); | |
if (!wrappedMethodDesc) { | |
error = new TypeError("Attempted to wrap " + (typeof wrappedMethod) + " property " + | |
property + " as function"); | |
} else if (wrappedMethodDesc.restore && wrappedMethodDesc.restore.sinon) { | |
error = new TypeError("Attempted to wrap " + property + " which is already wrapped"); | |
} | |
if (error) { | |
if (wrappedMethodDesc && wrappedMethodDesc.stackTrace) { | |
error.stack += "\n--------------\n" + wrappedMethodDesc.stackTrace; | |
} | |
throw error; | |
} | |
var types = sinon.objectKeys(methodDesc); | |
for (i = 0; i < types.length; i++) { | |
wrappedMethod = wrappedMethodDesc[types[i]]; | |
checkWrappedMethod(wrappedMethod); | |
} | |
mirrorProperties(methodDesc, wrappedMethodDesc); | |
for (i = 0; i < types.length; i++) { | |
mirrorProperties(methodDesc[types[i]], wrappedMethodDesc[types[i]]); | |
} | |
Object.defineProperty(object, property, methodDesc); | |
// catch failing assignment | |
// this is the converse of the check in `.restore` below | |
if ( typeof method === "function" && object[property] !== method ) { | |
// correct any wrongdoings caused by the defineProperty call above, | |
// such as adding new items (if object was a Storage object) | |
delete object[property]; | |
simplePropertyAssignment(); | |
} | |
} else { | |
simplePropertyAssignment(); | |
} | |
method.displayName = property; | |
// Set up a stack trace which can be used later to find what line of | |
// code the original method was created on. | |
method.stackTrace = (new Error("Stack Trace for original")).stack; | |
method.restore = function () { | |
// For prototype properties try to reset by delete first. | |
// If this fails (ex: localStorage on mobile safari) then force a reset | |
// via direct assignment. | |
if (!owned) { | |
// In some cases `delete` may throw an error | |
try { | |
delete object[property]; | |
} catch (e) {} // eslint-disable-line no-empty | |
// For native code functions `delete` fails without throwing an error | |
// on Chrome < 43, PhantomJS, etc. | |
} else if (hasES5Support) { | |
Object.defineProperty(object, property, wrappedMethodDesc); | |
} | |
// this only supports ES5 getter/setter, for ES3.1 and lower | |
// __lookupSetter__ / __lookupGetter__ should be integrated | |
if (hasES5Support) { | |
var checkDesc = sinon.getPropertyDescriptor(object, property); | |
if (checkDesc.value === method) { | |
object[property] = wrappedMethod; | |
} | |
// Use strict equality comparison to check failures then force a reset | |
// via direct assignment. | |
} else if (object[property] === method) { | |
object[property] = wrappedMethod; | |
} | |
}; | |
method.restore.sinon = true; | |
if (!hasES5Support) { | |
mirrorProperties(method, wrappedMethod); | |
} | |
return method; | |
}; | |
sinon.create = function create(proto) { | |
var F = function () {}; | |
F.prototype = proto; | |
return new F(); | |
}; | |
sinon.deepEqual = function deepEqual(a, b) { | |
if (sinon.match && sinon.match.isMatcher(a)) { | |
return a.test(b); | |
} | |
if (typeof a !== "object" || typeof b !== "object") { | |
return isReallyNaN(a) && isReallyNaN(b) || a === b; | |
} | |
if (isElement(a) || isElement(b)) { | |
return a === b; | |
} | |
if (a === b) { | |
return true; | |
} | |
if ((a === null && b !== null) || (a !== null && b === null)) { | |
return false; | |
} | |
if (a instanceof RegExp && b instanceof RegExp) { | |
return (a.source === b.source) && (a.global === b.global) && | |
(a.ignoreCase === b.ignoreCase) && (a.multiline === b.multiline); | |
} | |
var aString = Object.prototype.toString.call(a); | |
if (aString !== Object.prototype.toString.call(b)) { | |
return false; | |
} | |
if (aString === "[object Date]") { | |
return a.valueOf() === b.valueOf(); | |
} | |
var prop; | |
var aLength = 0; | |
var bLength = 0; | |
if (aString === "[object Array]" && a.length !== b.length) { | |
return false; | |
} | |
for (prop in a) { | |
if (hasOwn.call(a, prop)) { | |
aLength += 1; | |
if (!(prop in b)) { | |
return false; | |
} | |
if (!deepEqual(a[prop], b[prop])) { | |
return false; | |
} | |
} | |
} | |
for (prop in b) { | |
if (hasOwn.call(b, prop)) { | |
bLength += 1; | |
} | |
} | |
return aLength === bLength; | |
}; | |
sinon.functionName = function functionName(func) { | |
var name = func.displayName || func.name; | |
// Use function decomposition as a last resort to get function | |
// name. Does not rely on function decomposition to work - if it | |
// doesn't debugging will be slightly less informative | |
// (i.e. toString will say 'spy' rather than 'myFunc'). | |
if (!name) { | |
var matches = func.toString().match(/function ([^\s\(]+)/); | |
name = matches && matches[1]; | |
} | |
return name; | |
}; | |
sinon.functionToString = function toString() { | |
if (this.getCall && this.callCount) { | |
var thisValue, | |
prop; | |
var i = this.callCount; | |
while (i--) { | |
thisValue = this.getCall(i).thisValue; | |
for (prop in thisValue) { | |
if (thisValue[prop] === this) { | |
return prop; | |
} | |
} | |
} | |
} | |
return this.displayName || "sinon fake"; | |
}; | |
sinon.objectKeys = function objectKeys(obj) { | |
if (obj !== Object(obj)) { | |
throw new TypeError("sinon.objectKeys called on a non-object"); | |
} | |
var keys = []; | |
var key; | |
for (key in obj) { | |
if (hasOwn.call(obj, key)) { | |
keys.push(key); | |
} | |
} | |
return keys; | |
}; | |
sinon.getPropertyDescriptor = function getPropertyDescriptor(object, property) { | |
var proto = object; | |
var descriptor; | |
while (proto && !(descriptor = Object.getOwnPropertyDescriptor(proto, property))) { | |
proto = Object.getPrototypeOf(proto); | |
} | |
return descriptor; | |
}; | |
sinon.getConfig = function (custom) { | |
var config = {}; | |
custom = custom || {}; | |
var defaults = sinon.defaultConfig; | |
for (var prop in defaults) { | |
if (defaults.hasOwnProperty(prop)) { | |
config[prop] = custom.hasOwnProperty(prop) ? custom[prop] : defaults[prop]; | |
} | |
} | |
return config; | |
}; | |
sinon.defaultConfig = { | |
injectIntoThis: true, | |
injectInto: null, | |
properties: ["spy", "stub", "mock", "clock", "server", "requests"], | |
useFakeTimers: true, | |
useFakeServer: true | |
}; | |
sinon.timesInWords = function timesInWords(count) { | |
return count === 1 && "once" || | |
count === 2 && "twice" || | |
count === 3 && "thrice" || | |
(count || 0) + " times"; | |
}; | |
sinon.calledInOrder = function (spies) { | |
for (var i = 1, l = spies.length; i < l; i++) { | |
if (!spies[i - 1].calledBefore(spies[i]) || !spies[i].called) { | |
return false; | |
} | |
} | |
return true; | |
}; | |
sinon.orderByFirstCall = function (spies) { | |
return spies.sort(function (a, b) { | |
// uuid, won't ever be equal | |
var aCall = a.getCall(0); | |
var bCall = b.getCall(0); | |
var aId = aCall && aCall.callId || -1; | |
var bId = bCall && bCall.callId || -1; | |
return aId < bId ? -1 : 1; | |
}); | |
}; | |
sinon.createStubInstance = function (constructor) { | |
if (typeof constructor !== "function") { | |
throw new TypeError("The constructor should be a function."); | |
} | |
return sinon.stub(sinon.create(constructor.prototype)); | |
}; | |
sinon.restore = function (object) { | |
if (object !== null && typeof object === "object") { | |
for (var prop in object) { | |
if (isRestorable(object[prop])) { | |
object[prop].restore(); | |
} | |
} | |
} else if (isRestorable(object)) { | |
object.restore(); | |
} | |
}; | |
return sinon; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports) { | |
makeApi(exports); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{}],22:[function(require,module,exports){ | |
/** | |
* Minimal Event interface implementation | |
* | |
* Original implementation by Sven Fuchs: https://gist.github.com/995028 | |
* Modifications and tests by Christian Johansen. | |
* | |
* @author Sven Fuchs ([email protected]) | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2011 Sven Fuchs, Christian Johansen | |
*/ | |
if (typeof sinon === "undefined") { | |
this.sinon = {}; | |
} | |
(function () { | |
"use strict"; | |
var push = [].push; | |
function makeApi(sinon) { | |
sinon.Event = function Event(type, bubbles, cancelable, target) { | |
this.initEvent(type, bubbles, cancelable, target); | |
}; | |
sinon.Event.prototype = { | |
initEvent: function (type, bubbles, cancelable, target) { | |
this.type = type; | |
this.bubbles = bubbles; | |
this.cancelable = cancelable; | |
this.target = target; | |
}, | |
stopPropagation: function () {}, | |
preventDefault: function () { | |
this.defaultPrevented = true; | |
} | |
}; | |
sinon.ProgressEvent = function ProgressEvent(type, progressEventRaw, target) { | |
this.initEvent(type, false, false, target); | |
this.loaded = typeof progressEventRaw.loaded === "number" ? progressEventRaw.loaded : null; | |
this.total = typeof progressEventRaw.total === "number" ? progressEventRaw.total : null; | |
this.lengthComputable = !!progressEventRaw.total; | |
}; | |
sinon.ProgressEvent.prototype = new sinon.Event(); | |
sinon.ProgressEvent.prototype.constructor = sinon.ProgressEvent; | |
sinon.CustomEvent = function CustomEvent(type, customData, target) { | |
this.initEvent(type, false, false, target); | |
this.detail = customData.detail || null; | |
}; | |
sinon.CustomEvent.prototype = new sinon.Event(); | |
sinon.CustomEvent.prototype.constructor = sinon.CustomEvent; | |
sinon.EventTarget = { | |
addEventListener: function addEventListener(event, listener) { | |
this.eventListeners = this.eventListeners || {}; | |
this.eventListeners[event] = this.eventListeners[event] || []; | |
push.call(this.eventListeners[event], listener); | |
}, | |
removeEventListener: function removeEventListener(event, listener) { | |
var listeners = this.eventListeners && this.eventListeners[event] || []; | |
for (var i = 0, l = listeners.length; i < l; ++i) { | |
if (listeners[i] === listener) { | |
return listeners.splice(i, 1); | |
} | |
} | |
}, | |
dispatchEvent: function dispatchEvent(event) { | |
var type = event.type; | |
var listeners = this.eventListeners && this.eventListeners[type] || []; | |
for (var i = 0; i < listeners.length; i++) { | |
if (typeof listeners[i] === "function") { | |
listeners[i].call(this, event); | |
} else { | |
listeners[i].handleEvent(event); | |
} | |
} | |
return !!event.defaultPrevented; | |
} | |
}; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require) { | |
var sinon = require("./core"); | |
makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require); | |
} else { | |
makeApi(sinon); // eslint-disable-line no-undef | |
} | |
}()); | |
},{"./core":21}],23:[function(require,module,exports){ | |
/** | |
* @depend fake_xdomain_request.js | |
* @depend fake_xml_http_request.js | |
* @depend ../format.js | |
* @depend ../log_error.js | |
*/ | |
/** | |
* The Sinon "server" mimics a web server that receives requests from | |
* sinon.FakeXMLHttpRequest and provides an API to respond to those requests, | |
* both synchronously and asynchronously. To respond synchronuously, canned | |
* answers have to be provided upfront. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function () { | |
"use strict"; | |
var push = [].push; | |
function responseArray(handler) { | |
var response = handler; | |
if (Object.prototype.toString.call(handler) !== "[object Array]") { | |
response = [200, {}, handler]; | |
} | |
if (typeof response[2] !== "string") { | |
throw new TypeError("Fake server response body should be string, but was " + | |
typeof response[2]); | |
} | |
return response; | |
} | |
var wloc = typeof window !== "undefined" ? window.location : {}; | |
var rCurrLoc = new RegExp("^" + wloc.protocol + "//" + wloc.host); | |
function matchOne(response, reqMethod, reqUrl) { | |
var rmeth = response.method; | |
var matchMethod = !rmeth || rmeth.toLowerCase() === reqMethod.toLowerCase(); | |
var url = response.url; | |
var matchUrl = !url || url === reqUrl || (typeof url.test === "function" && url.test(reqUrl)); | |
return matchMethod && matchUrl; | |
} | |
function match(response, request) { | |
var requestUrl = request.url; | |
if (!/^https?:\/\//.test(requestUrl) || rCurrLoc.test(requestUrl)) { | |
requestUrl = requestUrl.replace(rCurrLoc, ""); | |
} | |
if (matchOne(response, this.getHTTPMethod(request), requestUrl)) { | |
if (typeof response.response === "function") { | |
var ru = response.url; | |
var args = [request].concat(ru && typeof ru.exec === "function" ? ru.exec(requestUrl).slice(1) : []); | |
return response.response.apply(response, args); | |
} | |
return true; | |
} | |
return false; | |
} | |
function makeApi(sinon) { | |
sinon.fakeServer = { | |
create: function (config) { | |
var server = sinon.create(this); | |
server.configure(config); | |
if (!sinon.xhr.supportsCORS) { | |
this.xhr = sinon.useFakeXDomainRequest(); | |
} else { | |
this.xhr = sinon.useFakeXMLHttpRequest(); | |
} | |
server.requests = []; | |
this.xhr.onCreate = function (xhrObj) { | |
server.addRequest(xhrObj); | |
}; | |
return server; | |
}, | |
configure: function (config) { | |
var whitelist = { | |
"autoRespond": true, | |
"autoRespondAfter": true, | |
"respondImmediately": true, | |
"fakeHTTPMethods": true | |
}; | |
var setting; | |
config = config || {}; | |
for (setting in config) { | |
if (whitelist.hasOwnProperty(setting) && config.hasOwnProperty(setting)) { | |
this[setting] = config[setting]; | |
} | |
} | |
}, | |
addRequest: function addRequest(xhrObj) { | |
var server = this; | |
push.call(this.requests, xhrObj); | |
xhrObj.onSend = function () { | |
server.handleRequest(this); | |
if (server.respondImmediately) { | |
server.respond(); | |
} else if (server.autoRespond && !server.responding) { | |
setTimeout(function () { | |
server.responding = false; | |
server.respond(); | |
}, server.autoRespondAfter || 10); | |
server.responding = true; | |
} | |
}; | |
}, | |
getHTTPMethod: function getHTTPMethod(request) { | |
if (this.fakeHTTPMethods && /post/i.test(request.method)) { | |
var matches = (request.requestBody || "").match(/_method=([^\b;]+)/); | |
return matches ? matches[1] : request.method; | |
} | |
return request.method; | |
}, | |
handleRequest: function handleRequest(xhr) { | |
if (xhr.async) { | |
if (!this.queue) { | |
this.queue = []; | |
} | |
push.call(this.queue, xhr); | |
} else { | |
this.processRequest(xhr); | |
} | |
}, | |
log: function log(response, request) { | |
var str; | |
str = "Request:\n" + sinon.format(request) + "\n\n"; | |
str += "Response:\n" + sinon.format(response) + "\n\n"; | |
sinon.log(str); | |
}, | |
respondWith: function respondWith(method, url, body) { | |
if (arguments.length === 1 && typeof method !== "function") { | |
this.response = responseArray(method); | |
return; | |
} | |
if (!this.responses) { | |
this.responses = []; | |
} | |
if (arguments.length === 1) { | |
body = method; | |
url = method = null; | |
} | |
if (arguments.length === 2) { | |
body = url; | |
url = method; | |
method = null; | |
} | |
push.call(this.responses, { | |
method: method, | |
url: url, | |
response: typeof body === "function" ? body : responseArray(body) | |
}); | |
}, | |
respond: function respond() { | |
if (arguments.length > 0) { | |
this.respondWith.apply(this, arguments); | |
} | |
var queue = this.queue || []; | |
var requests = queue.splice(0, queue.length); | |
for (var i = 0; i < requests.length; i++) { | |
this.processRequest(requests[i]); | |
} | |
}, | |
processRequest: function processRequest(request) { | |
try { | |
if (request.aborted) { | |
return; | |
} | |
var response = this.response || [404, {}, ""]; | |
if (this.responses) { | |
for (var l = this.responses.length, i = l - 1; i >= 0; i--) { | |
if (match.call(this, this.responses[i], request)) { | |
response = this.responses[i].response; | |
break; | |
} | |
} | |
} | |
if (request.readyState !== 4) { | |
this.log(response, request); | |
request.respond(response[0], response[1], response[2]); | |
} | |
} catch (e) { | |
sinon.logError("Fake server request processing", e); | |
} | |
}, | |
restore: function restore() { | |
return this.xhr.restore && this.xhr.restore.apply(this.xhr, arguments); | |
} | |
}; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./core"); | |
require("./fake_xdomain_request"); | |
require("./fake_xml_http_request"); | |
require("../format"); | |
makeApi(sinon); | |
module.exports = sinon; | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require, module.exports, module); | |
} else { | |
makeApi(sinon); // eslint-disable-line no-undef | |
} | |
}()); | |
},{"../format":10,"./core":21,"./fake_xdomain_request":26,"./fake_xml_http_request":27}],24:[function(require,module,exports){ | |
/** | |
* @depend fake_server.js | |
* @depend fake_timers.js | |
*/ | |
/** | |
* Add-on for sinon.fakeServer that automatically handles a fake timer along with | |
* the FakeXMLHttpRequest. The direct inspiration for this add-on is jQuery | |
* 1.3.x, which does not use xhr object's onreadystatehandler at all - instead, | |
* it polls the object for completion with setInterval. Dispite the direct | |
* motivation, there is nothing jQuery-specific in this file, so it can be used | |
* in any environment where the ajax implementation depends on setInterval or | |
* setTimeout. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function () { | |
"use strict"; | |
function makeApi(sinon) { | |
function Server() {} | |
Server.prototype = sinon.fakeServer; | |
sinon.fakeServerWithClock = new Server(); | |
sinon.fakeServerWithClock.addRequest = function addRequest(xhr) { | |
if (xhr.async) { | |
if (typeof setTimeout.clock === "object") { | |
this.clock = setTimeout.clock; | |
} else { | |
this.clock = sinon.useFakeTimers(); | |
this.resetClock = true; | |
} | |
if (!this.longestTimeout) { | |
var clockSetTimeout = this.clock.setTimeout; | |
var clockSetInterval = this.clock.setInterval; | |
var server = this; | |
this.clock.setTimeout = function (fn, timeout) { | |
server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); | |
return clockSetTimeout.apply(this, arguments); | |
}; | |
this.clock.setInterval = function (fn, timeout) { | |
server.longestTimeout = Math.max(timeout, server.longestTimeout || 0); | |
return clockSetInterval.apply(this, arguments); | |
}; | |
} | |
} | |
return sinon.fakeServer.addRequest.call(this, xhr); | |
}; | |
sinon.fakeServerWithClock.respond = function respond() { | |
var returnVal = sinon.fakeServer.respond.apply(this, arguments); | |
if (this.clock) { | |
this.clock.tick(this.longestTimeout || 0); | |
this.longestTimeout = 0; | |
if (this.resetClock) { | |
this.clock.restore(); | |
this.resetClock = false; | |
} | |
} | |
return returnVal; | |
}; | |
sinon.fakeServerWithClock.restore = function restore() { | |
if (this.clock) { | |
this.clock.restore(); | |
} | |
return sinon.fakeServer.restore.apply(this, arguments); | |
}; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require) { | |
var sinon = require("./core"); | |
require("./fake_server"); | |
require("./fake_timers"); | |
makeApi(sinon); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require); | |
} else { | |
makeApi(sinon); // eslint-disable-line no-undef | |
} | |
}()); | |
},{"./core":21,"./fake_server":23,"./fake_timers":25}],25:[function(require,module,exports){ | |
/** | |
* Fake timer API | |
* setTimeout | |
* setInterval | |
* clearTimeout | |
* clearInterval | |
* tick | |
* reset | |
* Date | |
* | |
* Inspired by jsUnitMockTimeOut from JsUnit | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function () { | |
"use strict"; | |
function makeApi(s, lol) { | |
/*global lolex */ | |
var llx = typeof lolex !== "undefined" ? lolex : lol; | |
s.useFakeTimers = function () { | |
var now; | |
var methods = Array.prototype.slice.call(arguments); | |
if (typeof methods[0] === "string") { | |
now = 0; | |
} else { | |
now = methods.shift(); | |
} | |
var clock = llx.install(now || 0, methods); | |
clock.restore = clock.uninstall; | |
return clock; | |
}; | |
s.clock = { | |
create: function (now) { | |
return llx.createClock(now); | |
} | |
}; | |
s.timers = { | |
setTimeout: setTimeout, | |
clearTimeout: clearTimeout, | |
setImmediate: (typeof setImmediate !== "undefined" ? setImmediate : undefined), | |
clearImmediate: (typeof clearImmediate !== "undefined" ? clearImmediate : undefined), | |
setInterval: setInterval, | |
clearInterval: clearInterval, | |
Date: Date | |
}; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, epxorts, module, lolex) { | |
var core = require("./core"); | |
makeApi(core, lolex); | |
module.exports = core; | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require, module.exports, module, require("lolex")); | |
} else { | |
makeApi(sinon); // eslint-disable-line no-undef | |
} | |
}()); | |
},{"./core":21,"lolex":30}],26:[function(require,module,exports){ | |
(function (global){ | |
/** | |
* @depend core.js | |
* @depend ../extend.js | |
* @depend event.js | |
* @depend ../log_error.js | |
*/ | |
/** | |
* Fake XDomainRequest object | |
*/ | |
/** | |
* Returns the global to prevent assigning values to 'this' when this is undefined. | |
* This can occur when files are interpreted by node in strict mode. | |
* @private | |
*/ | |
function getGlobal() { | |
"use strict"; | |
return typeof window !== "undefined" ? window : global; | |
} | |
if (typeof sinon === "undefined") { | |
if (typeof this === "undefined") { | |
getGlobal().sinon = {}; | |
} else { | |
this.sinon = {}; | |
} | |
} | |
// wrapper for global | |
(function (global) { | |
"use strict"; | |
var xdr = { XDomainRequest: global.XDomainRequest }; | |
xdr.GlobalXDomainRequest = global.XDomainRequest; | |
xdr.supportsXDR = typeof xdr.GlobalXDomainRequest !== "undefined"; | |
xdr.workingXDR = xdr.supportsXDR ? xdr.GlobalXDomainRequest : false; | |
function makeApi(sinon) { | |
sinon.xdr = xdr; | |
function FakeXDomainRequest() { | |
this.readyState = FakeXDomainRequest.UNSENT; | |
this.requestBody = null; | |
this.requestHeaders = {}; | |
this.status = 0; | |
this.timeout = null; | |
if (typeof FakeXDomainRequest.onCreate === "function") { | |
FakeXDomainRequest.onCreate(this); | |
} | |
} | |
function verifyState(x) { | |
if (x.readyState !== FakeXDomainRequest.OPENED) { | |
throw new Error("INVALID_STATE_ERR"); | |
} | |
if (x.sendFlag) { | |
throw new Error("INVALID_STATE_ERR"); | |
} | |
} | |
function verifyRequestSent(x) { | |
if (x.readyState === FakeXDomainRequest.UNSENT) { | |
throw new Error("Request not sent"); | |
} | |
if (x.readyState === FakeXDomainRequest.DONE) { | |
throw new Error("Request done"); | |
} | |
} | |
function verifyResponseBodyType(body) { | |
if (typeof body !== "string") { | |
var error = new Error("Attempted to respond to fake XDomainRequest with " + | |
body + ", which is not a string."); | |
error.name = "InvalidBodyException"; | |
throw error; | |
} | |
} | |
sinon.extend(FakeXDomainRequest.prototype, sinon.EventTarget, { | |
open: function open(method, url) { | |
this.method = method; | |
this.url = url; | |
this.responseText = null; | |
this.sendFlag = false; | |
this.readyStateChange(FakeXDomainRequest.OPENED); | |
}, | |
readyStateChange: function readyStateChange(state) { | |
this.readyState = state; | |
var eventName = ""; | |
switch (this.readyState) { | |
case FakeXDomainRequest.UNSENT: | |
break; | |
case FakeXDomainRequest.OPENED: | |
break; | |
case FakeXDomainRequest.LOADING: | |
if (this.sendFlag) { | |
//raise the progress event | |
eventName = "onprogress"; | |
} | |
break; | |
case FakeXDomainRequest.DONE: | |
if (this.isTimeout) { | |
eventName = "ontimeout"; | |
} else if (this.errorFlag || (this.status < 200 || this.status > 299)) { | |
eventName = "onerror"; | |
} else { | |
eventName = "onload"; | |
} | |
break; | |
} | |
// raising event (if defined) | |
if (eventName) { | |
if (typeof this[eventName] === "function") { | |
try { | |
this[eventName](); | |
} catch (e) { | |
sinon.logError("Fake XHR " + eventName + " handler", e); | |
} | |
} | |
} | |
}, | |
send: function send(data) { | |
verifyState(this); | |
if (!/^(get|head)$/i.test(this.method)) { | |
this.requestBody = data; | |
} | |
this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; | |
this.errorFlag = false; | |
this.sendFlag = true; | |
this.readyStateChange(FakeXDomainRequest.OPENED); | |
if (typeof this.onSend === "function") { | |
this.onSend(this); | |
} | |
}, | |
abort: function abort() { | |
this.aborted = true; | |
this.responseText = null; | |
this.errorFlag = true; | |
if (this.readyState > sinon.FakeXDomainRequest.UNSENT && this.sendFlag) { | |
this.readyStateChange(sinon.FakeXDomainRequest.DONE); | |
this.sendFlag = false; | |
} | |
}, | |
setResponseBody: function setResponseBody(body) { | |
verifyRequestSent(this); | |
verifyResponseBodyType(body); | |
var chunkSize = this.chunkSize || 10; | |
var index = 0; | |
this.responseText = ""; | |
do { | |
this.readyStateChange(FakeXDomainRequest.LOADING); | |
this.responseText += body.substring(index, index + chunkSize); | |
index += chunkSize; | |
} while (index < body.length); | |
this.readyStateChange(FakeXDomainRequest.DONE); | |
}, | |
respond: function respond(status, contentType, body) { | |
// content-type ignored, since XDomainRequest does not carry this | |
// we keep the same syntax for respond(...) as for FakeXMLHttpRequest to ease | |
// test integration across browsers | |
this.status = typeof status === "number" ? status : 200; | |
this.setResponseBody(body || ""); | |
}, | |
simulatetimeout: function simulatetimeout() { | |
this.status = 0; | |
this.isTimeout = true; | |
// Access to this should actually throw an error | |
this.responseText = undefined; | |
this.readyStateChange(FakeXDomainRequest.DONE); | |
} | |
}); | |
sinon.extend(FakeXDomainRequest, { | |
UNSENT: 0, | |
OPENED: 1, | |
LOADING: 3, | |
DONE: 4 | |
}); | |
sinon.useFakeXDomainRequest = function useFakeXDomainRequest() { | |
sinon.FakeXDomainRequest.restore = function restore(keepOnCreate) { | |
if (xdr.supportsXDR) { | |
global.XDomainRequest = xdr.GlobalXDomainRequest; | |
} | |
delete sinon.FakeXDomainRequest.restore; | |
if (keepOnCreate !== true) { | |
delete sinon.FakeXDomainRequest.onCreate; | |
} | |
}; | |
if (xdr.supportsXDR) { | |
global.XDomainRequest = sinon.FakeXDomainRequest; | |
} | |
return sinon.FakeXDomainRequest; | |
}; | |
sinon.FakeXDomainRequest = FakeXDomainRequest; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./core"); | |
require("../extend"); | |
require("./event"); | |
require("../log_error"); | |
makeApi(sinon); | |
module.exports = sinon; | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require, module.exports, module); | |
} else { | |
makeApi(sinon); // eslint-disable-line no-undef | |
} | |
})(typeof global !== "undefined" ? global : self); | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"../extend":9,"../log_error":11,"./core":21,"./event":22}],27:[function(require,module,exports){ | |
(function (global){ | |
/** | |
* @depend core.js | |
* @depend ../extend.js | |
* @depend event.js | |
* @depend ../log_error.js | |
*/ | |
/** | |
* Fake XMLHttpRequest object | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
(function (sinonGlobal, global) { | |
"use strict"; | |
function getWorkingXHR(globalScope) { | |
var supportsXHR = typeof globalScope.XMLHttpRequest !== "undefined"; | |
if (supportsXHR) { | |
return globalScope.XMLHttpRequest; | |
} | |
var supportsActiveX = typeof globalScope.ActiveXObject !== "undefined"; | |
if (supportsActiveX) { | |
return function () { | |
return new globalScope.ActiveXObject("MSXML2.XMLHTTP.3.0"); | |
}; | |
} | |
return false; | |
} | |
var supportsProgress = typeof ProgressEvent !== "undefined"; | |
var supportsCustomEvent = typeof CustomEvent !== "undefined"; | |
var supportsFormData = typeof FormData !== "undefined"; | |
var supportsArrayBuffer = typeof ArrayBuffer !== "undefined"; | |
var supportsBlob = (function () { | |
try { | |
return !!new Blob(); | |
} catch (e) { | |
return false; | |
} | |
})(); | |
var sinonXhr = { XMLHttpRequest: global.XMLHttpRequest }; | |
sinonXhr.GlobalXMLHttpRequest = global.XMLHttpRequest; | |
sinonXhr.GlobalActiveXObject = global.ActiveXObject; | |
sinonXhr.supportsActiveX = typeof sinonXhr.GlobalActiveXObject !== "undefined"; | |
sinonXhr.supportsXHR = typeof sinonXhr.GlobalXMLHttpRequest !== "undefined"; | |
sinonXhr.workingXHR = getWorkingXHR(global); | |
sinonXhr.supportsCORS = sinonXhr.supportsXHR && "withCredentials" in (new sinonXhr.GlobalXMLHttpRequest()); | |
var unsafeHeaders = { | |
"Accept-Charset": true, | |
"Accept-Encoding": true, | |
Connection: true, | |
"Content-Length": true, | |
Cookie: true, | |
Cookie2: true, | |
"Content-Transfer-Encoding": true, | |
Date: true, | |
Expect: true, | |
Host: true, | |
"Keep-Alive": true, | |
Referer: true, | |
TE: true, | |
Trailer: true, | |
"Transfer-Encoding": true, | |
Upgrade: true, | |
"User-Agent": true, | |
Via: true | |
}; | |
// An upload object is created for each | |
// FakeXMLHttpRequest and allows upload | |
// events to be simulated using uploadProgress | |
// and uploadError. | |
function UploadProgress() { | |
this.eventListeners = { | |
abort: [], | |
error: [], | |
load: [], | |
loadend: [], | |
progress: [] | |
}; | |
} | |
UploadProgress.prototype.addEventListener = function addEventListener(event, listener) { | |
this.eventListeners[event].push(listener); | |
}; | |
UploadProgress.prototype.removeEventListener = function removeEventListener(event, listener) { | |
var listeners = this.eventListeners[event] || []; | |
for (var i = 0, l = listeners.length; i < l; ++i) { | |
if (listeners[i] === listener) { | |
return listeners.splice(i, 1); | |
} | |
} | |
}; | |
UploadProgress.prototype.dispatchEvent = function dispatchEvent(event) { | |
var listeners = this.eventListeners[event.type] || []; | |
for (var i = 0, listener; (listener = listeners[i]) != null; i++) { | |
listener(event); | |
} | |
}; | |
// Note that for FakeXMLHttpRequest to work pre ES5 | |
// we lose some of the alignment with the spec. | |
// To ensure as close a match as possible, | |
// set responseType before calling open, send or respond; | |
function FakeXMLHttpRequest() { | |
this.readyState = FakeXMLHttpRequest.UNSENT; | |
this.requestHeaders = {}; | |
this.requestBody = null; | |
this.status = 0; | |
this.statusText = ""; | |
this.upload = new UploadProgress(); | |
this.responseType = ""; | |
this.response = ""; | |
if (sinonXhr.supportsCORS) { | |
this.withCredentials = false; | |
} | |
var xhr = this; | |
var events = ["loadstart", "load", "abort", "error", "loadend"]; | |
function addEventListener(eventName) { | |
xhr.addEventListener(eventName, function (event) { | |
var listener = xhr["on" + eventName]; | |
if (listener && typeof listener === "function") { | |
listener.call(this, event); | |
} | |
}); | |
} | |
for (var i = events.length - 1; i >= 0; i--) { | |
addEventListener(events[i]); | |
} | |
if (typeof FakeXMLHttpRequest.onCreate === "function") { | |
FakeXMLHttpRequest.onCreate(this); | |
} | |
} | |
function verifyState(xhr) { | |
if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { | |
throw new Error("INVALID_STATE_ERR"); | |
} | |
if (xhr.sendFlag) { | |
throw new Error("INVALID_STATE_ERR"); | |
} | |
} | |
function getHeader(headers, header) { | |
header = header.toLowerCase(); | |
for (var h in headers) { | |
if (h.toLowerCase() === header) { | |
return h; | |
} | |
} | |
return null; | |
} | |
// filtering to enable a white-list version of Sinon FakeXhr, | |
// where whitelisted requests are passed through to real XHR | |
function each(collection, callback) { | |
if (!collection) { | |
return; | |
} | |
for (var i = 0, l = collection.length; i < l; i += 1) { | |
callback(collection[i]); | |
} | |
} | |
function some(collection, callback) { | |
for (var index = 0; index < collection.length; index++) { | |
if (callback(collection[index]) === true) { | |
return true; | |
} | |
} | |
return false; | |
} | |
// largest arity in XHR is 5 - XHR#open | |
var apply = function (obj, method, args) { | |
switch (args.length) { | |
case 0: return obj[method](); | |
case 1: return obj[method](args[0]); | |
case 2: return obj[method](args[0], args[1]); | |
case 3: return obj[method](args[0], args[1], args[2]); | |
case 4: return obj[method](args[0], args[1], args[2], args[3]); | |
case 5: return obj[method](args[0], args[1], args[2], args[3], args[4]); | |
} | |
}; | |
FakeXMLHttpRequest.filters = []; | |
FakeXMLHttpRequest.addFilter = function addFilter(fn) { | |
this.filters.push(fn); | |
}; | |
var IE6Re = /MSIE 6/; | |
FakeXMLHttpRequest.defake = function defake(fakeXhr, xhrArgs) { | |
var xhr = new sinonXhr.workingXHR(); // eslint-disable-line new-cap | |
each([ | |
"open", | |
"setRequestHeader", | |
"send", | |
"abort", | |
"getResponseHeader", | |
"getAllResponseHeaders", | |
"addEventListener", | |
"overrideMimeType", | |
"removeEventListener" | |
], function (method) { | |
fakeXhr[method] = function () { | |
return apply(xhr, method, arguments); | |
}; | |
}); | |
var copyAttrs = function (args) { | |
each(args, function (attr) { | |
try { | |
fakeXhr[attr] = xhr[attr]; | |
} catch (e) { | |
if (!IE6Re.test(navigator.userAgent)) { | |
throw e; | |
} | |
} | |
}); | |
}; | |
var stateChange = function stateChange() { | |
fakeXhr.readyState = xhr.readyState; | |
if (xhr.readyState >= FakeXMLHttpRequest.HEADERS_RECEIVED) { | |
copyAttrs(["status", "statusText"]); | |
} | |
if (xhr.readyState >= FakeXMLHttpRequest.LOADING) { | |
copyAttrs(["responseText", "response"]); | |
} | |
if (xhr.readyState === FakeXMLHttpRequest.DONE) { | |
copyAttrs(["responseXML"]); | |
} | |
if (fakeXhr.onreadystatechange) { | |
fakeXhr.onreadystatechange.call(fakeXhr, { target: fakeXhr }); | |
} | |
}; | |
if (xhr.addEventListener) { | |
for (var event in fakeXhr.eventListeners) { | |
if (fakeXhr.eventListeners.hasOwnProperty(event)) { | |
/*eslint-disable no-loop-func*/ | |
each(fakeXhr.eventListeners[event], function (handler) { | |
xhr.addEventListener(event, handler); | |
}); | |
/*eslint-enable no-loop-func*/ | |
} | |
} | |
xhr.addEventListener("readystatechange", stateChange); | |
} else { | |
xhr.onreadystatechange = stateChange; | |
} | |
apply(xhr, "open", xhrArgs); | |
}; | |
FakeXMLHttpRequest.useFilters = false; | |
function verifyRequestOpened(xhr) { | |
if (xhr.readyState !== FakeXMLHttpRequest.OPENED) { | |
throw new Error("INVALID_STATE_ERR - " + xhr.readyState); | |
} | |
} | |
function verifyRequestSent(xhr) { | |
if (xhr.readyState === FakeXMLHttpRequest.DONE) { | |
throw new Error("Request done"); | |
} | |
} | |
function verifyHeadersReceived(xhr) { | |
if (xhr.async && xhr.readyState !== FakeXMLHttpRequest.HEADERS_RECEIVED) { | |
throw new Error("No headers received"); | |
} | |
} | |
function verifyResponseBodyType(body) { | |
if (typeof body !== "string") { | |
var error = new Error("Attempted to respond to fake XMLHttpRequest with " + | |
body + ", which is not a string."); | |
error.name = "InvalidBodyException"; | |
throw error; | |
} | |
} | |
function convertToArrayBuffer(body) { | |
var buffer = new ArrayBuffer(body.length); | |
var view = new Uint8Array(buffer); | |
for (var i = 0; i < body.length; i++) { | |
var charCode = body.charCodeAt(i); | |
if (charCode >= 256) { | |
throw new TypeError("arraybuffer or blob responseTypes require binary string, " + | |
"invalid character " + body[i] + " found."); | |
} | |
view[i] = charCode; | |
} | |
return buffer; | |
} | |
function isXmlContentType(contentType) { | |
return !contentType || /(text\/xml)|(application\/xml)|(\+xml)/.test(contentType); | |
} | |
function convertResponseBody(responseType, contentType, body) { | |
if (responseType === "" || responseType === "text") { | |
return body; | |
} else if (supportsArrayBuffer && responseType === "arraybuffer") { | |
return convertToArrayBuffer(body); | |
} else if (responseType === "json") { | |
try { | |
return JSON.parse(body); | |
} catch (e) { | |
// Return parsing failure as null | |
return null; | |
} | |
} else if (supportsBlob && responseType === "blob") { | |
var blobOptions = {}; | |
if (contentType) { | |
blobOptions.type = contentType; | |
} | |
return new Blob([convertToArrayBuffer(body)], blobOptions); | |
} else if (responseType === "document") { | |
if (isXmlContentType(contentType)) { | |
return FakeXMLHttpRequest.parseXML(body); | |
} | |
return null; | |
} | |
throw new Error("Invalid responseType " + responseType); | |
} | |
function clearResponse(xhr) { | |
if (xhr.responseType === "" || xhr.responseType === "text") { | |
xhr.response = xhr.responseText = ""; | |
} else { | |
xhr.response = xhr.responseText = null; | |
} | |
xhr.responseXML = null; | |
} | |
FakeXMLHttpRequest.parseXML = function parseXML(text) { | |
// Treat empty string as parsing failure | |
if (text !== "") { | |
try { | |
if (typeof DOMParser !== "undefined") { | |
var parser = new DOMParser(); | |
return parser.parseFromString(text, "text/xml"); | |
} | |
var xmlDoc = new window.ActiveXObject("Microsoft.XMLDOM"); | |
xmlDoc.async = "false"; | |
xmlDoc.loadXML(text); | |
return xmlDoc; | |
} catch (e) { | |
// Unable to parse XML - no biggie | |
} | |
} | |
return null; | |
}; | |
FakeXMLHttpRequest.statusCodes = { | |
100: "Continue", | |
101: "Switching Protocols", | |
200: "OK", | |
201: "Created", | |
202: "Accepted", | |
203: "Non-Authoritative Information", | |
204: "No Content", | |
205: "Reset Content", | |
206: "Partial Content", | |
207: "Multi-Status", | |
300: "Multiple Choice", | |
301: "Moved Permanently", | |
302: "Found", | |
303: "See Other", | |
304: "Not Modified", | |
305: "Use Proxy", | |
307: "Temporary Redirect", | |
400: "Bad Request", | |
401: "Unauthorized", | |
402: "Payment Required", | |
403: "Forbidden", | |
404: "Not Found", | |
405: "Method Not Allowed", | |
406: "Not Acceptable", | |
407: "Proxy Authentication Required", | |
408: "Request Timeout", | |
409: "Conflict", | |
410: "Gone", | |
411: "Length Required", | |
412: "Precondition Failed", | |
413: "Request Entity Too Large", | |
414: "Request-URI Too Long", | |
415: "Unsupported Media Type", | |
416: "Requested Range Not Satisfiable", | |
417: "Expectation Failed", | |
422: "Unprocessable Entity", | |
500: "Internal Server Error", | |
501: "Not Implemented", | |
502: "Bad Gateway", | |
503: "Service Unavailable", | |
504: "Gateway Timeout", | |
505: "HTTP Version Not Supported" | |
}; | |
function makeApi(sinon) { | |
sinon.xhr = sinonXhr; | |
sinon.extend(FakeXMLHttpRequest.prototype, sinon.EventTarget, { | |
async: true, | |
open: function open(method, url, async, username, password) { | |
this.method = method; | |
this.url = url; | |
this.async = typeof async === "boolean" ? async : true; | |
this.username = username; | |
this.password = password; | |
clearResponse(this); | |
this.requestHeaders = {}; | |
this.sendFlag = false; | |
if (FakeXMLHttpRequest.useFilters === true) { | |
var xhrArgs = arguments; | |
var defake = some(FakeXMLHttpRequest.filters, function (filter) { | |
return filter.apply(this, xhrArgs); | |
}); | |
if (defake) { | |
return FakeXMLHttpRequest.defake(this, arguments); | |
} | |
} | |
this.readyStateChange(FakeXMLHttpRequest.OPENED); | |
}, | |
readyStateChange: function readyStateChange(state) { | |
this.readyState = state; | |
var readyStateChangeEvent = new sinon.Event("readystatechange", false, false, this); | |
var event, progress; | |
if (typeof this.onreadystatechange === "function") { | |
try { | |
this.onreadystatechange(readyStateChangeEvent); | |
} catch (e) { | |
sinon.logError("Fake XHR onreadystatechange handler", e); | |
} | |
} | |
if (this.readyState === FakeXMLHttpRequest.DONE) { | |
// ensure loaded and total are numbers | |
progress = { | |
loaded: this.progress || 0, | |
total: this.progress || 0 | |
}; | |
if (this.status === 0) { | |
event = this.aborted ? "abort" : "error"; | |
} | |
else { | |
event = "load"; | |
} | |
if (supportsProgress) { | |
this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progress, this)); | |
this.upload.dispatchEvent(new sinon.ProgressEvent(event, progress, this)); | |
this.upload.dispatchEvent(new sinon.ProgressEvent("loadend", progress, this)); | |
} | |
this.dispatchEvent(new sinon.ProgressEvent("progress", progress, this)); | |
this.dispatchEvent(new sinon.ProgressEvent(event, progress, this)); | |
this.dispatchEvent(new sinon.ProgressEvent("loadend", progress, this)); | |
} | |
this.dispatchEvent(readyStateChangeEvent); | |
}, | |
setRequestHeader: function setRequestHeader(header, value) { | |
verifyState(this); | |
if (unsafeHeaders[header] || /^(Sec-|Proxy-)/.test(header)) { | |
throw new Error("Refused to set unsafe header \"" + header + "\""); | |
} | |
if (this.requestHeaders[header]) { | |
this.requestHeaders[header] += "," + value; | |
} else { | |
this.requestHeaders[header] = value; | |
} | |
}, | |
// Helps testing | |
setResponseHeaders: function setResponseHeaders(headers) { | |
verifyRequestOpened(this); | |
this.responseHeaders = {}; | |
for (var header in headers) { | |
if (headers.hasOwnProperty(header)) { | |
this.responseHeaders[header] = headers[header]; | |
} | |
} | |
if (this.async) { | |
this.readyStateChange(FakeXMLHttpRequest.HEADERS_RECEIVED); | |
} else { | |
this.readyState = FakeXMLHttpRequest.HEADERS_RECEIVED; | |
} | |
}, | |
// Currently treats ALL data as a DOMString (i.e. no Document) | |
send: function send(data) { | |
verifyState(this); | |
if (!/^(get|head)$/i.test(this.method)) { | |
var contentType = getHeader(this.requestHeaders, "Content-Type"); | |
if (this.requestHeaders[contentType]) { | |
var value = this.requestHeaders[contentType].split(";"); | |
this.requestHeaders[contentType] = value[0] + ";charset=utf-8"; | |
} else if (supportsFormData && !(data instanceof FormData)) { | |
this.requestHeaders["Content-Type"] = "text/plain;charset=utf-8"; | |
} | |
this.requestBody = data; | |
} | |
this.errorFlag = false; | |
this.sendFlag = this.async; | |
clearResponse(this); | |
this.readyStateChange(FakeXMLHttpRequest.OPENED); | |
if (typeof this.onSend === "function") { | |
this.onSend(this); | |
} | |
this.dispatchEvent(new sinon.Event("loadstart", false, false, this)); | |
}, | |
abort: function abort() { | |
this.aborted = true; | |
clearResponse(this); | |
this.errorFlag = true; | |
this.requestHeaders = {}; | |
this.responseHeaders = {}; | |
if (this.readyState > FakeXMLHttpRequest.UNSENT && this.sendFlag) { | |
this.readyStateChange(FakeXMLHttpRequest.DONE); | |
this.sendFlag = false; | |
} | |
this.readyState = FakeXMLHttpRequest.UNSENT; | |
}, | |
error: function error() { | |
clearResponse(this); | |
this.errorFlag = true; | |
this.requestHeaders = {}; | |
this.responseHeaders = {}; | |
this.readyStateChange(FakeXMLHttpRequest.DONE); | |
}, | |
getResponseHeader: function getResponseHeader(header) { | |
if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { | |
return null; | |
} | |
if (/^Set-Cookie2?$/i.test(header)) { | |
return null; | |
} | |
header = getHeader(this.responseHeaders, header); | |
return this.responseHeaders[header] || null; | |
}, | |
getAllResponseHeaders: function getAllResponseHeaders() { | |
if (this.readyState < FakeXMLHttpRequest.HEADERS_RECEIVED) { | |
return ""; | |
} | |
var headers = ""; | |
for (var header in this.responseHeaders) { | |
if (this.responseHeaders.hasOwnProperty(header) && | |
!/^Set-Cookie2?$/i.test(header)) { | |
headers += header + ": " + this.responseHeaders[header] + "\r\n"; | |
} | |
} | |
return headers; | |
}, | |
setResponseBody: function setResponseBody(body) { | |
verifyRequestSent(this); | |
verifyHeadersReceived(this); | |
verifyResponseBodyType(body); | |
var contentType = this.getResponseHeader("Content-Type"); | |
var isTextResponse = this.responseType === "" || this.responseType === "text"; | |
clearResponse(this); | |
if (this.async) { | |
var chunkSize = this.chunkSize || 10; | |
var index = 0; | |
do { | |
this.readyStateChange(FakeXMLHttpRequest.LOADING); | |
if (isTextResponse) { | |
this.responseText = this.response += body.substring(index, index + chunkSize); | |
} | |
index += chunkSize; | |
} while (index < body.length); | |
} | |
this.response = convertResponseBody(this.responseType, contentType, body); | |
if (isTextResponse) { | |
this.responseText = this.response; | |
} | |
if (this.responseType === "document") { | |
this.responseXML = this.response; | |
} else if (this.responseType === "" && isXmlContentType(contentType)) { | |
this.responseXML = FakeXMLHttpRequest.parseXML(this.responseText); | |
} | |
this.progress = body.length; | |
this.readyStateChange(FakeXMLHttpRequest.DONE); | |
}, | |
respond: function respond(status, headers, body) { | |
this.status = typeof status === "number" ? status : 200; | |
this.statusText = FakeXMLHttpRequest.statusCodes[this.status]; | |
this.setResponseHeaders(headers || {}); | |
this.setResponseBody(body || ""); | |
}, | |
uploadProgress: function uploadProgress(progressEventRaw) { | |
if (supportsProgress) { | |
this.upload.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); | |
} | |
}, | |
downloadProgress: function downloadProgress(progressEventRaw) { | |
if (supportsProgress) { | |
this.dispatchEvent(new sinon.ProgressEvent("progress", progressEventRaw)); | |
} | |
}, | |
uploadError: function uploadError(error) { | |
if (supportsCustomEvent) { | |
this.upload.dispatchEvent(new sinon.CustomEvent("error", {detail: error})); | |
} | |
} | |
}); | |
sinon.extend(FakeXMLHttpRequest, { | |
UNSENT: 0, | |
OPENED: 1, | |
HEADERS_RECEIVED: 2, | |
LOADING: 3, | |
DONE: 4 | |
}); | |
sinon.useFakeXMLHttpRequest = function () { | |
FakeXMLHttpRequest.restore = function restore(keepOnCreate) { | |
if (sinonXhr.supportsXHR) { | |
global.XMLHttpRequest = sinonXhr.GlobalXMLHttpRequest; | |
} | |
if (sinonXhr.supportsActiveX) { | |
global.ActiveXObject = sinonXhr.GlobalActiveXObject; | |
} | |
delete FakeXMLHttpRequest.restore; | |
if (keepOnCreate !== true) { | |
delete FakeXMLHttpRequest.onCreate; | |
} | |
}; | |
if (sinonXhr.supportsXHR) { | |
global.XMLHttpRequest = FakeXMLHttpRequest; | |
} | |
if (sinonXhr.supportsActiveX) { | |
global.ActiveXObject = function ActiveXObject(objId) { | |
if (objId === "Microsoft.XMLHTTP" || /^Msxml2\.XMLHTTP/i.test(objId)) { | |
return new FakeXMLHttpRequest(); | |
} | |
return new sinonXhr.GlobalActiveXObject(objId); | |
}; | |
} | |
return FakeXMLHttpRequest; | |
}; | |
sinon.FakeXMLHttpRequest = FakeXMLHttpRequest; | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./core"); | |
require("../extend"); | |
require("./event"); | |
require("../log_error"); | |
makeApi(sinon); | |
module.exports = sinon; | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon, // eslint-disable-line no-undef | |
typeof global !== "undefined" ? global : self | |
)); | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"../extend":9,"../log_error":11,"./core":21,"./event":22}],28:[function(require,module,exports){ | |
/** | |
* @depend util/core.js | |
*/ | |
(function (sinonGlobal) { | |
"use strict"; | |
function makeApi(sinon) { | |
function walkInternal(obj, iterator, context, originalObj, seen) { | |
var proto, prop; | |
if (typeof Object.getOwnPropertyNames !== "function") { | |
// We explicitly want to enumerate through all of the prototype's properties | |
// in this case, therefore we deliberately leave out an own property check. | |
/* eslint-disable guard-for-in */ | |
for (prop in obj) { | |
iterator.call(context, obj[prop], prop, obj); | |
} | |
/* eslint-enable guard-for-in */ | |
return; | |
} | |
Object.getOwnPropertyNames(obj).forEach(function (k) { | |
if (seen[k] !== true) { | |
seen[k] = true; | |
var target = typeof Object.getOwnPropertyDescriptor(obj, k).get === "function" ? | |
originalObj : obj; | |
iterator.call(context, target[k], k, target); | |
} | |
}); | |
proto = Object.getPrototypeOf(obj); | |
if (proto) { | |
walkInternal(proto, iterator, context, originalObj, seen); | |
} | |
} | |
/* Public: walks the prototype chain of an object and iterates over every own property | |
* name encountered. The iterator is called in the same fashion that Array.prototype.forEach | |
* works, where it is passed the value, key, and own object as the 1st, 2nd, and 3rd positional | |
* argument, respectively. In cases where Object.getOwnPropertyNames is not available, walk will | |
* default to using a simple for..in loop. | |
* | |
* obj - The object to walk the prototype chain for. | |
* iterator - The function to be called on each pass of the walk. | |
* context - (Optional) When given, the iterator will be called with this object as the receiver. | |
*/ | |
function walk(obj, iterator, context) { | |
return walkInternal(obj, iterator, context, obj, {}); | |
} | |
sinon.walk = walk; | |
return sinon.walk; | |
} | |
function loadDependencies(require, exports, module) { | |
var sinon = require("./util/core"); | |
module.exports = makeApi(sinon); | |
} | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
if (isAMD) { | |
define(loadDependencies); | |
return; | |
} | |
if (isNode) { | |
loadDependencies(require, module.exports, module); | |
return; | |
} | |
if (sinonGlobal) { | |
makeApi(sinonGlobal); | |
} | |
}( | |
typeof sinon === "object" && sinon // eslint-disable-line no-undef | |
)); | |
},{"./util/core":21}],29:[function(require,module,exports){ | |
(function (global){ | |
((typeof define === "function" && define.amd && function (m) { | |
define("formatio", ["samsam"], m); | |
}) || (typeof module === "object" && function (m) { | |
module.exports = m(require("samsam")); | |
}) || function (m) { this.formatio = m(this.samsam); } | |
)(function (samsam) { | |
"use strict"; | |
var formatio = { | |
excludeConstructors: ["Object", /^.$/], | |
quoteStrings: true, | |
limitChildrenCount: 0 | |
}; | |
var hasOwn = Object.prototype.hasOwnProperty; | |
var specialObjects = []; | |
if (typeof global !== "undefined") { | |
specialObjects.push({ object: global, value: "[object global]" }); | |
} | |
if (typeof document !== "undefined") { | |
specialObjects.push({ | |
object: document, | |
value: "[object HTMLDocument]" | |
}); | |
} | |
if (typeof window !== "undefined") { | |
specialObjects.push({ object: window, value: "[object Window]" }); | |
} | |
function functionName(func) { | |
if (!func) { return ""; } | |
if (func.displayName) { return func.displayName; } | |
if (func.name) { return func.name; } | |
var matches = func.toString().match(/function\s+([^\(]+)/m); | |
return (matches && matches[1]) || ""; | |
} | |
function constructorName(f, object) { | |
var name = functionName(object && object.constructor); | |
var excludes = f.excludeConstructors || | |
formatio.excludeConstructors || []; | |
var i, l; | |
for (i = 0, l = excludes.length; i < l; ++i) { | |
if (typeof excludes[i] === "string" && excludes[i] === name) { | |
return ""; | |
} else if (excludes[i].test && excludes[i].test(name)) { | |
return ""; | |
} | |
} | |
return name; | |
} | |
function isCircular(object, objects) { | |
if (typeof object !== "object") { return false; } | |
var i, l; | |
for (i = 0, l = objects.length; i < l; ++i) { | |
if (objects[i] === object) { return true; } | |
} | |
return false; | |
} | |
function ascii(f, object, processed, indent) { | |
if (typeof object === "string") { | |
var qs = f.quoteStrings; | |
var quote = typeof qs !== "boolean" || qs; | |
return processed || quote ? '"' + object + '"' : object; | |
} | |
if (typeof object === "function" && !(object instanceof RegExp)) { | |
return ascii.func(object); | |
} | |
processed = processed || []; | |
if (isCircular(object, processed)) { return "[Circular]"; } | |
if (Object.prototype.toString.call(object) === "[object Array]") { | |
return ascii.array.call(f, object, processed); | |
} | |
if (!object) { return String((1/object) === -Infinity ? "-0" : object); } | |
if (samsam.isElement(object)) { return ascii.element(object); } | |
if (typeof object.toString === "function" && | |
object.toString !== Object.prototype.toString) { | |
return object.toString(); | |
} | |
var i, l; | |
for (i = 0, l = specialObjects.length; i < l; i++) { | |
if (object === specialObjects[i].object) { | |
return specialObjects[i].value; | |
} | |
} | |
return ascii.object.call(f, object, processed, indent); | |
} | |
ascii.func = function (func) { | |
return "function " + functionName(func) + "() {}"; | |
}; | |
ascii.array = function (array, processed) { | |
processed = processed || []; | |
processed.push(array); | |
var pieces = []; | |
var i, l; | |
l = (this.limitChildrenCount > 0) ? | |
Math.min(this.limitChildrenCount, array.length) : array.length; | |
for (i = 0; i < l; ++i) { | |
pieces.push(ascii(this, array[i], processed)); | |
} | |
if(l < array.length) | |
pieces.push("[... " + (array.length - l) + " more elements]"); | |
return "[" + pieces.join(", ") + "]"; | |
}; | |
ascii.object = function (object, processed, indent) { | |
processed = processed || []; | |
processed.push(object); | |
indent = indent || 0; | |
var pieces = [], properties = samsam.keys(object).sort(); | |
var length = 3; | |
var prop, str, obj, i, k, l; | |
l = (this.limitChildrenCount > 0) ? | |
Math.min(this.limitChildrenCount, properties.length) : properties.length; | |
for (i = 0; i < l; ++i) { | |
prop = properties[i]; | |
obj = object[prop]; | |
if (isCircular(obj, processed)) { | |
str = "[Circular]"; | |
} else { | |
str = ascii(this, obj, processed, indent + 2); | |
} | |
str = (/\s/.test(prop) ? '"' + prop + '"' : prop) + ": " + str; | |
length += str.length; | |
pieces.push(str); | |
} | |
var cons = constructorName(this, object); | |
var prefix = cons ? "[" + cons + "] " : ""; | |
var is = ""; | |
for (i = 0, k = indent; i < k; ++i) { is += " "; } | |
if(l < properties.length) | |
pieces.push("[... " + (properties.length - l) + " more elements]"); | |
if (length + indent > 80) { | |
return prefix + "{\n " + is + pieces.join(",\n " + is) + "\n" + | |
is + "}"; | |
} | |
return prefix + "{ " + pieces.join(", ") + " }"; | |
}; | |
ascii.element = function (element) { | |
var tagName = element.tagName.toLowerCase(); | |
var attrs = element.attributes, attr, pairs = [], attrName, i, l, val; | |
for (i = 0, l = attrs.length; i < l; ++i) { | |
attr = attrs.item(i); | |
attrName = attr.nodeName.toLowerCase().replace("html:", ""); | |
val = attr.nodeValue; | |
if (attrName !== "contenteditable" || val !== "inherit") { | |
if (!!val) { pairs.push(attrName + "=\"" + val + "\""); } | |
} | |
} | |
var formatted = "<" + tagName + (pairs.length > 0 ? " " : ""); | |
var content = element.innerHTML; | |
if (content.length > 20) { | |
content = content.substr(0, 20) + "[...]"; | |
} | |
var res = formatted + pairs.join(" ") + ">" + content + | |
"</" + tagName + ">"; | |
return res.replace(/ contentEditable="inherit"/, ""); | |
}; | |
function Formatio(options) { | |
for (var opt in options) { | |
this[opt] = options[opt]; | |
} | |
} | |
Formatio.prototype = { | |
functionName: functionName, | |
configure: function (options) { | |
return new Formatio(options); | |
}, | |
constructorName: function (object) { | |
return constructorName(this, object); | |
}, | |
ascii: function (object, processed, indent) { | |
return ascii(this, object, processed, indent); | |
} | |
}; | |
return Formatio.prototype; | |
}); | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{"samsam":31}],30:[function(require,module,exports){ | |
(function (global){ | |
/*global global, window*/ | |
/** | |
* @author Christian Johansen ([email protected]) and contributors | |
* @license BSD | |
* | |
* Copyright (c) 2010-2014 Christian Johansen | |
*/ | |
(function (global) { | |
"use strict"; | |
// Make properties writable in IE, as per | |
// http://www.adequatelygood.com/Replacing-setTimeout-Globally.html | |
// JSLint being anal | |
var glbl = global; | |
global.setTimeout = glbl.setTimeout; | |
global.clearTimeout = glbl.clearTimeout; | |
global.setInterval = glbl.setInterval; | |
global.clearInterval = glbl.clearInterval; | |
global.Date = glbl.Date; | |
// setImmediate is not a standard function | |
// avoid adding the prop to the window object if not present | |
if('setImmediate' in global) { | |
global.setImmediate = glbl.setImmediate; | |
global.clearImmediate = glbl.clearImmediate; | |
} | |
// node expects setTimeout/setInterval to return a fn object w/ .ref()/.unref() | |
// browsers, a number. | |
// see https://github.com/cjohansen/Sinon.JS/pull/436 | |
var NOOP = function () { return undefined; }; | |
var timeoutResult = setTimeout(NOOP, 0); | |
var addTimerReturnsObject = typeof timeoutResult === "object"; | |
clearTimeout(timeoutResult); | |
var NativeDate = Date; | |
var uniqueTimerId = 1; | |
/** | |
* Parse strings like "01:10:00" (meaning 1 hour, 10 minutes, 0 seconds) into | |
* number of milliseconds. This is used to support human-readable strings passed | |
* to clock.tick() | |
*/ | |
function parseTime(str) { | |
if (!str) { | |
return 0; | |
} | |
var strings = str.split(":"); | |
var l = strings.length, i = l; | |
var ms = 0, parsed; | |
if (l > 3 || !/^(\d\d:){0,2}\d\d?$/.test(str)) { | |
throw new Error("tick only understands numbers and 'h:m:s'"); | |
} | |
while (i--) { | |
parsed = parseInt(strings[i], 10); | |
if (parsed >= 60) { | |
throw new Error("Invalid time " + str); | |
} | |
ms += parsed * Math.pow(60, (l - i - 1)); | |
} | |
return ms * 1000; | |
} | |
/** | |
* Used to grok the `now` parameter to createClock. | |
*/ | |
function getEpoch(epoch) { | |
if (!epoch) { return 0; } | |
if (typeof epoch.getTime === "function") { return epoch.getTime(); } | |
if (typeof epoch === "number") { return epoch; } | |
throw new TypeError("now should be milliseconds since UNIX epoch"); | |
} | |
function inRange(from, to, timer) { | |
return timer && timer.callAt >= from && timer.callAt <= to; | |
} | |
function mirrorDateProperties(target, source) { | |
var prop; | |
for (prop in source) { | |
if (source.hasOwnProperty(prop)) { | |
target[prop] = source[prop]; | |
} | |
} | |
// set special now implementation | |
if (source.now) { | |
target.now = function now() { | |
return target.clock.now; | |
}; | |
} else { | |
delete target.now; | |
} | |
// set special toSource implementation | |
if (source.toSource) { | |
target.toSource = function toSource() { | |
return source.toSource(); | |
}; | |
} else { | |
delete target.toSource; | |
} | |
// set special toString implementation | |
target.toString = function toString() { | |
return source.toString(); | |
}; | |
target.prototype = source.prototype; | |
target.parse = source.parse; | |
target.UTC = source.UTC; | |
target.prototype.toUTCString = source.prototype.toUTCString; | |
return target; | |
} | |
function createDate() { | |
function ClockDate(year, month, date, hour, minute, second, ms) { | |
// Defensive and verbose to avoid potential harm in passing | |
// explicit undefined when user does not pass argument | |
switch (arguments.length) { | |
case 0: | |
return new NativeDate(ClockDate.clock.now); | |
case 1: | |
return new NativeDate(year); | |
case 2: | |
return new NativeDate(year, month); | |
case 3: | |
return new NativeDate(year, month, date); | |
case 4: | |
return new NativeDate(year, month, date, hour); | |
case 5: | |
return new NativeDate(year, month, date, hour, minute); | |
case 6: | |
return new NativeDate(year, month, date, hour, minute, second); | |
default: | |
return new NativeDate(year, month, date, hour, minute, second, ms); | |
} | |
} | |
return mirrorDateProperties(ClockDate, NativeDate); | |
} | |
function addTimer(clock, timer) { | |
if (timer.func === undefined) { | |
throw new Error("Callback must be provided to timer calls"); | |
} | |
if (!clock.timers) { | |
clock.timers = {}; | |
} | |
timer.id = uniqueTimerId++; | |
timer.createdAt = clock.now; | |
timer.callAt = clock.now + (timer.delay || (clock.duringTick ? 1 : 0)); | |
clock.timers[timer.id] = timer; | |
if (addTimerReturnsObject) { | |
return { | |
id: timer.id, | |
ref: NOOP, | |
unref: NOOP | |
}; | |
} | |
return timer.id; | |
} | |
function compareTimers(a, b) { | |
// Sort first by absolute timing | |
if (a.callAt < b.callAt) { | |
return -1; | |
} | |
if (a.callAt > b.callAt) { | |
return 1; | |
} | |
// Sort next by immediate, immediate timers take precedence | |
if (a.immediate && !b.immediate) { | |
return -1; | |
} | |
if (!a.immediate && b.immediate) { | |
return 1; | |
} | |
// Sort next by creation time, earlier-created timers take precedence | |
if (a.createdAt < b.createdAt) { | |
return -1; | |
} | |
if (a.createdAt > b.createdAt) { | |
return 1; | |
} | |
// Sort next by id, lower-id timers take precedence | |
if (a.id < b.id) { | |
return -1; | |
} | |
if (a.id > b.id) { | |
return 1; | |
} | |
// As timer ids are unique, no fallback `0` is necessary | |
} | |
function firstTimerInRange(clock, from, to) { | |
var timers = clock.timers, | |
timer = null, | |
id, | |
isInRange; | |
for (id in timers) { | |
if (timers.hasOwnProperty(id)) { | |
isInRange = inRange(from, to, timers[id]); | |
if (isInRange && (!timer || compareTimers(timer, timers[id]) === 1)) { | |
timer = timers[id]; | |
} | |
} | |
} | |
return timer; | |
} | |
function callTimer(clock, timer) { | |
var exception; | |
if (typeof timer.interval === "number") { | |
clock.timers[timer.id].callAt += timer.interval; | |
} else { | |
delete clock.timers[timer.id]; | |
} | |
try { | |
if (typeof timer.func === "function") { | |
timer.func.apply(null, timer.args); | |
} else { | |
eval(timer.func); | |
} | |
} catch (e) { | |
exception = e; | |
} | |
if (!clock.timers[timer.id]) { | |
if (exception) { | |
throw exception; | |
} | |
return; | |
} | |
if (exception) { | |
throw exception; | |
} | |
} | |
function timerType(timer) { | |
if (timer.immediate) { | |
return "Immediate"; | |
} else if (typeof timer.interval !== "undefined") { | |
return "Interval"; | |
} else { | |
return "Timeout"; | |
} | |
} | |
function clearTimer(clock, timerId, ttype) { | |
if (!timerId) { | |
// null appears to be allowed in most browsers, and appears to be | |
// relied upon by some libraries, like Bootstrap carousel | |
return; | |
} | |
if (!clock.timers) { | |
clock.timers = []; | |
} | |
// in Node, timerId is an object with .ref()/.unref(), and | |
// its .id field is the actual timer id. | |
if (typeof timerId === "object") { | |
timerId = timerId.id; | |
} | |
if (clock.timers.hasOwnProperty(timerId)) { | |
// check that the ID matches a timer of the correct type | |
var timer = clock.timers[timerId]; | |
if (timerType(timer) === ttype) { | |
delete clock.timers[timerId]; | |
} else { | |
throw new Error("Cannot clear timer: timer created with set" + ttype + "() but cleared with clear" + timerType(timer) + "()"); | |
} | |
} | |
} | |
function uninstall(clock, target) { | |
var method, | |
i, | |
l; | |
for (i = 0, l = clock.methods.length; i < l; i++) { | |
method = clock.methods[i]; | |
if (target[method].hadOwnProperty) { | |
target[method] = clock["_" + method]; | |
} else { | |
try { | |
delete target[method]; | |
} catch (ignore) {} | |
} | |
} | |
// Prevent multiple executions which will completely remove these props | |
clock.methods = []; | |
} | |
function hijackMethod(target, method, clock) { | |
var prop; | |
clock[method].hadOwnProperty = Object.prototype.hasOwnProperty.call(target, method); | |
clock["_" + method] = target[method]; | |
if (method === "Date") { | |
var date = mirrorDateProperties(clock[method], target[method]); | |
target[method] = date; | |
} else { | |
target[method] = function () { | |
return clock[method].apply(clock, arguments); | |
}; | |
for (prop in clock[method]) { | |
if (clock[method].hasOwnProperty(prop)) { | |
target[method][prop] = clock[method][prop]; | |
} | |
} | |
} | |
target[method].clock = clock; | |
} | |
var timers = { | |
setTimeout: setTimeout, | |
clearTimeout: clearTimeout, | |
setImmediate: global.setImmediate, | |
clearImmediate: global.clearImmediate, | |
setInterval: setInterval, | |
clearInterval: clearInterval, | |
Date: Date | |
}; | |
var keys = Object.keys || function (obj) { | |
var ks = [], | |
key; | |
for (key in obj) { | |
if (obj.hasOwnProperty(key)) { | |
ks.push(key); | |
} | |
} | |
return ks; | |
}; | |
exports.timers = timers; | |
function createClock(now) { | |
var clock = { | |
now: getEpoch(now), | |
timeouts: {}, | |
Date: createDate() | |
}; | |
clock.Date.clock = clock; | |
clock.setTimeout = function setTimeout(func, timeout) { | |
return addTimer(clock, { | |
func: func, | |
args: Array.prototype.slice.call(arguments, 2), | |
delay: timeout | |
}); | |
}; | |
clock.clearTimeout = function clearTimeout(timerId) { | |
return clearTimer(clock, timerId, "Timeout"); | |
}; | |
clock.setInterval = function setInterval(func, timeout) { | |
return addTimer(clock, { | |
func: func, | |
args: Array.prototype.slice.call(arguments, 2), | |
delay: timeout, | |
interval: timeout | |
}); | |
}; | |
clock.clearInterval = function clearInterval(timerId) { | |
return clearTimer(clock, timerId, "Interval"); | |
}; | |
clock.setImmediate = function setImmediate(func) { | |
return addTimer(clock, { | |
func: func, | |
args: Array.prototype.slice.call(arguments, 1), | |
immediate: true | |
}); | |
}; | |
clock.clearImmediate = function clearImmediate(timerId) { | |
return clearTimer(clock, timerId, "Immediate"); | |
}; | |
clock.tick = function tick(ms) { | |
ms = typeof ms === "number" ? ms : parseTime(ms); | |
var tickFrom = clock.now, tickTo = clock.now + ms, previous = clock.now; | |
var timer = firstTimerInRange(clock, tickFrom, tickTo); | |
var oldNow; | |
clock.duringTick = true; | |
var firstException; | |
while (timer && tickFrom <= tickTo) { | |
if (clock.timers[timer.id]) { | |
tickFrom = clock.now = timer.callAt; | |
try { | |
oldNow = clock.now; | |
callTimer(clock, timer); | |
// compensate for any setSystemTime() call during timer callback | |
if (oldNow !== clock.now) { | |
tickFrom += clock.now - oldNow; | |
tickTo += clock.now - oldNow; | |
previous += clock.now - oldNow; | |
} | |
} catch (e) { | |
firstException = firstException || e; | |
} | |
} | |
timer = firstTimerInRange(clock, previous, tickTo); | |
previous = tickFrom; | |
} | |
clock.duringTick = false; | |
clock.now = tickTo; | |
if (firstException) { | |
throw firstException; | |
} | |
return clock.now; | |
}; | |
clock.reset = function reset() { | |
clock.timers = {}; | |
}; | |
clock.setSystemTime = function setSystemTime(now) { | |
// determine time difference | |
var newNow = getEpoch(now); | |
var difference = newNow - clock.now; | |
// update 'system clock' | |
clock.now = newNow; | |
// update timers and intervals to keep them stable | |
for (var id in clock.timers) { | |
if (clock.timers.hasOwnProperty(id)) { | |
var timer = clock.timers[id]; | |
timer.createdAt += difference; | |
timer.callAt += difference; | |
} | |
} | |
}; | |
return clock; | |
} | |
exports.createClock = createClock; | |
exports.install = function install(target, now, toFake) { | |
var i, | |
l; | |
if (typeof target === "number") { | |
toFake = now; | |
now = target; | |
target = null; | |
} | |
if (!target) { | |
target = global; | |
} | |
var clock = createClock(now); | |
clock.uninstall = function () { | |
uninstall(clock, target); | |
}; | |
clock.methods = toFake || []; | |
if (clock.methods.length === 0) { | |
clock.methods = keys(timers); | |
} | |
for (i = 0, l = clock.methods.length; i < l; i++) { | |
hijackMethod(target, clock.methods[i], clock); | |
} | |
return clock; | |
}; | |
}(global || this)); | |
}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) | |
},{}],31:[function(require,module,exports){ | |
((typeof define === "function" && define.amd && function (m) { define("samsam", m); }) || | |
(typeof module === "object" && | |
function (m) { module.exports = m(); }) || // Node | |
function (m) { this.samsam = m(); } // Browser globals | |
)(function () { | |
var o = Object.prototype; | |
var div = typeof document !== "undefined" && document.createElement("div"); | |
function isNaN(value) { | |
// Unlike global isNaN, this avoids type coercion | |
// typeof check avoids IE host object issues, hat tip to | |
// lodash | |
var val = value; // JsLint thinks value !== value is "weird" | |
return typeof value === "number" && value !== val; | |
} | |
function getClass(value) { | |
// Returns the internal [[Class]] by calling Object.prototype.toString | |
// with the provided value as this. Return value is a string, naming the | |
// internal class, e.g. "Array" | |
return o.toString.call(value).split(/[ \]]/)[1]; | |
} | |
/** | |
* @name samsam.isArguments | |
* @param Object object | |
* | |
* Returns ``true`` if ``object`` is an ``arguments`` object, | |
* ``false`` otherwise. | |
*/ | |
function isArguments(object) { | |
if (getClass(object) === 'Arguments') { return true; } | |
if (typeof object !== "object" || typeof object.length !== "number" || | |
getClass(object) === "Array") { | |
return false; | |
} | |
if (typeof object.callee == "function") { return true; } | |
try { | |
object[object.length] = 6; | |
delete object[object.length]; | |
} catch (e) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* @name samsam.isElement | |
* @param Object object | |
* | |
* Returns ``true`` if ``object`` is a DOM element node. Unlike | |
* Underscore.js/lodash, this function will return ``false`` if ``object`` | |
* is an *element-like* object, i.e. a regular object with a ``nodeType`` | |
* property that holds the value ``1``. | |
*/ | |
function isElement(object) { | |
if (!object || object.nodeType !== 1 || !div) { return false; } | |
try { | |
object.appendChild(div); | |
object.removeChild(div); | |
} catch (e) { | |
return false; | |
} | |
return true; | |
} | |
/** | |
* @name samsam.keys | |
* @param Object object | |
* | |
* Return an array of own property names. | |
*/ | |
function keys(object) { | |
var ks = [], prop; | |
for (prop in object) { | |
if (o.hasOwnProperty.call(object, prop)) { ks.push(prop); } | |
} | |
return ks; | |
} | |
/** | |
* @name samsam.isDate | |
* @param Object value | |
* | |
* Returns true if the object is a ``Date``, or *date-like*. Duck typing | |
* of date objects work by checking that the object has a ``getTime`` | |
* function whose return value equals the return value from the object's | |
* ``valueOf``. | |
*/ | |
function isDate(value) { | |
return typeof value.getTime == "function" && | |
value.getTime() == value.valueOf(); | |
} | |
/** | |
* @name samsam.isNegZero | |
* @param Object value | |
* | |
* Returns ``true`` if ``value`` is ``-0``. | |
*/ | |
function isNegZero(value) { | |
return value === 0 && 1 / value === -Infinity; | |
} | |
/** | |
* @name samsam.equal | |
* @param Object obj1 | |
* @param Object obj2 | |
* | |
* Returns ``true`` if two objects are strictly equal. Compared to | |
* ``===`` there are two exceptions: | |
* | |
* - NaN is considered equal to NaN | |
* - -0 and +0 are not considered equal | |
*/ | |
function identical(obj1, obj2) { | |
if (obj1 === obj2 || (isNaN(obj1) && isNaN(obj2))) { | |
return obj1 !== 0 || isNegZero(obj1) === isNegZero(obj2); | |
} | |
} | |
/** | |
* @name samsam.deepEqual | |
* @param Object obj1 | |
* @param Object obj2 | |
* | |
* Deep equal comparison. Two values are "deep equal" if: | |
* | |
* - They are equal, according to samsam.identical | |
* - They are both date objects representing the same time | |
* - They are both arrays containing elements that are all deepEqual | |
* - They are objects with the same set of properties, and each property | |
* in ``obj1`` is deepEqual to the corresponding property in ``obj2`` | |
* | |
* Supports cyclic objects. | |
*/ | |
function deepEqualCyclic(obj1, obj2) { | |
// used for cyclic comparison | |
// contain already visited objects | |
var objects1 = [], | |
objects2 = [], | |
// contain pathes (position in the object structure) | |
// of the already visited objects | |
// indexes same as in objects arrays | |
paths1 = [], | |
paths2 = [], | |
// contains combinations of already compared objects | |
// in the manner: { "$1['ref']$2['ref']": true } | |
compared = {}; | |
/** | |
* used to check, if the value of a property is an object | |
* (cyclic logic is only needed for objects) | |
* only needed for cyclic logic | |
*/ | |
function isObject(value) { | |
if (typeof value === 'object' && value !== null && | |
!(value instanceof Boolean) && | |
!(value instanceof Date) && | |
!(value instanceof Number) && | |
!(value instanceof RegExp) && | |
!(value instanceof String)) { | |
return true; | |
} | |
return false; | |
} | |
/** | |
* returns the index of the given object in the | |
* given objects array, -1 if not contained | |
* only needed for cyclic logic | |
*/ | |
function getIndex(objects, obj) { | |
var i; | |
for (i = 0; i < objects.length; i++) { | |
if (objects[i] === obj) { | |
return i; | |
} | |
} | |
return -1; | |
} | |
// does the recursion for the deep equal check | |
return (function deepEqual(obj1, obj2, path1, path2) { | |
var type1 = typeof obj1; | |
var type2 = typeof obj2; | |
// == null also matches undefined | |
if (obj1 === obj2 || | |
isNaN(obj1) || isNaN(obj2) || | |
obj1 == null || obj2 == null || | |
type1 !== "object" || type2 !== "object") { | |
return identical(obj1, obj2); | |
} | |
// Elements are only equal if identical(expected, actual) | |
if (isElement(obj1) || isElement(obj2)) { return false; } | |
var isDate1 = isDate(obj1), isDate2 = isDate(obj2); | |
if (isDate1 || isDate2) { | |
if (!isDate1 || !isDate2 || obj1.getTime() !== obj2.getTime()) { | |
return false; | |
} | |
} | |
if (obj1 instanceof RegExp && obj2 instanceof RegExp) { | |
if (obj1.toString() !== obj2.toString()) { return false; } | |
} | |
var class1 = getClass(obj1); | |
var class2 = getClass(obj2); | |
var keys1 = keys(obj1); | |
var keys2 = keys(obj2); | |
if (isArguments(obj1) || isArguments(obj2)) { | |
if (obj1.length !== obj2.length) { return false; } | |
} else { | |
if (type1 !== type2 || class1 !== class2 || | |
keys1.length !== keys2.length) { | |
return false; | |
} | |
} | |
var key, i, l, | |
// following vars are used for the cyclic logic | |
value1, value2, | |
isObject1, isObject2, | |
index1, index2, | |
newPath1, newPath2; | |
for (i = 0, l = keys1.length; i < l; i++) { | |
key = keys1[i]; | |
if (!o.hasOwnProperty.call(obj2, key)) { | |
return false; | |
} | |
// Start of the cyclic logic | |
value1 = obj1[key]; | |
value2 = obj2[key]; | |
isObject1 = isObject(value1); | |
isObject2 = isObject(value2); | |
// determine, if the objects were already visited | |
// (it's faster to check for isObject first, than to | |
// get -1 from getIndex for non objects) | |
index1 = isObject1 ? getIndex(objects1, value1) : -1; | |
index2 = isObject2 ? getIndex(objects2, value2) : -1; | |
// determine the new pathes of the objects | |
// - for non cyclic objects the current path will be extended | |
// by current property name | |
// - for cyclic objects the stored path is taken | |
newPath1 = index1 !== -1 | |
? paths1[index1] | |
: path1 + '[' + JSON.stringify(key) + ']'; | |
newPath2 = index2 !== -1 | |
? paths2[index2] | |
: path2 + '[' + JSON.stringify(key) + ']'; | |
// stop recursion if current objects are already compared | |
if (compared[newPath1 + newPath2]) { | |
return true; | |
} | |
// remember the current objects and their pathes | |
if (index1 === -1 && isObject1) { | |
objects1.push(value1); | |
paths1.push(newPath1); | |
} | |
if (index2 === -1 && isObject2) { | |
objects2.push(value2); | |
paths2.push(newPath2); | |
} | |
// remember that the current objects are already compared | |
if (isObject1 && isObject2) { | |
compared[newPath1 + newPath2] = true; | |
} | |
// End of cyclic logic | |
// neither value1 nor value2 is a cycle | |
// continue with next level | |
if (!deepEqual(value1, value2, newPath1, newPath2)) { | |
return false; | |
} | |
} | |
return true; | |
}(obj1, obj2, '$1', '$2')); | |
} | |
var match; | |
function arrayContains(array, subset) { | |
if (subset.length === 0) { return true; } | |
var i, l, j, k; | |
for (i = 0, l = array.length; i < l; ++i) { | |
if (match(array[i], subset[0])) { | |
for (j = 0, k = subset.length; j < k; ++j) { | |
if (!match(array[i + j], subset[j])) { return false; } | |
} | |
return true; | |
} | |
} | |
return false; | |
} | |
/** | |
* @name samsam.match | |
* @param Object object | |
* @param Object matcher | |
* | |
* Compare arbitrary value ``object`` with matcher. | |
*/ | |
match = function match(object, matcher) { | |
if (matcher && typeof matcher.test === "function") { | |
return matcher.test(object); | |
} | |
if (typeof matcher === "function") { | |
return matcher(object) === true; | |
} | |
if (typeof matcher === "string") { | |
matcher = matcher.toLowerCase(); | |
var notNull = typeof object === "string" || !!object; | |
return notNull && | |
(String(object)).toLowerCase().indexOf(matcher) >= 0; | |
} | |
if (typeof matcher === "number") { | |
return matcher === object; | |
} | |
if (typeof matcher === "boolean") { | |
return matcher === object; | |
} | |
if (typeof(matcher) === "undefined") { | |
return typeof(object) === "undefined"; | |
} | |
if (matcher === null) { | |
return object === null; | |
} | |
if (getClass(object) === "Array" && getClass(matcher) === "Array") { | |
return arrayContains(object, matcher); | |
} | |
if (matcher && typeof matcher === "object") { | |
if (matcher === object) { | |
return true; | |
} | |
var prop; | |
for (prop in matcher) { | |
var value = object[prop]; | |
if (typeof value === "undefined" && | |
typeof object.getAttribute === "function") { | |
value = object.getAttribute(prop); | |
} | |
if (matcher[prop] === null || typeof matcher[prop] === 'undefined') { | |
if (value !== matcher[prop]) { | |
return false; | |
} | |
} else if (typeof value === "undefined" || !match(value, matcher[prop])) { | |
return false; | |
} | |
} | |
return true; | |
} | |
throw new Error("Matcher was not a string, a number, a " + | |
"function, a boolean or an object"); | |
}; | |
return { | |
isArguments: isArguments, | |
isElement: isElement, | |
isDate: isDate, | |
isNegZero: isNegZero, | |
identical: identical, | |
deepEqual: deepEqualCyclic, | |
match: match, | |
keys: keys | |
}; | |
}); | |
},{}],"sinon":[function(require,module,exports){ | |
/** | |
* Sinon core utilities. For internal use only. | |
* | |
* @author Christian Johansen ([email protected]) | |
* @license BSD | |
* | |
* Copyright (c) 2010-2013 Christian Johansen | |
*/ | |
var sinon = (function () { // eslint-disable-line no-unused-vars | |
"use strict"; | |
var sinonModule; | |
var isNode = typeof module !== "undefined" && module.exports && typeof require === "function"; | |
var isAMD = typeof define === "function" && typeof define.amd === "object" && define.amd; | |
function loadDependencies(require, exports, module) { | |
sinonModule = module.exports = require("./sinon/util/core"); | |
require("./sinon/extend"); | |
require("./sinon/walk"); | |
require("./sinon/typeOf"); | |
require("./sinon/times_in_words"); | |
require("./sinon/spy"); | |
require("./sinon/call"); | |
require("./sinon/behavior"); | |
require("./sinon/stub"); | |
require("./sinon/mock"); | |
require("./sinon/collection"); | |
require("./sinon/assert"); | |
require("./sinon/sandbox"); | |
require("./sinon/test"); | |
require("./sinon/test_case"); | |
require("./sinon/match"); | |
require("./sinon/format"); | |
require("./sinon/log_error"); | |
} | |
if (isAMD) { | |
define(loadDependencies); | |
} else if (isNode) { | |
loadDependencies(require, module.exports, module); | |
sinonModule = module.exports; | |
} else { | |
sinonModule = {}; | |
} | |
return sinonModule; | |
}()); | |
},{"./sinon/assert":5,"./sinon/behavior":6,"./sinon/call":7,"./sinon/collection":8,"./sinon/extend":9,"./sinon/format":10,"./sinon/log_error":11,"./sinon/match":12,"./sinon/mock":13,"./sinon/sandbox":14,"./sinon/spy":15,"./sinon/stub":16,"./sinon/test":17,"./sinon/test_case":18,"./sinon/times_in_words":19,"./sinon/typeOf":20,"./sinon/util/core":21,"./sinon/walk":28}]},{},[]) | |
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3Byb2Nlc3MvYnJvd3Nlci5qcyIsIi4uLy4uLy4uLy4uL2hvbWUvYWRtaW4vYnJvd3NlcmlmeS1jZG4vbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL3V0aWwvbm9kZV9tb2R1bGVzL2luaGVyaXRzL2luaGVyaXRzX2Jyb3dzZXIuanMiLCIuLi8uLi8uLi8uLi9ob21lL2FkbWluL2Jyb3dzZXJpZnktY2RuL25vZGVfbW9kdWxlcy9icm93c2VyaWZ5L25vZGVfbW9kdWxlcy91dGlsL3N1cHBvcnQvaXNCdWZmZXJCcm93c2VyLmpzIiwiLi4vLi4vLi4vLi4vaG9tZS9hZG1pbi9icm93c2VyaWZ5LWNkbi9ub2RlX21vZHVsZXMvYnJvd3NlcmlmeS9ub2RlX21vZHVsZXMvdXRpbC91dGlsLmpzIiwibGliL3Npbm9uL2Fzc2VydC5qcyIsImxpYi9zaW5vbi9iZWhhdmlvci5qcyIsImxpYi9zaW5vbi9jYWxsLmpzIiwibGliL3Npbm9uL2NvbGxlY3Rpb24uanMiLCJsaWIvc2lub24vZXh0ZW5kLmpzIiwibGliL3Npbm9uL2Zvcm1hdC5qcyIsImxpYi9zaW5vbi9sb2dfZXJyb3IuanMiLCJsaWIvc2lub24vbWF0Y2guanMiLCJsaWIvc2lub24vbW9jay5qcyIsImxpYi9zaW5vbi9zYW5kYm94LmpzIiwibGliL3Npbm9uL3NweS5qcyIsImxpYi9zaW5vbi9zdHViLmpzIiwibGliL3Npbm9uL3Rlc3QuanMiLCJsaWIvc2lub24vdGVzdF9jYXNlLmpzIiwibGliL3Npbm9uL3RpbWVzX2luX3dvcmRzLmpzIiwibGliL3Npbm9uL3R5cGVPZi5qcyIsImxpYi9zaW5vbi91dGlsL2NvcmUuanMiLCJsaWIvc2lub24vdXRpbC9ldmVudC5qcyIsImxpYi9zaW5vbi91dGlsL2Zha2Vfc2VydmVyLmpzIiwibGliL3Npbm9uL3V0aWwvZmFrZV9zZXJ2ZXJfd2l0aF9jbG9jay5qcyIsImxpYi9zaW5vbi91dGlsL2Zha2VfdGltZXJzLmpzIiwibGliL3Npbm9uL3V0aWwvZmFrZV94ZG9tYWluX3JlcXVlc3QuanMiLCJsaWIvc2lub24vdXRpbC9mYWtlX3htbF9odHRwX3JlcXVlc3QuanMiLCJsaWIvc2lub24vd2Fsay5qcyIsIm5vZGVfbW9kdWxlcy9mb3JtYXRpby9saWIvZm9ybWF0aW8uanMiLCJub2RlX21vZHVsZXMvbG9sZXgvc3JjL2xvbGV4LmpzIiwibm9kZV9tb2R1bGVzL3NhbXNhbS9saWIvc2Ftc2FtLmpzIiwic2lub24iXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDMWtCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7Ozs7QUN0UEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDblhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDcEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDM2VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlLQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbmRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZhQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2UEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7OztBQy9PQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDbnVCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUMvRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FDck5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FDdmdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvWUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsIi8vIHNoaW0gZm9yIHVzaW5nIHByb2Nlc3MgaW4gYnJvd3NlclxudmFyIHByb2Nlc3MgPSBtb2R1bGUuZXhwb3J0cyA9IHt9O1xuXG4vLyBjYWNoZWQgZnJvbSB3aGF0ZXZlciBnbG9iYWwgaXMgcHJlc2VudCBzbyB0aGF0IHRlc3QgcnVubmVycyB0aGF0IHN0dWIgaXRcbi8vIGRvbid0IGJyZWFrIHRoaW5ncy4gIEJ1dCB3ZSBuZWVkIHRvIHdyYXAgaXQgaW4gYSB0cnkgY2F0Y2ggaW4gY2FzZSBpdCBpc1xuLy8gd3JhcHBlZCBpbiBzdHJpY3QgbW9kZSBjb2RlIHdoaWNoIGRvZXNuJ3QgZGVmaW5lIGFueSBnbG9iYWxzLiAgSXQncyBpbnNpZGUgYVxuLy8gZnVuY3Rpb24gYmVjYXVzZSB0cnkvY2F0Y2hlcyBkZW9wdGltaXplIGluIGNlcnRhaW4gZW5naW5lcy5cblxudmFyIGNhY2hlZFNldFRpbWVvdXQ7XG52YXIgY2FjaGVkQ2xlYXJUaW1lb3V0O1xuXG5mdW5jdGlvbiBkZWZhdWx0U2V0VGltb3V0KCkge1xuICAgIHRocm93IG5ldyBFcnJvcignc2V0VGltZW91dCBoYXMgbm90IGJlZW4gZGVmaW5lZCcpO1xufVxuZnVuY3Rpb24gZGVmYXVsdENsZWFyVGltZW91dCAoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdjbGVhclRpbWVvdXQgaGFzIG5vdCBiZWVuIGRlZmluZWQnKTtcbn1cbihmdW5jdGlvbiAoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBzZXRUaW1lb3V0ID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gc2V0VGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBkZWZhdWx0U2V0VGltb3V0O1xuICAgICAgICB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgICBjYWNoZWRTZXRUaW1lb3V0ID0gZGVmYXVsdFNldFRpbW91dDtcbiAgICB9XG4gICAgdHJ5IHtcbiAgICAgICAgaWYgKHR5cGVvZiBjbGVhclRpbWVvdXQgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGNsZWFyVGltZW91dDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgICAgIH1cbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNhY2hlZENsZWFyVGltZW91dCA9IGRlZmF1bHRDbGVhclRpbWVvdXQ7XG4gICAgfVxufSAoKSlcbmZ1bmN0aW9uIHJ1blRpbWVvdXQoZnVuKSB7XG4gICAgaWYgKGNhY2hlZFNldFRpbWVvdXQgPT09IHNldFRpbWVvdXQpIHtcbiAgICAgICAgLy9ub3JtYWwgZW52aXJvbWVudHMgaW4gc2FuZSBzaXR1YXRpb25zXG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfVxuICAgIC8vIGlmIHNldFRpbWVvdXQgd2Fzbid0IGF2YWlsYWJsZSBidXQgd2FzIGxhdHRlciBkZWZpbmVkXG4gICAgaWYgKChjYWNoZWRTZXRUaW1lb3V0ID09PSBkZWZhdWx0U2V0VGltb3V0IHx8ICFjYWNoZWRTZXRUaW1lb3V0KSAmJiBzZXRUaW1lb3V0KSB7XG4gICAgICAgIGNhY2hlZFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuICAgICAgICByZXR1cm4gc2V0VGltZW91dChmdW4sIDApO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgICAvLyB3aGVuIHdoZW4gc29tZWJvZHkgaGFzIHNjcmV3ZWQgd2l0aCBzZXRUaW1lb3V0IGJ1dCBubyBJLkUuIG1hZGRuZXNzXG4gICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0KGZ1biwgMCk7XG4gICAgfSBjYXRjaChlKXtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIC8vIFdoZW4gd2UgYXJlIGluIEkuRS4gYnV0IHRoZSBzY3JpcHQgaGFzIGJlZW4gZXZhbGVkIHNvIEkuRS4gZG9lc24ndCB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZFNldFRpbWVvdXQuY2FsbChudWxsLCBmdW4sIDApO1xuICAgICAgICB9IGNhdGNoKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3JcbiAgICAgICAgICAgIHJldHVybiBjYWNoZWRTZXRUaW1lb3V0LmNhbGwodGhpcywgZnVuLCAwKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG59XG5mdW5jdGlvbiBydW5DbGVhclRpbWVvdXQobWFya2VyKSB7XG4gICAgaWYgKGNhY2hlZENsZWFyVGltZW91dCA9PT0gY2xlYXJUaW1lb3V0KSB7XG4gICAgICAgIC8vbm9ybWFsIGVudmlyb21lbnRzIGluIHNhbmUgc2l0dWF0aW9uc1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIC8vIGlmIGNsZWFyVGltZW91dCB3YXNuJ3QgYXZhaWxhYmxlIGJ1dCB3YXMgbGF0dGVyIGRlZmluZWRcbiAgICBpZiAoKGNhY2hlZENsZWFyVGltZW91dCA9PT0gZGVmYXVsdENsZWFyVGltZW91dCB8fCAhY2FjaGVkQ2xlYXJUaW1lb3V0KSAmJiBjbGVhclRpbWVvdXQpIHtcbiAgICAgICAgY2FjaGVkQ2xlYXJUaW1lb3V0ID0gY2xlYXJUaW1lb3V0O1xuICAgICAgICByZXR1cm4gY2xlYXJUaW1lb3V0KG1hcmtlcik7XG4gICAgfVxuICAgIHRyeSB7XG4gICAgICAgIC8vIHdoZW4gd2hlbiBzb21lYm9keSBoYXMgc2NyZXdlZCB3aXRoIHNldFRpbWVvdXQgYnV0IG5vIEkuRS4gbWFkZG5lc3NcbiAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dChtYXJrZXIpO1xuICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgLy8gV2hlbiB3ZSBhcmUgaW4gSS5FLiBidXQgdGhlIHNjcmlwdCBoYXMgYmVlbiBldmFsZWQgc28gSS5FLiBkb2Vzbid0ICB0cnVzdCB0aGUgZ2xvYmFsIG9iamVjdCB3aGVuIGNhbGxlZCBub3JtYWxseVxuICAgICAgICAgICAgcmV0dXJuIGNhY2hlZENsZWFyVGltZW91dC5jYWxsKG51bGwsIG1hcmtlcik7XG4gICAgICAgIH0gY2F0Y2ggKGUpe1xuICAgICAgICAgICAgLy8gc2FtZSBhcyBhYm92ZSBidXQgd2hlbiBpdCdzIGEgdmVyc2lvbiBvZiBJLkUuIHRoYXQgbXVzdCBoYXZlIHRoZSBnbG9iYWwgb2JqZWN0IGZvciAndGhpcycsIGhvcGZ1bGx5IG91ciBjb250ZXh0IGNvcnJlY3Qgb3RoZXJ3aXNlIGl0IHdpbGwgdGhyb3cgYSBnbG9iYWwgZXJyb3IuXG4gICAgICAgICAgICAvLyBTb21lIHZlcnNpb25zIG9mIEkuRS4gaGF2ZSBkaWZmZXJlbnQgcnVsZXMgZm9yIGNsZWFyVGltZW91dCB2cyBzZXRUaW1lb3V0XG4gICAgICAgICAgICByZXR1cm4gY2FjaGVkQ2xlYXJUaW1lb3V0LmNhbGwodGhpcywgbWFya2VyKTtcbiAgICAgICAgfVxuICAgIH1cblxuXG5cbn1cbnZhciBxdWV1ZSA9IFtdO1xudmFyIGRyYWluaW5nID0gZmFsc2U7XG52YXIgY3VycmVudFF1ZXVlO1xudmFyIHF1ZXVlSW5kZXggPSAtMTtcblxuZnVuY3Rpb24gY2xlYW5VcE5leHRUaWNrKCkge1xuICAgIGlmICghZHJhaW5pbmcgfHwgIWN1cnJlbnRRdWV1ZSkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGRyYWluaW5nID0gZmFsc2U7XG4gICAgaWYgKGN1cnJlbnRRdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgcXVldWUgPSBjdXJyZW50UXVldWUuY29uY2F0KHF1ZXVlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgfVxuICAgIGlmIChxdWV1ZS5sZW5ndGgpIHtcbiAgICAgICAgZHJhaW5RdWV1ZSgpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZHJhaW5RdWV1ZSgpIHtcbiAgICBpZiAoZHJhaW5pbmcpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB2YXIgdGltZW91dCA9IHJ1blRpbWVvdXQoY2xlYW5VcE5leHRUaWNrKTtcbiAgICBkcmFpbmluZyA9IHRydWU7XG5cbiAgICB2YXIgbGVuID0gcXVldWUubGVuZ3RoO1xuICAgIHdoaWxlKGxlbikge1xuICAgICAgICBjdXJyZW50UXVldWUgPSBxdWV1ZTtcbiAgICAgICAgcXVldWUgPSBbXTtcbiAgICAgICAgd2hpbGUgKCsrcXVldWVJbmRleCA8IGxlbikge1xuICAgICAgICAgICAgaWYgKGN1cnJlbnRRdWV1ZSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRRdWV1ZVtxdWV1ZUluZGV4XS5ydW4oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBxdWV1ZUluZGV4ID0gLTE7XG4gICAgICAgIGxlbiA9IHF1ZXVlLmxlbmd0aDtcbiAgICB9XG4gICAgY3VycmVudFF1ZXVlID0gbnVsbDtcbiAgICBkcmFpbmluZyA9IGZhbHNlO1xuICAgIHJ1bkNsZWFyVGltZW91dCh0aW1lb3V0KTtcbn1cblxucHJvY2Vzcy5uZXh0VGljayA9IGZ1bmN0aW9uIChmdW4pIHtcbiAgICB2YXIgYXJncyA9IG5ldyBBcnJheShhcmd1bWVudHMubGVuZ3RoIC0gMSk7XG4gICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAxKSB7XG4gICAgICAgIGZvciAodmFyIGkgPSAxOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBxdWV1ZS5wdXNoKG5ldyBJdGVtKGZ1biwgYXJncykpO1xuICAgIGlmIChxdWV1ZS5sZW5ndGggPT09IDEgJiYgIWRyYWluaW5nKSB7XG4gICAgICAgIHJ1blRpbWVvdXQoZHJhaW5RdWV1ZSk7XG4gICAgfVxufTtcblxuLy8gdjggbGlrZXMgcHJlZGljdGlibGUgb2JqZWN0c1xuZnVuY3Rpb24gSXRlbShmdW4sIGFycmF5KSB7XG4gICAgdGhpcy5mdW4gPSBmdW47XG4gICAgdGhpcy5hcnJheSA9IGFycmF5O1xufVxuSXRlbS5wcm90b3R5cGUucnVuID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZnVuLmFwcGx5KG51bGwsIHRoaXMuYXJyYXkpO1xufTtcbnByb2Nlc3MudGl0bGUgPSAnYnJvd3Nlcic7XG5wcm9jZXNzLmJyb3dzZXIgPSB0cnVlO1xucHJvY2Vzcy5lbnYgPSB7fTtcbnByb2Nlc3MuYXJndiA9IFtdO1xucHJvY2Vzcy52ZXJzaW9uID0gJyc7IC8vIGVtcHR5IHN0cmluZyB0byBhdm9pZCByZWdleHAgaXNzdWVzXG5wcm9jZXNzLnZlcnNpb25zID0ge307XG5cbmZ1bmN0aW9uIG5vb3AoKSB7fVxuXG5wcm9jZXNzLm9uID0gbm9vcDtcbnByb2Nlc3MuYWRkTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5vbmNlID0gbm9vcDtcbnByb2Nlc3Mub2ZmID0gbm9vcDtcbnByb2Nlc3MucmVtb3ZlTGlzdGVuZXIgPSBub29wO1xucHJvY2Vzcy5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBub29wO1xucHJvY2Vzcy5lbWl0ID0gbm9vcDtcblxucHJvY2Vzcy5iaW5kaW5nID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuYmluZGluZyBpcyBub3Qgc3VwcG9ydGVkJyk7XG59O1xuXG5wcm9jZXNzLmN3ZCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuICcvJyB9O1xucHJvY2Vzcy5jaGRpciA9IGZ1bmN0aW9uIChkaXIpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ3Byb2Nlc3MuY2hkaXIgaXMgbm90IHN1cHBvcnRlZCcpO1xufTtcbnByb2Nlc3MudW1hc2sgPSBmdW5jdGlvbigpIHsgcmV0dXJuIDA7IH07XG4iLCJpZiAodHlwZW9mIE9iamVjdC5jcmVhdGUgPT09ICdmdW5jdGlvbicpIHtcbiAgLy8gaW1wbGVtZW50YXRpb24gZnJvbSBzdGFuZGFyZCBub2RlLmpzICd1dGlsJyBtb2R1bGVcbiAgbW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiBpbmhlcml0cyhjdG9yLCBzdXBlckN0b3IpIHtcbiAgICBjdG9yLnN1cGVyXyA9IHN1cGVyQ3RvclxuICAgIGN0b3IucHJvdG90eXBlID0gT2JqZWN0LmNyZWF0ZShzdXBlckN0b3IucHJvdG90eXBlLCB7XG4gICAgICBjb25zdHJ1Y3Rvcjoge1xuICAgICAgICB2YWx1ZTogY3RvcixcbiAgICAgICAgZW51bWVyYWJsZTogZmFsc2UsXG4gICAgICAgIHdyaXRhYmxlOiB0cnVlLFxuICAgICAgICBjb25maWd1cmFibGU6IHRydWVcbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcbn0gZWxzZSB7XG4gIC8vIG9sZCBzY2hvb2wgc2hpbSBmb3Igb2xkIGJyb3dzZXJzXG4gIG1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaW5oZXJpdHMoY3Rvciwgc3VwZXJDdG9yKSB7XG4gICAgY3Rvci5zdXBlcl8gPSBzdXBlckN0b3JcbiAgICB2YXIgVGVtcEN0b3IgPSBmdW5jdGlvbiAoKSB7fVxuICAgIFRlbXBDdG9yLnByb3RvdHlwZSA9IHN1cGVyQ3Rvci5wcm90b3R5cGVcbiAgICBjdG9yLnByb3RvdHlwZSA9IG5ldyBUZW1wQ3RvcigpXG4gICAgY3Rvci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBjdG9yXG4gIH1cbn1cbiIsIm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaXNCdWZmZXIoYXJnKSB7XG4gIHJldHVybiBhcmcgJiYgdHlwZW9mIGFyZyA9PT0gJ29iamVjdCdcbiAgICAmJiB0eXBlb2YgYXJnLmNvcHkgPT09ICdmdW5jdGlvbidcbiAgICAmJiB0eXBlb2YgYXJnLmZpbGwgPT09ICdmdW5jdGlvbidcbiAgICAmJiB0eXBlb2YgYXJnLnJlYWRVSW50OCA9PT0gJ2Z1bmN0aW9uJztcbn0iLCIvLyBDb3B5cmlnaHQgSm95ZW50LCBJbmMuIGFuZCBvdGhlciBOb2RlIGNvbnRyaWJ1dG9ycy5cbi8vXG4vLyBQZXJtaXNzaW9uIGlzIGhlcmVieSBncmFudGVkLCBmcmVlIG9mIGNoYXJnZSwgdG8gYW55IHBlcnNvbiBvYnRhaW5pbmcgYVxuLy8gY29weSBvZiB0aGlzIHNvZnR3YXJlIGFuZCBhc3NvY2lhdGVkIGRvY3VtZW50YXRpb24gZmlsZXMgKHRoZVxuLy8gXCJTb2Z0d2FyZVwiKSwgdG8gZGVhbCBpbiB0aGUgU29mdHdhcmUgd2l0aG91dCByZXN0cmljdGlvbiwgaW5jbHVkaW5nXG4vLyB3aXRob3V0IGxpbWl0YXRpb24gdGhlIHJpZ2h0cyB0byB1c2UsIGNvcHksIG1vZGlmeSwgbWVyZ2UsIHB1Ymxpc2gsXG4vLyBkaXN0cmlidXRlLCBzdWJsaWNlbnNlLCBhbmQvb3Igc2VsbCBjb3BpZXMgb2YgdGhlIFNvZnR3YXJlLCBhbmQgdG8gcGVybWl0XG4vLyBwZXJzb25zIHRvIHdob20gdGhlIFNvZnR3YXJlIGlzIGZ1cm5pc2hlZCB0byBkbyBzbywgc3ViamVjdCB0byB0aGVcbi8vIGZvbGxvd2luZyBjb25kaXRpb25zOlxuLy9cbi8vIFRoZSBhYm92ZSBjb3B5cmlnaHQgbm90aWNlIGFuZCB0aGlzIHBlcm1pc3Npb24gbm90aWNlIHNoYWxsIGJlIGluY2x1ZGVkXG4vLyBpbiBhbGwgY29waWVzIG9yIHN1YnN0YW50aWFsIHBvcnRpb25zIG9mIHRoZSBTb2Z0d2FyZS5cbi8vXG4vLyBUSEUgU09GVFdBUkUgSVMgUFJPVklERUQgXCJBUyBJU1wiLCBXSVRIT1VUIFdBUlJBTlRZIE9GIEFOWSBLSU5ELCBFWFBSRVNTXG4vLyBPUiBJTVBMSUVELCBJTkNMVURJTkcgQlVUIE5PVCBMSU1JVEVEIFRPIFRIRSBXQVJSQU5USUVTIE9GXG4vLyBNRVJDSEFOVEFCSUxJVFksIEZJVE5FU1MgRk9SIEEgUEFSVElDVUxBUiBQVVJQT1NFIEFORCBOT05JTkZSSU5HRU1FTlQuIElOXG4vLyBOTyBFVkVOVCBTSEFMTCBUSEUgQVVUSE9SUyBPUiBDT1BZUklHSFQgSE9MREVSUyBCRSBMSUFCTEUgRk9SIEFOWSBDTEFJTSxcbi8vIERBTUFHRVMgT1IgT1RIRVIgTElBQklMSVRZLCBXSEVUSEVSIElOIEFOIEFDVElPTiBPRiBDT05UUkFDVCwgVE9SVCBPUlxuLy8gT1RIRVJXSVNFLCBBUklTSU5HIEZST00sIE9VVCBPRiBPUiBJTiBDT05ORUNUSU9OIFdJVEggVEhFIFNPRlRXQVJFIE9SIFRIRVxuLy8gVVNFIE9SIE9USEVSIERFQUxJTkdTIElOIFRIRSBTT0ZUV0FSRS5cblxudmFyIGZvcm1hdFJlZ0V4cCA9IC8lW3NkaiVdL2c7XG5leHBvcnRzLmZvcm1hdCA9IGZ1bmN0aW9uKGYpIHtcbiAgaWYgKCFpc1N0cmluZyhmKSkge1xuICAgIHZhciBvYmplY3RzID0gW107XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIG9iamVjdHMucHVzaChpbnNwZWN0KGFyZ3VtZW50c1tpXSkpO1xuICAgIH1cbiAgICByZXR1cm4gb2JqZWN0cy5qb2luKCcgJyk7XG4gIH1cblxuICB2YXIgaSA9IDE7XG4gIHZhciBhcmdzID0gYXJndW1lbnRzO1xuICB2YXIgbGVuID0gYXJncy5sZW5ndGg7XG4gIHZhciBzdHIgPSBTdHJpbmcoZikucmVwbGFjZShmb3JtYXRSZWdFeHAsIGZ1bmN0aW9uKHgpIHtcbiAgICBpZiAoeCA9PT0gJyUlJykgcmV0dXJuICclJztcbiAgICBpZiAoaSA+PSBsZW4pIHJldHVybiB4O1xuICAgIHN3aXRjaCAoeCkge1xuICAgICAgY2FzZSAnJXMnOiByZXR1cm4gU3RyaW5nKGFyZ3NbaSsrXSk7XG4gICAgICBjYXNlICclZCc6IHJldHVybiBOdW1iZXIoYXJnc1tpKytdKTtcbiAgICAgIGNhc2UgJyVqJzpcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICByZXR1cm4gSlNPTi5zdHJpbmdpZnkoYXJnc1tpKytdKTtcbiAgICAgICAgfSBjYXRjaCAoXykge1xuICAgICAgICAgIHJldHVybiAnW0NpcmN1bGFyXSc7XG4gICAgICAgIH1cbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHJldHVybiB4O1xuICAgIH1cbiAgfSk7XG4gIGZvciAodmFyIHggPSBhcmdzW2ldOyBpIDwgbGVuOyB4ID0gYXJnc1srK2ldKSB7XG4gICAgaWYgKGlzTnVsbCh4KSB8fCAhaXNPYmplY3QoeCkpIHtcbiAgICAgIHN0ciArPSAnICcgKyB4O1xuICAgIH0gZWxzZSB7XG4gICAgICBzdHIgKz0gJyAnICsgaW5zcGVjdCh4KTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHN0cjtcbn07XG5cblxuLy8gTWFyayB0aGF0IGEgbWV0aG9kIHNob3VsZCBub3QgYmUgdXNlZC5cbi8vIFJldHVybnMgYSBtb2RpZmllZCBmdW5jdGlvbiB3aGljaCB3YXJucyBvbmNlIGJ5IGRlZmF1bHQuXG4vLyBJZiAtLW5vLWRlcHJlY2F0aW9uIGlzIHNldCwgdGhlbiBpdCBpcyBhIG5vLW9wLlxuZXhwb3J0cy5kZXByZWNhdGUgPSBmdW5jdGlvbihmbiwgbXNnKSB7XG4gIC8vIEFsbG93IGZvciBkZXByZWNhdGluZyB0aGluZ3MgaW4gdGhlIHByb2Nlc3Mgb2Ygc3RhcnRpbmcgdXAuXG4gIGlmIChpc1VuZGVmaW5lZChnbG9iYWwucHJvY2VzcykpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gZXhwb3J0cy5kZXByZWNhdGUoZm4sIG1zZykuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9O1xuICB9XG5cbiAgaWYgKHByb2Nlc3Mubm9EZXByZWNhdGlvbiA9PT0gdHJ1ZSkge1xuICAgIHJldHVybiBmbjtcbiAgfVxuXG4gIHZhciB3YXJuZWQgPSBmYWxzZTtcbiAgZnVuY3Rpb24gZGVwcmVjYXRlZCgpIHtcbiAgICBpZiAoIXdhcm5lZCkge1xuICAgICAgaWYgKHByb2Nlc3MudGhyb3dEZXByZWNhdGlvbikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IobXNnKTtcbiAgICAgIH0gZWxzZSBpZiAocHJvY2Vzcy50cmFjZURlcHJlY2F0aW9uKSB7XG4gICAgICAgIGNvbnNvbGUudHJhY2UobXNnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IobXNnKTtcbiAgICAgIH1cbiAgICAgIHdhcm5lZCA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmbi5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICB9XG5cbiAgcmV0dXJuIGRlcHJlY2F0ZWQ7XG59O1xuXG5cbnZhciBkZWJ1Z3MgPSB7fTtcbnZhciBkZWJ1Z0Vudmlyb247XG5leHBvcnRzLmRlYnVnbG9nID0gZnVuY3Rpb24oc2V0KSB7XG4gIGlmIChpc1VuZGVmaW5lZChkZWJ1Z0Vudmlyb24pKVxuICAgIGRlYnVnRW52aXJvbiA9IHByb2Nlc3MuZW52Lk5PREVfREVCVUcgfHwgJyc7XG4gIHNldCA9IHNldC50b1VwcGVyQ2FzZSgpO1xuICBpZiAoIWRlYnVnc1tzZXRdKSB7XG4gICAgaWYgKG5ldyBSZWdFeHAoJ1xcXFxiJyArIHNldCArICdcXFxcYicsICdpJykudGVzdChkZWJ1Z0Vudmlyb24pKSB7XG4gICAgICB2YXIgcGlkID0gcHJvY2Vzcy5waWQ7XG4gICAgICBkZWJ1Z3Nbc2V0XSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgbXNnID0gZXhwb3J0cy5mb3JtYXQuYXBwbHkoZXhwb3J0cywgYXJndW1lbnRzKTtcbiAgICAgICAgY29uc29sZS5lcnJvcignJXMgJWQ6ICVzJywgc2V0LCBwaWQsIG1zZyk7XG4gICAgICB9O1xuICAgIH0gZWxzZSB7XG4gICAgICBkZWJ1Z3Nbc2V0XSA9IGZ1bmN0aW9uKCkge307XG4gICAgfVxuICB9XG4gIHJldHVybiBkZWJ1Z3Nbc2V0XTtcbn07XG5cblxuLyoqXG4gKiBFY2hvcyB0aGUgdmFsdWUgb2YgYSB2YWx1ZS4gVHJ5cyB0byBwcmludCB0aGUgdmFsdWUgb3V0XG4gKiBpbiB0aGUgYmVzdCB3YXkgcG9zc2libGUgZ2l2ZW4gdGhlIGRpZmZlcmVudCB0eXBlcy5cbiAqXG4gKiBAcGFyYW0ge09iamVjdH0gb2JqIFRoZSBvYmplY3QgdG8gcHJpbnQgb3V0LlxuICogQHBhcmFtIHtPYmplY3R9IG9wdHMgT3B0aW9uYWwgb3B0aW9ucyBvYmplY3QgdGhhdCBhbHRlcnMgdGhlIG91dHB1dC5cbiAqL1xuLyogbGVnYWN5OiBvYmosIHNob3dIaWRkZW4sIGRlcHRoLCBjb2xvcnMqL1xuZnVuY3Rpb24gaW5zcGVjdChvYmosIG9wdHMpIHtcbiAgLy8gZGVmYXVsdCBvcHRpb25zXG4gIHZhciBjdHggPSB7XG4gICAgc2VlbjogW10sXG4gICAgc3R5bGl6ZTogc3R5bGl6ZU5vQ29sb3JcbiAgfTtcbiAgLy8gbGVnYWN5Li4uXG4gIGlmIChhcmd1bWVudHMubGVuZ3RoID49IDMpIGN0eC5kZXB0aCA9IGFyZ3VtZW50c1syXTtcbiAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPj0gNCkgY3R4LmNvbG9ycyA9IGFyZ3VtZW50c1szXTtcbiAgaWYgKGlzQm9vbGVhbihvcHRzKSkge1xuICAgIC8vIGxlZ2FjeS4uLlxuICAgIGN0eC5zaG93SGlkZGVuID0gb3B0cztcbiAgfSBlbHNlIGlmIChvcHRzKSB7XG4gICAgLy8gZ290IGFuIFwib3B0aW9uc1wiIG9iamVjdFxuICAgIGV4cG9ydHMuX2V4dGVuZChjdHgsIG9wdHMpO1xuICB9XG4gIC8vIHNldCBkZWZhdWx0IG9wdGlvbnNcbiAgaWYgKGlzVW5kZWZpbmVkKGN0eC5zaG93SGlkZGVuKSkgY3R4LnNob3dIaWRkZW4gPSBmYWxzZTtcbiAgaWYgKGlzVW5kZWZpbmVkKGN0eC5kZXB0aCkpIGN0eC5kZXB0aCA9IDI7XG4gIGlmIChpc1VuZGVmaW5lZChjdHguY29sb3JzKSkgY3R4LmNvbG9ycyA9IGZhbHNlO1xuICBpZiAoaXNVbmRlZmluZWQoY3R4LmN1c3RvbUluc3BlY3QpKSBjdHguY3VzdG9tSW5zcGVjdCA9IHRydWU7XG4gIGlmIChjdHguY29sb3JzKSBjdHguc3R5bGl6ZSA9IHN0eWxpemVXaXRoQ29sb3I7XG4gIHJldHVybiBmb3JtYXRWYWx1ZShjdHgsIG9iaiwgY3R4LmRlcHRoKTtcbn1cbmV4cG9ydHMuaW5zcGVjdCA9IGluc3BlY3Q7XG5cblxuLy8gaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9BTlNJX2VzY2FwZV9jb2RlI2dyYXBoaWNzXG5pbnNwZWN0LmNvbG9ycyA9IHtcbiAgJ2JvbGQnIDogWzEsIDIyXSxcbiAgJ2l0YWxpYycgOiBbMywgMjNdLFxuICAndW5kZXJsaW5lJyA6IFs0LCAyNF0sXG4gICdpbnZlcnNlJyA6IFs3LCAyN10sXG4gICd3aGl0ZScgOiBbMzcsIDM5XSxcbiAgJ2dyZXknIDogWzkwLCAzOV0sXG4gICdibGFjaycgOiBbMzAsIDM5XSxcbiAgJ2JsdWUnIDogWzM0LCAzOV0sXG4gICdjeWFuJyA6IFszNiwgMzldLFxuICAnZ3JlZW4nIDogWzMyLCAzOV0sXG4gICdtYWdlbnRhJyA6IFszNSwgMzldLFxuICAncmVkJyA6IFszMSwgMzldLFxuICAneWVsbG93JyA6IFszMywgMzldXG59O1xuXG4vLyBEb24ndCB1c2UgJ2JsdWUnIG5vdCB2aXNpYmxlIG9uIGNtZC5leGVcbmluc3BlY3Quc3R5bGVzID0ge1xuICAnc3BlY2lhbCc6ICdjeWFuJyxcbiAgJ251bWJlcic6ICd5ZWxsb3cnLFxuICAnYm9vbGVhbic6ICd5ZWxsb3cnLFxuICAndW5kZWZpbmVkJzogJ2dyZXknLFxuICAnbnVsbCc6ICdib2xkJyxcbiAgJ3N0cmluZyc6ICdncmVlbicsXG4gICdkYXRlJzogJ21hZ2VudGEnLFxuICAvLyBcIm5hbWVcIjogaW50ZW50aW9uYWxseSBub3Qgc3R5bGluZ1xuICAncmVnZXhwJzogJ3JlZCdcbn07XG5cblxuZnVuY3Rpb24gc3R5bGl6ZVdpdGhDb2xvcihzdHIsIHN0eWxlVHlwZSkge1xuICB2YXIgc3R5bGUgPSBpbnNwZWN0LnN0eWxlc1tzdHlsZVR5cGVdO1xuXG4gIGlmIChzdHlsZSkge1xuICAgIHJldHVybiAnXFx1MDAxYlsnICsgaW5zcGVjdC5jb2xvcnNbc3R5bGVdWzBdICsgJ20nICsgc3RyICtcbiAgICAgICAgICAgJ1xcdTAwMWJbJyArIGluc3BlY3QuY29sb3JzW3N0eWxlXVsxXSArICdtJztcbiAgfSBlbHNlIHtcbiAgICByZXR1cm4gc3RyO1xuICB9XG59XG5cblxuZnVuY3Rpb24gc3R5bGl6ZU5vQ29sb3Ioc3RyLCBzdHlsZVR5cGUpIHtcbiAgcmV0dXJuIHN0cjtcbn1cblxuXG5mdW5jdGlvbiBhcnJheVRvSGFzaChhcnJheSkge1xuICB2YXIgaGFzaCA9IHt9O1xuXG4gIGFycmF5LmZvckVhY2goZnVuY3Rpb24odmFsLCBpZHgpIHtcbiAgICBoYXNoW3ZhbF0gPSB0cnVlO1xuICB9KTtcblxuICByZXR1cm4gaGFzaDtcbn1cblxuXG5mdW5jdGlvbiBmb3JtYXRWYWx1ZShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMpIHtcbiAgLy8gUHJvdmlkZSBhIGhvb2sgZm9yIHVzZXItc3BlY2lmaWVkIGluc3BlY3QgZnVuY3Rpb25zLlxuICAvLyBDaGVjayB0aGF0IHZhbHVlIGlzIGFuIG9iamVjdCB3aXRoIGFuIGluc3BlY3QgZnVuY3Rpb24gb24gaXRcbiAgaWYgKGN0eC5jdXN0b21JbnNwZWN0ICYmXG4gICAgICB2YWx1ZSAmJlxuICAgICAgaXNGdW5jdGlvbih2YWx1ZS5pbnNwZWN0KSAmJlxuICAgICAgLy8gRmlsdGVyIG91dCB0aGUgdXRpbCBtb2R1bGUsIGl0J3MgaW5zcGVjdCBmdW5jdGlvbiBpcyBzcGVjaWFsXG4gICAgICB2YWx1ZS5pbnNwZWN0ICE9PSBleHBvcnRzLmluc3BlY3QgJiZcbiAgICAgIC8vIEFsc28gZmlsdGVyIG91dCBhbnkgcHJvdG90eXBlIG9iamVjdHMgdXNpbmcgdGhlIGNpcmN1bGFyIGNoZWNrLlxuICAgICAgISh2YWx1ZS5jb25zdHJ1Y3RvciAmJiB2YWx1ZS5jb25zdHJ1Y3Rvci5wcm90b3R5cGUgPT09IHZhbHVlKSkge1xuICAgIHZhciByZXQgPSB2YWx1ZS5pbnNwZWN0KHJlY3Vyc2VUaW1lcywgY3R4KTtcbiAgICBpZiAoIWlzU3RyaW5nKHJldCkpIHtcbiAgICAgIHJldCA9IGZvcm1hdFZhbHVlKGN0eCwgcmV0LCByZWN1cnNlVGltZXMpO1xuICAgIH1cbiAgICByZXR1cm4gcmV0O1xuICB9XG5cbiAgLy8gUHJpbWl0aXZlIHR5cGVzIGNhbm5vdCBoYXZlIHByb3BlcnRpZXNcbiAgdmFyIHByaW1pdGl2ZSA9IGZvcm1hdFByaW1pdGl2ZShjdHgsIHZhbHVlKTtcbiAgaWYgKHByaW1pdGl2ZSkge1xuICAgIHJldHVybiBwcmltaXRpdmU7XG4gIH1cblxuICAvLyBMb29rIHVwIHRoZSBrZXlzIG9mIHRoZSBvYmplY3QuXG4gIHZhciBrZXlzID0gT2JqZWN0LmtleXModmFsdWUpO1xuICB2YXIgdmlzaWJsZUtleXMgPSBhcnJheVRvSGFzaChrZXlzKTtcblxuICBpZiAoY3R4LnNob3dIaWRkZW4pIHtcbiAgICBrZXlzID0gT2JqZWN0LmdldE93blByb3BlcnR5TmFtZXModmFsdWUpO1xuICB9XG5cbiAgLy8gSUUgZG9lc24ndCBtYWtlIGVycm9yIGZpZWxkcyBub24tZW51bWVyYWJsZVxuICAvLyBodHRwOi8vbXNkbi5taWNyb3NvZnQuY29tL2VuLXVzL2xpYnJhcnkvaWUvZHd3NTJzYnQodj12cy45NCkuYXNweFxuICBpZiAoaXNFcnJvcih2YWx1ZSlcbiAgICAgICYmIChrZXlzLmluZGV4T2YoJ21lc3NhZ2UnKSA+PSAwIHx8IGtleXMuaW5kZXhPZignZGVzY3JpcHRpb24nKSA+PSAwKSkge1xuICAgIHJldHVybiBmb3JtYXRFcnJvcih2YWx1ZSk7XG4gIH1cblxuICAvLyBTb21lIHR5cGUgb2Ygb2JqZWN0IHdpdGhvdXQgcHJvcGVydGllcyBjYW4gYmUgc2hvcnRjdXR0ZWQuXG4gIGlmIChrZXlzLmxlbmd0aCA9PT0gMCkge1xuICAgIGlmIChpc0Z1bmN0aW9uKHZhbHVlKSkge1xuICAgICAgdmFyIG5hbWUgPSB2YWx1ZS5uYW1lID8gJzogJyArIHZhbHVlLm5hbWUgOiAnJztcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZSgnW0Z1bmN0aW9uJyArIG5hbWUgKyAnXScsICdzcGVjaWFsJyk7XG4gICAgfVxuICAgIGlmIChpc1JlZ0V4cCh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiBjdHguc3R5bGl6ZShSZWdFeHAucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwodmFsdWUpLCAncmVnZXhwJyk7XG4gICAgfVxuICAgIGlmIChpc0RhdGUodmFsdWUpKSB7XG4gICAgICByZXR1cm4gY3R4LnN0eWxpemUoRGF0ZS5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSksICdkYXRlJyk7XG4gICAgfVxuICAgIGlmIChpc0Vycm9yKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIGZvcm1hdEVycm9yKHZhbHVlKTtcbiAgICB9XG4gIH1cblxuICB2YXIgYmFzZSA9ICcnLCBhcnJheSA9IGZhbHNlLCBicmFjZXMgPSBbJ3snLCAnfSddO1xuXG4gIC8vIE1ha2UgQXJyYXkgc2F5IHRoYXQgdGhleSBhcmUgQXJyYXlcbiAgaWYgKGlzQXJyYXkodmFsdWUpKSB7XG4gICAgYXJyYXkgPSB0cnVlO1xuICAgIGJyYWNlcyA9IFsnWycsICddJ107XG4gIH1cblxuICAvLyBNYWtlIGZ1bmN0aW9ucyBzYXkgdGhhdCB0aGV5IGFyZSBmdW5jdGlvbnNcbiAgaWYgKGlzRnVuY3Rpb24odmFsdWUpKSB7XG4gICAgdmFyIG4gPSB2YWx1ZS5uYW1lID8gJzogJyArIHZhbHVlLm5hbWUgOiAnJztcbiAgICBiYXNlID0gJyBbRnVuY3Rpb24nICsgbiArICddJztcbiAgfVxuXG4gIC8vIE1ha2UgUmVnRXhwcyBzYXkgdGhhdCB0aGV5IGFyZSBSZWdFeHBzXG4gIGlmIChpc1JlZ0V4cCh2YWx1ZSkpIHtcbiAgICBiYXNlID0gJyAnICsgUmVnRXhwLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKTtcbiAgfVxuXG4gIC8vIE1ha2UgZGF0ZXMgd2l0aCBwcm9wZXJ0aWVzIGZpcnN0IHNheSB0aGUgZGF0ZVxuICBpZiAoaXNEYXRlKHZhbHVlKSkge1xuICAgIGJhc2UgPSAnICcgKyBEYXRlLnByb3RvdHlwZS50b1VUQ1N0cmluZy5jYWxsKHZhbHVlKTtcbiAgfVxuXG4gIC8vIE1ha2UgZXJyb3Igd2l0aCBtZXNzYWdlIGZpcnN0IHNheSB0aGUgZXJyb3JcbiAgaWYgKGlzRXJyb3IodmFsdWUpKSB7XG4gICAgYmFzZSA9ICcgJyArIGZvcm1hdEVycm9yKHZhbHVlKTtcbiAgfVxuXG4gIGlmIChrZXlzLmxlbmd0aCA9PT0gMCAmJiAoIWFycmF5IHx8IHZhbHVlLmxlbmd0aCA9PSAwKSkge1xuICAgIHJldHVybiBicmFjZXNbMF0gKyBiYXNlICsgYnJhY2VzWzFdO1xuICB9XG5cbiAgaWYgKHJlY3Vyc2VUaW1lcyA8IDApIHtcbiAgICBpZiAoaXNSZWdFeHAodmFsdWUpKSB7XG4gICAgICByZXR1cm4gY3R4LnN0eWxpemUoUmVnRXhwLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKSwgJ3JlZ2V4cCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gY3R4LnN0eWxpemUoJ1tPYmplY3RdJywgJ3NwZWNpYWwnKTtcbiAgICB9XG4gIH1cblxuICBjdHguc2Vlbi5wdXNoKHZhbHVlKTtcblxuICB2YXIgb3V0cHV0O1xuICBpZiAoYXJyYXkpIHtcbiAgICBvdXRwdXQgPSBmb3JtYXRBcnJheShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMsIHZpc2libGVLZXlzLCBrZXlzKTtcbiAgfSBlbHNlIHtcbiAgICBvdXRwdXQgPSBrZXlzLm1hcChmdW5jdGlvbihrZXkpIHtcbiAgICAgIHJldHVybiBmb3JtYXRQcm9wZXJ0eShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMsIHZpc2libGVLZXlzLCBrZXksIGFycmF5KTtcbiAgICB9KTtcbiAgfVxuXG4gIGN0eC5zZWVuLnBvcCgpO1xuXG4gIHJldHVybiByZWR1Y2VUb1NpbmdsZVN0cmluZyhvdXRwdXQsIGJhc2UsIGJyYWNlcyk7XG59XG5cblxuZnVuY3Rpb24gZm9ybWF0UHJpbWl0aXZlKGN0eCwgdmFsdWUpIHtcbiAgaWYgKGlzVW5kZWZpbmVkKHZhbHVlKSlcbiAgICByZXR1cm4gY3R4LnN0eWxpemUoJ3VuZGVmaW5lZCcsICd1bmRlZmluZWQnKTtcbiAgaWYgKGlzU3RyaW5nKHZhbHVlKSkge1xuICAgIHZhciBzaW1wbGUgPSAnXFwnJyArIEpTT04uc3RyaW5naWZ5KHZhbHVlKS5yZXBsYWNlKC9eXCJ8XCIkL2csICcnKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoLycvZywgXCJcXFxcJ1wiKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnJlcGxhY2UoL1xcXFxcIi9nLCAnXCInKSArICdcXCcnO1xuICAgIHJldHVybiBjdHguc3R5bGl6ZShzaW1wbGUsICdzdHJpbmcnKTtcbiAgfVxuICBpZiAoaXNOdW1iZXIodmFsdWUpKVxuICAgIHJldHVybiBjdHguc3R5bGl6ZSgnJyArIHZhbHVlLCAnbnVtYmVyJyk7XG4gIGlmIChpc0Jvb2xlYW4odmFsdWUpKVxuICAgIHJldHVybiBjdHguc3R5bGl6ZSgnJyArIHZhbHVlLCAnYm9vbGVhbicpO1xuICAvLyBGb3Igc29tZSByZWFzb24gdHlwZW9mIG51bGwgaXMgXCJvYmplY3RcIiwgc28gc3BlY2lhbCBjYXNlIGhlcmUuXG4gIGlmIChpc051bGwodmFsdWUpKVxuICAgIHJldHVybiBjdHguc3R5bGl6ZSgnbnVsbCcsICdudWxsJyk7XG59XG5cblxuZnVuY3Rpb24gZm9ybWF0RXJyb3IodmFsdWUpIHtcbiAgcmV0dXJuICdbJyArIEVycm9yLnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHZhbHVlKSArICddJztcbn1cblxuXG5mdW5jdGlvbiBmb3JtYXRBcnJheShjdHgsIHZhbHVlLCByZWN1cnNlVGltZXMsIHZpc2libGVLZXlzLCBrZXlzKSB7XG4gIHZhciBvdXRwdXQgPSBbXTtcbiAgZm9yICh2YXIgaSA9IDAsIGwgPSB2YWx1ZS5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICBpZiAoaGFzT3duUHJvcGVydHkodmFsdWUsIFN0cmluZyhpKSkpIHtcbiAgICAgIG91dHB1dC5wdXNoKGZvcm1hdFByb3BlcnR5KGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcywgdmlzaWJsZUtleXMsXG4gICAgICAgICAgU3RyaW5nKGkpLCB0cnVlKSk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG91dHB1dC5wdXNoKCcnKTtcbiAgICB9XG4gIH1cbiAga2V5cy5mb3JFYWNoKGZ1bmN0aW9uKGtleSkge1xuICAgIGlmICgha2V5Lm1hdGNoKC9eXFxkKyQvKSkge1xuICAgICAgb3V0cHV0LnB1c2goZm9ybWF0UHJvcGVydHkoY3R4LCB2YWx1ZSwgcmVjdXJzZVRpbWVzLCB2aXNpYmxlS2V5cyxcbiAgICAgICAgICBrZXksIHRydWUpKTtcbiAgICB9XG4gIH0pO1xuICByZXR1cm4gb3V0cHV0O1xufVxuXG5cbmZ1bmN0aW9uIGZvcm1hdFByb3BlcnR5KGN0eCwgdmFsdWUsIHJlY3Vyc2VUaW1lcywgdmlzaWJsZUtleXMsIGtleSwgYXJyYXkpIHtcbiAgdmFyIG5hbWUsIHN0ciwgZGVzYztcbiAgZGVzYyA9IE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3IodmFsdWUsIGtleSkgfHwgeyB2YWx1ZTogdmFsdWVba2V5XSB9O1xuICBpZiAoZGVzYy5nZXQpIHtcbiAgICBpZiAoZGVzYy5zZXQpIHtcbiAgICAgIHN0ciA9IGN0eC5zdHlsaXplKCdbR2V0dGVyL1NldHRlcl0nLCAnc3BlY2lhbCcpO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdHIgPSBjdHguc3R5bGl6ZSgnW0dldHRlcl0nLCAnc3BlY2lhbCcpO1xuICAgIH1cbiAgfSBlbHNlIHtcbiAgICBpZiAoZGVzYy5zZXQpIHtcbiAgICAgIHN0ciA9IGN0eC5zdHlsaXplKCdbU2V0dGVyXScsICdzcGVjaWFsJyk7XG4gICAgfVxuICB9XG4gIGlmICghaGFzT3duUHJvcGVydHkodmlzaWJsZUtleXMsIGtleSkpIHtcbiAgICBuYW1lID0gJ1snICsga2V5ICsgJ10nO1xuICB9XG4gIGlmICghc3RyKSB7XG4gICAgaWYgKGN0eC5zZWVuLmluZGV4T2YoZGVzYy52YWx1ZSkgPCAwKSB7XG4gICAgICBpZiAoaXNOdWxsKHJlY3Vyc2VUaW1lcykpIHtcbiAgICAgICAgc3RyID0gZm9ybWF0VmFsdWUoY3R4LCBkZXNjLnZhbHVlLCBudWxsKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHN0ciA9IGZvcm1hdFZhbHVlKGN0eCwgZGVzYy52YWx1ZSwgcmVjdXJzZVRpbWVzIC0gMSk7XG4gICAgICB9XG4gICAgICBpZiAoc3RyLmluZGV4T2YoJ1xcbicpID4gLTEpIHtcbiAgICAgICAgaWYgKGFycmF5KSB7XG4gICAgICAgICAgc3RyID0gc3RyLnNwbGl0KCdcXG4nKS5tYXAoZnVuY3Rpb24obGluZSkge1xuICAgICAgICAgICAgcmV0dXJuICcgICcgKyBsaW5lO1xuICAgICAgICAgIH0pLmpvaW4oJ1xcbicpLnN1YnN0cigyKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzdHIgPSAnXFxuJyArIHN0ci5zcGxpdCgnXFxuJykubWFwKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgICAgIHJldHVybiAnICAgJyArIGxpbmU7XG4gICAgICAgICAgfSkuam9pbignXFxuJyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgc3RyID0gY3R4LnN0eWxpemUoJ1tDaXJjdWxhcl0nLCAnc3BlY2lhbCcpO1xuICAgIH1cbiAgfVxuICBpZiAoaXNVbmRlZmluZWQobmFtZSkpIHtcbiAgICBpZiAoYXJyYXkgJiYga2V5Lm1hdGNoKC9eXFxkKyQvKSkge1xuICAgICAgcmV0dXJuIHN0cjtcbiAgICB9XG4gICAgbmFtZSA9IEpTT04uc3RyaW5naWZ5KCcnICsga2V5KTtcbiAgICBpZiAobmFtZS5tYXRjaCgvXlwiKFthLXpBLVpfXVthLXpBLVpfMC05XSopXCIkLykpIHtcbiAgICAgIG5hbWUgPSBuYW1lLnN1YnN0cigxLCBuYW1lLmxlbmd0aCAtIDIpO1xuICAgICAgbmFtZSA9IGN0eC5zdHlsaXplKG5hbWUsICduYW1lJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIG5hbWUgPSBuYW1lLnJlcGxhY2UoLycvZywgXCJcXFxcJ1wiKVxuICAgICAgICAgICAgICAgICAucmVwbGFjZSgvXFxcXFwiL2csICdcIicpXG4gICAgICAgICAgICAgICAgIC5yZXBsYWNlKC8oXlwifFwiJCkvZywgXCInXCIpO1xuICAgICAgbmFtZSA9IGN0eC5zdHlsaXplKG5hbWUsICdzdHJpbmcnKTtcbiAgICB9XG4gIH1cblxuICByZXR1cm4gbmFtZSArICc6ICcgKyBzdHI7XG59XG5cblxuZnVuY3Rpb24gcmVkdWNlVG9TaW5nbGVTdHJpbmcob3V0cHV0LCBiYXNlLCBicmFjZXMpIHtcbiAgdmFyIG51bUxpbmVzRXN0ID0gMDtcbiAgdmFyIGxlbmd0aCA9IG91dHB1dC5yZWR1Y2UoZnVuY3Rpb24ocHJldiwgY3VyKSB7XG4gICAgbnVtTGluZXNFc3QrKztcbiAgICBpZiAoY3VyLmluZGV4T2YoJ1xcbicpID49IDApIG51bUxpbmVzRXN0Kys7XG4gICAgcmV0dXJuIHByZXYgKyBjdXIucmVwbGFjZSgvXFx1MDAxYlxcW1xcZFxcZD9tL2csICcnKS5sZW5ndGggKyAxO1xuICB9LCAwKTtcblxuICBpZiAobGVuZ3RoID4gNjApIHtcbiAgICByZXR1cm4gYnJhY2VzWzBdICtcbiAgICAgICAgICAgKGJhc2UgPT09ICcnID8gJycgOiBiYXNlICsgJ1xcbiAnKSArXG4gICAgICAgICAgICcgJyArXG4gICAgICAgICAgIG91dHB1dC5qb2luKCcsXFxuICAnKSArXG4gICAgICAgICAgICcgJyArXG4gICAgICAgICAgIGJyYWNlc1sxXTtcbiAgfVxuXG4gIHJldHVybiBicmFjZXNbMF0gKyBiYXNlICsgJyAnICsgb3V0cHV0LmpvaW4oJywgJykgKyAnICcgKyBicmFjZXNbMV07XG59XG5cblxuLy8gTk9URTogVGhlc2UgdHlwZSBjaGVja2luZyBmdW5jdGlvbnMgaW50ZW50aW9uYWxseSBkb24ndCB1c2UgYGluc3RhbmNlb2ZgXG4vLyBiZWNhdXNlIGl0IGlzIGZyYWdpbGUgYW5kIGNhbiBiZSBlYXNpbHkgZmFrZWQgd2l0aCBgT2JqZWN0LmNyZWF0ZSgpYC5cbmZ1bmN0aW9uIGlzQXJyYXkoYXIpIHtcbiAgcmV0dXJuIEFycmF5LmlzQXJyYXkoYXIpO1xufVxuZXhwb3J0cy5pc0FycmF5ID0gaXNBcnJheTtcblxuZnVuY3Rpb24gaXNCb29sZWFuKGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ2Jvb2xlYW4nO1xufVxuZXhwb3J0cy5pc0Jvb2xlYW4gPSBpc0Jvb2xlYW47XG5cbmZ1bmN0aW9uIGlzTnVsbChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gbnVsbDtcbn1cbmV4cG9ydHMuaXNOdWxsID0gaXNOdWxsO1xuXG5mdW5jdGlvbiBpc051bGxPclVuZGVmaW5lZChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PSBudWxsO1xufVxuZXhwb3J0cy5pc051bGxPclVuZGVmaW5lZCA9IGlzTnVsbE9yVW5kZWZpbmVkO1xuXG5mdW5jdGlvbiBpc051bWJlcihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdudW1iZXInO1xufVxuZXhwb3J0cy5pc051bWJlciA9IGlzTnVtYmVyO1xuXG5mdW5jdGlvbiBpc1N0cmluZyhhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnO1xufVxuZXhwb3J0cy5pc1N0cmluZyA9IGlzU3RyaW5nO1xuXG5mdW5jdGlvbiBpc1N5bWJvbChhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdzeW1ib2wnO1xufVxuZXhwb3J0cy5pc1N5bWJvbCA9IGlzU3ltYm9sO1xuXG5mdW5jdGlvbiBpc1VuZGVmaW5lZChhcmcpIHtcbiAgcmV0dXJuIGFyZyA9PT0gdm9pZCAwO1xufVxuZXhwb3J0cy5pc1VuZGVmaW5lZCA9IGlzVW5kZWZpbmVkO1xuXG5mdW5jdGlvbiBpc1JlZ0V4cChyZSkge1xuICByZXR1cm4gaXNPYmplY3QocmUpICYmIG9iamVjdFRvU3RyaW5nKHJlKSA9PT0gJ1tvYmplY3QgUmVnRXhwXSc7XG59XG5leHBvcnRzLmlzUmVnRXhwID0gaXNSZWdFeHA7XG5cbmZ1bmN0aW9uIGlzT2JqZWN0KGFyZykge1xuICByZXR1cm4gdHlwZW9mIGFyZyA9PT0gJ29iamVjdCcgJiYgYXJnICE9PSBudWxsO1xufVxuZXhwb3J0cy5pc09iamVjdCA9IGlzT2JqZWN0O1xuXG5mdW5jdGlvbiBpc0RhdGUoZCkge1xuICByZXR1cm4gaXNPYmplY3QoZCkgJiYgb2JqZWN0VG9TdHJpbmcoZCkgPT09ICdbb2JqZWN0IERhdGVdJztcbn1cbmV4cG9ydHMuaXNEYXRlID0gaXNEYXRlO1xuXG5mdW5jdGlvbiBpc0Vycm9yKGUpIHtcbiAgcmV0dXJuIGlzT2JqZWN0KGUpICYmXG4gICAgICAob2JqZWN0VG9TdHJpbmcoZSkgPT09ICdbb2JqZWN0IEVycm9yXScgfHwgZSBpbnN0YW5jZW9mIEVycm9yKTtcbn1cbmV4cG9ydHMuaXNFcnJvciA9IGlzRXJyb3I7XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24oYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnZnVuY3Rpb24nO1xufVxuZXhwb3J0cy5pc0Z1bmN0aW9uID0gaXNGdW5jdGlvbjtcblxuZnVuY3Rpb24gaXNQcmltaXRpdmUoYXJnKSB7XG4gIHJldHVybiBhcmcgPT09IG51bGwgfHxcbiAgICAgICAgIHR5cGVvZiBhcmcgPT09ICdib29sZWFuJyB8fFxuICAgICAgICAgdHlwZW9mIGFyZyA9PT0gJ251bWJlcicgfHxcbiAgICAgICAgIHR5cGVvZiBhcmcgPT09ICdzdHJpbmcnIHx8XG4gICAgICAgICB0eXBlb2YgYXJnID09PSAnc3ltYm9sJyB8fCAgLy8gRVM2IHN5bWJvbFxuICAgICAgICAgdHlwZW9mIGFyZyA9PT0gJ3VuZGVmaW5lZCc7XG59XG5leHBvcnRzLmlzUHJpbWl0aXZlID0gaXNQcmltaXRpdmU7XG5cbmV4cG9ydHMuaXNCdWZmZXIgPSByZXF1aXJlKCcuL3N1cHBvcnQvaXNCdWZmZXInKTtcblxuZnVuY3Rpb24gb2JqZWN0VG9TdHJpbmcobykge1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG8pO1xufVxuXG5cbmZ1bmN0aW9uIHBhZChuKSB7XG4gIHJldHVybiBuIDwgMTAgPyAnMCcgKyBuLnRvU3RyaW5nKDEwKSA6IG4udG9TdHJpbmcoMTApO1xufVxuXG5cbnZhciBtb250aHMgPSBbJ0phbicsICdGZWInLCAnTWFyJywgJ0FwcicsICdNYXknLCAnSnVuJywgJ0p1bCcsICdBdWcnLCAnU2VwJyxcbiAgICAgICAgICAgICAgJ09jdCcsICdOb3YnLCAnRGVjJ107XG5cbi8vIDI2IEZlYiAxNjoxOTozNFxuZnVuY3Rpb24gdGltZXN0YW1wKCkge1xuICB2YXIgZCA9IG5ldyBEYXRlKCk7XG4gIHZhciB0aW1lID0gW3BhZChkLmdldEhvdXJzKCkpLFxuICAgICAgICAgICAgICBwYWQoZC5nZXRNaW51dGVzKCkpLFxuICAgICAgICAgICAgICBwYWQoZC5nZXRTZWNvbmRzKCkpXS5qb2luKCc6Jyk7XG4gIHJldHVybiBbZC5nZXREYXRlKCksIG1vbnRoc1tkLmdldE1vbnRoKCldLCB0aW1lXS5qb2luKCcgJyk7XG59XG5cblxuLy8gbG9nIGlzIGp1c3QgYSB0aGluIHdyYXBwZXIgdG8gY29uc29sZS5sb2cgdGhhdCBwcmVwZW5kcyBhIHRpbWVzdGFtcFxuZXhwb3J0cy5sb2cgPSBmdW5jdGlvbigpIHtcbiAgY29uc29sZS5sb2coJyVzIC0gJXMnLCB0aW1lc3RhbXAoKSwgZXhwb3J0cy5mb3JtYXQuYXBwbHkoZXhwb3J0cywgYXJndW1lbnRzKSk7XG59O1xuXG5cbi8qKlxuICogSW5oZXJpdCB0aGUgcHJvdG90eXBlIG1ldGhvZHMgZnJvbSBvbmUgY29uc3RydWN0b3IgaW50byBhbm90aGVyLlxuICpcbiAqIFRoZSBGdW5jdGlvbi5wcm90b3R5cGUuaW5oZXJpdHMgZnJvbSBsYW5nLmpzIHJld3JpdHRlbiBhcyBhIHN0YW5kYWxvbmVcbiAqIGZ1bmN0aW9uIChub3Qgb24gRnVuY3Rpb24ucHJvdG90eXBlKS4gTk9URTogSWYgdGhpcyBmaWxlIGlzIHRvIGJlIGxvYWRlZFxuICogZHVyaW5nIGJvb3RzdHJhcHBpbmcgdGhpcyBmdW5jdGlvbiBuZWVkcyB0byBiZSByZXdyaXR0ZW4gdXNpbmcgc29tZSBuYXRpdmVcbiAqIGZ1bmN0aW9ucyBhcyBwcm90b3R5cGUgc2V0dXAgdXNpbmcgbm9ybWFsIEphdmFTY3JpcHQgZG9lcyBub3Qgd29yayBhc1xuICogZXhwZWN0ZWQgZHVyaW5nIGJvb3RzdHJhcHBpbmcgKHNlZSBtaXJyb3IuanMgaW4gcjExNDkwMykuXG4gKlxuICogQHBhcmFtIHtmdW5jdGlvbn0gY3RvciBDb25zdHJ1Y3RvciBmdW5jdGlvbiB3aGljaCBuZWVkcyB0byBpbmhlcml0IHRoZVxuICogICAgIHByb3RvdHlwZS5cbiAqIEBwYXJhbSB7ZnVuY3Rpb259IHN1cGVyQ3RvciBDb25zdHJ1Y3RvciBmdW5jdGlvbiB0byBpbmhlcml0IHByb3RvdHlwZSBmcm9tLlxuICovXG5leHBvcnRzLmluaGVyaXRzID0gcmVxdWlyZSgnaW5oZXJpdHMnKTtcblxuZXhwb3J0cy5fZXh0ZW5kID0gZnVuY3Rpb24ob3JpZ2luLCBhZGQpIHtcbiAgLy8gRG9uJ3QgZG8gYW55dGhpbmcgaWYgYWRkIGlzbid0IGFuIG9iamVjdFxuICBpZiAoIWFkZCB8fCAhaXNPYmplY3QoYWRkKSkgcmV0dXJuIG9yaWdpbjtcblxuICB2YXIga2V5cyA9IE9iamVjdC5rZXlzKGFkZCk7XG4gIHZhciBpID0ga2V5cy5sZW5ndGg7XG4gIHdoaWxlIChpLS0pIHtcbiAgICBvcmlnaW5ba2V5c1tpXV0gPSBhZGRba2V5c1tpXV07XG4gIH1cbiAgcmV0dXJuIG9yaWdpbjtcbn07XG5cbmZ1bmN0aW9uIGhhc093blByb3BlcnR5KG9iaiwgcHJvcCkge1xuICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eS5jYWxsKG9iaiwgcHJvcCk7XG59XG4iLCIvKipcbiAqIEBkZXBlbmQgdGltZXNfaW5fd29yZHMuanNcbiAqIEBkZXBlbmQgdXRpbC9jb3JlLmpzXG4gKiBAZGVwZW5kIG1hdGNoLmpzXG4gKiBAZGVwZW5kIGZvcm1hdC5qc1xuICovXG4vKipcbiAqIEFzc2VydGlvbnMgbWF0Y2hpbmcgdGhlIHRlc3Qgc3B5IHJldHJpZXZhbCBpbnRlcmZhY2UuXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMyBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCwgZ2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICB2YXIgc2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIHZhciBhc3NlcnQ7XG5cbiAgICAgICAgZnVuY3Rpb24gdmVyaWZ5SXNTdHViKCkge1xuICAgICAgICAgICAgdmFyIG1ldGhvZDtcblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBhcmd1bWVudHMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgbWV0aG9kID0gYXJndW1lbnRzW2ldO1xuXG4gICAgICAgICAgICAgICAgaWYgKCFtZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgYXNzZXJ0LmZhaWwoXCJmYWtlIGlzIG5vdCBhIHNweVwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAobWV0aG9kLnByb3h5ICYmIG1ldGhvZC5wcm94eS5pc1Npbm9uUHJveHkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmVyaWZ5SXNTdHViKG1ldGhvZC5wcm94eSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgYXNzZXJ0LmZhaWwobWV0aG9kICsgXCIgaXMgbm90IGEgZnVuY3Rpb25cIik7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG1ldGhvZC5nZXRDYWxsICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFzc2VydC5mYWlsKG1ldGhvZCArIFwiIGlzIG5vdCBzdHViYmVkXCIpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiB2ZXJpZnlJc1ZhbGlkQXNzZXJ0aW9uKGFzc2VydGlvbk1ldGhvZCwgYXNzZXJ0aW9uQXJncykge1xuICAgICAgICAgICAgc3dpdGNoIChhc3NlcnRpb25NZXRob2QpIHtcbiAgICAgICAgICAgICAgICBjYXNlIFwibm90Q2FsbGVkXCI6XG4gICAgICAgICAgICAgICAgY2FzZSBcImNhbGxlZFwiOlxuICAgICAgICAgICAgICAgIGNhc2UgXCJjYWxsZWRPbmNlXCI6XG4gICAgICAgICAgICAgICAgY2FzZSBcImNhbGxlZFR3aWNlXCI6XG4gICAgICAgICAgICAgICAgY2FzZSBcImNhbGxlZFRocmljZVwiOlxuICAgICAgICAgICAgICAgICAgICBpZiAoYXNzZXJ0aW9uQXJncy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFzc2VydC5mYWlsKGFzc2VydGlvbk1ldGhvZCArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIiB0YWtlcyAxIGFyZ3VtZW50IGJ1dCB3YXMgY2FsbGVkIHdpdGggXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGFzc2VydGlvbkFyZ3MubGVuZ3RoICsgMSkgKyBcIiBhcmd1bWVudHNcIik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBmYWlsQXNzZXJ0aW9uKG9iamVjdCwgbXNnKSB7XG4gICAgICAgICAgICBvYmplY3QgPSBvYmplY3QgfHwgZ2xvYmFsO1xuICAgICAgICAgICAgdmFyIGZhaWxNZXRob2QgPSBvYmplY3QuZmFpbCB8fCBhc3NlcnQuZmFpbDtcbiAgICAgICAgICAgIGZhaWxNZXRob2QuY2FsbChvYmplY3QsIG1zZyk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBtaXJyb3JQcm9wQXNBc3NlcnRpb24obmFtZSwgbWV0aG9kLCBtZXNzYWdlKSB7XG4gICAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMikge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2UgPSBtZXRob2Q7XG4gICAgICAgICAgICAgICAgbWV0aG9kID0gbmFtZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYXNzZXJ0W25hbWVdID0gZnVuY3Rpb24gKGZha2UpIHtcbiAgICAgICAgICAgICAgICB2ZXJpZnlJc1N0dWIoZmFrZSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgICAgICAgICB2ZXJpZnlJc1ZhbGlkQXNzZXJ0aW9uKG5hbWUsIGFyZ3MpO1xuXG4gICAgICAgICAgICAgICAgdmFyIGZhaWxlZCA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBtZXRob2QgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICBmYWlsZWQgPSAhbWV0aG9kKGZha2UpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGZhaWxlZCA9IHR5cGVvZiBmYWtlW21ldGhvZF0gPT09IFwiZnVuY3Rpb25cIiA/XG4gICAgICAgICAgICAgICAgICAgICAgICAhZmFrZVttZXRob2RdLmFwcGx5KGZha2UsIGFyZ3MpIDogIWZha2VbbWV0aG9kXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoZmFpbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIGZhaWxBc3NlcnRpb24odGhpcywgKGZha2UucHJpbnRmIHx8IGZha2UucHJveHkucHJpbnRmKS5hcHBseShmYWtlLCBbbWVzc2FnZV0uY29uY2F0KGFyZ3MpKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgYXNzZXJ0LnBhc3MobmFtZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGV4cG9zZWROYW1lKHByZWZpeCwgcHJvcCkge1xuICAgICAgICAgICAgcmV0dXJuICFwcmVmaXggfHwgL15mYWlsLy50ZXN0KHByb3ApID8gcHJvcCA6XG4gICAgICAgICAgICAgICAgcHJlZml4ICsgcHJvcC5zbGljZSgwLCAxKS50b1VwcGVyQ2FzZSgpICsgcHJvcC5zbGljZSgxKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGFzc2VydCA9IHtcbiAgICAgICAgICAgIGZhaWxFeGNlcHRpb246IFwiQXNzZXJ0RXJyb3JcIixcblxuICAgICAgICAgICAgZmFpbDogZnVuY3Rpb24gZmFpbChtZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGVycm9yID0gbmV3IEVycm9yKG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIGVycm9yLm5hbWUgPSB0aGlzLmZhaWxFeGNlcHRpb24gfHwgYXNzZXJ0LmZhaWxFeGNlcHRpb247XG5cbiAgICAgICAgICAgICAgICB0aHJvdyBlcnJvcjtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHBhc3M6IGZ1bmN0aW9uIHBhc3MoKSB7fSxcblxuICAgICAgICAgICAgY2FsbE9yZGVyOiBmdW5jdGlvbiBhc3NlcnRDYWxsT3JkZXIoKSB7XG4gICAgICAgICAgICAgICAgdmVyaWZ5SXNTdHViLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgdmFyIGV4cGVjdGVkID0gXCJcIjtcbiAgICAgICAgICAgICAgICB2YXIgYWN0dWFsID0gXCJcIjtcblxuICAgICAgICAgICAgICAgIGlmICghc2lub24uY2FsbGVkSW5PcmRlcihhcmd1bWVudHMpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBleHBlY3RlZCA9IFtdLmpvaW4uY2FsbChhcmd1bWVudHMsIFwiLCBcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgY2FsbHMgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgaSA9IGNhbGxzLmxlbmd0aDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIChpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFjYWxsc1stLWldLmNhbGxlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYWxscy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0dWFsID0gc2lub24ub3JkZXJCeUZpcnN0Q2FsbChjYWxscykuam9pbihcIiwgXCIpO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGlzIGZhaWxzLCB3ZSdsbCBqdXN0IGZhbGwgYmFjayB0byB0aGUgYmxhbmsgc3RyaW5nXG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBmYWlsQXNzZXJ0aW9uKHRoaXMsIFwiZXhwZWN0ZWQgXCIgKyBleHBlY3RlZCArIFwiIHRvIGJlIFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJjYWxsZWQgaW4gb3JkZXIgYnV0IHdlcmUgY2FsbGVkIGFzIFwiICsgYWN0dWFsKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQucGFzcyhcImNhbGxPcmRlclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsQ291bnQ6IGZ1bmN0aW9uIGFzc2VydENhbGxDb3VudChtZXRob2QsIGNvdW50KSB7XG4gICAgICAgICAgICAgICAgdmVyaWZ5SXNTdHViKG1ldGhvZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAobWV0aG9kLmNhbGxDb3VudCAhPT0gY291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1zZyA9IFwiZXhwZWN0ZWQgJW4gdG8gYmUgY2FsbGVkIFwiICsgc2lub24udGltZXNJbldvcmRzKGNvdW50KSArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBidXQgd2FzIGNhbGxlZCAlYyVDXCI7XG4gICAgICAgICAgICAgICAgICAgIGZhaWxBc3NlcnRpb24odGhpcywgbWV0aG9kLnByaW50Zihtc2cpKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQucGFzcyhcImNhbGxDb3VudFwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBleHBvc2U6IGZ1bmN0aW9uIGV4cG9zZSh0YXJnZXQsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwidGFyZ2V0IGlzIG51bGwgb3IgdW5kZWZpbmVkXCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBvID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgICAgICAgICB2YXIgcHJlZml4ID0gdHlwZW9mIG8ucHJlZml4ID09PSBcInVuZGVmaW5lZFwiICYmIFwiYXNzZXJ0XCIgfHwgby5wcmVmaXg7XG4gICAgICAgICAgICAgICAgdmFyIGluY2x1ZGVGYWlsID0gdHlwZW9mIG8uaW5jbHVkZUZhaWwgPT09IFwidW5kZWZpbmVkXCIgfHwgISFvLmluY2x1ZGVGYWlsO1xuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgbWV0aG9kIGluIHRoaXMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1ldGhvZCAhPT0gXCJleHBvc2VcIiAmJiAoaW5jbHVkZUZhaWwgfHwgIS9eKGZhaWwpLy50ZXN0KG1ldGhvZCkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRbZXhwb3NlZE5hbWUocHJlZml4LCBtZXRob2QpXSA9IHRoaXNbbWV0aG9kXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBtYXRjaDogZnVuY3Rpb24gbWF0Y2goYWN0dWFsLCBleHBlY3RhdGlvbikge1xuICAgICAgICAgICAgICAgIHZhciBtYXRjaGVyID0gc2lub24ubWF0Y2goZXhwZWN0YXRpb24pO1xuICAgICAgICAgICAgICAgIGlmIChtYXRjaGVyLnRlc3QoYWN0dWFsKSkge1xuICAgICAgICAgICAgICAgICAgICBhc3NlcnQucGFzcyhcIm1hdGNoXCIpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBmb3JtYXR0ZWQgPSBbXG4gICAgICAgICAgICAgICAgICAgICAgICBcImV4cGVjdGVkIHZhbHVlIHRvIG1hdGNoXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiAgICBleHBlY3RlZCA9IFwiICsgc2lub24uZm9ybWF0KGV4cGVjdGF0aW9uKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiICAgIGFjdHVhbCA9IFwiICsgc2lub24uZm9ybWF0KGFjdHVhbClcbiAgICAgICAgICAgICAgICAgICAgXTtcblxuICAgICAgICAgICAgICAgICAgICBmYWlsQXNzZXJ0aW9uKHRoaXMsIGZvcm1hdHRlZC5qb2luKFwiXFxuXCIpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgbWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkXCIsIFwiZXhwZWN0ZWQgJW4gdG8gaGF2ZSBiZWVuIGNhbGxlZCBhdCBsZWFzdCBvbmNlIGJ1dCB3YXMgbmV2ZXIgY2FsbGVkXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJub3RDYWxsZWRcIiwgZnVuY3Rpb24gKHNweSkge1xuICAgICAgICAgICAgcmV0dXJuICFzcHkuY2FsbGVkO1xuICAgICAgICB9LCBcImV4cGVjdGVkICVuIHRvIG5vdCBoYXZlIGJlZW4gY2FsbGVkIGJ1dCB3YXMgY2FsbGVkICVjJUNcIik7XG4gICAgICAgIG1pcnJvclByb3BBc0Fzc2VydGlvbihcImNhbGxlZE9uY2VcIiwgXCJleHBlY3RlZCAlbiB0byBiZSBjYWxsZWQgb25jZSBidXQgd2FzIGNhbGxlZCAlYyVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRUd2ljZVwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB0d2ljZSBidXQgd2FzIGNhbGxlZCAlYyVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRUaHJpY2VcIiwgXCJleHBlY3RlZCAlbiB0byBiZSBjYWxsZWQgdGhyaWNlIGJ1dCB3YXMgY2FsbGVkICVjJUNcIik7XG4gICAgICAgIG1pcnJvclByb3BBc0Fzc2VydGlvbihcImNhbGxlZE9uXCIsIFwiZXhwZWN0ZWQgJW4gdG8gYmUgY2FsbGVkIHdpdGggJTEgYXMgdGhpcyBidXQgd2FzIGNhbGxlZCB3aXRoICV0XCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXG4gICAgICAgICAgICBcImFsd2F5c0NhbGxlZE9uXCIsXG4gICAgICAgICAgICBcImV4cGVjdGVkICVuIHRvIGFsd2F5cyBiZSBjYWxsZWQgd2l0aCAlMSBhcyB0aGlzIGJ1dCB3YXMgY2FsbGVkIHdpdGggJXRcIlxuICAgICAgICApO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRXaXRoTmV3XCIsIFwiZXhwZWN0ZWQgJW4gdG8gYmUgY2FsbGVkIHdpdGggbmV3XCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJhbHdheXNDYWxsZWRXaXRoTmV3XCIsIFwiZXhwZWN0ZWQgJW4gdG8gYWx3YXlzIGJlIGNhbGxlZCB3aXRoIG5ld1wiKTtcbiAgICAgICAgbWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkV2l0aFwiLCBcImV4cGVjdGVkICVuIHRvIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50cyAlKiVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJjYWxsZWRXaXRoTWF0Y2hcIiwgXCJleHBlY3RlZCAlbiB0byBiZSBjYWxsZWQgd2l0aCBtYXRjaCAlKiVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJhbHdheXNDYWxsZWRXaXRoXCIsIFwiZXhwZWN0ZWQgJW4gdG8gYWx3YXlzIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50cyAlKiVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJhbHdheXNDYWxsZWRXaXRoTWF0Y2hcIiwgXCJleHBlY3RlZCAlbiB0byBhbHdheXMgYmUgY2FsbGVkIHdpdGggbWF0Y2ggJSolQ1wiKTtcbiAgICAgICAgbWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiY2FsbGVkV2l0aEV4YWN0bHlcIiwgXCJleHBlY3RlZCAlbiB0byBiZSBjYWxsZWQgd2l0aCBleGFjdCBhcmd1bWVudHMgJSolQ1wiKTtcbiAgICAgICAgbWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiYWx3YXlzQ2FsbGVkV2l0aEV4YWN0bHlcIiwgXCJleHBlY3RlZCAlbiB0byBhbHdheXMgYmUgY2FsbGVkIHdpdGggZXhhY3QgYXJndW1lbnRzICUqJUNcIik7XG4gICAgICAgIG1pcnJvclByb3BBc0Fzc2VydGlvbihcIm5ldmVyQ2FsbGVkV2l0aFwiLCBcImV4cGVjdGVkICVuIHRvIG5ldmVyIGJlIGNhbGxlZCB3aXRoIGFyZ3VtZW50cyAlKiVDXCIpO1xuICAgICAgICBtaXJyb3JQcm9wQXNBc3NlcnRpb24oXCJuZXZlckNhbGxlZFdpdGhNYXRjaFwiLCBcImV4cGVjdGVkICVuIHRvIG5ldmVyIGJlIGNhbGxlZCB3aXRoIG1hdGNoICUqJUNcIik7XG4gICAgICAgIG1pcnJvclByb3BBc0Fzc2VydGlvbihcInRocmV3XCIsIFwiJW4gZGlkIG5vdCB0aHJvdyBleGNlcHRpb24lQ1wiKTtcbiAgICAgICAgbWlycm9yUHJvcEFzQXNzZXJ0aW9uKFwiYWx3YXlzVGhyZXdcIiwgXCIlbiBkaWQgbm90IGFsd2F5cyB0aHJvdyBleGNlcHRpb24lQ1wiKTtcblxuICAgICAgICBzaW5vbi5hc3NlcnQgPSBhc3NlcnQ7XG4gICAgICAgIHJldHVybiBhc3NlcnQ7XG4gICAgfVxuXG4gICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICB2YXIgaXNBTUQgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT09IFwib2JqZWN0XCIgJiYgZGVmaW5lLmFtZDtcblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7XG4gICAgICAgIHZhciBzaW5vbiA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vbWF0Y2hcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2Zvcm1hdFwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uLCAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4gICAgdHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIiA/IGdsb2JhbCA6IHNlbGZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICogQGRlcGVuZCBleHRlbmQuanNcbiAqL1xuLyoqXG4gKiBTdHViIGJlaGF2aW9yXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAYXV0aG9yIFRpbSBGaXNjaGJhY2ggKG1haWxAdGltZmlzY2hiYWNoLmRlKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoc2lub25HbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIHZhciBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcbiAgICB2YXIgam9pbiA9IEFycmF5LnByb3RvdHlwZS5qb2luO1xuICAgIHZhciB1c2VMZWZ0TW9zdENhbGxiYWNrID0gLTE7XG4gICAgdmFyIHVzZVJpZ2h0TW9zdENhbGxiYWNrID0gLTI7XG5cbiAgICB2YXIgbmV4dFRpY2sgPSAoZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAodHlwZW9mIHByb2Nlc3MgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIHByb2Nlc3MubmV4dFRpY2sgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIHByb2Nlc3MubmV4dFRpY2s7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIHNldEltbWVkaWF0ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICByZXR1cm4gc2V0SW1tZWRpYXRlO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICAgICAgc2V0VGltZW91dChjYWxsYmFjaywgMCk7XG4gICAgICAgIH07XG4gICAgfSkoKTtcblxuICAgIGZ1bmN0aW9uIHRocm93c0V4Y2VwdGlvbihlcnJvciwgbWVzc2FnZSkge1xuICAgICAgICBpZiAodHlwZW9mIGVycm9yID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICB0aGlzLmV4Y2VwdGlvbiA9IG5ldyBFcnJvcihtZXNzYWdlIHx8IFwiXCIpO1xuICAgICAgICAgICAgdGhpcy5leGNlcHRpb24ubmFtZSA9IGVycm9yO1xuICAgICAgICB9IGVsc2UgaWYgKCFlcnJvcikge1xuICAgICAgICAgICAgdGhpcy5leGNlcHRpb24gPSBuZXcgRXJyb3IoXCJFcnJvclwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuZXhjZXB0aW9uID0gZXJyb3I7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBnZXRDYWxsYmFjayhiZWhhdmlvciwgYXJncykge1xuICAgICAgICB2YXIgY2FsbEFyZ0F0ID0gYmVoYXZpb3IuY2FsbEFyZ0F0O1xuXG4gICAgICAgIGlmIChjYWxsQXJnQXQgPj0gMCkge1xuICAgICAgICAgICAgcmV0dXJuIGFyZ3NbY2FsbEFyZ0F0XTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBhcmd1bWVudExpc3Q7XG5cbiAgICAgICAgaWYgKGNhbGxBcmdBdCA9PT0gdXNlTGVmdE1vc3RDYWxsYmFjaykge1xuICAgICAgICAgICAgYXJndW1lbnRMaXN0ID0gYXJncztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjYWxsQXJnQXQgPT09IHVzZVJpZ2h0TW9zdENhbGxiYWNrKSB7XG4gICAgICAgICAgICBhcmd1bWVudExpc3QgPSBzbGljZS5jYWxsKGFyZ3MpLnJldmVyc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBjYWxsQXJnUHJvcCA9IGJlaGF2aW9yLmNhbGxBcmdQcm9wO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gYXJndW1lbnRMaXN0Lmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgaWYgKCFjYWxsQXJnUHJvcCAmJiB0eXBlb2YgYXJndW1lbnRMaXN0W2ldID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXJndW1lbnRMaXN0W2ldO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY2FsbEFyZ1Byb3AgJiYgYXJndW1lbnRMaXN0W2ldICYmXG4gICAgICAgICAgICAgICAgdHlwZW9mIGFyZ3VtZW50TGlzdFtpXVtjYWxsQXJnUHJvcF0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIHJldHVybiBhcmd1bWVudExpc3RbaV1bY2FsbEFyZ1Byb3BdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBmdW5jdGlvbiBnZXRDYWxsYmFja0Vycm9yKGJlaGF2aW9yLCBmdW5jLCBhcmdzKSB7XG4gICAgICAgICAgICBpZiAoYmVoYXZpb3IuY2FsbEFyZ0F0IDwgMCkge1xuICAgICAgICAgICAgICAgIHZhciBtc2c7XG5cbiAgICAgICAgICAgICAgICBpZiAoYmVoYXZpb3IuY2FsbEFyZ1Byb3ApIHtcbiAgICAgICAgICAgICAgICAgICAgbXNnID0gc2lub24uZnVuY3Rpb25OYW1lKGJlaGF2aW9yLnN0dWIpICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiIGV4cGVjdGVkIHRvIHlpZWxkIHRvICdcIiArIGJlaGF2aW9yLmNhbGxBcmdQcm9wICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiJywgYnV0IG5vIG9iamVjdCB3aXRoIHN1Y2ggYSBwcm9wZXJ0eSB3YXMgcGFzc2VkLlwiO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIG1zZyA9IHNpbm9uLmZ1bmN0aW9uTmFtZShiZWhhdmlvci5zdHViKSArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBleHBlY3RlZCB0byB5aWVsZCwgYnV0IG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQuXCI7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGFyZ3MubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICBtc2cgKz0gXCIgUmVjZWl2ZWQgW1wiICsgam9pbi5jYWxsKGFyZ3MsIFwiLCBcIikgKyBcIl1cIjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gbXNnO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gXCJhcmd1bWVudCBhdCBpbmRleCBcIiArIGJlaGF2aW9yLmNhbGxBcmdBdCArIFwiIGlzIG5vdCBhIGZ1bmN0aW9uOiBcIiArIGZ1bmM7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBjYWxsQ2FsbGJhY2soYmVoYXZpb3IsIGFyZ3MpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgYmVoYXZpb3IuY2FsbEFyZ0F0ID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgdmFyIGZ1bmMgPSBnZXRDYWxsYmFjayhiZWhhdmlvciwgYXJncyk7XG5cbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGZ1bmMgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGdldENhbGxiYWNrRXJyb3IoYmVoYXZpb3IsIGZ1bmMsIGFyZ3MpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoYmVoYXZpb3IuY2FsbGJhY2tBc3luYykge1xuICAgICAgICAgICAgICAgICAgICBuZXh0VGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5jLmFwcGx5KGJlaGF2aW9yLmNhbGxiYWNrQ29udGV4dCwgYmVoYXZpb3IuY2FsbGJhY2tBcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBmdW5jLmFwcGx5KGJlaGF2aW9yLmNhbGxiYWNrQ29udGV4dCwgYmVoYXZpb3IuY2FsbGJhY2tBcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBwcm90byA9IHtcbiAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gY3JlYXRlKHN0dWIpIHtcbiAgICAgICAgICAgICAgICB2YXIgYmVoYXZpb3IgPSBzaW5vbi5leHRlbmQoe30sIHNpbm9uLmJlaGF2aW9yKTtcbiAgICAgICAgICAgICAgICBkZWxldGUgYmVoYXZpb3IuY3JlYXRlO1xuICAgICAgICAgICAgICAgIGJlaGF2aW9yLnN0dWIgPSBzdHViO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGJlaGF2aW9yO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgaXNQcmVzZW50OiBmdW5jdGlvbiBpc1ByZXNlbnQoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICh0eXBlb2YgdGhpcy5jYWxsQXJnQXQgPT09IFwibnVtYmVyXCIgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZXhjZXB0aW9uIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgdGhpcy5yZXR1cm5BcmdBdCA9PT0gXCJudW1iZXJcIiB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXR1cm5UaGlzIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJldHVyblZhbHVlRGVmaW5lZCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBpbnZva2U6IGZ1bmN0aW9uIGludm9rZShjb250ZXh0LCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgY2FsbENhbGxiYWNrKHRoaXMsIGFyZ3MpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZXhjZXB0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IHRoaXMuZXhjZXB0aW9uO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHRoaXMucmV0dXJuQXJnQXQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGFyZ3NbdGhpcy5yZXR1cm5BcmdBdF07XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnJldHVyblRoaXMpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRleHQ7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMucmV0dXJuVmFsdWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBvbkNhbGw6IGZ1bmN0aW9uIG9uQ2FsbChpbmRleCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0dWIub25DYWxsKGluZGV4KTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uRmlyc3RDYWxsOiBmdW5jdGlvbiBvbkZpcnN0Q2FsbCgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zdHViLm9uRmlyc3RDYWxsKCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBvblNlY29uZENhbGw6IGZ1bmN0aW9uIG9uU2Vjb25kQ2FsbCgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5zdHViLm9uU2Vjb25kQ2FsbCgpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgb25UaGlyZENhbGw6IGZ1bmN0aW9uIG9uVGhpcmRDYWxsKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnN0dWIub25UaGlyZENhbGwoKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHdpdGhBcmdzOiBmdW5jdGlvbiB3aXRoQXJncygvKiBhcmd1bWVudHMgKi8pIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAgICAgICAgICAgICAgIFwiRGVmaW5pbmcgYSBzdHViIGJ5IGludm9raW5nIFxcXCJzdHViLm9uQ2FsbCguLi4pLndpdGhBcmdzKC4uLilcXFwiIFwiICtcbiAgICAgICAgICAgICAgICAgICAgXCJpcyBub3Qgc3VwcG9ydGVkLiBVc2UgXFxcInN0dWIud2l0aEFyZ3MoLi4uKS5vbkNhbGwoLi4uKVxcXCIgXCIgK1xuICAgICAgICAgICAgICAgICAgICBcInRvIGRlZmluZSBzZXF1ZW50aWFsIGJlaGF2aW9yIGZvciBjYWxscyB3aXRoIGNlcnRhaW4gYXJndW1lbnRzLlwiXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxzQXJnOiBmdW5jdGlvbiBjYWxsc0FyZyhwb3MpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHBvcyAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdBdCA9IHBvcztcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXJndW1lbnRzID0gW107XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0NvbnRleHQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQXJnUHJvcCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXN5bmMgPSBmYWxzZTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgY2FsbHNBcmdPbjogZnVuY3Rpb24gY2FsbHNBcmdPbihwb3MsIGNvbnRleHQpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHBvcyAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBjb250ZXh0ICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJhcmd1bWVudCBjb250ZXh0IGlzIG5vdCBhbiBvYmplY3RcIik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQXJnQXQgPSBwb3M7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FyZ3VtZW50cyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tDb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdQcm9wID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsc0FyZ1dpdGg6IGZ1bmN0aW9uIGNhbGxzQXJnV2l0aChwb3MpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHBvcyAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgaW5kZXggaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdBdCA9IHBvcztcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tDb250ZXh0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxzQXJnT25XaXRoOiBmdW5jdGlvbiBjYWxsc0FyZ1dpdGgocG9zLCBjb250ZXh0KSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBwb3MgIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcImFyZ3VtZW50IGluZGV4IGlzIG5vdCBudW1iZXJcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY29udGV4dCAhPT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgY29udGV4dCBpcyBub3QgYW4gb2JqZWN0XCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ0F0ID0gcG9zO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tBcmd1bWVudHMgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0NvbnRleHQgPSBjb250ZXh0O1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHlpZWxkczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ0F0ID0gdXNlTGVmdE1vc3RDYWxsYmFjaztcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tDb250ZXh0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHlpZWxkc1JpZ2h0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQXJnQXQgPSB1c2VSaWdodE1vc3RDYWxsYmFjaztcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDApO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tDb250ZXh0ID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ1Byb3AgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHlpZWxkc09uOiBmdW5jdGlvbiAoY29udGV4dCkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY29udGV4dCAhPT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJndW1lbnQgY29udGV4dCBpcyBub3QgYW4gb2JqZWN0XCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuY2FsbEFyZ0F0ID0gdXNlTGVmdE1vc3RDYWxsYmFjaztcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXJndW1lbnRzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tDb250ZXh0ID0gY29udGV4dDtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdQcm9wID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tBc3luYyA9IGZhbHNlO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICB5aWVsZHNUbzogZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdBdCA9IHVzZUxlZnRNb3N0Q2FsbGJhY2s7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FyZ3VtZW50cyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQ29udGV4dCA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdQcm9wID0gcHJvcDtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXN5bmMgPSBmYWxzZTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgeWllbGRzVG9PbjogZnVuY3Rpb24gKHByb3AsIGNvbnRleHQpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGNvbnRleHQgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcImFyZ3VtZW50IGNvbnRleHQgaXMgbm90IGFuIG9iamVjdFwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxBcmdBdCA9IHVzZUxlZnRNb3N0Q2FsbGJhY2s7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FyZ3VtZW50cyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQ29udGV4dCA9IGNvbnRleHQ7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQXJnUHJvcCA9IHByb3A7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja0FzeW5jID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHRocm93czogdGhyb3dzRXhjZXB0aW9uLFxuICAgICAgICAgICAgdGhyb3dzRXhjZXB0aW9uOiB0aHJvd3NFeGNlcHRpb24sXG5cbiAgICAgICAgICAgIHJldHVybnM6IGZ1bmN0aW9uIHJldHVybnModmFsdWUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJldHVyblZhbHVlID0gdmFsdWU7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXR1cm5WYWx1ZURlZmluZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMuZXhjZXB0aW9uID0gdW5kZWZpbmVkO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXR1cm5zQXJnOiBmdW5jdGlvbiByZXR1cm5zQXJnKHBvcykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgcG9zICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJhcmd1bWVudCBpbmRleCBpcyBub3QgbnVtYmVyXCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMucmV0dXJuQXJnQXQgPSBwb3M7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJldHVybnNUaGlzOiBmdW5jdGlvbiByZXR1cm5zVGhpcygpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJldHVyblRoaXMgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgZnVuY3Rpb24gY3JlYXRlQXN5bmNWZXJzaW9uKHN5bmNGbk5hbWUpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlc3VsdCA9IHRoaXNbc3luY0ZuTmFtZV0uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrQXN5bmMgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gY3JlYXRlIGFzeW5jaHJvbm91cyB2ZXJzaW9ucyBvZiBjYWxsc0FyZyogYW5kIHlpZWxkcyogbWV0aG9kc1xuICAgICAgICBmb3IgKHZhciBtZXRob2QgaW4gcHJvdG8pIHtcbiAgICAgICAgICAgIC8vIG5lZWQgdG8gYXZvaWQgY3JlYXRpbmcgYW5vdGhlcmFzeW5jIHZlcnNpb25zIG9mIHRoZSBuZXdseSBhZGRlZCBhc3luYyBtZXRob2RzXG4gICAgICAgICAgICBpZiAocHJvdG8uaGFzT3duUHJvcGVydHkobWV0aG9kKSAmJiBtZXRob2QubWF0Y2goL14oY2FsbHNBcmd8eWllbGRzKS8pICYmICFtZXRob2QubWF0Y2goL0FzeW5jLykpIHtcbiAgICAgICAgICAgICAgICBwcm90b1ttZXRob2QgKyBcIkFzeW5jXCJdID0gY3JlYXRlQXN5bmNWZXJzaW9uKG1ldGhvZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBzaW5vbi5iZWhhdmlvciA9IHByb3RvO1xuICAgICAgICByZXR1cm4gcHJvdG87XG4gICAgfVxuXG4gICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICB2YXIgaXNBTUQgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT09IFwib2JqZWN0XCIgJiYgZGVmaW5lLmFtZDtcblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7XG4gICAgICAgIHZhciBzaW5vbiA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZXh0ZW5kXCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoc2lub24pO1xuICAgIH1cblxuICAgIGlmIChpc0FNRCkge1xuICAgICAgICBkZWZpbmUobG9hZERlcGVuZGVuY2llcyk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgbW9kdWxlLmV4cG9ydHMsIG1vZHVsZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2lub25HbG9iYWwpIHtcbiAgICAgICAgbWFrZUFwaShzaW5vbkdsb2JhbCk7XG4gICAgfVxufShcbiAgICB0eXBlb2Ygc2lub24gPT09IFwib2JqZWN0XCIgJiYgc2lub24gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuKSk7XG4iLCIvKipcbiAgKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICAqIEBkZXBlbmQgbWF0Y2guanNcbiAgKiBAZGVwZW5kIGZvcm1hdC5qc1xuICAqL1xuLyoqXG4gICogU3B5IGNhbGxzXG4gICpcbiAgKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAgKiBAYXV0aG9yIE1heGltaWxpYW4gQW50b25pIChtYWlsQG1heGFudG9uaS5kZSlcbiAgKiBAbGljZW5zZSBCU0RcbiAgKlxuICAqIENvcHlyaWdodCAoYykgMjAxMC0yMDEzIENocmlzdGlhbiBKb2hhbnNlblxuICAqIENvcHlyaWdodCAoYykgMjAxMyBNYXhpbWlsaWFuIEFudG9uaVxuICAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBmdW5jdGlvbiB0aHJvd1lpZWxkRXJyb3IocHJveHksIHRleHQsIGFyZ3MpIHtcbiAgICAgICAgICAgIHZhciBtc2cgPSBzaW5vbi5mdW5jdGlvbk5hbWUocHJveHkpICsgdGV4dDtcbiAgICAgICAgICAgIGlmIChhcmdzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIG1zZyArPSBcIiBSZWNlaXZlZCBbXCIgKyBzbGljZS5jYWxsKGFyZ3MpLmpvaW4oXCIsIFwiKSArIFwiXVwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKG1zZyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgY2FsbFByb3RvID0ge1xuICAgICAgICAgICAgY2FsbGVkT246IGZ1bmN0aW9uIGNhbGxlZE9uKHRoaXNWYWx1ZSkge1xuICAgICAgICAgICAgICAgIGlmIChzaW5vbi5tYXRjaCAmJiBzaW5vbi5tYXRjaC5pc01hdGNoZXIodGhpc1ZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpc1ZhbHVlLnRlc3QodGhpcy50aGlzVmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy50aGlzVmFsdWUgPT09IHRoaXNWYWx1ZTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxlZFdpdGg6IGZ1bmN0aW9uIGNhbGxlZFdpdGgoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGwgPSBhcmd1bWVudHMubGVuZ3RoO1xuICAgICAgICAgICAgICAgIGlmIChsID4gdGhpcy5hcmdzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbDsgaSArPSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghc2lub24uZGVlcEVxdWFsKGFyZ3VtZW50c1tpXSwgdGhpcy5hcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsZWRXaXRoTWF0Y2g6IGZ1bmN0aW9uIGNhbGxlZFdpdGhNYXRjaCgpIHtcbiAgICAgICAgICAgICAgICB2YXIgbCA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgaWYgKGwgPiB0aGlzLmFyZ3MubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsOyBpICs9IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjdHVhbCA9IHRoaXMuYXJnc1tpXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGV4cGVjdGF0aW9uID0gYXJndW1lbnRzW2ldO1xuICAgICAgICAgICAgICAgICAgICBpZiAoIXNpbm9uLm1hdGNoIHx8ICFzaW5vbi5tYXRjaChleHBlY3RhdGlvbikudGVzdChhY3R1YWwpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsZWRXaXRoRXhhY3RseTogZnVuY3Rpb24gY2FsbGVkV2l0aEV4YWN0bHkoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPT09IHRoaXMuYXJncy5sZW5ndGggJiZcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxsZWRXaXRoLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBub3RDYWxsZWRXaXRoOiBmdW5jdGlvbiBub3RDYWxsZWRXaXRoKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAhdGhpcy5jYWxsZWRXaXRoLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBub3RDYWxsZWRXaXRoTWF0Y2g6IGZ1bmN0aW9uIG5vdENhbGxlZFdpdGhNYXRjaCgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gIXRoaXMuY2FsbGVkV2l0aE1hdGNoLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXR1cm5lZDogZnVuY3Rpb24gcmV0dXJuZWQodmFsdWUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2lub24uZGVlcEVxdWFsKHZhbHVlLCB0aGlzLnJldHVyblZhbHVlKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHRocmV3OiBmdW5jdGlvbiB0aHJldyhlcnJvcikge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZXJyb3IgPT09IFwidW5kZWZpbmVkXCIgfHwgIXRoaXMuZXhjZXB0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhIXRoaXMuZXhjZXB0aW9uO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmV4Y2VwdGlvbiA9PT0gZXJyb3IgfHwgdGhpcy5leGNlcHRpb24ubmFtZSA9PT0gZXJyb3I7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsZWRXaXRoTmV3OiBmdW5jdGlvbiBjYWxsZWRXaXRoTmV3KCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnByb3h5LnByb3RvdHlwZSAmJiB0aGlzLnRoaXNWYWx1ZSBpbnN0YW5jZW9mIHRoaXMucHJveHk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsZWRCZWZvcmU6IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmNhbGxJZCA8IG90aGVyLmNhbGxJZDtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxlZEFmdGVyOiBmdW5jdGlvbiAob3RoZXIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jYWxsSWQgPiBvdGhlci5jYWxsSWQ7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjYWxsQXJnOiBmdW5jdGlvbiAocG9zKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hcmdzW3Bvc10oKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxBcmdPbjogZnVuY3Rpb24gKHBvcywgdGhpc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hcmdzW3Bvc10uYXBwbHkodGhpc1ZhbHVlKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxBcmdXaXRoOiBmdW5jdGlvbiAocG9zKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQXJnT25XaXRoLmFwcGx5KHRoaXMsIFtwb3MsIG51bGxdLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cywgMSkpKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNhbGxBcmdPbldpdGg6IGZ1bmN0aW9uIChwb3MsIHRoaXNWYWx1ZSkge1xuICAgICAgICAgICAgICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgICAgICAgICAgICAgIHRoaXMuYXJnc1twb3NdLmFwcGx5KHRoaXNWYWx1ZSwgYXJncyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBcInlpZWxkXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnlpZWxkT24uYXBwbHkodGhpcywgW251bGxdLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cywgMCkpKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHlpZWxkT246IGZ1bmN0aW9uICh0aGlzVmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgYXJncyA9IHRoaXMuYXJncztcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGFyZ3MubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgYXJnc1tpXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmdzW2ldLmFwcGx5KHRoaXNWYWx1ZSwgc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aHJvd1lpZWxkRXJyb3IodGhpcy5wcm94eSwgXCIgY2Fubm90IHlpZWxkIHNpbmNlIG5vIGNhbGxiYWNrIHdhcyBwYXNzZWQuXCIsIGFyZ3MpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgeWllbGRUbzogZnVuY3Rpb24gKHByb3ApIHtcbiAgICAgICAgICAgICAgICB0aGlzLnlpZWxkVG9Pbi5hcHBseSh0aGlzLCBbcHJvcCwgbnVsbF0uY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSkpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgeWllbGRUb09uOiBmdW5jdGlvbiAocHJvcCwgdGhpc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGFyZ3MgPSB0aGlzLmFyZ3M7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBhcmdzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoYXJnc1tpXSAmJiB0eXBlb2YgYXJnc1tpXVtwcm9wXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmdzW2ldW3Byb3BdLmFwcGx5KHRoaXNWYWx1ZSwgc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aHJvd1lpZWxkRXJyb3IodGhpcy5wcm94eSwgXCIgY2Fubm90IHlpZWxkIHRvICdcIiArIHByb3AgK1xuICAgICAgICAgICAgICAgICAgICBcIicgc2luY2Ugbm8gY2FsbGJhY2sgd2FzIHBhc3NlZC5cIiwgYXJncyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBnZXRTdGFja0ZyYW1lczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIC8vIE9taXQgdGhlIGVycm9yIG1lc3NhZ2UgYW5kIHRoZSB0d28gdG9wIHN0YWNrIGZyYW1lcyBpbiBzaW5vbiBpdHNlbGY6XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuc3RhY2sgJiYgdGhpcy5zdGFjay5zcGxpdChcIlxcblwiKS5zbGljZSgzKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNhbGxTdHIgPSB0aGlzLnByb3h5ID8gdGhpcy5wcm94eS50b1N0cmluZygpICsgXCIoXCIgOiBcIlwiO1xuICAgICAgICAgICAgICAgIHZhciBhcmdzID0gW107XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuYXJncykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCI6KFwiO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gdGhpcy5hcmdzLmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICBhcmdzLnB1c2goc2lub24uZm9ybWF0KHRoaXMuYXJnc1tpXSkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGNhbGxTdHIgPSBjYWxsU3RyICsgYXJncy5qb2luKFwiLCBcIikgKyBcIilcIjtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5yZXR1cm5WYWx1ZSAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgICAgICAgICAgICAgICBjYWxsU3RyICs9IFwiID0+IFwiICsgc2lub24uZm9ybWF0KHRoaXMucmV0dXJuVmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmV4Y2VwdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBjYWxsU3RyICs9IFwiICFcIiArIHRoaXMuZXhjZXB0aW9uLm5hbWU7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuZXhjZXB0aW9uLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxTdHIgKz0gXCIoXCIgKyB0aGlzLmV4Y2VwdGlvbi5tZXNzYWdlICsgXCIpXCI7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbFN0ciArPSB0aGlzLmdldFN0YWNrRnJhbWVzKClbMF0ucmVwbGFjZSgvXlxccyooPzphdFxccyt8QCk/LywgXCIgYXQgXCIpO1xuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxTdHI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgY2FsbFByb3RvLmludm9rZUNhbGxiYWNrID0gY2FsbFByb3RvLnlpZWxkO1xuXG4gICAgICAgIGZ1bmN0aW9uIGNyZWF0ZVNweUNhbGwoc3B5LCB0aGlzVmFsdWUsIGFyZ3MsIHJldHVyblZhbHVlLCBleGNlcHRpb24sIGlkLCBzdGFjaykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiBpZCAhPT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYWxsIGlkIGlzIG5vdCBhIG51bWJlclwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBwcm94eUNhbGwgPSBzaW5vbi5jcmVhdGUoY2FsbFByb3RvKTtcbiAgICAgICAgICAgIHByb3h5Q2FsbC5wcm94eSA9IHNweTtcbiAgICAgICAgICAgIHByb3h5Q2FsbC50aGlzVmFsdWUgPSB0aGlzVmFsdWU7XG4gICAgICAgICAgICBwcm94eUNhbGwuYXJncyA9IGFyZ3M7XG4gICAgICAgICAgICBwcm94eUNhbGwucmV0dXJuVmFsdWUgPSByZXR1cm5WYWx1ZTtcbiAgICAgICAgICAgIHByb3h5Q2FsbC5leGNlcHRpb24gPSBleGNlcHRpb247XG4gICAgICAgICAgICBwcm94eUNhbGwuY2FsbElkID0gaWQ7XG4gICAgICAgICAgICBwcm94eUNhbGwuc3RhY2sgPSBzdGFjaztcblxuICAgICAgICAgICAgcmV0dXJuIHByb3h5Q2FsbDtcbiAgICAgICAgfVxuICAgICAgICBjcmVhdGVTcHlDYWxsLnRvU3RyaW5nID0gY2FsbFByb3RvLnRvU3RyaW5nOyAvLyB1c2VkIGJ5IG1vY2tzXG5cbiAgICAgICAgc2lub24uc3B5Q2FsbCA9IGNyZWF0ZVNweUNhbGw7XG4gICAgICAgIHJldHVybiBjcmVhdGVTcHlDYWxsO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL21hdGNoXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9mb3JtYXRcIik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gbWFrZUFwaShzaW5vbik7XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqIEBkZXBlbmQgc3B5LmpzXG4gKiBAZGVwZW5kIHN0dWIuanNcbiAqIEBkZXBlbmQgbW9jay5qc1xuICovXG4vKipcbiAqIENvbGxlY3Rpb25zIG9mIHN0dWJzLCBzcGllcyBhbmQgbW9ja3MuXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMyBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIHB1c2ggPSBbXS5wdXNoO1xuICAgIHZhciBoYXNPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbiAgICBmdW5jdGlvbiBnZXRGYWtlcyhmYWtlQ29sbGVjdGlvbikge1xuICAgICAgICBpZiAoIWZha2VDb2xsZWN0aW9uLmZha2VzKSB7XG4gICAgICAgICAgICBmYWtlQ29sbGVjdGlvbi5mYWtlcyA9IFtdO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGZha2VDb2xsZWN0aW9uLmZha2VzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGVhY2goZmFrZUNvbGxlY3Rpb24sIG1ldGhvZCkge1xuICAgICAgICB2YXIgZmFrZXMgPSBnZXRGYWtlcyhmYWtlQ29sbGVjdGlvbik7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBmYWtlcy5sZW5ndGg7IGkgPCBsOyBpICs9IDEpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgZmFrZXNbaV1bbWV0aG9kXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgZmFrZXNbaV1bbWV0aG9kXSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY29tcGFjdChmYWtlQ29sbGVjdGlvbikge1xuICAgICAgICB2YXIgZmFrZXMgPSBnZXRGYWtlcyhmYWtlQ29sbGVjdGlvbik7XG4gICAgICAgIHZhciBpID0gMDtcbiAgICAgICAgd2hpbGUgKGkgPCBmYWtlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGZha2VzLnNwbGljZShpLCAxKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1ha2VBcGkoc2lub24pIHtcbiAgICAgICAgdmFyIGNvbGxlY3Rpb24gPSB7XG4gICAgICAgICAgICB2ZXJpZnk6IGZ1bmN0aW9uIHJlc29sdmUoKSB7XG4gICAgICAgICAgICAgICAgZWFjaCh0aGlzLCBcInZlcmlmeVwiKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlc3RvcmU6IGZ1bmN0aW9uIHJlc3RvcmUoKSB7XG4gICAgICAgICAgICAgICAgZWFjaCh0aGlzLCBcInJlc3RvcmVcIik7XG4gICAgICAgICAgICAgICAgY29tcGFjdCh0aGlzKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlc2V0OiBmdW5jdGlvbiByZXN0b3JlKCkge1xuICAgICAgICAgICAgICAgIGVhY2godGhpcywgXCJyZXNldFwiKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHZlcmlmeUFuZFJlc3RvcmU6IGZ1bmN0aW9uIHZlcmlmeUFuZFJlc3RvcmUoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGV4Y2VwdGlvbjtcblxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudmVyaWZ5KCk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBleGNlcHRpb24gPSBlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMucmVzdG9yZSgpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGV4Y2VwdGlvbikge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBleGNlcHRpb247XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgYWRkOiBmdW5jdGlvbiBhZGQoZmFrZSkge1xuICAgICAgICAgICAgICAgIHB1c2guY2FsbChnZXRGYWtlcyh0aGlzKSwgZmFrZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZha2U7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBzcHk6IGZ1bmN0aW9uIHNweSgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hZGQoc2lub24uc3B5LmFwcGx5KHNpbm9uLCBhcmd1bWVudHMpKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHN0dWI6IGZ1bmN0aW9uIHN0dWIob2JqZWN0LCBwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBpZiAocHJvcGVydHkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9yaWdpbmFsID0gb2JqZWN0W3Byb3BlcnR5XTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIG9yaWdpbmFsICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghaGFzT3duUHJvcGVydHkuY2FsbChvYmplY3QsIHByb3BlcnR5KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJDYW5ub3Qgc3R1YiBub24tZXhpc3RlbnQgb3duIHByb3BlcnR5IFwiICsgcHJvcGVydHkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmplY3RbcHJvcGVydHldID0gdmFsdWU7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkZCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdG9yZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvYmplY3RbcHJvcGVydHldID0gb3JpZ2luYWw7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKCFwcm9wZXJ0eSAmJiAhIW9iamVjdCAmJiB0eXBlb2Ygb2JqZWN0ID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzdHViYmVkT2JqID0gc2lub24uc3R1Yi5hcHBseShzaW5vbiwgYXJndW1lbnRzKTtcblxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIHN0dWJiZWRPYmopIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc3R1YmJlZE9ialtwcm9wXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5hZGQoc3R1YmJlZE9ialtwcm9wXSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc3R1YmJlZE9iajtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hZGQoc2lub24uc3R1Yi5hcHBseShzaW5vbiwgYXJndW1lbnRzKSk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBtb2NrOiBmdW5jdGlvbiBtb2NrKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkZChzaW5vbi5tb2NrLmFwcGx5KHNpbm9uLCBhcmd1bWVudHMpKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGluamVjdDogZnVuY3Rpb24gaW5qZWN0KG9iaikge1xuICAgICAgICAgICAgICAgIHZhciBjb2wgPSB0aGlzO1xuXG4gICAgICAgICAgICAgICAgb2JqLnNweSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbC5zcHkuYXBwbHkoY29sLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICBvYmouc3R1YiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGNvbC5zdHViLmFwcGx5KGNvbCwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICAgICAgb2JqLm1vY2sgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjb2wubW9jay5hcHBseShjb2wsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBvYmo7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uY29sbGVjdGlvbiA9IGNvbGxlY3Rpb247XG4gICAgICAgIHJldHVybiBjb2xsZWN0aW9uO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL21vY2tcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3NweVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc3R1YlwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG5cbiAgICAgICAgLy8gQWRhcHRlZCBmcm9tIGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2VuL2RvY3MvRUNNQVNjcmlwdF9Eb250RW51bV9hdHRyaWJ1dGUjSlNjcmlwdF9Eb250RW51bV9CdWdcbiAgICAgICAgdmFyIGhhc0RvbnRFbnVtQnVnID0gKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBvYmogPSB7XG4gICAgICAgICAgICAgICAgY29uc3RydWN0b3I6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiMFwiO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdG9TdHJpbmc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiMVwiO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdmFsdWVPZjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCIyXCI7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICB0b0xvY2FsZVN0cmluZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCIzXCI7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBwcm90b3R5cGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiNFwiO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgaXNQcm90b3R5cGVPZjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCI1XCI7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBwcm9wZXJ0eUlzRW51bWVyYWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCI2XCI7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBoYXNPd25Qcm9wZXJ0eTogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCI3XCI7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBsZW5ndGg6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwiOFwiO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgdW5pcXVlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBcIjlcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIG9iaikge1xuICAgICAgICAgICAgICAgIGlmIChvYmouaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gob2JqW3Byb3BdKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiByZXN1bHQuam9pbihcIlwiKSAhPT0gXCIwMTIzNDU2Nzg5XCI7XG4gICAgICAgIH0pKCk7XG5cbiAgICAgICAgLyogUHVibGljOiBFeHRlbmQgdGFyZ2V0IGluIHBsYWNlIHdpdGggYWxsIChvd24pIHByb3BlcnRpZXMgZnJvbSBzb3VyY2VzIGluLW9yZGVyLiBUaHVzLCBsYXN0IHNvdXJjZSB3aWxsXG4gICAgICAgICAqICAgICAgICAgb3ZlcnJpZGUgcHJvcGVydGllcyBpbiBwcmV2aW91cyBzb3VyY2VzLlxuICAgICAgICAgKlxuICAgICAgICAgKiB0YXJnZXQgLSBUaGUgT2JqZWN0IHRvIGV4dGVuZFxuICAgICAgICAgKiBzb3VyY2VzIC0gT2JqZWN0cyB0byBjb3B5IHByb3BlcnRpZXMgZnJvbS5cbiAgICAgICAgICpcbiAgICAgICAgICogUmV0dXJucyB0aGUgZXh0ZW5kZWQgdGFyZ2V0XG4gICAgICAgICAqL1xuICAgICAgICBmdW5jdGlvbiBleHRlbmQodGFyZ2V0IC8qLCBzb3VyY2VzICovKSB7XG4gICAgICAgICAgICB2YXIgc291cmNlcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gICAgICAgICAgICB2YXIgc291cmNlLCBpLCBwcm9wO1xuXG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgc291cmNlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHNvdXJjZSA9IHNvdXJjZXNbaV07XG5cbiAgICAgICAgICAgICAgICBmb3IgKHByb3AgaW4gc291cmNlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzb3VyY2UuaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIE1ha2Ugc3VyZSB3ZSBjb3B5IChvd24pIHRvU3RyaW5nIG1ldGhvZCBldmVuIHdoZW4gaW4gSlNjcmlwdCB3aXRoIERvbnRFbnVtIGJ1Z1xuICAgICAgICAgICAgICAgIC8vIFNlZSBodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9lbi9kb2NzL0VDTUFTY3JpcHRfRG9udEVudW1fYXR0cmlidXRlI0pTY3JpcHRfRG9udEVudW1fQnVnXG4gICAgICAgICAgICAgICAgaWYgKGhhc0RvbnRFbnVtQnVnICYmIHNvdXJjZS5oYXNPd25Qcm9wZXJ0eShcInRvU3RyaW5nXCIpICYmIHNvdXJjZS50b1N0cmluZyAhPT0gdGFyZ2V0LnRvU3RyaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHRhcmdldC50b1N0cmluZyA9IHNvdXJjZS50b1N0cmluZztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgICAgIH1cblxuICAgICAgICBzaW5vbi5leHRlbmQgPSBleHRlbmQ7XG4gICAgICAgIHJldHVybiBzaW5vbi5leHRlbmQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIHNpbm9uID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlXCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoc2lub24pO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICovXG4vKipcbiAqIEZvcm1hdCBmdW5jdGlvbnNcbiAqXG4gKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAqIEBsaWNlbnNlIEJTRFxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMC0yMDE0IENocmlzdGlhbiBKb2hhbnNlblxuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsLCBmb3JtYXRpbykge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBmdW5jdGlvbiB2YWx1ZUZvcm1hdHRlcih2YWx1ZSkge1xuICAgICAgICAgICAgcmV0dXJuIFwiXCIgKyB2YWx1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGdldEZvcm1hdGlvRm9ybWF0dGVyKCkge1xuICAgICAgICAgICAgdmFyIGZvcm1hdHRlciA9IGZvcm1hdGlvLmNvbmZpZ3VyZSh7XG4gICAgICAgICAgICAgICAgICAgIHF1b3RlU3RyaW5nczogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGxpbWl0Q2hpbGRyZW5Db3VudDogMjUwXG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIGZvcm1hdCgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZm9ybWF0dGVyLmFzY2lpLmFwcGx5KGZvcm1hdHRlciwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGZvcm1hdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGdldE5vZGVGb3JtYXR0ZXIoKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHZhciB1dGlsID0gcmVxdWlyZShcInV0aWxcIik7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgLyogTm9kZSwgYnV0IG5vIHV0aWwgbW9kdWxlIC0gd291bGQgYmUgdmVyeSBvbGQsIGJ1dCBiZXR0ZXIgc2FmZSB0aGFuIHNvcnJ5ICovXG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZ1bmN0aW9uIGZvcm1hdCh2KSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzT2JqZWN0V2l0aE5hdGl2ZVRvU3RyaW5nID0gdHlwZW9mIHYgPT09IFwib2JqZWN0XCIgJiYgdi50b1N0cmluZyA9PT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZztcbiAgICAgICAgICAgICAgICByZXR1cm4gaXNPYmplY3RXaXRoTmF0aXZlVG9TdHJpbmcgPyB1dGlsLmluc3BlY3QodikgOiB2O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdXRpbCA/IGZvcm1hdCA6IHZhbHVlRm9ybWF0dGVyO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICAgICAgdmFyIGZvcm1hdHRlcjtcblxuICAgICAgICBpZiAoaXNOb2RlKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGZvcm1hdGlvID0gcmVxdWlyZShcImZvcm1hdGlvXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHt9IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tZW1wdHlcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChmb3JtYXRpbykge1xuICAgICAgICAgICAgZm9ybWF0dGVyID0gZ2V0Rm9ybWF0aW9Gb3JtYXR0ZXIoKTtcbiAgICAgICAgfSBlbHNlIGlmIChpc05vZGUpIHtcbiAgICAgICAgICAgIGZvcm1hdHRlciA9IGdldE5vZGVGb3JtYXR0ZXIoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGZvcm1hdHRlciA9IHZhbHVlRm9ybWF0dGVyO1xuICAgICAgICB9XG5cbiAgICAgICAgc2lub24uZm9ybWF0ID0gZm9ybWF0dGVyO1xuICAgICAgICByZXR1cm4gc2lub24uZm9ybWF0O1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7XG4gICAgICAgIHZhciBzaW5vbiA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgIHR5cGVvZiBmb3JtYXRpbyA9PT0gXCJvYmplY3RcIiAmJiBmb3JtYXRpbyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqL1xuLyoqXG4gKiBMb2dzIGVycm9yc1xuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTQgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoc2lub25HbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIC8vIGNhY2hlIGEgcmVmZXJlbmNlIHRvIHNldFRpbWVvdXQsIHNvIHRoYXQgb3VyIHJlZmVyZW5jZSB3b24ndCBiZSBzdHViYmVkIG91dFxuICAgIC8vIHdoZW4gdXNpbmcgZmFrZSB0aW1lcnMgYW5kIGVycm9ycyB3aWxsIHN0aWxsIGdldCBsb2dnZWRcbiAgICAvLyBodHRwczovL2dpdGh1Yi5jb20vY2pvaGFuc2VuL1Npbm9uLkpTL2lzc3Vlcy8zODFcbiAgICB2YXIgcmVhbFNldFRpbWVvdXQgPSBzZXRUaW1lb3V0O1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuXG4gICAgICAgIGZ1bmN0aW9uIGxvZygpIHt9XG5cbiAgICAgICAgZnVuY3Rpb24gbG9nRXJyb3IobGFiZWwsIGVycikge1xuICAgICAgICAgICAgdmFyIG1zZyA9IGxhYmVsICsgXCIgdGhyZXcgZXhjZXB0aW9uOiBcIjtcblxuICAgICAgICAgICAgZnVuY3Rpb24gdGhyb3dMb2dnZWRFcnJvcigpIHtcbiAgICAgICAgICAgICAgICBlcnIubWVzc2FnZSA9IG1zZyArIGVyci5tZXNzYWdlO1xuICAgICAgICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc2lub24ubG9nKG1zZyArIFwiW1wiICsgZXJyLm5hbWUgKyBcIl0gXCIgKyBlcnIubWVzc2FnZSk7XG5cbiAgICAgICAgICAgIGlmIChlcnIuc3RhY2spIHtcbiAgICAgICAgICAgICAgICBzaW5vbi5sb2coZXJyLnN0YWNrKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGxvZ0Vycm9yLnVzZUltbWVkaWF0ZUV4Y2VwdGlvbnMpIHtcbiAgICAgICAgICAgICAgICB0aHJvd0xvZ2dlZEVycm9yKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxvZ0Vycm9yLnNldFRpbWVvdXQodGhyb3dMb2dnZWRFcnJvciwgMCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvLyBXaGVuIHNldCB0byB0cnVlLCBhbnkgZXJyb3JzIGxvZ2dlZCB3aWxsIGJlIHRocm93biBpbW1lZGlhdGVseTtcbiAgICAgICAgLy8gSWYgc2V0IHRvIGZhbHNlLCB0aGUgZXJyb3JzIHdpbGwgYmUgdGhyb3duIGluIHNlcGFyYXRlIGV4ZWN1dGlvbiBmcmFtZS5cbiAgICAgICAgbG9nRXJyb3IudXNlSW1tZWRpYXRlRXhjZXB0aW9ucyA9IGZhbHNlO1xuXG4gICAgICAgIC8vIHdyYXAgcmVhbFNldFRpbWVvdXQgd2l0aCBzb21ldGhpbmcgd2UgY2FuIHN0dWIgaW4gdGVzdHNcbiAgICAgICAgbG9nRXJyb3Iuc2V0VGltZW91dCA9IGZ1bmN0aW9uIChmdW5jLCB0aW1lb3V0KSB7XG4gICAgICAgICAgICByZWFsU2V0VGltZW91dChmdW5jLCB0aW1lb3V0KTtcbiAgICAgICAgfTtcblxuICAgICAgICB2YXIgZXhwb3J0cyA9IHt9O1xuICAgICAgICBleHBvcnRzLmxvZyA9IHNpbm9uLmxvZyA9IGxvZztcbiAgICAgICAgZXhwb3J0cy5sb2dFcnJvciA9IHNpbm9uLmxvZ0Vycm9yID0gbG9nRXJyb3I7XG5cbiAgICAgICAgcmV0dXJuIGV4cG9ydHM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIHNpbm9uID0gcmVxdWlyZShcIi4vdXRpbC9jb3JlXCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoc2lub24pO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICogQGRlcGVuZCB0eXBlT2YuanNcbiAqL1xuLypqc2xpbnQgZXFlcWVxOiBmYWxzZSwgb25ldmFyOiBmYWxzZSwgcGx1c3BsdXM6IGZhbHNlKi9cbi8qZ2xvYmFsIG1vZHVsZSwgcmVxdWlyZSwgc2lub24qL1xuLyoqXG4gKiBNYXRjaCBmdW5jdGlvbnNcbiAqXG4gKiBAYXV0aG9yIE1heGltaWxpYW4gQW50b25pIChtYWlsQG1heGFudG9uaS5kZSlcbiAqIEBsaWNlbnNlIEJTRFxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMiBNYXhpbWlsaWFuIEFudG9uaVxuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIGZ1bmN0aW9uIGFzc2VydFR5cGUodmFsdWUsIHR5cGUsIG5hbWUpIHtcbiAgICAgICAgICAgIHZhciBhY3R1YWwgPSBzaW5vbi50eXBlT2YodmFsdWUpO1xuICAgICAgICAgICAgaWYgKGFjdHVhbCAhPT0gdHlwZSkge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJFeHBlY3RlZCB0eXBlIG9mIFwiICsgbmFtZSArIFwiIHRvIGJlIFwiICtcbiAgICAgICAgICAgICAgICAgICAgdHlwZSArIFwiLCBidXQgd2FzIFwiICsgYWN0dWFsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBtYXRjaGVyID0ge1xuICAgICAgICAgICAgdG9TdHJpbmc6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5tZXNzYWdlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGZ1bmN0aW9uIGlzTWF0Y2hlcihvYmplY3QpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaGVyLmlzUHJvdG90eXBlT2Yob2JqZWN0KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIG1hdGNoT2JqZWN0KGV4cGVjdGF0aW9uLCBhY3R1YWwpIHtcbiAgICAgICAgICAgIGlmIChhY3R1YWwgPT09IG51bGwgfHwgYWN0dWFsID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gZXhwZWN0YXRpb24pIHtcbiAgICAgICAgICAgICAgICBpZiAoZXhwZWN0YXRpb24uaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZXhwID0gZXhwZWN0YXRpb25ba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGFjdCA9IGFjdHVhbFtrZXldO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNNYXRjaGVyKGV4cCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghZXhwLnRlc3QoYWN0KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChzaW5vbi50eXBlT2YoZXhwKSA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFtYXRjaE9iamVjdChleHAsIGFjdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIXNpbm9uLmRlZXBFcXVhbChleHAsIGFjdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gbWF0Y2goZXhwZWN0YXRpb24sIG1lc3NhZ2UpIHtcbiAgICAgICAgICAgIHZhciBtID0gc2lub24uY3JlYXRlKG1hdGNoZXIpO1xuICAgICAgICAgICAgdmFyIHR5cGUgPSBzaW5vbi50eXBlT2YoZXhwZWN0YXRpb24pO1xuICAgICAgICAgICAgc3dpdGNoICh0eXBlKSB7XG4gICAgICAgICAgICBjYXNlIFwib2JqZWN0XCI6XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBleHBlY3RhdGlvbi50ZXN0ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uLnRlc3QoYWN0dWFsKSA9PT0gdHJ1ZTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgbS5tZXNzYWdlID0gXCJtYXRjaChcIiArIHNpbm9uLmZ1bmN0aW9uTmFtZShleHBlY3RhdGlvbi50ZXN0KSArIFwiKVwiO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdmFyIHN0ciA9IFtdO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGtleSBpbiBleHBlY3RhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXhwZWN0YXRpb24uaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc3RyLnB1c2goa2V5ICsgXCI6IFwiICsgZXhwZWN0YXRpb25ba2V5XSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWF0Y2hPYmplY3QoZXhwZWN0YXRpb24sIGFjdHVhbCk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBtLm1lc3NhZ2UgPSBcIm1hdGNoKFwiICsgc3RyLmpvaW4oXCIsIFwiKSArIFwiKVwiO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcIm51bWJlclwiOlxuICAgICAgICAgICAgICAgIG0udGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gd2UgbmVlZCB0eXBlIGNvZXJjaW9uIGhlcmVcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uID09IGFjdHVhbDsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBlcWVxZXFcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcInN0cmluZ1wiOlxuICAgICAgICAgICAgICAgIG0udGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBhY3R1YWwgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYWN0dWFsLmluZGV4T2YoZXhwZWN0YXRpb24pICE9PSAtMTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIG0ubWVzc2FnZSA9IFwibWF0Y2goXFxcIlwiICsgZXhwZWN0YXRpb24gKyBcIlxcXCIpXCI7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwicmVnZXhwXCI6XG4gICAgICAgICAgICAgICAgbS50ZXN0ID0gZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGFjdHVhbCAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBleHBlY3RhdGlvbi50ZXN0KGFjdHVhbCk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJmdW5jdGlvblwiOlxuICAgICAgICAgICAgICAgIG0udGVzdCA9IGV4cGVjdGF0aW9uO1xuICAgICAgICAgICAgICAgIGlmIChtZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIG0ubWVzc2FnZSA9IG1lc3NhZ2U7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgbS5tZXNzYWdlID0gXCJtYXRjaChcIiArIHNpbm9uLmZ1bmN0aW9uTmFtZShleHBlY3RhdGlvbikgKyBcIilcIjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgICAgICAgIG0udGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNpbm9uLmRlZXBFcXVhbChleHBlY3RhdGlvbiwgYWN0dWFsKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFtLm1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBtLm1lc3NhZ2UgPSBcIm1hdGNoKFwiICsgZXhwZWN0YXRpb24gKyBcIilcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBtO1xuICAgICAgICB9XG5cbiAgICAgICAgbWF0Y2hlci5vciA9IGZ1bmN0aW9uIChtMikge1xuICAgICAgICAgICAgaWYgKCFhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIk1hdGNoZXIgZXhwZWN0ZWRcIik7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFpc01hdGNoZXIobTIpKSB7XG4gICAgICAgICAgICAgICAgbTIgPSBtYXRjaChtMik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgbTEgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIG9yID0gc2lub24uY3JlYXRlKG1hdGNoZXIpO1xuICAgICAgICAgICAgb3IudGVzdCA9IGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbTEudGVzdChhY3R1YWwpIHx8IG0yLnRlc3QoYWN0dWFsKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBvci5tZXNzYWdlID0gbTEubWVzc2FnZSArIFwiLm9yKFwiICsgbTIubWVzc2FnZSArIFwiKVwiO1xuICAgICAgICAgICAgcmV0dXJuIG9yO1xuICAgICAgICB9O1xuXG4gICAgICAgIG1hdGNoZXIuYW5kID0gZnVuY3Rpb24gKG0yKSB7XG4gICAgICAgICAgICBpZiAoIWFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWF0Y2hlciBleHBlY3RlZFwiKTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzTWF0Y2hlcihtMikpIHtcbiAgICAgICAgICAgICAgICBtMiA9IG1hdGNoKG0yKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBtMSA9IHRoaXM7XG4gICAgICAgICAgICB2YXIgYW5kID0gc2lub24uY3JlYXRlKG1hdGNoZXIpO1xuICAgICAgICAgICAgYW5kLnRlc3QgPSBmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG0xLnRlc3QoYWN0dWFsKSAmJiBtMi50ZXN0KGFjdHVhbCk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgYW5kLm1lc3NhZ2UgPSBtMS5tZXNzYWdlICsgXCIuYW5kKFwiICsgbTIubWVzc2FnZSArIFwiKVwiO1xuICAgICAgICAgICAgcmV0dXJuIGFuZDtcbiAgICAgICAgfTtcblxuICAgICAgICBtYXRjaC5pc01hdGNoZXIgPSBpc01hdGNoZXI7XG5cbiAgICAgICAgbWF0Y2guYW55ID0gbWF0Y2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sIFwiYW55XCIpO1xuXG4gICAgICAgIG1hdGNoLmRlZmluZWQgPSBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgICAgICByZXR1cm4gYWN0dWFsICE9PSBudWxsICYmIGFjdHVhbCAhPT0gdW5kZWZpbmVkO1xuICAgICAgICB9LCBcImRlZmluZWRcIik7XG5cbiAgICAgICAgbWF0Y2gudHJ1dGh5ID0gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgcmV0dXJuICEhYWN0dWFsO1xuICAgICAgICB9LCBcInRydXRoeVwiKTtcblxuICAgICAgICBtYXRjaC5mYWxzeSA9IG1hdGNoKGZ1bmN0aW9uIChhY3R1YWwpIHtcbiAgICAgICAgICAgIHJldHVybiAhYWN0dWFsO1xuICAgICAgICB9LCBcImZhbHN5XCIpO1xuXG4gICAgICAgIG1hdGNoLnNhbWUgPSBmdW5jdGlvbiAoZXhwZWN0YXRpb24pIHtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uID09PSBhY3R1YWw7XG4gICAgICAgICAgICB9LCBcInNhbWUoXCIgKyBleHBlY3RhdGlvbiArIFwiKVwiKTtcbiAgICAgICAgfTtcblxuICAgICAgICBtYXRjaC50eXBlT2YgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICAgICAgYXNzZXJ0VHlwZSh0eXBlLCBcInN0cmluZ1wiLCBcInR5cGVcIik7XG4gICAgICAgICAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzaW5vbi50eXBlT2YoYWN0dWFsKSA9PT0gdHlwZTtcbiAgICAgICAgICAgIH0sIFwidHlwZU9mKFxcXCJcIiArIHR5cGUgKyBcIlxcXCIpXCIpO1xuICAgICAgICB9O1xuXG4gICAgICAgIG1hdGNoLmluc3RhbmNlT2YgPSBmdW5jdGlvbiAodHlwZSkge1xuICAgICAgICAgICAgYXNzZXJ0VHlwZSh0eXBlLCBcImZ1bmN0aW9uXCIsIFwidHlwZVwiKTtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaChmdW5jdGlvbiAoYWN0dWFsKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFjdHVhbCBpbnN0YW5jZW9mIHR5cGU7XG4gICAgICAgICAgICB9LCBcImluc3RhbmNlT2YoXCIgKyBzaW5vbi5mdW5jdGlvbk5hbWUodHlwZSkgKyBcIilcIik7XG4gICAgICAgIH07XG5cbiAgICAgICAgZnVuY3Rpb24gY3JlYXRlUHJvcGVydHlNYXRjaGVyKHByb3BlcnR5VGVzdCwgbWVzc2FnZVByZWZpeCkge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uIChwcm9wZXJ0eSwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICBhc3NlcnRUeXBlKHByb3BlcnR5LCBcInN0cmluZ1wiLCBcInByb3BlcnR5XCIpO1xuICAgICAgICAgICAgICAgIHZhciBvbmx5UHJvcGVydHkgPSBhcmd1bWVudHMubGVuZ3RoID09PSAxO1xuICAgICAgICAgICAgICAgIHZhciBtZXNzYWdlID0gbWVzc2FnZVByZWZpeCArIFwiKFxcXCJcIiArIHByb3BlcnR5ICsgXCJcXFwiXCI7XG4gICAgICAgICAgICAgICAgaWYgKCFvbmx5UHJvcGVydHkpIHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSArPSBcIiwgXCIgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbWVzc2FnZSArPSBcIilcIjtcbiAgICAgICAgICAgICAgICByZXR1cm4gbWF0Y2goZnVuY3Rpb24gKGFjdHVhbCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoYWN0dWFsID09PSB1bmRlZmluZWQgfHwgYWN0dWFsID09PSBudWxsIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIXByb3BlcnR5VGVzdChhY3R1YWwsIHByb3BlcnR5KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBvbmx5UHJvcGVydHkgfHwgc2lub24uZGVlcEVxdWFsKHZhbHVlLCBhY3R1YWxbcHJvcGVydHldKTtcbiAgICAgICAgICAgICAgICB9LCBtZXNzYWdlKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH1cblxuICAgICAgICBtYXRjaC5oYXMgPSBjcmVhdGVQcm9wZXJ0eU1hdGNoZXIoZnVuY3Rpb24gKGFjdHVhbCwgcHJvcGVydHkpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgYWN0dWFsID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb3BlcnR5IGluIGFjdHVhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBhY3R1YWxbcHJvcGVydHldICE9PSB1bmRlZmluZWQ7XG4gICAgICAgIH0sIFwiaGFzXCIpO1xuXG4gICAgICAgIG1hdGNoLmhhc093biA9IGNyZWF0ZVByb3BlcnR5TWF0Y2hlcihmdW5jdGlvbiAoYWN0dWFsLCBwcm9wZXJ0eSkge1xuICAgICAgICAgICAgcmV0dXJuIGFjdHVhbC5oYXNPd25Qcm9wZXJ0eShwcm9wZXJ0eSk7XG4gICAgICAgIH0sIFwiaGFzT3duXCIpO1xuXG4gICAgICAgIG1hdGNoLmJvb2wgPSBtYXRjaC50eXBlT2YoXCJib29sZWFuXCIpO1xuICAgICAgICBtYXRjaC5udW1iZXIgPSBtYXRjaC50eXBlT2YoXCJudW1iZXJcIik7XG4gICAgICAgIG1hdGNoLnN0cmluZyA9IG1hdGNoLnR5cGVPZihcInN0cmluZ1wiKTtcbiAgICAgICAgbWF0Y2gub2JqZWN0ID0gbWF0Y2gudHlwZU9mKFwib2JqZWN0XCIpO1xuICAgICAgICBtYXRjaC5mdW5jID0gbWF0Y2gudHlwZU9mKFwiZnVuY3Rpb25cIik7XG4gICAgICAgIG1hdGNoLmFycmF5ID0gbWF0Y2gudHlwZU9mKFwiYXJyYXlcIik7XG4gICAgICAgIG1hdGNoLnJlZ2V4cCA9IG1hdGNoLnR5cGVPZihcInJlZ2V4cFwiKTtcbiAgICAgICAgbWF0Y2guZGF0ZSA9IG1hdGNoLnR5cGVPZihcImRhdGVcIik7XG5cbiAgICAgICAgc2lub24ubWF0Y2ggPSBtYXRjaDtcbiAgICAgICAgcmV0dXJuIG1hdGNoO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3R5cGVPZlwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHRpbWVzX2luX3dvcmRzLmpzXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICogQGRlcGVuZCBjYWxsLmpzXG4gKiBAZGVwZW5kIGV4dGVuZC5qc1xuICogQGRlcGVuZCBtYXRjaC5qc1xuICogQGRlcGVuZCBzcHkuanNcbiAqIEBkZXBlbmQgc3R1Yi5qc1xuICogQGRlcGVuZCBmb3JtYXQuanNcbiAqL1xuLyoqXG4gKiBNb2NrIGZ1bmN0aW9ucy5cbiAqXG4gKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAqIEBsaWNlbnNlIEJTRFxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMC0yMDEzIENocmlzdGlhbiBKb2hhbnNlblxuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIHZhciBwdXNoID0gW10ucHVzaDtcbiAgICAgICAgdmFyIG1hdGNoID0gc2lub24ubWF0Y2g7XG5cbiAgICAgICAgZnVuY3Rpb24gbW9jayhvYmplY3QpIHtcbiAgICAgICAgICAgIC8vIGlmICh0eXBlb2YgY29uc29sZSAhPT0gdW5kZWZpbmVkICYmIGNvbnNvbGUud2Fybikge1xuICAgICAgICAgICAgLy8gICAgIGNvbnNvbGUud2FybihcIm1vY2sgd2lsbCBiZSByZW1vdmVkIGZyb20gU2lub24uSlMgdjIuMFwiKTtcbiAgICAgICAgICAgIC8vIH1cblxuICAgICAgICAgICAgaWYgKCFvYmplY3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc2lub24uZXhwZWN0YXRpb24uY3JlYXRlKFwiQW5vbnltb3VzIG1vY2tcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBtb2NrLmNyZWF0ZShvYmplY3QpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gZWFjaChjb2xsZWN0aW9uLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGNvbGxlY3Rpb24ubGVuZ3RoOyBpIDwgbDsgaSArPSAxKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2soY29sbGVjdGlvbltpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBhcnJheUVxdWFscyhhcnIxLCBhcnIyLCBjb21wYXJlTGVuZ3RoKSB7XG4gICAgICAgICAgICBpZiAoY29tcGFyZUxlbmd0aCAmJiAoYXJyMS5sZW5ndGggIT09IGFycjIubGVuZ3RoKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBhcnIxLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICghc2lub24uZGVlcEVxdWFsKGFycjFbaV0sIGFycjJbaV0pKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNpbm9uLmV4dGVuZChtb2NrLCB7XG4gICAgICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIGNyZWF0ZShvYmplY3QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIW9iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwib2JqZWN0IGlzIG51bGxcIik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIG1vY2tPYmplY3QgPSBzaW5vbi5leHRlbmQoe30sIG1vY2spO1xuICAgICAgICAgICAgICAgIG1vY2tPYmplY3Qub2JqZWN0ID0gb2JqZWN0O1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBtb2NrT2JqZWN0LmNyZWF0ZTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBtb2NrT2JqZWN0O1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZXhwZWN0czogZnVuY3Rpb24gZXhwZWN0cyhtZXRob2QpIHtcbiAgICAgICAgICAgICAgICBpZiAoIW1ldGhvZCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwibWV0aG9kIGlzIGZhbHN5XCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5leHBlY3RhdGlvbnMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5leHBlY3RhdGlvbnMgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm94aWVzID0gW107XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmV4cGVjdGF0aW9uc1ttZXRob2RdKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZXhwZWN0YXRpb25zW21ldGhvZF0gPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1vY2tPYmplY3QgPSB0aGlzO1xuXG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLndyYXBNZXRob2QodGhpcy5vYmplY3QsIG1ldGhvZCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG1vY2tPYmplY3QuaW52b2tlTWV0aG9kKG1ldGhvZCwgdGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgICAgICAgICAgcHVzaC5jYWxsKHRoaXMucHJveGllcywgbWV0aG9kKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgZXhwZWN0YXRpb24gPSBzaW5vbi5leHBlY3RhdGlvbi5jcmVhdGUobWV0aG9kKTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5leHBlY3RhdGlvbnNbbWV0aG9kXSwgZXhwZWN0YXRpb24pO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGV4cGVjdGF0aW9uO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgcmVzdG9yZTogZnVuY3Rpb24gcmVzdG9yZSgpIHtcbiAgICAgICAgICAgICAgICB2YXIgb2JqZWN0ID0gdGhpcy5vYmplY3Q7XG5cbiAgICAgICAgICAgICAgICBlYWNoKHRoaXMucHJveGllcywgZnVuY3Rpb24gKHByb3h5KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygb2JqZWN0W3Byb3h5XS5yZXN0b3JlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9iamVjdFtwcm94eV0ucmVzdG9yZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICB2ZXJpZnk6IGZ1bmN0aW9uIHZlcmlmeSgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXhwZWN0YXRpb25zID0gdGhpcy5leHBlY3RhdGlvbnMgfHwge307XG4gICAgICAgICAgICAgICAgdmFyIG1lc3NhZ2VzID0gW107XG4gICAgICAgICAgICAgICAgdmFyIG1ldCA9IFtdO1xuXG4gICAgICAgICAgICAgICAgZWFjaCh0aGlzLnByb3hpZXMsIGZ1bmN0aW9uIChwcm94eSkge1xuICAgICAgICAgICAgICAgICAgICBlYWNoKGV4cGVjdGF0aW9uc1twcm94eV0sIGZ1bmN0aW9uIChleHBlY3RhdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFleHBlY3RhdGlvbi5tZXQoKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChtZXNzYWdlcywgZXhwZWN0YXRpb24udG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChtZXQsIGV4cGVjdGF0aW9uLnRvU3RyaW5nKCkpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHRoaXMucmVzdG9yZSgpO1xuXG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2VzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgc2lub24uZXhwZWN0YXRpb24uZmFpbChtZXNzYWdlcy5jb25jYXQobWV0KS5qb2luKFwiXFxuXCIpKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG1ldC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmV4cGVjdGF0aW9uLnBhc3MobWVzc2FnZXMuY29uY2F0KG1ldCkuam9pbihcIlxcblwiKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBpbnZva2VNZXRob2Q6IGZ1bmN0aW9uIGludm9rZU1ldGhvZChtZXRob2QsIHRoaXNWYWx1ZSwgYXJncykge1xuICAgICAgICAgICAgICAgIHZhciBleHBlY3RhdGlvbnMgPSB0aGlzLmV4cGVjdGF0aW9ucyAmJiB0aGlzLmV4cGVjdGF0aW9uc1ttZXRob2RdID8gdGhpcy5leHBlY3RhdGlvbnNbbWV0aG9kXSA6IFtdO1xuICAgICAgICAgICAgICAgIHZhciBleHBlY3RhdGlvbnNXaXRoTWF0Y2hpbmdBcmdzID0gW107XG4gICAgICAgICAgICAgICAgdmFyIGN1cnJlbnRBcmdzID0gYXJncyB8fCBbXTtcbiAgICAgICAgICAgICAgICB2YXIgaSwgYXZhaWxhYmxlO1xuXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGV4cGVjdGF0aW9ucy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgZXhwZWN0ZWRBcmdzID0gZXhwZWN0YXRpb25zW2ldLmV4cGVjdGVkQXJndW1lbnRzIHx8IFtdO1xuICAgICAgICAgICAgICAgICAgICBpZiAoYXJyYXlFcXVhbHMoZXhwZWN0ZWRBcmdzLCBjdXJyZW50QXJncywgZXhwZWN0YXRpb25zW2ldLmV4cGVjdHNFeGFjdEFyZ0NvdW50KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJncy5wdXNoKGV4cGVjdGF0aW9uc1tpXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJncy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIWV4cGVjdGF0aW9uc1dpdGhNYXRjaGluZ0FyZ3NbaV0ubWV0KCkgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cGVjdGF0aW9uc1dpdGhNYXRjaGluZ0FyZ3NbaV0uYWxsb3dzQ2FsbCh0aGlzVmFsdWUsIGFyZ3MpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJnc1tpXS5hcHBseSh0aGlzVmFsdWUsIGFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIG1lc3NhZ2VzID0gW107XG4gICAgICAgICAgICAgICAgdmFyIGV4aGF1c3RlZCA9IDA7XG5cbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJncy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoZXhwZWN0YXRpb25zV2l0aE1hdGNoaW5nQXJnc1tpXS5hbGxvd3NDYWxsKHRoaXNWYWx1ZSwgYXJncykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGF2YWlsYWJsZSA9IGF2YWlsYWJsZSB8fCBleHBlY3RhdGlvbnNXaXRoTWF0Y2hpbmdBcmdzW2ldO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXhoYXVzdGVkICs9IDE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoYXZhaWxhYmxlICYmIGV4aGF1c3RlZCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gYXZhaWxhYmxlLmFwcGx5KHRoaXNWYWx1ZSwgYXJncyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGV4cGVjdGF0aW9ucy5sZW5ndGg7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICBwdXNoLmNhbGwobWVzc2FnZXMsIFwiICAgIFwiICsgZXhwZWN0YXRpb25zW2ldLnRvU3RyaW5nKCkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG1lc3NhZ2VzLnVuc2hpZnQoXCJVbmV4cGVjdGVkIGNhbGw6IFwiICsgc2lub24uc3B5Q2FsbC50b1N0cmluZy5jYWxsKHtcbiAgICAgICAgICAgICAgICAgICAgcHJveHk6IG1ldGhvZCxcbiAgICAgICAgICAgICAgICAgICAgYXJnczogYXJnc1xuICAgICAgICAgICAgICAgIH0pKTtcblxuICAgICAgICAgICAgICAgIHNpbm9uLmV4cGVjdGF0aW9uLmZhaWwobWVzc2FnZXMuam9pbihcIlxcblwiKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHZhciB0aW1lcyA9IHNpbm9uLnRpbWVzSW5Xb3JkcztcbiAgICAgICAgdmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG4gICAgICAgIGZ1bmN0aW9uIGNhbGxDb3VudEluV29yZHMoY2FsbENvdW50KSB7XG4gICAgICAgICAgICBpZiAoY2FsbENvdW50ID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwibmV2ZXIgY2FsbGVkXCI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBcImNhbGxlZCBcIiArIHRpbWVzKGNhbGxDb3VudCk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBleHBlY3RlZENhbGxDb3VudEluV29yZHMoZXhwZWN0YXRpb24pIHtcbiAgICAgICAgICAgIHZhciBtaW4gPSBleHBlY3RhdGlvbi5taW5DYWxscztcbiAgICAgICAgICAgIHZhciBtYXggPSBleHBlY3RhdGlvbi5tYXhDYWxscztcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBtaW4gPT09IFwibnVtYmVyXCIgJiYgdHlwZW9mIG1heCA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgICAgIHZhciBzdHIgPSB0aW1lcyhtaW4pO1xuXG4gICAgICAgICAgICAgICAgaWYgKG1pbiAhPT0gbWF4KSB7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9IFwiYXQgbGVhc3QgXCIgKyBzdHIgKyBcIiBhbmQgYXQgbW9zdCBcIiArIHRpbWVzKG1heCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHN0cjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBtaW4gPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJhdCBsZWFzdCBcIiArIHRpbWVzKG1pbik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBcImF0IG1vc3QgXCIgKyB0aW1lcyhtYXgpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gcmVjZWl2ZWRNaW5DYWxscyhleHBlY3RhdGlvbikge1xuICAgICAgICAgICAgdmFyIGhhc01pbkxpbWl0ID0gdHlwZW9mIGV4cGVjdGF0aW9uLm1pbkNhbGxzID09PSBcIm51bWJlclwiO1xuICAgICAgICAgICAgcmV0dXJuICFoYXNNaW5MaW1pdCB8fCBleHBlY3RhdGlvbi5jYWxsQ291bnQgPj0gZXhwZWN0YXRpb24ubWluQ2FsbHM7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiByZWNlaXZlZE1heENhbGxzKGV4cGVjdGF0aW9uKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGV4cGVjdGF0aW9uLm1heENhbGxzICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZXhwZWN0YXRpb24uY2FsbENvdW50ID09PSBleHBlY3RhdGlvbi5tYXhDYWxscztcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHZlcmlmeU1hdGNoZXIocG9zc2libGVNYXRjaGVyLCBhcmcpIHtcbiAgICAgICAgICAgIHZhciBpc01hdGNoZXIgPSBtYXRjaCAmJiBtYXRjaC5pc01hdGNoZXIocG9zc2libGVNYXRjaGVyKTtcblxuICAgICAgICAgICAgcmV0dXJuIGlzTWF0Y2hlciAmJiBwb3NzaWJsZU1hdGNoZXIudGVzdChhcmcpIHx8IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBzaW5vbi5leHBlY3RhdGlvbiA9IHtcbiAgICAgICAgICAgIG1pbkNhbGxzOiAxLFxuICAgICAgICAgICAgbWF4Q2FsbHM6IDEsXG5cbiAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gY3JlYXRlKG1ldGhvZE5hbWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXhwZWN0YXRpb24gPSBzaW5vbi5leHRlbmQoc2lub24uc3R1Yi5jcmVhdGUoKSwgc2lub24uZXhwZWN0YXRpb24pO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBleHBlY3RhdGlvbi5jcmVhdGU7XG4gICAgICAgICAgICAgICAgZXhwZWN0YXRpb24ubWV0aG9kID0gbWV0aG9kTmFtZTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBleHBlY3RhdGlvbjtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGludm9rZTogZnVuY3Rpb24gaW52b2tlKGZ1bmMsIHRoaXNWYWx1ZSwgYXJncykge1xuICAgICAgICAgICAgICAgIHRoaXMudmVyaWZ5Q2FsbEFsbG93ZWQodGhpc1ZhbHVlLCBhcmdzKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBzaW5vbi5zcHkuaW52b2tlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBhdExlYXN0OiBmdW5jdGlvbiBhdExlYXN0KG51bSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgbnVtICE9PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCInXCIgKyBudW0gKyBcIicgaXMgbm90IG51bWJlclwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMubGltaXRzU2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubWF4Q2FsbHMgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpbWl0c1NldCA9IHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5taW5DYWxscyA9IG51bTtcblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgYXRNb3N0OiBmdW5jdGlvbiBhdE1vc3QobnVtKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBudW0gIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIidcIiArIG51bSArIFwiJyBpcyBub3QgbnVtYmVyXCIpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5saW1pdHNTZXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5taW5DYWxscyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGltaXRzU2V0ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLm1heENhbGxzID0gbnVtO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBuZXZlcjogZnVuY3Rpb24gbmV2ZXIoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZXhhY3RseSgwKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uY2U6IGZ1bmN0aW9uIG9uY2UoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZXhhY3RseSgxKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHR3aWNlOiBmdW5jdGlvbiB0d2ljZSgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5leGFjdGx5KDIpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgdGhyaWNlOiBmdW5jdGlvbiB0aHJpY2UoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZXhhY3RseSgzKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGV4YWN0bHk6IGZ1bmN0aW9uIGV4YWN0bHkobnVtKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBudW0gIT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIidcIiArIG51bSArIFwiJyBpcyBub3QgYSBudW1iZXJcIik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5hdExlYXN0KG51bSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuYXRNb3N0KG51bSk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBtZXQ6IGZ1bmN0aW9uIG1ldCgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gIXRoaXMuZmFpbGVkICYmIHJlY2VpdmVkTWluQ2FsbHModGhpcyk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICB2ZXJpZnlDYWxsQWxsb3dlZDogZnVuY3Rpb24gdmVyaWZ5Q2FsbEFsbG93ZWQodGhpc1ZhbHVlLCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgaWYgKHJlY2VpdmVkTWF4Q2FsbHModGhpcykpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mYWlsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBzaW5vbi5leHBlY3RhdGlvbi5mYWlsKHRoaXMubWV0aG9kICsgXCIgYWxyZWFkeSBjYWxsZWQgXCIgKyB0aW1lcyh0aGlzLm1heENhbGxzKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKFwiZXhwZWN0ZWRUaGlzXCIgaW4gdGhpcyAmJiB0aGlzLmV4cGVjdGVkVGhpcyAhPT0gdGhpc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmV4cGVjdGF0aW9uLmZhaWwodGhpcy5tZXRob2QgKyBcIiBjYWxsZWQgd2l0aCBcIiArIHRoaXNWYWx1ZSArIFwiIGFzIHRoaXNWYWx1ZSwgZXhwZWN0ZWQgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5leHBlY3RlZFRoaXMpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghKFwiZXhwZWN0ZWRBcmd1bWVudHNcIiBpbiB0aGlzKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKCFhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmV4cGVjdGF0aW9uLmZhaWwodGhpcy5tZXRob2QgKyBcIiByZWNlaXZlZCBubyBhcmd1bWVudHMsIGV4cGVjdGVkIFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNpbm9uLmZvcm1hdCh0aGlzLmV4cGVjdGVkQXJndW1lbnRzKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGFyZ3MubGVuZ3RoIDwgdGhpcy5leHBlY3RlZEFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgc2lub24uZXhwZWN0YXRpb24uZmFpbCh0aGlzLm1ldGhvZCArIFwiIHJlY2VpdmVkIHRvbyBmZXcgYXJndW1lbnRzIChcIiArIHNpbm9uLmZvcm1hdChhcmdzKSArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiksIGV4cGVjdGVkIFwiICsgc2lub24uZm9ybWF0KHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5leHBlY3RzRXhhY3RBcmdDb3VudCAmJlxuICAgICAgICAgICAgICAgICAgICBhcmdzLmxlbmd0aCAhPT0gdGhpcy5leHBlY3RlZEFyZ3VtZW50cy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgc2lub24uZXhwZWN0YXRpb24uZmFpbCh0aGlzLm1ldGhvZCArIFwiIHJlY2VpdmVkIHRvbyBtYW55IGFyZ3VtZW50cyAoXCIgKyBzaW5vbi5mb3JtYXQoYXJncykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIpLCBleHBlY3RlZCBcIiArIHNpbm9uLmZvcm1hdCh0aGlzLmV4cGVjdGVkQXJndW1lbnRzKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSB0aGlzLmV4cGVjdGVkQXJndW1lbnRzLmxlbmd0aDsgaSA8IGw7IGkgKz0gMSkge1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghdmVyaWZ5TWF0Y2hlcih0aGlzLmV4cGVjdGVkQXJndW1lbnRzW2ldLCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2lub24uZXhwZWN0YXRpb24uZmFpbCh0aGlzLm1ldGhvZCArIFwiIHJlY2VpdmVkIHdyb25nIGFyZ3VtZW50cyBcIiArIHNpbm9uLmZvcm1hdChhcmdzKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIsIGRpZG4ndCBtYXRjaCBcIiArIHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBpZiAoIXNpbm9uLmRlZXBFcXVhbCh0aGlzLmV4cGVjdGVkQXJndW1lbnRzW2ldLCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2lub24uZXhwZWN0YXRpb24uZmFpbCh0aGlzLm1ldGhvZCArIFwiIHJlY2VpdmVkIHdyb25nIGFyZ3VtZW50cyBcIiArIHNpbm9uLmZvcm1hdChhcmdzKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCIsIGV4cGVjdGVkIFwiICsgc2lub24uZm9ybWF0KHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGFsbG93c0NhbGw6IGZ1bmN0aW9uIGFsbG93c0NhbGwodGhpc1ZhbHVlLCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubWV0KCkgJiYgcmVjZWl2ZWRNYXhDYWxscyh0aGlzKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKFwiZXhwZWN0ZWRUaGlzXCIgaW4gdGhpcyAmJiB0aGlzLmV4cGVjdGVkVGhpcyAhPT0gdGhpc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIShcImV4cGVjdGVkQXJndW1lbnRzXCIgaW4gdGhpcykpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgYXJncyA9IGFyZ3MgfHwgW107XG5cbiAgICAgICAgICAgICAgICBpZiAoYXJncy5sZW5ndGggPCB0aGlzLmV4cGVjdGVkQXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZXhwZWN0c0V4YWN0QXJnQ291bnQgJiZcbiAgICAgICAgICAgICAgICAgICAgYXJncy5sZW5ndGggIT09IHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMubGVuZ3RoOyBpIDwgbDsgaSArPSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghdmVyaWZ5TWF0Y2hlcih0aGlzLmV4cGVjdGVkQXJndW1lbnRzW2ldLCBhcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFzaW5vbi5kZWVwRXF1YWwodGhpcy5leHBlY3RlZEFyZ3VtZW50c1tpXSwgYXJnc1tpXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgd2l0aEFyZ3M6IGZ1bmN0aW9uIHdpdGhBcmdzKCkge1xuICAgICAgICAgICAgICAgIHRoaXMuZXhwZWN0ZWRBcmd1bWVudHMgPSBzbGljZS5jYWxsKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICB3aXRoRXhhY3RBcmdzOiBmdW5jdGlvbiB3aXRoRXhhY3RBcmdzKCkge1xuICAgICAgICAgICAgICAgIHRoaXMud2l0aEFyZ3MuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB0aGlzLmV4cGVjdHNFeGFjdEFyZ0NvdW50ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uOiBmdW5jdGlvbiBvbih0aGlzVmFsdWUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmV4cGVjdGVkVGhpcyA9IHRoaXNWYWx1ZTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGFyZ3MgPSAodGhpcy5leHBlY3RlZEFyZ3VtZW50cyB8fCBbXSkuc2xpY2UoKTtcblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5leHBlY3RzRXhhY3RBcmdDb3VudCkge1xuICAgICAgICAgICAgICAgICAgICBwdXNoLmNhbGwoYXJncywgXCJbLi4uXVwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgY2FsbFN0ciA9IHNpbm9uLnNweUNhbGwudG9TdHJpbmcuY2FsbCh7XG4gICAgICAgICAgICAgICAgICAgIHByb3h5OiB0aGlzLm1ldGhvZCB8fCBcImFub255bW91cyBtb2NrIGV4cGVjdGF0aW9uXCIsXG4gICAgICAgICAgICAgICAgICAgIGFyZ3M6IGFyZ3NcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHZhciBtZXNzYWdlID0gY2FsbFN0ci5yZXBsYWNlKFwiLCBbLi4uXCIsIFwiWywgLi4uXCIpICsgXCIgXCIgK1xuICAgICAgICAgICAgICAgICAgICBleHBlY3RlZENhbGxDb3VudEluV29yZHModGhpcyk7XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5tZXQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJFeHBlY3RhdGlvbiBtZXQ6IFwiICsgbWVzc2FnZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gXCJFeHBlY3RlZCBcIiArIG1lc3NhZ2UgKyBcIiAoXCIgK1xuICAgICAgICAgICAgICAgICAgICBjYWxsQ291bnRJbldvcmRzKHRoaXMuY2FsbENvdW50KSArIFwiKVwiO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgdmVyaWZ5OiBmdW5jdGlvbiB2ZXJpZnkoKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLm1ldCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmV4cGVjdGF0aW9uLmZhaWwodGhpcy50b1N0cmluZygpKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzaW5vbi5leHBlY3RhdGlvbi5wYXNzKHRoaXMudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBwYXNzOiBmdW5jdGlvbiBwYXNzKG1lc3NhZ2UpIHtcbiAgICAgICAgICAgICAgICBzaW5vbi5hc3NlcnQucGFzcyhtZXNzYWdlKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGZhaWw6IGZ1bmN0aW9uIGZhaWwobWVzc2FnZSkge1xuICAgICAgICAgICAgICAgIHZhciBleGNlcHRpb24gPSBuZXcgRXJyb3IobWVzc2FnZSk7XG4gICAgICAgICAgICAgICAgZXhjZXB0aW9uLm5hbWUgPSBcIkV4cGVjdGF0aW9uRXJyb3JcIjtcblxuICAgICAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5tb2NrID0gbW9jaztcbiAgICAgICAgcmV0dXJuIG1vY2s7XG4gICAgfVxuXG4gICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICB2YXIgaXNBTUQgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT09IFwib2JqZWN0XCIgJiYgZGVmaW5lLmFtZDtcblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7XG4gICAgICAgIHZhciBzaW5vbiA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vdGltZXNfaW5fd29yZHNcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2NhbGxcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2V4dGVuZFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vbWF0Y2hcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3NweVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc3R1YlwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZm9ybWF0XCIpO1xuXG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gbWFrZUFwaShzaW5vbik7XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqIEBkZXBlbmQgZXh0ZW5kLmpzXG4gKiBAZGVwZW5kIGNvbGxlY3Rpb24uanNcbiAqIEBkZXBlbmQgdXRpbC9mYWtlX3RpbWVycy5qc1xuICogQGRlcGVuZCB1dGlsL2Zha2Vfc2VydmVyX3dpdGhfY2xvY2suanNcbiAqL1xuLyoqXG4gKiBNYW5hZ2VzIGZha2UgY29sbGVjdGlvbnMgYXMgd2VsbCBhcyBmYWtlIHV0aWxpdGllcyBzdWNoIGFzIFNpbm9uJ3NcbiAqIHRpbWVycyBhbmQgZmFrZSBYSFIgaW1wbGVtZW50YXRpb24gaW4gb25lIGNvbnZlbmllbnQgb2JqZWN0LlxuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoc2lub25HbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGZ1bmN0aW9uIG1ha2VBcGkoc2lub24pIHtcbiAgICAgICAgdmFyIHB1c2ggPSBbXS5wdXNoO1xuXG4gICAgICAgIGZ1bmN0aW9uIGV4cG9zZVZhbHVlKHNhbmRib3gsIGNvbmZpZywga2V5LCB2YWx1ZSkge1xuICAgICAgICAgICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNvbmZpZy5pbmplY3RJbnRvICYmICEoa2V5IGluIGNvbmZpZy5pbmplY3RJbnRvKSkge1xuICAgICAgICAgICAgICAgIGNvbmZpZy5pbmplY3RJbnRvW2tleV0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICBzYW5kYm94LmluamVjdGVkS2V5cy5wdXNoKGtleSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHB1c2guY2FsbChzYW5kYm94LmFyZ3MsIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHByZXBhcmVTYW5kYm94RnJvbUNvbmZpZyhjb25maWcpIHtcbiAgICAgICAgICAgIHZhciBzYW5kYm94ID0gc2lub24uY3JlYXRlKHNpbm9uLnNhbmRib3gpO1xuXG4gICAgICAgICAgICBpZiAoY29uZmlnLnVzZUZha2VTZXJ2ZXIpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIGNvbmZpZy51c2VGYWtlU2VydmVyID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNhbmRib3guc2VydmVyUHJvdG90eXBlID0gY29uZmlnLnVzZUZha2VTZXJ2ZXI7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgc2FuZGJveC51c2VGYWtlU2VydmVyKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjb25maWcudXNlRmFrZVRpbWVycykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgY29uZmlnLnVzZUZha2VUaW1lcnMgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICAgICAgc2FuZGJveC51c2VGYWtlVGltZXJzLmFwcGx5KHNhbmRib3gsIGNvbmZpZy51c2VGYWtlVGltZXJzKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzYW5kYm94LnVzZUZha2VUaW1lcnMoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBzYW5kYm94O1xuICAgICAgICB9XG5cbiAgICAgICAgc2lub24uc2FuZGJveCA9IHNpbm9uLmV4dGVuZChzaW5vbi5jcmVhdGUoc2lub24uY29sbGVjdGlvbiksIHtcbiAgICAgICAgICAgIHVzZUZha2VUaW1lcnM6IGZ1bmN0aW9uIHVzZUZha2VUaW1lcnMoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5jbG9jayA9IHNpbm9uLnVzZUZha2VUaW1lcnMuYXBwbHkoc2lub24sIGFyZ3VtZW50cyk7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5hZGQodGhpcy5jbG9jayk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBzZXJ2ZXJQcm90b3R5cGU6IHNpbm9uLmZha2VTZXJ2ZXIsXG5cbiAgICAgICAgICAgIHVzZUZha2VTZXJ2ZXI6IGZ1bmN0aW9uIHVzZUZha2VTZXJ2ZXIoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHByb3RvID0gdGhpcy5zZXJ2ZXJQcm90b3R5cGUgfHwgc2lub24uZmFrZVNlcnZlcjtcblxuICAgICAgICAgICAgICAgIGlmICghcHJvdG8gfHwgIXByb3RvLmNyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLnNlcnZlciA9IHByb3RvLmNyZWF0ZSgpO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmFkZCh0aGlzLnNlcnZlcik7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBpbmplY3Q6IGZ1bmN0aW9uIChvYmopIHtcbiAgICAgICAgICAgICAgICBzaW5vbi5jb2xsZWN0aW9uLmluamVjdC5jYWxsKHRoaXMsIG9iaik7XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5jbG9jaykge1xuICAgICAgICAgICAgICAgICAgICBvYmouY2xvY2sgPSB0aGlzLmNsb2NrO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnNlcnZlcikge1xuICAgICAgICAgICAgICAgICAgICBvYmouc2VydmVyID0gdGhpcy5zZXJ2ZXI7XG4gICAgICAgICAgICAgICAgICAgIG9iai5yZXF1ZXN0cyA9IHRoaXMuc2VydmVyLnJlcXVlc3RzO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG9iai5tYXRjaCA9IHNpbm9uLm1hdGNoO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9iajtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlc3RvcmU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJzYW5kYm94LnJlc3RvcmUoKSBkb2VzIG5vdCB0YWtlIGFueSBwYXJhbWV0ZXJzLiBQZXJoYXBzIHlvdSBtZWFudCBzdHViLnJlc3RvcmUoKVwiKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBzaW5vbi5jb2xsZWN0aW9uLnJlc3RvcmUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc3RvcmVDb250ZXh0KCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXN0b3JlQ29udGV4dDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmluamVjdGVkS2V5cykge1xuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgaiA9IHRoaXMuaW5qZWN0ZWRLZXlzLmxlbmd0aDsgaSA8IGo7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuaW5qZWN0SW50b1t0aGlzLmluamVjdGVkS2V5c1tpXV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5pbmplY3RlZEtleXMgPSBbXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgICAgICBpZiAoIWNvbmZpZykge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gc2lub24uY3JlYXRlKHNpbm9uLnNhbmRib3gpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBzYW5kYm94ID0gcHJlcGFyZVNhbmRib3hGcm9tQ29uZmlnKGNvbmZpZyk7XG4gICAgICAgICAgICAgICAgc2FuZGJveC5hcmdzID0gc2FuZGJveC5hcmdzIHx8IFtdO1xuICAgICAgICAgICAgICAgIHNhbmRib3guaW5qZWN0ZWRLZXlzID0gW107XG4gICAgICAgICAgICAgICAgc2FuZGJveC5pbmplY3RJbnRvID0gY29uZmlnLmluamVjdEludG87XG4gICAgICAgICAgICAgICAgdmFyIHByb3AsXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlO1xuICAgICAgICAgICAgICAgIHZhciBleHBvc2VkID0gc2FuZGJveC5pbmplY3Qoe30pO1xuXG4gICAgICAgICAgICAgICAgaWYgKGNvbmZpZy5wcm9wZXJ0aWVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gY29uZmlnLnByb3BlcnRpZXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBwcm9wID0gY29uZmlnLnByb3BlcnRpZXNbaV07XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGV4cG9zZWRbcHJvcF0gfHwgcHJvcCA9PT0gXCJzYW5kYm94XCIgJiYgc2FuZGJveDtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV4cG9zZVZhbHVlKHNhbmRib3gsIGNvbmZpZywgcHJvcCwgdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZXhwb3NlVmFsdWUoc2FuZGJveCwgY29uZmlnLCBcInNhbmRib3hcIiwgdmFsdWUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBzYW5kYm94O1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgbWF0Y2g6IHNpbm9uLm1hdGNoXG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNpbm9uLnNhbmRib3gudXNlRmFrZVhNTEh0dHBSZXF1ZXN0ID0gc2lub24uc2FuZGJveC51c2VGYWtlU2VydmVyO1xuXG4gICAgICAgIHJldHVybiBzaW5vbi5zYW5kYm94O1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2V4dGVuZFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vdXRpbC9mYWtlX3NlcnZlcl93aXRoX2Nsb2NrXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi91dGlsL2Zha2VfdGltZXJzXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9jb2xsZWN0aW9uXCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoc2lub24pO1xuICAgIH1cblxuICAgIGlmIChpc0FNRCkge1xuICAgICAgICBkZWZpbmUobG9hZERlcGVuZGVuY2llcyk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgbW9kdWxlLmV4cG9ydHMsIG1vZHVsZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2lub25HbG9iYWwpIHtcbiAgICAgICAgbWFrZUFwaShzaW5vbkdsb2JhbCk7XG4gICAgfVxufShcbiAgICB0eXBlb2Ygc2lub24gPT09IFwib2JqZWN0XCIgJiYgc2lub24gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuKSk7XG4iLCIvKipcbiAgKiBAZGVwZW5kIHRpbWVzX2luX3dvcmRzLmpzXG4gICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAgKiBAZGVwZW5kIGV4dGVuZC5qc1xuICAqIEBkZXBlbmQgY2FsbC5qc1xuICAqIEBkZXBlbmQgZm9ybWF0LmpzXG4gICovXG4vKipcbiAgKiBTcHkgZnVuY3Rpb25zXG4gICpcbiAgKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAgKiBAbGljZW5zZSBCU0RcbiAgKlxuICAqIENvcHlyaWdodCAoYykgMjAxMC0yMDEzIENocmlzdGlhbiBKb2hhbnNlblxuICAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICB2YXIgcHVzaCA9IEFycmF5LnByb3RvdHlwZS5wdXNoO1xuICAgICAgICB2YXIgc2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XG4gICAgICAgIHZhciBjYWxsSWQgPSAwO1xuXG4gICAgICAgIGZ1bmN0aW9uIHNweShvYmplY3QsIHByb3BlcnR5LCB0eXBlcykge1xuICAgICAgICAgICAgaWYgKCFwcm9wZXJ0eSAmJiB0eXBlb2Ygb2JqZWN0ID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3B5LmNyZWF0ZShvYmplY3QpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIW9iamVjdCAmJiAhcHJvcGVydHkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3B5LmNyZWF0ZShmdW5jdGlvbiAoKSB7IH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHlwZXMpIHtcbiAgICAgICAgICAgICAgICAvLyBBIG5ldyBkZXNjcmlwdG9yIGlzIG5lZWRlZCBoZXJlIGJlY2F1c2Ugd2UgY2FuIG9ubHkgd3JhcCBmdW5jdGlvbnNcbiAgICAgICAgICAgICAgICAvLyBCeSBwYXNzaW5nIHRoZSBvcmlnaW5hbCBkZXNjcmlwdG9yIHdlIHdvdWxkIGVuZCB1cCB0cnlpbmcgdG8gc3B5IG5vbi1mdW5jdGlvbiBwcm9wZXJ0aWVzXG4gICAgICAgICAgICAgICAgdmFyIGRlc2NyaXB0b3IgPSB7fTtcbiAgICAgICAgICAgICAgICB2YXIgbWV0aG9kRGVzYyA9IHNpbm9uLmdldFByb3BlcnR5RGVzY3JpcHRvcihvYmplY3QsIHByb3BlcnR5KTtcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdHlwZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgZGVzY3JpcHRvclt0eXBlc1tpXV0gPSBzcHkuY3JlYXRlKG1ldGhvZERlc2NbdHlwZXNbaV1dKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNpbm9uLndyYXBNZXRob2Qob2JqZWN0LCBwcm9wZXJ0eSwgZGVzY3JpcHRvcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBzaW5vbi53cmFwTWV0aG9kKG9iamVjdCwgcHJvcGVydHksIHNweS5jcmVhdGUob2JqZWN0W3Byb3BlcnR5XSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gbWF0Y2hpbmdGYWtlKGZha2VzLCBhcmdzLCBzdHJpY3QpIHtcbiAgICAgICAgICAgIGlmICghZmFrZXMpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGZha2VzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmIChmYWtlc1tpXS5tYXRjaGVzKGFyZ3MsIHN0cmljdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZha2VzW2ldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGluY3JlbWVudENhbGxDb3VudCgpIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHRoaXMuY2FsbENvdW50ICs9IDE7XG4gICAgICAgICAgICB0aGlzLm5vdENhbGxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgdGhpcy5jYWxsZWRPbmNlID0gdGhpcy5jYWxsQ291bnQgPT09IDE7XG4gICAgICAgICAgICB0aGlzLmNhbGxlZFR3aWNlID0gdGhpcy5jYWxsQ291bnQgPT09IDI7XG4gICAgICAgICAgICB0aGlzLmNhbGxlZFRocmljZSA9IHRoaXMuY2FsbENvdW50ID09PSAzO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gY3JlYXRlQ2FsbFByb3BlcnRpZXMoKSB7XG4gICAgICAgICAgICB0aGlzLmZpcnN0Q2FsbCA9IHRoaXMuZ2V0Q2FsbCgwKTtcbiAgICAgICAgICAgIHRoaXMuc2Vjb25kQ2FsbCA9IHRoaXMuZ2V0Q2FsbCgxKTtcbiAgICAgICAgICAgIHRoaXMudGhpcmRDYWxsID0gdGhpcy5nZXRDYWxsKDIpO1xuICAgICAgICAgICAgdGhpcy5sYXN0Q2FsbCA9IHRoaXMuZ2V0Q2FsbCh0aGlzLmNhbGxDb3VudCAtIDEpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZhcnMgPSBcImEsYixjLGQsZSxmLGcsaCxpLGosayxsXCI7XG4gICAgICAgIGZ1bmN0aW9uIGNyZWF0ZVByb3h5KGZ1bmMsIHByb3h5TGVuZ3RoKSB7XG4gICAgICAgICAgICAvLyBSZXRhaW4gdGhlIGZ1bmN0aW9uIGxlbmd0aDpcbiAgICAgICAgICAgIHZhciBwO1xuICAgICAgICAgICAgaWYgKHByb3h5TGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgZXZhbChcInAgPSAoZnVuY3Rpb24gcHJveHkoXCIgKyB2YXJzLnN1YnN0cmluZygwLCBwcm94eUxlbmd0aCAqIDIgLSAxKSArIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tZXZhbFxuICAgICAgICAgICAgICAgICAgICBcIikgeyByZXR1cm4gcC5pbnZva2UoZnVuYywgdGhpcywgc2xpY2UuY2FsbChhcmd1bWVudHMpKTsgfSk7XCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwID0gZnVuY3Rpb24gcHJveHkoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwLmludm9rZShmdW5jLCB0aGlzLCBzbGljZS5jYWxsKGFyZ3VtZW50cykpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBwLmlzU2lub25Qcm94eSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gcDtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB1dWlkID0gMDtcblxuICAgICAgICAvLyBQdWJsaWMgQVBJXG4gICAgICAgIHZhciBzcHlBcGkgPSB7XG4gICAgICAgICAgICByZXNldDogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmludm9raW5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBlcnIgPSBuZXcgRXJyb3IoXCJDYW5ub3QgcmVzZXQgU2lub24gZnVuY3Rpb24gd2hpbGUgaW52b2tpbmcgaXQuIFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIk1vdmUgdGhlIGNhbGwgdG8gLnJlc2V0IG91dHNpZGUgb2YgdGhlIGNhbGxiYWNrLlwiKTtcbiAgICAgICAgICAgICAgICAgICAgZXJyLm5hbWUgPSBcIkludmFsaWRSZXNldEV4Y2VwdGlvblwiO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBlcnI7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsZWQgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLm5vdENhbGxlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsZWRPbmNlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsZWRUd2ljZSA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbGVkVGhyaWNlID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgdGhpcy5jYWxsQ291bnQgPSAwO1xuICAgICAgICAgICAgICAgIHRoaXMuZmlyc3RDYWxsID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLnNlY29uZENhbGwgPSBudWxsO1xuICAgICAgICAgICAgICAgIHRoaXMudGhpcmRDYWxsID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLmxhc3RDYWxsID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLmFyZ3MgPSBbXTtcbiAgICAgICAgICAgICAgICB0aGlzLnJldHVyblZhbHVlcyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMudGhpc1ZhbHVlcyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuZXhjZXB0aW9ucyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuY2FsbElkcyA9IFtdO1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhY2tzID0gW107XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuZmFrZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmZha2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZha2VzW2ldLnJlc2V0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gY3JlYXRlKGZ1bmMsIHNweUxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBuYW1lO1xuXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBmdW5jICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgZnVuYyA9IGZ1bmN0aW9uICgpIHsgfTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBuYW1lID0gc2lub24uZnVuY3Rpb25OYW1lKGZ1bmMpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghc3B5TGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHNweUxlbmd0aCA9IGZ1bmMubGVuZ3RoO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBwcm94eSA9IGNyZWF0ZVByb3h5KGZ1bmMsIHNweUxlbmd0aCk7XG5cbiAgICAgICAgICAgICAgICBzaW5vbi5leHRlbmQocHJveHksIHNweSk7XG4gICAgICAgICAgICAgICAgZGVsZXRlIHByb3h5LmNyZWF0ZTtcbiAgICAgICAgICAgICAgICBzaW5vbi5leHRlbmQocHJveHksIGZ1bmMpO1xuXG4gICAgICAgICAgICAgICAgcHJveHkucmVzZXQoKTtcbiAgICAgICAgICAgICAgICBwcm94eS5wcm90b3R5cGUgPSBmdW5jLnByb3RvdHlwZTtcbiAgICAgICAgICAgICAgICBwcm94eS5kaXNwbGF5TmFtZSA9IG5hbWUgfHwgXCJzcHlcIjtcbiAgICAgICAgICAgICAgICBwcm94eS50b1N0cmluZyA9IHNpbm9uLmZ1bmN0aW9uVG9TdHJpbmc7XG4gICAgICAgICAgICAgICAgcHJveHkuaW5zdGFudGlhdGVGYWtlID0gc2lub24uc3B5LmNyZWF0ZTtcbiAgICAgICAgICAgICAgICBwcm94eS5pZCA9IFwic3B5I1wiICsgdXVpZCsrO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHByb3h5O1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgaW52b2tlOiBmdW5jdGlvbiBpbnZva2UoZnVuYywgdGhpc1ZhbHVlLCBhcmdzKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1hdGNoaW5nID0gbWF0Y2hpbmdGYWtlKHRoaXMuZmFrZXMsIGFyZ3MpO1xuICAgICAgICAgICAgICAgIHZhciBleGNlcHRpb24sIHJldHVyblZhbHVlO1xuXG4gICAgICAgICAgICAgICAgaW5jcmVtZW50Q2FsbENvdW50LmNhbGwodGhpcyk7XG4gICAgICAgICAgICAgICAgcHVzaC5jYWxsKHRoaXMudGhpc1ZhbHVlcywgdGhpc1ZhbHVlKTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5hcmdzLCBhcmdzKTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5jYWxsSWRzLCBjYWxsSWQrKyk7XG5cbiAgICAgICAgICAgICAgICAvLyBNYWtlIGNhbGwgcHJvcGVydGllcyBhdmFpbGFibGUgZnJvbSB3aXRoaW4gdGhlIHNwaWVkIGZ1bmN0aW9uOlxuICAgICAgICAgICAgICAgIGNyZWF0ZUNhbGxQcm9wZXJ0aWVzLmNhbGwodGhpcyk7XG5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmludm9raW5nID0gdHJ1ZTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2hpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVyblZhbHVlID0gbWF0Y2hpbmcuaW52b2tlKGZ1bmMsIHRoaXNWYWx1ZSwgYXJncyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm5WYWx1ZSA9ICh0aGlzLmZ1bmMgfHwgZnVuYykuYXBwbHkodGhpc1ZhbHVlLCBhcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHZhciB0aGlzQ2FsbCA9IHRoaXMuZ2V0Q2FsbCh0aGlzLmNhbGxDb3VudCAtIDEpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpc0NhbGwuY2FsbGVkV2l0aE5ldygpICYmIHR5cGVvZiByZXR1cm5WYWx1ZSAhPT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVmFsdWUgPSB0aGlzVmFsdWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGV4Y2VwdGlvbiA9IGU7XG4gICAgICAgICAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuaW52b2tpbmc7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcHVzaC5jYWxsKHRoaXMuZXhjZXB0aW9ucywgZXhjZXB0aW9uKTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5yZXR1cm5WYWx1ZXMsIHJldHVyblZhbHVlKTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5zdGFja3MsIG5ldyBFcnJvcigpLnN0YWNrKTtcblxuICAgICAgICAgICAgICAgIC8vIE1ha2UgcmV0dXJuIHZhbHVlIGFuZCBleGNlcHRpb24gYXZhaWxhYmxlIGluIHRoZSBjYWxsczpcbiAgICAgICAgICAgICAgICBjcmVhdGVDYWxsUHJvcGVydGllcy5jYWxsKHRoaXMpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGV4Y2VwdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcmV0dXJuVmFsdWU7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBuYW1lZDogZnVuY3Rpb24gbmFtZWQobmFtZSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZGlzcGxheU5hbWUgPSBuYW1lO1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZ2V0Q2FsbDogZnVuY3Rpb24gZ2V0Q2FsbChpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGkgPCAwIHx8IGkgPj0gdGhpcy5jYWxsQ291bnQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHNpbm9uLnNweUNhbGwodGhpcywgdGhpcy50aGlzVmFsdWVzW2ldLCB0aGlzLmFyZ3NbaV0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXR1cm5WYWx1ZXNbaV0sIHRoaXMuZXhjZXB0aW9uc1tpXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNhbGxJZHNbaV0sIHRoaXMuc3RhY2tzW2ldKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldENhbGxzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNhbGxzID0gW107XG4gICAgICAgICAgICAgICAgdmFyIGk7XG5cbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdGhpcy5jYWxsQ291bnQ7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBjYWxscy5wdXNoKHRoaXMuZ2V0Q2FsbChpKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNhbGxzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgY2FsbGVkQmVmb3JlOiBmdW5jdGlvbiBjYWxsZWRCZWZvcmUoc3B5Rm4pIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY2FsbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoIXNweUZuLmNhbGxlZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jYWxsSWRzWzBdIDwgc3B5Rm4uY2FsbElkc1tzcHlGbi5jYWxsSWRzLmxlbmd0aCAtIDFdO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgY2FsbGVkQWZ0ZXI6IGZ1bmN0aW9uIGNhbGxlZEFmdGVyKHNweUZuKSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmNhbGxlZCB8fCAhc3B5Rm4uY2FsbGVkKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5jYWxsSWRzW3RoaXMuY2FsbENvdW50IC0gMV0gPiBzcHlGbi5jYWxsSWRzW3NweUZuLmNhbGxDb3VudCAtIDFdO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgd2l0aEFyZ3M6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzKTtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmZha2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtYXRjaCA9IG1hdGNoaW5nRmFrZSh0aGlzLmZha2VzLCBhcmdzLCB0cnVlKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBtYXRjaDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmFrZXMgPSBbXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgb3JpZ2luYWwgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciBmYWtlID0gdGhpcy5pbnN0YW50aWF0ZUZha2UoKTtcbiAgICAgICAgICAgICAgICBmYWtlLm1hdGNoaW5nQWd1bWVudHMgPSBhcmdzO1xuICAgICAgICAgICAgICAgIGZha2UucGFyZW50ID0gdGhpcztcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5mYWtlcywgZmFrZSk7XG5cbiAgICAgICAgICAgICAgICBmYWtlLndpdGhBcmdzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gb3JpZ2luYWwud2l0aEFyZ3MuYXBwbHkob3JpZ2luYWwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5hcmdzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChmYWtlLm1hdGNoZXModGhpcy5hcmdzW2ldKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaW5jcmVtZW50Q2FsbENvdW50LmNhbGwoZmFrZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwdXNoLmNhbGwoZmFrZS50aGlzVmFsdWVzLCB0aGlzLnRoaXNWYWx1ZXNbaV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcHVzaC5jYWxsKGZha2UuYXJncywgdGhpcy5hcmdzW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChmYWtlLnJldHVyblZhbHVlcywgdGhpcy5yZXR1cm5WYWx1ZXNbaV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgcHVzaC5jYWxsKGZha2UuZXhjZXB0aW9ucywgdGhpcy5leGNlcHRpb25zW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChmYWtlLmNhbGxJZHMsIHRoaXMuY2FsbElkc1tpXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY3JlYXRlQ2FsbFByb3BlcnRpZXMuY2FsbChmYWtlKTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBmYWtlO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgbWF0Y2hlczogZnVuY3Rpb24gKGFyZ3MsIHN0cmljdCkge1xuICAgICAgICAgICAgICAgIHZhciBtYXJncyA9IHRoaXMubWF0Y2hpbmdBZ3VtZW50cztcblxuICAgICAgICAgICAgICAgIGlmIChtYXJncy5sZW5ndGggPD0gYXJncy5sZW5ndGggJiZcbiAgICAgICAgICAgICAgICAgICAgc2lub24uZGVlcEVxdWFsKG1hcmdzLCBhcmdzLnNsaWNlKDAsIG1hcmdzLmxlbmd0aCkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhc3RyaWN0IHx8IG1hcmdzLmxlbmd0aCA9PT0gYXJncy5sZW5ndGg7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgcHJpbnRmOiBmdW5jdGlvbiAoZm9ybWF0KSB7XG4gICAgICAgICAgICAgICAgdmFyIHNweUluc3RhbmNlID0gdGhpcztcbiAgICAgICAgICAgICAgICB2YXIgYXJncyA9IHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKTtcbiAgICAgICAgICAgICAgICB2YXIgZm9ybWF0dGVyO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIChmb3JtYXQgfHwgXCJcIikucmVwbGFjZSgvJSguKS9nLCBmdW5jdGlvbiAobWF0Y2gsIHNwZWNpZnllcikge1xuICAgICAgICAgICAgICAgICAgICBmb3JtYXR0ZXIgPSBzcHlBcGkuZm9ybWF0dGVyc1tzcGVjaWZ5ZXJdO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZm9ybWF0dGVyID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmb3JtYXR0ZXIuY2FsbChudWxsLCBzcHlJbnN0YW5jZSwgYXJncyk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoIWlzTmFOKHBhcnNlSW50KHNwZWNpZnllciwgMTApKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNpbm9uLmZvcm1hdChhcmdzW3NwZWNpZnllciAtIDFdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBcIiVcIiArIHNwZWNpZnllcjtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBmdW5jdGlvbiBkZWxlZ2F0ZVRvQ2FsbHMobWV0aG9kLCBtYXRjaEFueSwgYWN0dWFsLCBub3RDYWxsZWQpIHtcbiAgICAgICAgICAgIHNweUFwaVttZXRob2RdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5jYWxsZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG5vdENhbGxlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG5vdENhbGxlZC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudENhbGw7XG4gICAgICAgICAgICAgICAgdmFyIG1hdGNoZXMgPSAwO1xuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSB0aGlzLmNhbGxDb3VudDsgaSA8IGw7IGkgKz0gMSkge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50Q2FsbCA9IHRoaXMuZ2V0Q2FsbChpKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoY3VycmVudENhbGxbYWN0dWFsIHx8IG1ldGhvZF0uYXBwbHkoY3VycmVudENhbGwsIGFyZ3VtZW50cykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoZXMgKz0gMTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoQW55KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gbWF0Y2hlcyA9PT0gdGhpcy5jYWxsQ291bnQ7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgZGVsZWdhdGVUb0NhbGxzKFwiY2FsbGVkT25cIiwgdHJ1ZSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcImFsd2F5c0NhbGxlZE9uXCIsIGZhbHNlLCBcImNhbGxlZE9uXCIpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJjYWxsZWRXaXRoXCIsIHRydWUpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJjYWxsZWRXaXRoTWF0Y2hcIiwgdHJ1ZSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcImFsd2F5c0NhbGxlZFdpdGhcIiwgZmFsc2UsIFwiY2FsbGVkV2l0aFwiKTtcbiAgICAgICAgZGVsZWdhdGVUb0NhbGxzKFwiYWx3YXlzQ2FsbGVkV2l0aE1hdGNoXCIsIGZhbHNlLCBcImNhbGxlZFdpdGhNYXRjaFwiKTtcbiAgICAgICAgZGVsZWdhdGVUb0NhbGxzKFwiY2FsbGVkV2l0aEV4YWN0bHlcIiwgdHJ1ZSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcImFsd2F5c0NhbGxlZFdpdGhFeGFjdGx5XCIsIGZhbHNlLCBcImNhbGxlZFdpdGhFeGFjdGx5XCIpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJuZXZlckNhbGxlZFdpdGhcIiwgZmFsc2UsIFwibm90Q2FsbGVkV2l0aFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcIm5ldmVyQ2FsbGVkV2l0aE1hdGNoXCIsIGZhbHNlLCBcIm5vdENhbGxlZFdpdGhNYXRjaFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcInRocmV3XCIsIHRydWUpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJhbHdheXNUaHJld1wiLCBmYWxzZSwgXCJ0aHJld1wiKTtcbiAgICAgICAgZGVsZWdhdGVUb0NhbGxzKFwicmV0dXJuZWRcIiwgdHJ1ZSk7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcImFsd2F5c1JldHVybmVkXCIsIGZhbHNlLCBcInJldHVybmVkXCIpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJjYWxsZWRXaXRoTmV3XCIsIHRydWUpO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJhbHdheXNDYWxsZWRXaXRoTmV3XCIsIGZhbHNlLCBcImNhbGxlZFdpdGhOZXdcIik7XG4gICAgICAgIGRlbGVnYXRlVG9DYWxscyhcImNhbGxBcmdcIiwgZmFsc2UsIFwiY2FsbEFyZ1dpdGhcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMudG9TdHJpbmcoKSArIFwiIGNhbm5vdCBjYWxsIGFyZyBzaW5jZSBpdCB3YXMgbm90IHlldCBpbnZva2VkLlwiKTtcbiAgICAgICAgfSk7XG4gICAgICAgIHNweUFwaS5jYWxsQXJnV2l0aCA9IHNweUFwaS5jYWxsQXJnO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJjYWxsQXJnT25cIiwgZmFsc2UsIFwiY2FsbEFyZ09uV2l0aFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy50b1N0cmluZygpICsgXCIgY2Fubm90IGNhbGwgYXJnIHNpbmNlIGl0IHdhcyBub3QgeWV0IGludm9rZWQuXCIpO1xuICAgICAgICB9KTtcbiAgICAgICAgc3B5QXBpLmNhbGxBcmdPbldpdGggPSBzcHlBcGkuY2FsbEFyZ09uO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJ5aWVsZFwiLCBmYWxzZSwgXCJ5aWVsZFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy50b1N0cmluZygpICsgXCIgY2Fubm90IHlpZWxkIHNpbmNlIGl0IHdhcyBub3QgeWV0IGludm9rZWQuXCIpO1xuICAgICAgICB9KTtcbiAgICAgICAgLy8gXCJpbnZva2VDYWxsYmFja1wiIGlzIGFuIGFsaWFzIGZvciBcInlpZWxkXCIgc2luY2UgXCJ5aWVsZFwiIGlzIGludmFsaWQgaW4gc3RyaWN0IG1vZGUuXG4gICAgICAgIHNweUFwaS5pbnZva2VDYWxsYmFjayA9IHNweUFwaS55aWVsZDtcbiAgICAgICAgZGVsZWdhdGVUb0NhbGxzKFwieWllbGRPblwiLCBmYWxzZSwgXCJ5aWVsZE9uXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcih0aGlzLnRvU3RyaW5nKCkgKyBcIiBjYW5ub3QgeWllbGQgc2luY2UgaXQgd2FzIG5vdCB5ZXQgaW52b2tlZC5cIik7XG4gICAgICAgIH0pO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJ5aWVsZFRvXCIsIGZhbHNlLCBcInlpZWxkVG9cIiwgZnVuY3Rpb24gKHByb3BlcnR5KSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IodGhpcy50b1N0cmluZygpICsgXCIgY2Fubm90IHlpZWxkIHRvICdcIiArIHByb3BlcnR5ICtcbiAgICAgICAgICAgICAgICBcIicgc2luY2UgaXQgd2FzIG5vdCB5ZXQgaW52b2tlZC5cIik7XG4gICAgICAgIH0pO1xuICAgICAgICBkZWxlZ2F0ZVRvQ2FsbHMoXCJ5aWVsZFRvT25cIiwgZmFsc2UsIFwieWllbGRUb09uXCIsIGZ1bmN0aW9uIChwcm9wZXJ0eSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMudG9TdHJpbmcoKSArIFwiIGNhbm5vdCB5aWVsZCB0byAnXCIgKyBwcm9wZXJ0eSArXG4gICAgICAgICAgICAgICAgXCInIHNpbmNlIGl0IHdhcyBub3QgeWV0IGludm9rZWQuXCIpO1xuICAgICAgICB9KTtcblxuICAgICAgICBzcHlBcGkuZm9ybWF0dGVycyA9IHtcbiAgICAgICAgICAgIGM6IGZ1bmN0aW9uIChzcHlJbnN0YW5jZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzaW5vbi50aW1lc0luV29yZHMoc3B5SW5zdGFuY2UuY2FsbENvdW50KTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG46IGZ1bmN0aW9uIChzcHlJbnN0YW5jZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzcHlJbnN0YW5jZS50b1N0cmluZygpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgQzogZnVuY3Rpb24gKHNweUluc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNhbGxzID0gW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IHNweUluc3RhbmNlLmNhbGxDb3VudDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgc3RyaW5naWZpZWRDYWxsID0gXCIgICAgXCIgKyBzcHlJbnN0YW5jZS5nZXRDYWxsKGkpLnRvU3RyaW5nKCk7XG4gICAgICAgICAgICAgICAgICAgIGlmICgvXFxuLy50ZXN0KGNhbGxzW2kgLSAxXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0cmluZ2lmaWVkQ2FsbCA9IFwiXFxuXCIgKyBzdHJpbmdpZmllZENhbGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcHVzaC5jYWxsKGNhbGxzLCBzdHJpbmdpZmllZENhbGwpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBjYWxscy5sZW5ndGggPiAwID8gXCJcXG5cIiArIGNhbGxzLmpvaW4oXCJcXG5cIikgOiBcIlwiO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgdDogZnVuY3Rpb24gKHNweUluc3RhbmNlKSB7XG4gICAgICAgICAgICAgICAgdmFyIG9iamVjdHMgPSBbXTtcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gc3B5SW5zdGFuY2UuY2FsbENvdW50OyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChvYmplY3RzLCBzaW5vbi5mb3JtYXQoc3B5SW5zdGFuY2UudGhpc1ZhbHVlc1tpXSkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBvYmplY3RzLmpvaW4oXCIsIFwiKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIFwiKlwiOiBmdW5jdGlvbiAoc3B5SW5zdGFuY2UsIGFyZ3MpIHtcbiAgICAgICAgICAgICAgICB2YXIgZm9ybWF0dGVkID0gW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGFyZ3MubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIHB1c2guY2FsbChmb3JtYXR0ZWQsIHNpbm9uLmZvcm1hdChhcmdzW2ldKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgcmV0dXJuIGZvcm1hdHRlZC5qb2luKFwiLCBcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uZXh0ZW5kKHNweSwgc3B5QXBpKTtcblxuICAgICAgICBzcHkuc3B5Q2FsbCA9IHNpbm9uLnNweUNhbGw7XG4gICAgICAgIHNpbm9uLnNweSA9IHNweTtcblxuICAgICAgICByZXR1cm4gc3B5O1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgY29yZSA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vY2FsbFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZXh0ZW5kXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi90aW1lc19pbl93b3Jkc1wiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZm9ybWF0XCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoY29yZSk7XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqIEBkZXBlbmQgZXh0ZW5kLmpzXG4gKiBAZGVwZW5kIHNweS5qc1xuICogQGRlcGVuZCBiZWhhdmlvci5qc1xuICogQGRlcGVuZCB3YWxrLmpzXG4gKi9cbi8qKlxuICogU3R1YiBmdW5jdGlvbnNcbiAqXG4gKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAqIEBsaWNlbnNlIEJTRFxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMC0yMDEzIENocmlzdGlhbiBKb2hhbnNlblxuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIGZ1bmN0aW9uIHN0dWIob2JqZWN0LCBwcm9wZXJ0eSwgZnVuYykge1xuICAgICAgICAgICAgaWYgKCEhZnVuYyAmJiB0eXBlb2YgZnVuYyAhPT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBmdW5jICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkN1c3RvbSBzdHViIHNob3VsZCBiZSBhIGZ1bmN0aW9uIG9yIGEgcHJvcGVydHkgZGVzY3JpcHRvclwiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHdyYXBwZXI7XG5cbiAgICAgICAgICAgIGlmIChmdW5jKSB7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBmdW5jID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgd3JhcHBlciA9IHNpbm9uLnNweSAmJiBzaW5vbi5zcHkuY3JlYXRlID8gc2lub24uc3B5LmNyZWF0ZShmdW5jKSA6IGZ1bmM7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgd3JhcHBlciA9IGZ1bmM7XG4gICAgICAgICAgICAgICAgICAgIGlmIChzaW5vbi5zcHkgJiYgc2lub24uc3B5LmNyZWF0ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHR5cGVzID0gc2lub24ub2JqZWN0S2V5cyh3cmFwcGVyKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdHlwZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB3cmFwcGVyW3R5cGVzW2ldXSA9IHNpbm9uLnNweS5jcmVhdGUod3JhcHBlclt0eXBlc1tpXV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgc3R1Ykxlbmd0aCA9IDA7XG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG9iamVjdFtwcm9wZXJ0eV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICBzdHViTGVuZ3RoID0gb2JqZWN0W3Byb3BlcnR5XS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHdyYXBwZXIgPSBzdHViLmNyZWF0ZShzdHViTGVuZ3RoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKCFvYmplY3QgJiYgdHlwZW9mIHByb3BlcnR5ID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHNpbm9uLnN0dWIuY3JlYXRlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgcHJvcGVydHkgPT09IFwidW5kZWZpbmVkXCIgJiYgdHlwZW9mIG9iamVjdCA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgIHNpbm9uLndhbGsob2JqZWN0IHx8IHt9LCBmdW5jdGlvbiAodmFsdWUsIHByb3AsIHByb3BPd25lcikge1xuICAgICAgICAgICAgICAgICAgICAvLyB3ZSBkb24ndCB3YW50IHRvIHN0dWIgdGhpbmdzIGxpa2UgdG9TdHJpbmcoKSwgdmFsdWVPZigpLCBldGMuIHNvIHdlIG9ubHkgc3R1YiBpZiB0aGUgb2JqZWN0XG4gICAgICAgICAgICAgICAgICAgIC8vIGlzIG5vdCBPYmplY3QucHJvdG90eXBlXG4gICAgICAgICAgICAgICAgICAgIGlmIChcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb3BPd25lciAhPT0gT2JqZWN0LnByb3RvdHlwZSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvcCAhPT0gXCJjb25zdHJ1Y3RvclwiICYmXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2Ygc2lub24uZ2V0UHJvcGVydHlEZXNjcmlwdG9yKHByb3BPd25lciwgcHJvcCkudmFsdWUgPT09IFwiZnVuY3Rpb25cIlxuICAgICAgICAgICAgICAgICAgICApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0dWIob2JqZWN0LCBwcm9wKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHNpbm9uLndyYXBNZXRob2Qob2JqZWN0LCBwcm9wZXJ0eSwgd3JhcHBlcik7XG4gICAgICAgIH1cblxuXG4gICAgICAgIC8qZXNsaW50LWRpc2FibGUgbm8tdXNlLWJlZm9yZS1kZWZpbmUqL1xuICAgICAgICBmdW5jdGlvbiBnZXRQYXJlbnRCZWhhdmlvdXIoc3R1Ykluc3RhbmNlKSB7XG4gICAgICAgICAgICByZXR1cm4gKHN0dWJJbnN0YW5jZS5wYXJlbnQgJiYgZ2V0Q3VycmVudEJlaGF2aW9yKHN0dWJJbnN0YW5jZS5wYXJlbnQpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGdldERlZmF1bHRCZWhhdmlvcihzdHViSW5zdGFuY2UpIHtcbiAgICAgICAgICAgIHJldHVybiBzdHViSW5zdGFuY2UuZGVmYXVsdEJlaGF2aW9yIHx8XG4gICAgICAgICAgICAgICAgICAgIGdldFBhcmVudEJlaGF2aW91cihzdHViSW5zdGFuY2UpIHx8XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmJlaGF2aW9yLmNyZWF0ZShzdHViSW5zdGFuY2UpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gZ2V0Q3VycmVudEJlaGF2aW9yKHN0dWJJbnN0YW5jZSkge1xuICAgICAgICAgICAgdmFyIGJlaGF2aW9yID0gc3R1Ykluc3RhbmNlLmJlaGF2aW9yc1tzdHViSW5zdGFuY2UuY2FsbENvdW50IC0gMV07XG4gICAgICAgICAgICByZXR1cm4gYmVoYXZpb3IgJiYgYmVoYXZpb3IuaXNQcmVzZW50KCkgPyBiZWhhdmlvciA6IGdldERlZmF1bHRCZWhhdmlvcihzdHViSW5zdGFuY2UpO1xuICAgICAgICB9XG4gICAgICAgIC8qZXNsaW50LWVuYWJsZSBuby11c2UtYmVmb3JlLWRlZmluZSovXG5cbiAgICAgICAgdmFyIHV1aWQgPSAwO1xuXG4gICAgICAgIHZhciBwcm90byA9IHtcbiAgICAgICAgICAgIGNyZWF0ZTogZnVuY3Rpb24gY3JlYXRlKHN0dWJMZW5ndGgpIHtcbiAgICAgICAgICAgICAgICB2YXIgZnVuY3Rpb25TdHViID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZ2V0Q3VycmVudEJlaGF2aW9yKGZ1bmN0aW9uU3R1YikuaW52b2tlKHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uU3R1Yi5pZCA9IFwic3R1YiNcIiArIHV1aWQrKztcbiAgICAgICAgICAgICAgICB2YXIgb3JpZyA9IGZ1bmN0aW9uU3R1YjtcbiAgICAgICAgICAgICAgICBmdW5jdGlvblN0dWIgPSBzaW5vbi5zcHkuY3JlYXRlKGZ1bmN0aW9uU3R1Yiwgc3R1Ykxlbmd0aCk7XG4gICAgICAgICAgICAgICAgZnVuY3Rpb25TdHViLmZ1bmMgPSBvcmlnO1xuXG4gICAgICAgICAgICAgICAgc2lub24uZXh0ZW5kKGZ1bmN0aW9uU3R1Yiwgc3R1Yik7XG4gICAgICAgICAgICAgICAgZnVuY3Rpb25TdHViLmluc3RhbnRpYXRlRmFrZSA9IHNpbm9uLnN0dWIuY3JlYXRlO1xuICAgICAgICAgICAgICAgIGZ1bmN0aW9uU3R1Yi5kaXNwbGF5TmFtZSA9IFwic3R1YlwiO1xuICAgICAgICAgICAgICAgIGZ1bmN0aW9uU3R1Yi50b1N0cmluZyA9IHNpbm9uLmZ1bmN0aW9uVG9TdHJpbmc7XG5cbiAgICAgICAgICAgICAgICBmdW5jdGlvblN0dWIuZGVmYXVsdEJlaGF2aW9yID0gbnVsbDtcbiAgICAgICAgICAgICAgICBmdW5jdGlvblN0dWIuYmVoYXZpb3JzID0gW107XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb25TdHViO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgcmVzZXRCZWhhdmlvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBpO1xuXG4gICAgICAgICAgICAgICAgdGhpcy5kZWZhdWx0QmVoYXZpb3IgPSBudWxsO1xuICAgICAgICAgICAgICAgIHRoaXMuYmVoYXZpb3JzID0gW107XG5cbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5yZXR1cm5WYWx1ZTtcbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5yZXR1cm5BcmdBdDtcbiAgICAgICAgICAgICAgICB0aGlzLnJldHVyblRoaXMgPSBmYWxzZTtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmZha2VzKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLmZha2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmZha2VzW2ldLnJlc2V0QmVoYXZpb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIG9uQ2FsbDogZnVuY3Rpb24gb25DYWxsKGluZGV4KSB7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmJlaGF2aW9yc1tpbmRleF0pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5iZWhhdmlvcnNbaW5kZXhdID0gc2lub24uYmVoYXZpb3IuY3JlYXRlKHRoaXMpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmJlaGF2aW9yc1tpbmRleF07XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBvbkZpcnN0Q2FsbDogZnVuY3Rpb24gb25GaXJzdENhbGwoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub25DYWxsKDApO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgb25TZWNvbmRDYWxsOiBmdW5jdGlvbiBvblNlY29uZENhbGwoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMub25DYWxsKDEpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgb25UaGlyZENhbGw6IGZ1bmN0aW9uIG9uVGhpcmRDYWxsKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm9uQ2FsbCgyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBmdW5jdGlvbiBjcmVhdGVCZWhhdmlvcihiZWhhdmlvck1ldGhvZCkge1xuICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmRlZmF1bHRCZWhhdmlvciA9IHRoaXMuZGVmYXVsdEJlaGF2aW9yIHx8IHNpbm9uLmJlaGF2aW9yLmNyZWF0ZSh0aGlzKTtcbiAgICAgICAgICAgICAgICB0aGlzLmRlZmF1bHRCZWhhdmlvcltiZWhhdmlvck1ldGhvZF0uYXBwbHkodGhpcy5kZWZhdWx0QmVoYXZpb3IsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9XG5cbiAgICAgICAgZm9yICh2YXIgbWV0aG9kIGluIHNpbm9uLmJlaGF2aW9yKSB7XG4gICAgICAgICAgICBpZiAoc2lub24uYmVoYXZpb3IuaGFzT3duUHJvcGVydHkobWV0aG9kKSAmJlxuICAgICAgICAgICAgICAgICFwcm90by5oYXNPd25Qcm9wZXJ0eShtZXRob2QpICYmXG4gICAgICAgICAgICAgICAgbWV0aG9kICE9PSBcImNyZWF0ZVwiICYmXG4gICAgICAgICAgICAgICAgbWV0aG9kICE9PSBcIndpdGhBcmdzXCIgJiZcbiAgICAgICAgICAgICAgICBtZXRob2QgIT09IFwiaW52b2tlXCIpIHtcbiAgICAgICAgICAgICAgICBwcm90b1ttZXRob2RdID0gY3JlYXRlQmVoYXZpb3IobWV0aG9kKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHNpbm9uLmV4dGVuZChzdHViLCBwcm90byk7XG4gICAgICAgIHNpbm9uLnN0dWIgPSBzdHViO1xuXG4gICAgICAgIHJldHVybiBzdHViO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgY29yZSA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vYmVoYXZpb3JcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3NweVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZXh0ZW5kXCIpO1xuICAgICAgICBtb2R1bGUuZXhwb3J0cyA9IG1ha2VBcGkoY29yZSk7XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqIEBkZXBlbmQgc2FuZGJveC5qc1xuICovXG4vKipcbiAqIFRlc3QgZnVuY3Rpb24sIHNhbmRib3hlcyBmYWtlc1xuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoc2lub25HbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGZ1bmN0aW9uIG1ha2VBcGkoc2lub24pIHtcbiAgICAgICAgdmFyIHNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG4gICAgICAgIGZ1bmN0aW9uIHRlc3QoY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHZhciB0eXBlID0gdHlwZW9mIGNhbGxiYWNrO1xuXG4gICAgICAgICAgICBpZiAodHlwZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcInNpbm9uLnRlc3QgbmVlZHMgdG8gd3JhcCBhIHRlc3QgZnVuY3Rpb24sIGdvdCBcIiArIHR5cGUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmdW5jdGlvbiBzaW5vblNhbmRib3hlZFRlc3QoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvbmZpZyA9IHNpbm9uLmdldENvbmZpZyhzaW5vbi5jb25maWcpO1xuICAgICAgICAgICAgICAgIGNvbmZpZy5pbmplY3RJbnRvID0gY29uZmlnLmluamVjdEludG9UaGlzICYmIHRoaXMgfHwgY29uZmlnLmluamVjdEludG87XG4gICAgICAgICAgICAgICAgdmFyIHNhbmRib3ggPSBzaW5vbi5zYW5kYm94LmNyZWF0ZShjb25maWcpO1xuICAgICAgICAgICAgICAgIHZhciBhcmdzID0gc2xpY2UuY2FsbChhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIHZhciBvbGREb25lID0gYXJncy5sZW5ndGggJiYgYXJnc1thcmdzLmxlbmd0aCAtIDFdO1xuICAgICAgICAgICAgICAgIHZhciBleGNlcHRpb24sIHJlc3VsdDtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygb2xkRG9uZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGFyZ3NbYXJncy5sZW5ndGggLSAxXSA9IGZ1bmN0aW9uIHNpbm9uRG9uZShyZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzYW5kYm94LnJlc3RvcmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2FuZGJveC52ZXJpZnlBbmRSZXN0b3JlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBvbGREb25lKHJlcyk7XG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0ID0gY2FsbGJhY2suYXBwbHkodGhpcywgYXJncy5jb25jYXQoc2FuZGJveC5hcmdzKSk7XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICBleGNlcHRpb24gPSBlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgZXhjZXB0aW9uICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNhbmRib3gucmVzdG9yZSgpO1xuICAgICAgICAgICAgICAgICAgICB0aHJvdyBleGNlcHRpb247XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb2xkRG9uZSAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNhbmRib3gudmVyaWZ5QW5kUmVzdG9yZSgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjYWxsYmFjay5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24gc2lub25Bc3luY1NhbmRib3hlZFRlc3QoZG9uZSkgeyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVudXNlZC12YXJzXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBzaW5vblNhbmRib3hlZFRlc3QuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gc2lub25TYW5kYm94ZWRUZXN0O1xuICAgICAgICB9XG5cbiAgICAgICAgdGVzdC5jb25maWcgPSB7XG4gICAgICAgICAgICBpbmplY3RJbnRvVGhpczogdHJ1ZSxcbiAgICAgICAgICAgIGluamVjdEludG86IG51bGwsXG4gICAgICAgICAgICBwcm9wZXJ0aWVzOiBbXCJzcHlcIiwgXCJzdHViXCIsIFwibW9ja1wiLCBcImNsb2NrXCIsIFwic2VydmVyXCIsIFwicmVxdWVzdHNcIl0sXG4gICAgICAgICAgICB1c2VGYWtlVGltZXJzOiB0cnVlLFxuICAgICAgICAgICAgdXNlRmFrZVNlcnZlcjogdHJ1ZVxuICAgICAgICB9O1xuXG4gICAgICAgIHNpbm9uLnRlc3QgPSB0ZXN0O1xuICAgICAgICByZXR1cm4gdGVzdDtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIGNvcmUgPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3NhbmRib3hcIik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gbWFrZUFwaShjb3JlKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgIH0gZWxzZSBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgbW9kdWxlLmV4cG9ydHMsIG1vZHVsZSk7XG4gICAgfSBlbHNlIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiB8fCBudWxsKSk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqIEBkZXBlbmQgdGVzdC5qc1xuICovXG4vKipcbiAqIFRlc3QgY2FzZSwgc2FuZGJveGVzIGFsbCB0ZXN0IGZ1bmN0aW9uc1xuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoc2lub25HbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGZ1bmN0aW9uIGNyZWF0ZVRlc3QocHJvcGVydHksIHNldFVwLCB0ZWFyRG93bikge1xuICAgICAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKHNldFVwKSB7XG4gICAgICAgICAgICAgICAgc2V0VXAuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGV4Y2VwdGlvbiwgcmVzdWx0O1xuXG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHJlc3VsdCA9IHByb3BlcnR5LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgZXhjZXB0aW9uID0gZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRlYXJEb3duKSB7XG4gICAgICAgICAgICAgICAgdGVhckRvd24uYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGV4Y2VwdGlvbikge1xuICAgICAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIGZ1bmN0aW9uIHRlc3RDYXNlKHRlc3RzLCBwcmVmaXgpIHtcbiAgICAgICAgICAgIGlmICghdGVzdHMgfHwgdHlwZW9mIHRlc3RzICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcInNpbm9uLnRlc3RDYXNlIG5lZWRzIGFuIG9iamVjdCB3aXRoIHRlc3QgZnVuY3Rpb25zXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwcmVmaXggPSBwcmVmaXggfHwgXCJ0ZXN0XCI7XG4gICAgICAgICAgICB2YXIgclByZWZpeCA9IG5ldyBSZWdFeHAoXCJeXCIgKyBwcmVmaXgpO1xuICAgICAgICAgICAgdmFyIG1ldGhvZHMgPSB7fTtcbiAgICAgICAgICAgIHZhciBzZXRVcCA9IHRlc3RzLnNldFVwO1xuICAgICAgICAgICAgdmFyIHRlYXJEb3duID0gdGVzdHMudGVhckRvd247XG4gICAgICAgICAgICB2YXIgdGVzdE5hbWUsXG4gICAgICAgICAgICAgICAgcHJvcGVydHksXG4gICAgICAgICAgICAgICAgbWV0aG9kO1xuXG4gICAgICAgICAgICBmb3IgKHRlc3ROYW1lIGluIHRlc3RzKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRlc3RzLmhhc093blByb3BlcnR5KHRlc3ROYW1lKSAmJiAhL14oc2V0VXB8dGVhckRvd24pJC8udGVzdCh0ZXN0TmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgcHJvcGVydHkgPSB0ZXN0c1t0ZXN0TmFtZV07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBwcm9wZXJ0eSA9PT0gXCJmdW5jdGlvblwiICYmIHJQcmVmaXgudGVzdCh0ZXN0TmFtZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZCA9IHByb3BlcnR5O1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2V0VXAgfHwgdGVhckRvd24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSBjcmVhdGVUZXN0KHByb3BlcnR5LCBzZXRVcCwgdGVhckRvd24pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgICAgICBtZXRob2RzW3Rlc3ROYW1lXSA9IHNpbm9uLnRlc3QobWV0aG9kKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1ldGhvZHNbdGVzdE5hbWVdID0gdGVzdHNbdGVzdE5hbWVdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gbWV0aG9kcztcbiAgICAgICAgfVxuXG4gICAgICAgIHNpbm9uLnRlc3RDYXNlID0gdGVzdENhc2U7XG4gICAgICAgIHJldHVybiB0ZXN0Q2FzZTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIGNvcmUgPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Rlc3RcIik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gbWFrZUFwaShjb3JlKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIHV0aWwvY29yZS5qc1xuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG5cbiAgICAgICAgZnVuY3Rpb24gdGltZXNJbldvcmRzKGNvdW50KSB7XG4gICAgICAgICAgICBzd2l0Y2ggKGNvdW50KSB7XG4gICAgICAgICAgICAgICAgY2FzZSAxOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJvbmNlXCI7XG4gICAgICAgICAgICAgICAgY2FzZSAyOlxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCJ0d2ljZVwiO1xuICAgICAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIFwidGhyaWNlXCI7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIChjb3VudCB8fCAwKSArIFwiIHRpbWVzXCI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBzaW5vbi50aW1lc0luV29yZHMgPSB0aW1lc0luV29yZHM7XG4gICAgICAgIHJldHVybiBzaW5vbi50aW1lc0luV29yZHM7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIGNvcmUgPSByZXF1aXJlKFwiLi91dGlsL2NvcmVcIik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gbWFrZUFwaShjb3JlKTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqL1xuLyoqXG4gKiBGb3JtYXQgZnVuY3Rpb25zXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxNCBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBmdW5jdGlvbiB0eXBlT2YodmFsdWUpIHtcbiAgICAgICAgICAgIGlmICh2YWx1ZSA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIm51bGxcIjtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcInVuZGVmaW5lZFwiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHN0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YWx1ZSk7XG4gICAgICAgICAgICByZXR1cm4gc3RyaW5nLnN1YnN0cmluZyg4LCBzdHJpbmcubGVuZ3RoIC0gMSkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHNpbm9uLnR5cGVPZiA9IHR5cGVPZjtcbiAgICAgICAgcmV0dXJuIHNpbm9uLnR5cGVPZjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgY29yZSA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKGNvcmUpO1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHNpbm9uR2xvYmFsKSB7XG4gICAgICAgIG1ha2VBcGkoc2lub25HbG9iYWwpO1xuICAgIH1cbn0oXG4gICAgdHlwZW9mIHNpbm9uID09PSBcIm9iamVjdFwiICYmIHNpbm9uIC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbikpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIC4uLy4uL3Npbm9uLmpzXG4gKi9cbi8qKlxuICogU2lub24gY29yZSB1dGlsaXRpZXMuIEZvciBpbnRlcm5hbCB1c2Ugb25seS5cbiAqXG4gKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubylcbiAqIEBsaWNlbnNlIEJTRFxuICpcbiAqIENvcHlyaWdodCAoYykgMjAxMC0yMDEzIENocmlzdGlhbiBKb2hhbnNlblxuICovXG4oZnVuY3Rpb24gKHNpbm9uR2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICB2YXIgZGl2ID0gdHlwZW9mIGRvY3VtZW50ICE9PSBcInVuZGVmaW5lZFwiICYmIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG4gICAgdmFyIGhhc093biA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHk7XG5cbiAgICBmdW5jdGlvbiBpc0RPTU5vZGUob2JqKSB7XG4gICAgICAgIHZhciBzdWNjZXNzID0gZmFsc2U7XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIG9iai5hcHBlbmRDaGlsZChkaXYpO1xuICAgICAgICAgICAgc3VjY2VzcyA9IGRpdi5wYXJlbnROb2RlID09PSBvYmo7XG4gICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfSBmaW5hbGx5IHtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgb2JqLnJlbW92ZUNoaWxkKGRpdik7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgLy8gUmVtb3ZlIGZhaWxlZCwgbm90IG11Y2ggd2UgY2FuIGRvIGFib3V0IHRoYXRcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBzdWNjZXNzO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzRWxlbWVudChvYmopIHtcbiAgICAgICAgcmV0dXJuIGRpdiAmJiBvYmogJiYgb2JqLm5vZGVUeXBlID09PSAxICYmIGlzRE9NTm9kZShvYmopO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzRnVuY3Rpb24ob2JqKSB7XG4gICAgICAgIHJldHVybiB0eXBlb2Ygb2JqID09PSBcImZ1bmN0aW9uXCIgfHwgISEob2JqICYmIG9iai5jb25zdHJ1Y3RvciAmJiBvYmouY2FsbCAmJiBvYmouYXBwbHkpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzUmVhbGx5TmFOKHZhbCkge1xuICAgICAgICByZXR1cm4gdHlwZW9mIHZhbCA9PT0gXCJudW1iZXJcIiAmJiBpc05hTih2YWwpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIG1pcnJvclByb3BlcnRpZXModGFyZ2V0LCBzb3VyY2UpIHtcbiAgICAgICAgZm9yICh2YXIgcHJvcCBpbiBzb3VyY2UpIHtcbiAgICAgICAgICAgIGlmICghaGFzT3duLmNhbGwodGFyZ2V0LCBwcm9wKSkge1xuICAgICAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGlzUmVzdG9yYWJsZShvYmopIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2Ygb2JqLnJlc3RvcmUgPT09IFwiZnVuY3Rpb25cIiAmJiBvYmoucmVzdG9yZS5zaW5vbjtcbiAgICB9XG5cbiAgICAvLyBDaGVhcCB3YXkgdG8gZGV0ZWN0IGlmIHdlIGhhdmUgRVM1IHN1cHBvcnQuXG4gICAgdmFyIGhhc0VTNVN1cHBvcnQgPSBcImtleXNcIiBpbiBPYmplY3Q7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIHNpbm9uLndyYXBNZXRob2QgPSBmdW5jdGlvbiB3cmFwTWV0aG9kKG9iamVjdCwgcHJvcGVydHksIG1ldGhvZCkge1xuICAgICAgICAgICAgaWYgKCFvYmplY3QpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiU2hvdWxkIHdyYXAgcHJvcGVydHkgb2Ygb2JqZWN0XCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHlwZW9mIG1ldGhvZCAhPT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBtZXRob2QgIT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiTWV0aG9kIHdyYXBwZXIgc2hvdWxkIGJlIGEgZnVuY3Rpb24gb3IgYSBwcm9wZXJ0eSBkZXNjcmlwdG9yXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmdW5jdGlvbiBjaGVja1dyYXBwZWRNZXRob2Qod3JhcHBlZE1ldGhvZCkge1xuICAgICAgICAgICAgICAgIHZhciBlcnJvcjtcblxuICAgICAgICAgICAgICAgIGlmICghaXNGdW5jdGlvbih3cmFwcGVkTWV0aG9kKSkge1xuICAgICAgICAgICAgICAgICAgICBlcnJvciA9IG5ldyBUeXBlRXJyb3IoXCJBdHRlbXB0ZWQgdG8gd3JhcCBcIiArICh0eXBlb2Ygd3JhcHBlZE1ldGhvZCkgKyBcIiBwcm9wZXJ0eSBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHkgKyBcIiBhcyBmdW5jdGlvblwiKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHdyYXBwZWRNZXRob2QucmVzdG9yZSAmJiB3cmFwcGVkTWV0aG9kLnJlc3RvcmUuc2lub24pIHtcbiAgICAgICAgICAgICAgICAgICAgZXJyb3IgPSBuZXcgVHlwZUVycm9yKFwiQXR0ZW1wdGVkIHRvIHdyYXAgXCIgKyBwcm9wZXJ0eSArIFwiIHdoaWNoIGlzIGFscmVhZHkgd3JhcHBlZFwiKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHdyYXBwZWRNZXRob2QuY2FsbGVkQmVmb3JlKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB2ZXJiID0gd3JhcHBlZE1ldGhvZC5yZXR1cm5zID8gXCJzdHViYmVkXCIgOiBcInNwaWVkIG9uXCI7XG4gICAgICAgICAgICAgICAgICAgIGVycm9yID0gbmV3IFR5cGVFcnJvcihcIkF0dGVtcHRlZCB0byB3cmFwIFwiICsgcHJvcGVydHkgKyBcIiB3aGljaCBpcyBhbHJlYWR5IFwiICsgdmVyYik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh3cmFwcGVkTWV0aG9kICYmIHdyYXBwZWRNZXRob2Quc3RhY2tUcmFjZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3Iuc3RhY2sgKz0gXCJcXG4tLS0tLS0tLS0tLS0tLVxcblwiICsgd3JhcHBlZE1ldGhvZC5zdGFja1RyYWNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGVycm9yLCB3cmFwcGVkTWV0aG9kLCBpO1xuXG4gICAgICAgICAgICBmdW5jdGlvbiBzaW1wbGVQcm9wZXJ0eUFzc2lnbm1lbnQoKSB7XG4gICAgICAgICAgICAgICAgd3JhcHBlZE1ldGhvZCA9IG9iamVjdFtwcm9wZXJ0eV07XG4gICAgICAgICAgICAgICAgY2hlY2tXcmFwcGVkTWV0aG9kKHdyYXBwZWRNZXRob2QpO1xuICAgICAgICAgICAgICAgIG9iamVjdFtwcm9wZXJ0eV0gPSBtZXRob2Q7XG4gICAgICAgICAgICAgICAgbWV0aG9kLmRpc3BsYXlOYW1lID0gcHJvcGVydHk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIElFIDggZG9lcyBub3Qgc3VwcG9ydCBoYXNPd25Qcm9wZXJ0eSBvbiB0aGUgd2luZG93IG9iamVjdCBhbmQgRmlyZWZveCBoYXMgYSBwcm9ibGVtXG4gICAgICAgICAgICAvLyB3aGVuIHVzaW5nIGhhc093bi5jYWxsIG9uIG9iamVjdHMgZnJvbSBvdGhlciBmcmFtZXMuXG4gICAgICAgICAgICB2YXIgb3duZWQgPSAob2JqZWN0Lmhhc093blByb3BlcnR5ICYmIG9iamVjdC5oYXNPd25Qcm9wZXJ0eSA9PT0gaGFzT3duKSA/XG4gICAgICAgICAgICAgICAgb2JqZWN0Lmhhc093blByb3BlcnR5KHByb3BlcnR5KSA6IGhhc093bi5jYWxsKG9iamVjdCwgcHJvcGVydHkpO1xuXG4gICAgICAgICAgICBpZiAoaGFzRVM1U3VwcG9ydCkge1xuICAgICAgICAgICAgICAgIHZhciBtZXRob2REZXNjID0gKHR5cGVvZiBtZXRob2QgPT09IFwiZnVuY3Rpb25cIikgPyB7dmFsdWU6IG1ldGhvZH0gOiBtZXRob2Q7XG4gICAgICAgICAgICAgICAgdmFyIHdyYXBwZWRNZXRob2REZXNjID0gc2lub24uZ2V0UHJvcGVydHlEZXNjcmlwdG9yKG9iamVjdCwgcHJvcGVydHkpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCF3cmFwcGVkTWV0aG9kRGVzYykge1xuICAgICAgICAgICAgICAgICAgICBlcnJvciA9IG5ldyBUeXBlRXJyb3IoXCJBdHRlbXB0ZWQgdG8gd3JhcCBcIiArICh0eXBlb2Ygd3JhcHBlZE1ldGhvZCkgKyBcIiBwcm9wZXJ0eSBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHkgKyBcIiBhcyBmdW5jdGlvblwiKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHdyYXBwZWRNZXRob2REZXNjLnJlc3RvcmUgJiYgd3JhcHBlZE1ldGhvZERlc2MucmVzdG9yZS5zaW5vbikge1xuICAgICAgICAgICAgICAgICAgICBlcnJvciA9IG5ldyBUeXBlRXJyb3IoXCJBdHRlbXB0ZWQgdG8gd3JhcCBcIiArIHByb3BlcnR5ICsgXCIgd2hpY2ggaXMgYWxyZWFkeSB3cmFwcGVkXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHdyYXBwZWRNZXRob2REZXNjICYmIHdyYXBwZWRNZXRob2REZXNjLnN0YWNrVHJhY2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVycm9yLnN0YWNrICs9IFwiXFxuLS0tLS0tLS0tLS0tLS1cXG5cIiArIHdyYXBwZWRNZXRob2REZXNjLnN0YWNrVHJhY2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIHR5cGVzID0gc2lub24ub2JqZWN0S2V5cyhtZXRob2REZXNjKTtcbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHlwZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgd3JhcHBlZE1ldGhvZCA9IHdyYXBwZWRNZXRob2REZXNjW3R5cGVzW2ldXTtcbiAgICAgICAgICAgICAgICAgICAgY2hlY2tXcmFwcGVkTWV0aG9kKHdyYXBwZWRNZXRob2QpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG1pcnJvclByb3BlcnRpZXMobWV0aG9kRGVzYywgd3JhcHBlZE1ldGhvZERlc2MpO1xuICAgICAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCB0eXBlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICBtaXJyb3JQcm9wZXJ0aWVzKG1ldGhvZERlc2NbdHlwZXNbaV1dLCB3cmFwcGVkTWV0aG9kRGVzY1t0eXBlc1tpXV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBPYmplY3QuZGVmaW5lUHJvcGVydHkob2JqZWN0LCBwcm9wZXJ0eSwgbWV0aG9kRGVzYyk7XG5cbiAgICAgICAgICAgICAgICAvLyBjYXRjaCBmYWlsaW5nIGFzc2lnbm1lbnRcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGlzIHRoZSBjb252ZXJzZSBvZiB0aGUgY2hlY2sgaW4gYC5yZXN0b3JlYCBiZWxvd1xuICAgICAgICAgICAgICAgIGlmICggdHlwZW9mIG1ldGhvZCA9PT0gXCJmdW5jdGlvblwiICYmIG9iamVjdFtwcm9wZXJ0eV0gIT09IG1ldGhvZCApIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gY29ycmVjdCBhbnkgd3Jvbmdkb2luZ3MgY2F1c2VkIGJ5IHRoZSBkZWZpbmVQcm9wZXJ0eSBjYWxsIGFib3ZlLFxuICAgICAgICAgICAgICAgICAgICAvLyBzdWNoIGFzIGFkZGluZyBuZXcgaXRlbXMgKGlmIG9iamVjdCB3YXMgYSBTdG9yYWdlIG9iamVjdClcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG9iamVjdFtwcm9wZXJ0eV07XG4gICAgICAgICAgICAgICAgICAgIHNpbXBsZVByb3BlcnR5QXNzaWdubWVudCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc2ltcGxlUHJvcGVydHlBc3NpZ25tZW50KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG1ldGhvZC5kaXNwbGF5TmFtZSA9IHByb3BlcnR5O1xuXG4gICAgICAgICAgICAvLyBTZXQgdXAgYSBzdGFjayB0cmFjZSB3aGljaCBjYW4gYmUgdXNlZCBsYXRlciB0byBmaW5kIHdoYXQgbGluZSBvZlxuICAgICAgICAgICAgLy8gY29kZSB0aGUgb3JpZ2luYWwgbWV0aG9kIHdhcyBjcmVhdGVkIG9uLlxuICAgICAgICAgICAgbWV0aG9kLnN0YWNrVHJhY2UgPSAobmV3IEVycm9yKFwiU3RhY2sgVHJhY2UgZm9yIG9yaWdpbmFsXCIpKS5zdGFjaztcblxuICAgICAgICAgICAgbWV0aG9kLnJlc3RvcmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgLy8gRm9yIHByb3RvdHlwZSBwcm9wZXJ0aWVzIHRyeSB0byByZXNldCBieSBkZWxldGUgZmlyc3QuXG4gICAgICAgICAgICAgICAgLy8gSWYgdGhpcyBmYWlscyAoZXg6IGxvY2FsU3RvcmFnZSBvbiBtb2JpbGUgc2FmYXJpKSB0aGVuIGZvcmNlIGEgcmVzZXRcbiAgICAgICAgICAgICAgICAvLyB2aWEgZGlyZWN0IGFzc2lnbm1lbnQuXG4gICAgICAgICAgICAgICAgaWYgKCFvd25lZCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBJbiBzb21lIGNhc2VzIGBkZWxldGVgIG1heSB0aHJvdyBhbiBlcnJvclxuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG9iamVjdFtwcm9wZXJ0eV07XG4gICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHt9IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tZW1wdHlcbiAgICAgICAgICAgICAgICAgICAgLy8gRm9yIG5hdGl2ZSBjb2RlIGZ1bmN0aW9ucyBgZGVsZXRlYCBmYWlscyB3aXRob3V0IHRocm93aW5nIGFuIGVycm9yXG4gICAgICAgICAgICAgICAgICAgIC8vIG9uIENocm9tZSA8IDQzLCBQaGFudG9tSlMsIGV0Yy5cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGhhc0VTNVN1cHBvcnQpIHtcbiAgICAgICAgICAgICAgICAgICAgT2JqZWN0LmRlZmluZVByb3BlcnR5KG9iamVjdCwgcHJvcGVydHksIHdyYXBwZWRNZXRob2REZXNjKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyB0aGlzIG9ubHkgc3VwcG9ydHMgRVM1IGdldHRlci9zZXR0ZXIsIGZvciBFUzMuMSBhbmQgbG93ZXJcbiAgICAgICAgICAgICAgICAvLyBfX2xvb2t1cFNldHRlcl9fIC8gX19sb29rdXBHZXR0ZXJfXyBzaG91bGQgYmUgaW50ZWdyYXRlZFxuICAgICAgICAgICAgICAgIGlmIChoYXNFUzVTdXBwb3J0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBjaGVja0Rlc2MgPSBzaW5vbi5nZXRQcm9wZXJ0eURlc2NyaXB0b3Iob2JqZWN0LCBwcm9wZXJ0eSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjaGVja0Rlc2MudmFsdWUgPT09IG1ldGhvZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgb2JqZWN0W3Byb3BlcnR5XSA9IHdyYXBwZWRNZXRob2Q7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIFVzZSBzdHJpY3QgZXF1YWxpdHkgY29tcGFyaXNvbiB0byBjaGVjayBmYWlsdXJlcyB0aGVuIGZvcmNlIGEgcmVzZXRcbiAgICAgICAgICAgICAgICAvLyB2aWEgZGlyZWN0IGFzc2lnbm1lbnQuXG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmIChvYmplY3RbcHJvcGVydHldID09PSBtZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgb2JqZWN0W3Byb3BlcnR5XSA9IHdyYXBwZWRNZXRob2Q7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgbWV0aG9kLnJlc3RvcmUuc2lub24gPSB0cnVlO1xuXG4gICAgICAgICAgICBpZiAoIWhhc0VTNVN1cHBvcnQpIHtcbiAgICAgICAgICAgICAgICBtaXJyb3JQcm9wZXJ0aWVzKG1ldGhvZCwgd3JhcHBlZE1ldGhvZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBtZXRob2Q7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uY3JlYXRlID0gZnVuY3Rpb24gY3JlYXRlKHByb3RvKSB7XG4gICAgICAgICAgICB2YXIgRiA9IGZ1bmN0aW9uICgpIHt9O1xuICAgICAgICAgICAgRi5wcm90b3R5cGUgPSBwcm90bztcbiAgICAgICAgICAgIHJldHVybiBuZXcgRigpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNpbm9uLmRlZXBFcXVhbCA9IGZ1bmN0aW9uIGRlZXBFcXVhbChhLCBiKSB7XG4gICAgICAgICAgICBpZiAoc2lub24ubWF0Y2ggJiYgc2lub24ubWF0Y2guaXNNYXRjaGVyKGEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGEudGVzdChiKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBhICE9PSBcIm9iamVjdFwiIHx8IHR5cGVvZiBiICE9PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlzUmVhbGx5TmFOKGEpICYmIGlzUmVhbGx5TmFOKGIpIHx8IGEgPT09IGI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc0VsZW1lbnQoYSkgfHwgaXNFbGVtZW50KGIpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGEgPT09IGI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChhID09PSBiKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICgoYSA9PT0gbnVsbCAmJiBiICE9PSBudWxsKSB8fCAoYSAhPT0gbnVsbCAmJiBiID09PSBudWxsKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGEgaW5zdGFuY2VvZiBSZWdFeHAgJiYgYiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgICAgICAgIHJldHVybiAoYS5zb3VyY2UgPT09IGIuc291cmNlKSAmJiAoYS5nbG9iYWwgPT09IGIuZ2xvYmFsKSAmJlxuICAgICAgICAgICAgICAgICAgICAoYS5pZ25vcmVDYXNlID09PSBiLmlnbm9yZUNhc2UpICYmIChhLm11bHRpbGluZSA9PT0gYi5tdWx0aWxpbmUpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgYVN0cmluZyA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChhKTtcbiAgICAgICAgICAgIGlmIChhU3RyaW5nICE9PSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoYikpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChhU3RyaW5nID09PSBcIltvYmplY3QgRGF0ZV1cIikge1xuICAgICAgICAgICAgICAgIHJldHVybiBhLnZhbHVlT2YoKSA9PT0gYi52YWx1ZU9mKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBwcm9wO1xuICAgICAgICAgICAgdmFyIGFMZW5ndGggPSAwO1xuICAgICAgICAgICAgdmFyIGJMZW5ndGggPSAwO1xuXG4gICAgICAgICAgICBpZiAoYVN0cmluZyA9PT0gXCJbb2JqZWN0IEFycmF5XVwiICYmIGEubGVuZ3RoICE9PSBiLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZm9yIChwcm9wIGluIGEpIHtcbiAgICAgICAgICAgICAgICBpZiAoaGFzT3duLmNhbGwoYSwgcHJvcCkpIHtcbiAgICAgICAgICAgICAgICAgICAgYUxlbmd0aCArPSAxO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghKHByb3AgaW4gYikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmICghZGVlcEVxdWFsKGFbcHJvcF0sIGJbcHJvcF0pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGZvciAocHJvcCBpbiBiKSB7XG4gICAgICAgICAgICAgICAgaWYgKGhhc093bi5jYWxsKGIsIHByb3ApKSB7XG4gICAgICAgICAgICAgICAgICAgIGJMZW5ndGggKz0gMTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBhTGVuZ3RoID09PSBiTGVuZ3RoO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNpbm9uLmZ1bmN0aW9uTmFtZSA9IGZ1bmN0aW9uIGZ1bmN0aW9uTmFtZShmdW5jKSB7XG4gICAgICAgICAgICB2YXIgbmFtZSA9IGZ1bmMuZGlzcGxheU5hbWUgfHwgZnVuYy5uYW1lO1xuXG4gICAgICAgICAgICAvLyBVc2UgZnVuY3Rpb24gZGVjb21wb3NpdGlvbiBhcyBhIGxhc3QgcmVzb3J0IHRvIGdldCBmdW5jdGlvblxuICAgICAgICAgICAgLy8gbmFtZS4gRG9lcyBub3QgcmVseSBvbiBmdW5jdGlvbiBkZWNvbXBvc2l0aW9uIHRvIHdvcmsgLSBpZiBpdFxuICAgICAgICAgICAgLy8gZG9lc24ndCBkZWJ1Z2dpbmcgd2lsbCBiZSBzbGlnaHRseSBsZXNzIGluZm9ybWF0aXZlXG4gICAgICAgICAgICAvLyAoaS5lLiB0b1N0cmluZyB3aWxsIHNheSAnc3B5JyByYXRoZXIgdGhhbiAnbXlGdW5jJykuXG4gICAgICAgICAgICBpZiAoIW5hbWUpIHtcbiAgICAgICAgICAgICAgICB2YXIgbWF0Y2hlcyA9IGZ1bmMudG9TdHJpbmcoKS5tYXRjaCgvZnVuY3Rpb24gKFteXFxzXFwoXSspLyk7XG4gICAgICAgICAgICAgICAgbmFtZSA9IG1hdGNoZXMgJiYgbWF0Y2hlc1sxXTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIG5hbWU7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uZnVuY3Rpb25Ub1N0cmluZyA9IGZ1bmN0aW9uIHRvU3RyaW5nKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0Q2FsbCAmJiB0aGlzLmNhbGxDb3VudCkge1xuICAgICAgICAgICAgICAgIHZhciB0aGlzVmFsdWUsXG4gICAgICAgICAgICAgICAgICAgIHByb3A7XG4gICAgICAgICAgICAgICAgdmFyIGkgPSB0aGlzLmNhbGxDb3VudDtcblxuICAgICAgICAgICAgICAgIHdoaWxlIChpLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpc1ZhbHVlID0gdGhpcy5nZXRDYWxsKGkpLnRoaXNWYWx1ZTtcblxuICAgICAgICAgICAgICAgICAgICBmb3IgKHByb3AgaW4gdGhpc1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodGhpc1ZhbHVlW3Byb3BdID09PSB0aGlzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHByb3A7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aGlzLmRpc3BsYXlOYW1lIHx8IFwic2lub24gZmFrZVwiO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNpbm9uLm9iamVjdEtleXMgPSBmdW5jdGlvbiBvYmplY3RLZXlzKG9iaikge1xuICAgICAgICAgICAgaWYgKG9iaiAhPT0gT2JqZWN0KG9iaikpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwic2lub24ub2JqZWN0S2V5cyBjYWxsZWQgb24gYSBub24tb2JqZWN0XCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIga2V5cyA9IFtdO1xuICAgICAgICAgICAgdmFyIGtleTtcbiAgICAgICAgICAgIGZvciAoa2V5IGluIG9iaikge1xuICAgICAgICAgICAgICAgIGlmIChoYXNPd24uY2FsbChvYmosIGtleSkpIHtcbiAgICAgICAgICAgICAgICAgICAga2V5cy5wdXNoKGtleSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4ga2V5cztcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5nZXRQcm9wZXJ0eURlc2NyaXB0b3IgPSBmdW5jdGlvbiBnZXRQcm9wZXJ0eURlc2NyaXB0b3Iob2JqZWN0LCBwcm9wZXJ0eSkge1xuICAgICAgICAgICAgdmFyIHByb3RvID0gb2JqZWN0O1xuICAgICAgICAgICAgdmFyIGRlc2NyaXB0b3I7XG5cbiAgICAgICAgICAgIHdoaWxlIChwcm90byAmJiAhKGRlc2NyaXB0b3IgPSBPYmplY3QuZ2V0T3duUHJvcGVydHlEZXNjcmlwdG9yKHByb3RvLCBwcm9wZXJ0eSkpKSB7XG4gICAgICAgICAgICAgICAgcHJvdG8gPSBPYmplY3QuZ2V0UHJvdG90eXBlT2YocHJvdG8pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGRlc2NyaXB0b3I7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uZ2V0Q29uZmlnID0gZnVuY3Rpb24gKGN1c3RvbSkge1xuICAgICAgICAgICAgdmFyIGNvbmZpZyA9IHt9O1xuICAgICAgICAgICAgY3VzdG9tID0gY3VzdG9tIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGRlZmF1bHRzID0gc2lub24uZGVmYXVsdENvbmZpZztcblxuICAgICAgICAgICAgZm9yICh2YXIgcHJvcCBpbiBkZWZhdWx0cykge1xuICAgICAgICAgICAgICAgIGlmIChkZWZhdWx0cy5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25maWdbcHJvcF0gPSBjdXN0b20uaGFzT3duUHJvcGVydHkocHJvcCkgPyBjdXN0b21bcHJvcF0gOiBkZWZhdWx0c1twcm9wXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBjb25maWc7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uZGVmYXVsdENvbmZpZyA9IHtcbiAgICAgICAgICAgIGluamVjdEludG9UaGlzOiB0cnVlLFxuICAgICAgICAgICAgaW5qZWN0SW50bzogbnVsbCxcbiAgICAgICAgICAgIHByb3BlcnRpZXM6IFtcInNweVwiLCBcInN0dWJcIiwgXCJtb2NrXCIsIFwiY2xvY2tcIiwgXCJzZXJ2ZXJcIiwgXCJyZXF1ZXN0c1wiXSxcbiAgICAgICAgICAgIHVzZUZha2VUaW1lcnM6IHRydWUsXG4gICAgICAgICAgICB1c2VGYWtlU2VydmVyOiB0cnVlXG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24udGltZXNJbldvcmRzID0gZnVuY3Rpb24gdGltZXNJbldvcmRzKGNvdW50KSB7XG4gICAgICAgICAgICByZXR1cm4gY291bnQgPT09IDEgJiYgXCJvbmNlXCIgfHxcbiAgICAgICAgICAgICAgICBjb3VudCA9PT0gMiAmJiBcInR3aWNlXCIgfHxcbiAgICAgICAgICAgICAgICBjb3VudCA9PT0gMyAmJiBcInRocmljZVwiIHx8XG4gICAgICAgICAgICAgICAgKGNvdW50IHx8IDApICsgXCIgdGltZXNcIjtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5jYWxsZWRJbk9yZGVyID0gZnVuY3Rpb24gKHNwaWVzKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMSwgbCA9IHNwaWVzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgIGlmICghc3BpZXNbaSAtIDFdLmNhbGxlZEJlZm9yZShzcGllc1tpXSkgfHwgIXNwaWVzW2ldLmNhbGxlZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5vcmRlckJ5Rmlyc3RDYWxsID0gZnVuY3Rpb24gKHNwaWVzKSB7XG4gICAgICAgICAgICByZXR1cm4gc3BpZXMuc29ydChmdW5jdGlvbiAoYSwgYikge1xuICAgICAgICAgICAgICAgIC8vIHV1aWQsIHdvbid0IGV2ZXIgYmUgZXF1YWxcbiAgICAgICAgICAgICAgICB2YXIgYUNhbGwgPSBhLmdldENhbGwoMCk7XG4gICAgICAgICAgICAgICAgdmFyIGJDYWxsID0gYi5nZXRDYWxsKDApO1xuICAgICAgICAgICAgICAgIHZhciBhSWQgPSBhQ2FsbCAmJiBhQ2FsbC5jYWxsSWQgfHwgLTE7XG4gICAgICAgICAgICAgICAgdmFyIGJJZCA9IGJDYWxsICYmIGJDYWxsLmNhbGxJZCB8fCAtMTtcblxuICAgICAgICAgICAgICAgIHJldHVybiBhSWQgPCBiSWQgPyAtMSA6IDE7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5jcmVhdGVTdHViSW5zdGFuY2UgPSBmdW5jdGlvbiAoY29uc3RydWN0b3IpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY29uc3RydWN0b3IgIT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoXCJUaGUgY29uc3RydWN0b3Igc2hvdWxkIGJlIGEgZnVuY3Rpb24uXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHNpbm9uLnN0dWIoc2lub24uY3JlYXRlKGNvbnN0cnVjdG9yLnByb3RvdHlwZSkpO1xuICAgICAgICB9O1xuXG4gICAgICAgIHNpbm9uLnJlc3RvcmUgPSBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgICAgICAgICBpZiAob2JqZWN0ICE9PSBudWxsICYmIHR5cGVvZiBvYmplY3QgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBwcm9wIGluIG9iamVjdCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaXNSZXN0b3JhYmxlKG9iamVjdFtwcm9wXSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9iamVjdFtwcm9wXS5yZXN0b3JlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGlzUmVzdG9yYWJsZShvYmplY3QpKSB7XG4gICAgICAgICAgICAgICAgb2JqZWN0LnJlc3RvcmUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gc2lub247XG4gICAgfVxuXG4gICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICB2YXIgaXNBTUQgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT09IFwib2JqZWN0XCIgJiYgZGVmaW5lLmFtZDtcblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cykge1xuICAgICAgICBtYWtlQXBpKGV4cG9ydHMpO1xuICAgIH1cblxuICAgIGlmIChpc0FNRCkge1xuICAgICAgICBkZWZpbmUobG9hZERlcGVuZGVuY2llcyk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgbW9kdWxlLmV4cG9ydHMsIG1vZHVsZSk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc2lub25HbG9iYWwpIHtcbiAgICAgICAgbWFrZUFwaShzaW5vbkdsb2JhbCk7XG4gICAgfVxufShcbiAgICB0eXBlb2Ygc2lub24gPT09IFwib2JqZWN0XCIgJiYgc2lub24gLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuKSk7XG4iLCIvKipcbiAqIE1pbmltYWwgRXZlbnQgaW50ZXJmYWNlIGltcGxlbWVudGF0aW9uXG4gKlxuICogT3JpZ2luYWwgaW1wbGVtZW50YXRpb24gYnkgU3ZlbiBGdWNoczogaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vOTk1MDI4XG4gKiBNb2RpZmljYXRpb25zIGFuZCB0ZXN0cyBieSBDaHJpc3RpYW4gSm9oYW5zZW4uXG4gKlxuICogQGF1dGhvciBTdmVuIEZ1Y2hzIChzdmVuZnVjaHNAYXJ0d2ViLWRlc2lnbi5kZSlcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDExIFN2ZW4gRnVjaHMsIENocmlzdGlhbiBKb2hhbnNlblxuICovXG5pZiAodHlwZW9mIHNpbm9uID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgdGhpcy5zaW5vbiA9IHt9O1xufVxuXG4oZnVuY3Rpb24gKCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIHB1c2ggPSBbXS5wdXNoO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBzaW5vbi5FdmVudCA9IGZ1bmN0aW9uIEV2ZW50KHR5cGUsIGJ1YmJsZXMsIGNhbmNlbGFibGUsIHRhcmdldCkge1xuICAgICAgICAgICAgdGhpcy5pbml0RXZlbnQodHlwZSwgYnViYmxlcywgY2FuY2VsYWJsZSwgdGFyZ2V0KTtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5FdmVudC5wcm90b3R5cGUgPSB7XG4gICAgICAgICAgICBpbml0RXZlbnQ6IGZ1bmN0aW9uICh0eXBlLCBidWJibGVzLCBjYW5jZWxhYmxlLCB0YXJnZXQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnR5cGUgPSB0eXBlO1xuICAgICAgICAgICAgICAgIHRoaXMuYnViYmxlcyA9IGJ1YmJsZXM7XG4gICAgICAgICAgICAgICAgdGhpcy5jYW5jZWxhYmxlID0gY2FuY2VsYWJsZTtcbiAgICAgICAgICAgICAgICB0aGlzLnRhcmdldCA9IHRhcmdldDtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24gKCkge30sXG5cbiAgICAgICAgICAgIHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5kZWZhdWx0UHJldmVudGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5Qcm9ncmVzc0V2ZW50ID0gZnVuY3Rpb24gUHJvZ3Jlc3NFdmVudCh0eXBlLCBwcm9ncmVzc0V2ZW50UmF3LCB0YXJnZXQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdEV2ZW50KHR5cGUsIGZhbHNlLCBmYWxzZSwgdGFyZ2V0KTtcbiAgICAgICAgICAgIHRoaXMubG9hZGVkID0gdHlwZW9mIHByb2dyZXNzRXZlbnRSYXcubG9hZGVkID09PSBcIm51bWJlclwiID8gcHJvZ3Jlc3NFdmVudFJhdy5sb2FkZWQgOiBudWxsO1xuICAgICAgICAgICAgdGhpcy50b3RhbCA9IHR5cGVvZiBwcm9ncmVzc0V2ZW50UmF3LnRvdGFsID09PSBcIm51bWJlclwiID8gcHJvZ3Jlc3NFdmVudFJhdy50b3RhbCA6IG51bGw7XG4gICAgICAgICAgICB0aGlzLmxlbmd0aENvbXB1dGFibGUgPSAhIXByb2dyZXNzRXZlbnRSYXcudG90YWw7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uUHJvZ3Jlc3NFdmVudC5wcm90b3R5cGUgPSBuZXcgc2lub24uRXZlbnQoKTtcblxuICAgICAgICBzaW5vbi5Qcm9ncmVzc0V2ZW50LnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IHNpbm9uLlByb2dyZXNzRXZlbnQ7XG5cbiAgICAgICAgc2lub24uQ3VzdG9tRXZlbnQgPSBmdW5jdGlvbiBDdXN0b21FdmVudCh0eXBlLCBjdXN0b21EYXRhLCB0YXJnZXQpIHtcbiAgICAgICAgICAgIHRoaXMuaW5pdEV2ZW50KHR5cGUsIGZhbHNlLCBmYWxzZSwgdGFyZ2V0KTtcbiAgICAgICAgICAgIHRoaXMuZGV0YWlsID0gY3VzdG9tRGF0YS5kZXRhaWwgfHwgbnVsbDtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5DdXN0b21FdmVudC5wcm90b3R5cGUgPSBuZXcgc2lub24uRXZlbnQoKTtcblxuICAgICAgICBzaW5vbi5DdXN0b21FdmVudC5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBzaW5vbi5DdXN0b21FdmVudDtcblxuICAgICAgICBzaW5vbi5FdmVudFRhcmdldCA9IHtcbiAgICAgICAgICAgIGFkZEV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5ldmVudExpc3RlbmVycyA9IHRoaXMuZXZlbnRMaXN0ZW5lcnMgfHwge307XG4gICAgICAgICAgICAgICAgdGhpcy5ldmVudExpc3RlbmVyc1tldmVudF0gPSB0aGlzLmV2ZW50TGlzdGVuZXJzW2V2ZW50XSB8fCBbXTtcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5ldmVudExpc3RlbmVyc1tldmVudF0sIGxpc3RlbmVyKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlbW92ZUV2ZW50TGlzdGVuZXI6IGZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIGxpc3RlbmVycyA9IHRoaXMuZXZlbnRMaXN0ZW5lcnMgJiYgdGhpcy5ldmVudExpc3RlbmVyc1tldmVudF0gfHwgW107XG5cbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGxpc3RlbmVyc1tpXSA9PT0gbGlzdGVuZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBsaXN0ZW5lcnMuc3BsaWNlKGksIDEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZGlzcGF0Y2hFdmVudDogZnVuY3Rpb24gZGlzcGF0Y2hFdmVudChldmVudCkge1xuICAgICAgICAgICAgICAgIHZhciB0eXBlID0gZXZlbnQudHlwZTtcbiAgICAgICAgICAgICAgICB2YXIgbGlzdGVuZXJzID0gdGhpcy5ldmVudExpc3RlbmVycyAmJiB0aGlzLmV2ZW50TGlzdGVuZXJzW3R5cGVdIHx8IFtdO1xuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaXN0ZW5lcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBsaXN0ZW5lcnNbaV0gPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXJzW2ldLmNhbGwodGhpcywgZXZlbnQpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXJzW2ldLmhhbmRsZUV2ZW50KGV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiAhIWV2ZW50LmRlZmF1bHRQcmV2ZW50ZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdmFyIGlzTm9kZSA9IHR5cGVvZiBtb2R1bGUgIT09IFwidW5kZWZpbmVkXCIgJiYgbW9kdWxlLmV4cG9ydHMgJiYgdHlwZW9mIHJlcXVpcmUgPT09IFwiZnVuY3Rpb25cIjtcbiAgICB2YXIgaXNBTUQgPSB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgdHlwZW9mIGRlZmluZS5hbWQgPT09IFwib2JqZWN0XCIgJiYgZGVmaW5lLmFtZDtcblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi9jb3JlXCIpO1xuICAgICAgICBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgIH0gZWxzZSBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbWFrZUFwaShzaW5vbik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiAgICB9XG59KCkpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIGZha2VfeGRvbWFpbl9yZXF1ZXN0LmpzXG4gKiBAZGVwZW5kIGZha2VfeG1sX2h0dHBfcmVxdWVzdC5qc1xuICogQGRlcGVuZCAuLi9mb3JtYXQuanNcbiAqIEBkZXBlbmQgLi4vbG9nX2Vycm9yLmpzXG4gKi9cbi8qKlxuICogVGhlIFNpbm9uIFwic2VydmVyXCIgbWltaWNzIGEgd2ViIHNlcnZlciB0aGF0IHJlY2VpdmVzIHJlcXVlc3RzIGZyb21cbiAqIHNpbm9uLkZha2VYTUxIdHRwUmVxdWVzdCBhbmQgcHJvdmlkZXMgYW4gQVBJIHRvIHJlc3BvbmQgdG8gdGhvc2UgcmVxdWVzdHMsXG4gKiBib3RoIHN5bmNocm9ub3VzbHkgYW5kIGFzeW5jaHJvbm91c2x5LiBUbyByZXNwb25kIHN5bmNocm9udW91c2x5LCBjYW5uZWRcbiAqIGFuc3dlcnMgaGF2ZSB0byBiZSBwcm92aWRlZCB1cGZyb250LlxuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICB2YXIgcHVzaCA9IFtdLnB1c2g7XG5cbiAgICBmdW5jdGlvbiByZXNwb25zZUFycmF5KGhhbmRsZXIpIHtcbiAgICAgICAgdmFyIHJlc3BvbnNlID0gaGFuZGxlcjtcblxuICAgICAgICBpZiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKGhhbmRsZXIpICE9PSBcIltvYmplY3QgQXJyYXldXCIpIHtcbiAgICAgICAgICAgIHJlc3BvbnNlID0gWzIwMCwge30sIGhhbmRsZXJdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiByZXNwb25zZVsyXSAhPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIkZha2Ugc2VydmVyIHJlc3BvbnNlIGJvZHkgc2hvdWxkIGJlIHN0cmluZywgYnV0IHdhcyBcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiByZXNwb25zZVsyXSk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gcmVzcG9uc2U7XG4gICAgfVxuXG4gICAgdmFyIHdsb2MgPSB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93LmxvY2F0aW9uIDoge307XG4gICAgdmFyIHJDdXJyTG9jID0gbmV3IFJlZ0V4cChcIl5cIiArIHdsb2MucHJvdG9jb2wgKyBcIi8vXCIgKyB3bG9jLmhvc3QpO1xuXG4gICAgZnVuY3Rpb24gbWF0Y2hPbmUocmVzcG9uc2UsIHJlcU1ldGhvZCwgcmVxVXJsKSB7XG4gICAgICAgIHZhciBybWV0aCA9IHJlc3BvbnNlLm1ldGhvZDtcbiAgICAgICAgdmFyIG1hdGNoTWV0aG9kID0gIXJtZXRoIHx8IHJtZXRoLnRvTG93ZXJDYXNlKCkgPT09IHJlcU1ldGhvZC50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgdXJsID0gcmVzcG9uc2UudXJsO1xuICAgICAgICB2YXIgbWF0Y2hVcmwgPSAhdXJsIHx8IHVybCA9PT0gcmVxVXJsIHx8ICh0eXBlb2YgdXJsLnRlc3QgPT09IFwiZnVuY3Rpb25cIiAmJiB1cmwudGVzdChyZXFVcmwpKTtcblxuICAgICAgICByZXR1cm4gbWF0Y2hNZXRob2QgJiYgbWF0Y2hVcmw7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbWF0Y2gocmVzcG9uc2UsIHJlcXVlc3QpIHtcbiAgICAgICAgdmFyIHJlcXVlc3RVcmwgPSByZXF1ZXN0LnVybDtcblxuICAgICAgICBpZiAoIS9eaHR0cHM/OlxcL1xcLy8udGVzdChyZXF1ZXN0VXJsKSB8fCByQ3VyckxvYy50ZXN0KHJlcXVlc3RVcmwpKSB7XG4gICAgICAgICAgICByZXF1ZXN0VXJsID0gcmVxdWVzdFVybC5yZXBsYWNlKHJDdXJyTG9jLCBcIlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtYXRjaE9uZShyZXNwb25zZSwgdGhpcy5nZXRIVFRQTWV0aG9kKHJlcXVlc3QpLCByZXF1ZXN0VXJsKSkge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiByZXNwb25zZS5yZXNwb25zZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJ1ID0gcmVzcG9uc2UudXJsO1xuICAgICAgICAgICAgICAgIHZhciBhcmdzID0gW3JlcXVlc3RdLmNvbmNhdChydSAmJiB0eXBlb2YgcnUuZXhlYyA9PT0gXCJmdW5jdGlvblwiID8gcnUuZXhlYyhyZXF1ZXN0VXJsKS5zbGljZSgxKSA6IFtdKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gcmVzcG9uc2UucmVzcG9uc2UuYXBwbHkocmVzcG9uc2UsIGFyZ3MpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIHNpbm9uLmZha2VTZXJ2ZXIgPSB7XG4gICAgICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChjb25maWcpIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VydmVyID0gc2lub24uY3JlYXRlKHRoaXMpO1xuICAgICAgICAgICAgICAgIHNlcnZlci5jb25maWd1cmUoY29uZmlnKTtcbiAgICAgICAgICAgICAgICBpZiAoIXNpbm9uLnhoci5zdXBwb3J0c0NPUlMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy54aHIgPSBzaW5vbi51c2VGYWtlWERvbWFpblJlcXVlc3QoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnhociA9IHNpbm9uLnVzZUZha2VYTUxIdHRwUmVxdWVzdCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBzZXJ2ZXIucmVxdWVzdHMgPSBbXTtcblxuICAgICAgICAgICAgICAgIHRoaXMueGhyLm9uQ3JlYXRlID0gZnVuY3Rpb24gKHhock9iaikge1xuICAgICAgICAgICAgICAgICAgICBzZXJ2ZXIuYWRkUmVxdWVzdCh4aHJPYmopO1xuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gc2VydmVyO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGNvbmZpZ3VyZTogZnVuY3Rpb24gKGNvbmZpZykge1xuICAgICAgICAgICAgICAgIHZhciB3aGl0ZWxpc3QgPSB7XG4gICAgICAgICAgICAgICAgICAgIFwiYXV0b1Jlc3BvbmRcIjogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgXCJhdXRvUmVzcG9uZEFmdGVyXCI6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIFwicmVzcG9uZEltbWVkaWF0ZWx5XCI6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgIFwiZmFrZUhUVFBNZXRob2RzXCI6IHRydWVcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIHZhciBzZXR0aW5nO1xuXG4gICAgICAgICAgICAgICAgY29uZmlnID0gY29uZmlnIHx8IHt9O1xuICAgICAgICAgICAgICAgIGZvciAoc2V0dGluZyBpbiBjb25maWcpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHdoaXRlbGlzdC5oYXNPd25Qcm9wZXJ0eShzZXR0aW5nKSAmJiBjb25maWcuaGFzT3duUHJvcGVydHkoc2V0dGluZykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbc2V0dGluZ10gPSBjb25maWdbc2V0dGluZ107XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgYWRkUmVxdWVzdDogZnVuY3Rpb24gYWRkUmVxdWVzdCh4aHJPYmopIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VydmVyID0gdGhpcztcbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5yZXF1ZXN0cywgeGhyT2JqKTtcblxuICAgICAgICAgICAgICAgIHhock9iai5vblNlbmQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlcnZlci5oYW5kbGVSZXF1ZXN0KHRoaXMpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmIChzZXJ2ZXIucmVzcG9uZEltbWVkaWF0ZWx5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZXJ2ZXIucmVzcG9uZCgpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHNlcnZlci5hdXRvUmVzcG9uZCAmJiAhc2VydmVyLnJlc3BvbmRpbmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlcnZlci5yZXNwb25kaW5nID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyLnJlc3BvbmQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sIHNlcnZlci5hdXRvUmVzcG9uZEFmdGVyIHx8IDEwKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyLnJlc3BvbmRpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldEhUVFBNZXRob2Q6IGZ1bmN0aW9uIGdldEhUVFBNZXRob2QocmVxdWVzdCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmZha2VIVFRQTWV0aG9kcyAmJiAvcG9zdC9pLnRlc3QocmVxdWVzdC5tZXRob2QpKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtYXRjaGVzID0gKHJlcXVlc3QucmVxdWVzdEJvZHkgfHwgXCJcIikubWF0Y2goL19tZXRob2Q9KFteXFxiO10rKS8pO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbWF0Y2hlcyA/IG1hdGNoZXNbMV0gOiByZXF1ZXN0Lm1ldGhvZDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gcmVxdWVzdC5tZXRob2Q7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBoYW5kbGVSZXF1ZXN0OiBmdW5jdGlvbiBoYW5kbGVSZXF1ZXN0KHhocikge1xuICAgICAgICAgICAgICAgIGlmICh4aHIuYXN5bmMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCF0aGlzLnF1ZXVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnF1ZXVlID0gW107XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5xdWV1ZSwgeGhyKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnByb2Nlc3NSZXF1ZXN0KHhocik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgbG9nOiBmdW5jdGlvbiBsb2cocmVzcG9uc2UsIHJlcXVlc3QpIHtcbiAgICAgICAgICAgICAgICB2YXIgc3RyO1xuXG4gICAgICAgICAgICAgICAgc3RyID0gXCJSZXF1ZXN0OlxcblwiICsgc2lub24uZm9ybWF0KHJlcXVlc3QpICsgXCJcXG5cXG5cIjtcbiAgICAgICAgICAgICAgICBzdHIgKz0gXCJSZXNwb25zZTpcXG5cIiArIHNpbm9uLmZvcm1hdChyZXNwb25zZSkgKyBcIlxcblxcblwiO1xuXG4gICAgICAgICAgICAgICAgc2lub24ubG9nKHN0cik7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXNwb25kV2l0aDogZnVuY3Rpb24gcmVzcG9uZFdpdGgobWV0aG9kLCB1cmwsIGJvZHkpIHtcbiAgICAgICAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSAmJiB0eXBlb2YgbWV0aG9kICE9PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZSA9IHJlc3BvbnNlQXJyYXkobWV0aG9kKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5yZXNwb25zZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZXMgPSBbXTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICBib2R5ID0gbWV0aG9kO1xuICAgICAgICAgICAgICAgICAgICB1cmwgPSBtZXRob2QgPSBudWxsO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAyKSB7XG4gICAgICAgICAgICAgICAgICAgIGJvZHkgPSB1cmw7XG4gICAgICAgICAgICAgICAgICAgIHVybCA9IG1ldGhvZDtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kID0gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBwdXNoLmNhbGwodGhpcy5yZXNwb25zZXMsIHtcbiAgICAgICAgICAgICAgICAgICAgbWV0aG9kOiBtZXRob2QsXG4gICAgICAgICAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgICAgICAgICByZXNwb25zZTogdHlwZW9mIGJvZHkgPT09IFwiZnVuY3Rpb25cIiA/IGJvZHkgOiByZXNwb25zZUFycmF5KGJvZHkpXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXNwb25kOiBmdW5jdGlvbiByZXNwb25kKCkge1xuICAgICAgICAgICAgICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbmRXaXRoLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIHF1ZXVlID0gdGhpcy5xdWV1ZSB8fCBbXTtcbiAgICAgICAgICAgICAgICB2YXIgcmVxdWVzdHMgPSBxdWV1ZS5zcGxpY2UoMCwgcXVldWUubGVuZ3RoKTtcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVxdWVzdHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcm9jZXNzUmVxdWVzdChyZXF1ZXN0c1tpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgcHJvY2Vzc1JlcXVlc3Q6IGZ1bmN0aW9uIHByb2Nlc3NSZXF1ZXN0KHJlcXVlc3QpIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBpZiAocmVxdWVzdC5hYm9ydGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICB2YXIgcmVzcG9uc2UgPSB0aGlzLnJlc3BvbnNlIHx8IFs0MDQsIHt9LCBcIlwiXTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5yZXNwb25zZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGwgPSB0aGlzLnJlc3BvbnNlcy5sZW5ndGgsIGkgPSBsIC0gMTsgaSA+PSAwOyBpLS0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobWF0Y2guY2FsbCh0aGlzLCB0aGlzLnJlc3BvbnNlc1tpXSwgcmVxdWVzdCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UgPSB0aGlzLnJlc3BvbnNlc1tpXS5yZXNwb25zZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHJlcXVlc3QucmVhZHlTdGF0ZSAhPT0gNCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2cocmVzcG9uc2UsIHJlcXVlc3QpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXF1ZXN0LnJlc3BvbmQocmVzcG9uc2VbMF0sIHJlc3BvbnNlWzFdLCByZXNwb25zZVsyXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNpbm9uLmxvZ0Vycm9yKFwiRmFrZSBzZXJ2ZXIgcmVxdWVzdCBwcm9jZXNzaW5nXCIsIGUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlc3RvcmU6IGZ1bmN0aW9uIHJlc3RvcmUoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMueGhyLnJlc3RvcmUgJiYgdGhpcy54aHIucmVzdG9yZS5hcHBseSh0aGlzLnhociwgYXJndW1lbnRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBleHBvcnRzLCBtb2R1bGUpIHtcbiAgICAgICAgdmFyIHNpbm9uID0gcmVxdWlyZShcIi4vY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZmFrZV94ZG9tYWluX3JlcXVlc3RcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2Zha2VfeG1sX2h0dHBfcmVxdWVzdFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4uL2Zvcm1hdFwiKTtcbiAgICAgICAgbWFrZUFwaShzaW5vbik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gc2lub247XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICB9IGVsc2UgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG1ha2VBcGkoc2lub24pOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4gICAgfVxufSgpKTtcbiIsIi8qKlxuICogQGRlcGVuZCBmYWtlX3NlcnZlci5qc1xuICogQGRlcGVuZCBmYWtlX3RpbWVycy5qc1xuICovXG4vKipcbiAqIEFkZC1vbiBmb3Igc2lub24uZmFrZVNlcnZlciB0aGF0IGF1dG9tYXRpY2FsbHkgaGFuZGxlcyBhIGZha2UgdGltZXIgYWxvbmcgd2l0aFxuICogdGhlIEZha2VYTUxIdHRwUmVxdWVzdC4gVGhlIGRpcmVjdCBpbnNwaXJhdGlvbiBmb3IgdGhpcyBhZGQtb24gaXMgalF1ZXJ5XG4gKiAxLjMueCwgd2hpY2ggZG9lcyBub3QgdXNlIHhociBvYmplY3QncyBvbnJlYWR5c3RhdGVoYW5kbGVyIGF0IGFsbCAtIGluc3RlYWQsXG4gKiBpdCBwb2xscyB0aGUgb2JqZWN0IGZvciBjb21wbGV0aW9uIHdpdGggc2V0SW50ZXJ2YWwuIERpc3BpdGUgdGhlIGRpcmVjdFxuICogbW90aXZhdGlvbiwgdGhlcmUgaXMgbm90aGluZyBqUXVlcnktc3BlY2lmaWMgaW4gdGhpcyBmaWxlLCBzbyBpdCBjYW4gYmUgdXNlZFxuICogaW4gYW55IGVudmlyb25tZW50IHdoZXJlIHRoZSBhamF4IGltcGxlbWVudGF0aW9uIGRlcGVuZHMgb24gc2V0SW50ZXJ2YWwgb3JcbiAqIHNldFRpbWVvdXQuXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMyBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xuKGZ1bmN0aW9uICgpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIGZ1bmN0aW9uIG1ha2VBcGkoc2lub24pIHtcbiAgICAgICAgZnVuY3Rpb24gU2VydmVyKCkge31cbiAgICAgICAgU2VydmVyLnByb3RvdHlwZSA9IHNpbm9uLmZha2VTZXJ2ZXI7XG5cbiAgICAgICAgc2lub24uZmFrZVNlcnZlcldpdGhDbG9jayA9IG5ldyBTZXJ2ZXIoKTtcblxuICAgICAgICBzaW5vbi5mYWtlU2VydmVyV2l0aENsb2NrLmFkZFJlcXVlc3QgPSBmdW5jdGlvbiBhZGRSZXF1ZXN0KHhocikge1xuICAgICAgICAgICAgaWYgKHhoci5hc3luYykge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc2V0VGltZW91dC5jbG9jayA9PT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNsb2NrID0gc2V0VGltZW91dC5jbG9jaztcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNsb2NrID0gc2lub24udXNlRmFrZVRpbWVycygpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlc2V0Q2xvY2sgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5sb25nZXN0VGltZW91dCkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgY2xvY2tTZXRUaW1lb3V0ID0gdGhpcy5jbG9jay5zZXRUaW1lb3V0O1xuICAgICAgICAgICAgICAgICAgICB2YXIgY2xvY2tTZXRJbnRlcnZhbCA9IHRoaXMuY2xvY2suc2V0SW50ZXJ2YWw7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzZXJ2ZXIgPSB0aGlzO1xuXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuY2xvY2suc2V0VGltZW91dCA9IGZ1bmN0aW9uIChmbiwgdGltZW91dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyLmxvbmdlc3RUaW1lb3V0ID0gTWF0aC5tYXgodGltZW91dCwgc2VydmVyLmxvbmdlc3RUaW1lb3V0IHx8IDApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2xvY2tTZXRUaW1lb3V0LmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jbG9jay5zZXRJbnRlcnZhbCA9IGZ1bmN0aW9uIChmbiwgdGltZW91dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VydmVyLmxvbmdlc3RUaW1lb3V0ID0gTWF0aC5tYXgodGltZW91dCwgc2VydmVyLmxvbmdlc3RUaW1lb3V0IHx8IDApO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gY2xvY2tTZXRJbnRlcnZhbC5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHNpbm9uLmZha2VTZXJ2ZXIuYWRkUmVxdWVzdC5jYWxsKHRoaXMsIHhocik7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uZmFrZVNlcnZlcldpdGhDbG9jay5yZXNwb25kID0gZnVuY3Rpb24gcmVzcG9uZCgpIHtcbiAgICAgICAgICAgIHZhciByZXR1cm5WYWwgPSBzaW5vbi5mYWtlU2VydmVyLnJlc3BvbmQuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuY2xvY2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNsb2NrLnRpY2sodGhpcy5sb25nZXN0VGltZW91dCB8fCAwKTtcbiAgICAgICAgICAgICAgICB0aGlzLmxvbmdlc3RUaW1lb3V0ID0gMDtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJlc2V0Q2xvY2spIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jbG9jay5yZXN0b3JlKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVzZXRDbG9jayA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHJldHVyblZhbDtcbiAgICAgICAgfTtcblxuICAgICAgICBzaW5vbi5mYWtlU2VydmVyV2l0aENsb2NrLnJlc3RvcmUgPSBmdW5jdGlvbiByZXN0b3JlKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuY2xvY2spIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNsb2NrLnJlc3RvcmUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHNpbm9uLmZha2VTZXJ2ZXIucmVzdG9yZS5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUpIHtcbiAgICAgICAgdmFyIHNpbm9uID0gcmVxdWlyZShcIi4vY29yZVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vZmFrZV9zZXJ2ZXJcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL2Zha2VfdGltZXJzXCIpO1xuICAgICAgICBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgIH0gZWxzZSBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbWFrZUFwaShzaW5vbik7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbm8tdW5kZWZcbiAgICB9XG59KCkpO1xuIiwiLyoqXG4gKiBGYWtlIHRpbWVyIEFQSVxuICogc2V0VGltZW91dFxuICogc2V0SW50ZXJ2YWxcbiAqIGNsZWFyVGltZW91dFxuICogY2xlYXJJbnRlcnZhbFxuICogdGlja1xuICogcmVzZXRcbiAqIERhdGVcbiAqXG4gKiBJbnNwaXJlZCBieSBqc1VuaXRNb2NrVGltZU91dCBmcm9tIEpzVW5pdFxuICpcbiAqIEBhdXRob3IgQ2hyaXN0aWFuIEpvaGFuc2VuIChjaHJpc3RpYW5AY2pvaGFuc2VuLm5vKVxuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTMgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cbihmdW5jdGlvbiAoKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHMsIGxvbCkge1xuICAgICAgICAvKmdsb2JhbCBsb2xleCAqL1xuICAgICAgICB2YXIgbGx4ID0gdHlwZW9mIGxvbGV4ICE9PSBcInVuZGVmaW5lZFwiID8gbG9sZXggOiBsb2w7XG5cbiAgICAgICAgcy51c2VGYWtlVGltZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIG5vdztcbiAgICAgICAgICAgIHZhciBtZXRob2RzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBtZXRob2RzWzBdID09PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICAgICAgbm93ID0gMDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbm93ID0gbWV0aG9kcy5zaGlmdCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgY2xvY2sgPSBsbHguaW5zdGFsbChub3cgfHwgMCwgbWV0aG9kcyk7XG4gICAgICAgICAgICBjbG9jay5yZXN0b3JlID0gY2xvY2sudW5pbnN0YWxsO1xuICAgICAgICAgICAgcmV0dXJuIGNsb2NrO1xuICAgICAgICB9O1xuXG4gICAgICAgIHMuY2xvY2sgPSB7XG4gICAgICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uIChub3cpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGx4LmNyZWF0ZUNsb2NrKG5vdyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgcy50aW1lcnMgPSB7XG4gICAgICAgICAgICBzZXRUaW1lb3V0OiBzZXRUaW1lb3V0LFxuICAgICAgICAgICAgY2xlYXJUaW1lb3V0OiBjbGVhclRpbWVvdXQsXG4gICAgICAgICAgICBzZXRJbW1lZGlhdGU6ICh0eXBlb2Ygc2V0SW1tZWRpYXRlICE9PSBcInVuZGVmaW5lZFwiID8gc2V0SW1tZWRpYXRlIDogdW5kZWZpbmVkKSxcbiAgICAgICAgICAgIGNsZWFySW1tZWRpYXRlOiAodHlwZW9mIGNsZWFySW1tZWRpYXRlICE9PSBcInVuZGVmaW5lZFwiID8gY2xlYXJJbW1lZGlhdGUgOiB1bmRlZmluZWQpLFxuICAgICAgICAgICAgc2V0SW50ZXJ2YWw6IHNldEludGVydmFsLFxuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbDogY2xlYXJJbnRlcnZhbCxcbiAgICAgICAgICAgIERhdGU6IERhdGVcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgZnVuY3Rpb24gbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBlcHhvcnRzLCBtb2R1bGUsIGxvbGV4KSB7XG4gICAgICAgIHZhciBjb3JlID0gcmVxdWlyZShcIi4vY29yZVwiKTtcbiAgICAgICAgbWFrZUFwaShjb3JlLCBsb2xleCk7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gY29yZTtcbiAgICB9XG5cbiAgICBpZiAoaXNBTUQpIHtcbiAgICAgICAgZGVmaW5lKGxvYWREZXBlbmRlbmNpZXMpO1xuICAgIH0gZWxzZSBpZiAoaXNOb2RlKSB7XG4gICAgICAgIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgbW9kdWxlLmV4cG9ydHMsIG1vZHVsZSwgcmVxdWlyZShcImxvbGV4XCIpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBtYWtlQXBpKHNpbm9uKTsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgIH1cbn0oKSk7XG4iLCIvKipcbiAqIEBkZXBlbmQgY29yZS5qc1xuICogQGRlcGVuZCAuLi9leHRlbmQuanNcbiAqIEBkZXBlbmQgZXZlbnQuanNcbiAqIEBkZXBlbmQgLi4vbG9nX2Vycm9yLmpzXG4gKi9cbi8qKlxuICogRmFrZSBYRG9tYWluUmVxdWVzdCBvYmplY3RcbiAqL1xuXG4vKipcbiAqIFJldHVybnMgdGhlIGdsb2JhbCB0byBwcmV2ZW50IGFzc2lnbmluZyB2YWx1ZXMgdG8gJ3RoaXMnIHdoZW4gdGhpcyBpcyB1bmRlZmluZWQuXG4gKiBUaGlzIGNhbiBvY2N1ciB3aGVuIGZpbGVzIGFyZSBpbnRlcnByZXRlZCBieSBub2RlIGluIHN0cmljdCBtb2RlLlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gZ2V0R2xvYmFsKCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgcmV0dXJuIHR5cGVvZiB3aW5kb3cgIT09IFwidW5kZWZpbmVkXCIgPyB3aW5kb3cgOiBnbG9iYWw7XG59XG5cbmlmICh0eXBlb2Ygc2lub24gPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBpZiAodHlwZW9mIHRoaXMgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgZ2V0R2xvYmFsKCkuc2lub24gPSB7fTtcbiAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLnNpbm9uID0ge307XG4gICAgfVxufVxuXG4vLyB3cmFwcGVyIGZvciBnbG9iYWxcbihmdW5jdGlvbiAoZ2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICB2YXIgeGRyID0geyBYRG9tYWluUmVxdWVzdDogZ2xvYmFsLlhEb21haW5SZXF1ZXN0IH07XG4gICAgeGRyLkdsb2JhbFhEb21haW5SZXF1ZXN0ID0gZ2xvYmFsLlhEb21haW5SZXF1ZXN0O1xuICAgIHhkci5zdXBwb3J0c1hEUiA9IHR5cGVvZiB4ZHIuR2xvYmFsWERvbWFpblJlcXVlc3QgIT09IFwidW5kZWZpbmVkXCI7XG4gICAgeGRyLndvcmtpbmdYRFIgPSB4ZHIuc3VwcG9ydHNYRFIgPyB4ZHIuR2xvYmFsWERvbWFpblJlcXVlc3QgOiBmYWxzZTtcblxuICAgIGZ1bmN0aW9uIG1ha2VBcGkoc2lub24pIHtcbiAgICAgICAgc2lub24ueGRyID0geGRyO1xuXG4gICAgICAgIGZ1bmN0aW9uIEZha2VYRG9tYWluUmVxdWVzdCgpIHtcbiAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZSA9IEZha2VYRG9tYWluUmVxdWVzdC5VTlNFTlQ7XG4gICAgICAgICAgICB0aGlzLnJlcXVlc3RCb2R5ID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnMgPSB7fTtcbiAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gMDtcbiAgICAgICAgICAgIHRoaXMudGltZW91dCA9IG51bGw7XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgRmFrZVhEb21haW5SZXF1ZXN0Lm9uQ3JlYXRlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBGYWtlWERvbWFpblJlcXVlc3Qub25DcmVhdGUodGhpcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiB2ZXJpZnlTdGF0ZSh4KSB7XG4gICAgICAgICAgICBpZiAoeC5yZWFkeVN0YXRlICE9PSBGYWtlWERvbWFpblJlcXVlc3QuT1BFTkVEKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSU5WQUxJRF9TVEFURV9FUlJcIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh4LnNlbmRGbGFnKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSU5WQUxJRF9TVEFURV9FUlJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiB2ZXJpZnlSZXF1ZXN0U2VudCh4KSB7XG4gICAgICAgICAgICBpZiAoeC5yZWFkeVN0YXRlID09PSBGYWtlWERvbWFpblJlcXVlc3QuVU5TRU5UKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVxdWVzdCBub3Qgc2VudFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh4LnJlYWR5U3RhdGUgPT09IEZha2VYRG9tYWluUmVxdWVzdC5ET05FKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVxdWVzdCBkb25lXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gdmVyaWZ5UmVzcG9uc2VCb2R5VHlwZShib2R5KSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGJvZHkgIT09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoXCJBdHRlbXB0ZWQgdG8gcmVzcG9uZCB0byBmYWtlIFhEb21haW5SZXF1ZXN0IHdpdGggXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9keSArIFwiLCB3aGljaCBpcyBub3QgYSBzdHJpbmcuXCIpO1xuICAgICAgICAgICAgICAgIGVycm9yLm5hbWUgPSBcIkludmFsaWRCb2R5RXhjZXB0aW9uXCI7XG4gICAgICAgICAgICAgICAgdGhyb3cgZXJyb3I7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBzaW5vbi5leHRlbmQoRmFrZVhEb21haW5SZXF1ZXN0LnByb3RvdHlwZSwgc2lub24uRXZlbnRUYXJnZXQsIHtcbiAgICAgICAgICAgIG9wZW46IGZ1bmN0aW9uIG9wZW4obWV0aG9kLCB1cmwpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm1ldGhvZCA9IG1ldGhvZDtcbiAgICAgICAgICAgICAgICB0aGlzLnVybCA9IHVybDtcblxuICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2VUZXh0ID0gbnVsbDtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRGbGFnID0gZmFsc2U7XG5cbiAgICAgICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGVDaGFuZ2UoRmFrZVhEb21haW5SZXF1ZXN0Lk9QRU5FRCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZWFkeVN0YXRlQ2hhbmdlOiBmdW5jdGlvbiByZWFkeVN0YXRlQ2hhbmdlKHN0YXRlKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gc3RhdGU7XG4gICAgICAgICAgICAgICAgdmFyIGV2ZW50TmFtZSA9IFwiXCI7XG4gICAgICAgICAgICAgICAgc3dpdGNoICh0aGlzLnJlYWR5U3RhdGUpIHtcbiAgICAgICAgICAgICAgICBjYXNlIEZha2VYRG9tYWluUmVxdWVzdC5VTlNFTlQ6XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgRmFrZVhEb21haW5SZXF1ZXN0Lk9QRU5FRDpcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBGYWtlWERvbWFpblJlcXVlc3QuTE9BRElORzpcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2VuZEZsYWcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vcmFpc2UgdGhlIHByb2dyZXNzIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudE5hbWUgPSBcIm9ucHJvZ3Jlc3NcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIEZha2VYRG9tYWluUmVxdWVzdC5ET05FOlxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5pc1RpbWVvdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50TmFtZSA9IFwib250aW1lb3V0XCI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAodGhpcy5lcnJvckZsYWcgfHwgKHRoaXMuc3RhdHVzIDwgMjAwIHx8IHRoaXMuc3RhdHVzID4gMjk5KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnROYW1lID0gXCJvbmVycm9yXCI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudE5hbWUgPSBcIm9ubG9hZFwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIHJhaXNpbmcgZXZlbnQgKGlmIGRlZmluZWQpXG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50TmFtZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHRoaXNbZXZlbnROYW1lXSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNbZXZlbnROYW1lXSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNpbm9uLmxvZ0Vycm9yKFwiRmFrZSBYSFIgXCIgKyBldmVudE5hbWUgKyBcIiBoYW5kbGVyXCIsIGUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgc2VuZDogZnVuY3Rpb24gc2VuZChkYXRhKSB7XG4gICAgICAgICAgICAgICAgdmVyaWZ5U3RhdGUodGhpcyk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIS9eKGdldHxoZWFkKSQvaS50ZXN0KHRoaXMubWV0aG9kKSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RCb2R5ID0gZGF0YTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0SGVhZGVyc1tcIkNvbnRlbnQtVHlwZVwiXSA9IFwidGV4dC9wbGFpbjtjaGFyc2V0PXV0Zi04XCI7XG5cbiAgICAgICAgICAgICAgICB0aGlzLmVycm9yRmxhZyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHRoaXMuc2VuZEZsYWcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWERvbWFpblJlcXVlc3QuT1BFTkVEKTtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5vblNlbmQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uU2VuZCh0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBhYm9ydDogZnVuY3Rpb24gYWJvcnQoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5hYm9ydGVkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbnNlVGV4dCA9IG51bGw7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckZsYWcgPSB0cnVlO1xuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucmVhZHlTdGF0ZSA+IHNpbm9uLkZha2VYRG9tYWluUmVxdWVzdC5VTlNFTlQgJiYgdGhpcy5zZW5kRmxhZykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGVDaGFuZ2Uoc2lub24uRmFrZVhEb21haW5SZXF1ZXN0LkRPTkUpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnNlbmRGbGFnID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgc2V0UmVzcG9uc2VCb2R5OiBmdW5jdGlvbiBzZXRSZXNwb25zZUJvZHkoYm9keSkge1xuICAgICAgICAgICAgICAgIHZlcmlmeVJlcXVlc3RTZW50KHRoaXMpO1xuICAgICAgICAgICAgICAgIHZlcmlmeVJlc3BvbnNlQm9keVR5cGUoYm9keSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgY2h1bmtTaXplID0gdGhpcy5jaHVua1NpemUgfHwgMTA7XG4gICAgICAgICAgICAgICAgdmFyIGluZGV4ID0gMDtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbnNlVGV4dCA9IFwiXCI7XG5cbiAgICAgICAgICAgICAgICBkbyB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWERvbWFpblJlcXVlc3QuTE9BRElORyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2VUZXh0ICs9IGJvZHkuc3Vic3RyaW5nKGluZGV4LCBpbmRleCArIGNodW5rU2l6ZSk7XG4gICAgICAgICAgICAgICAgICAgIGluZGV4ICs9IGNodW5rU2l6ZTtcbiAgICAgICAgICAgICAgICB9IHdoaWxlIChpbmRleCA8IGJvZHkubGVuZ3RoKTtcblxuICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWERvbWFpblJlcXVlc3QuRE9ORSk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICByZXNwb25kOiBmdW5jdGlvbiByZXNwb25kKHN0YXR1cywgY29udGVudFR5cGUsIGJvZHkpIHtcbiAgICAgICAgICAgICAgICAvLyBjb250ZW50LXR5cGUgaWdub3JlZCwgc2luY2UgWERvbWFpblJlcXVlc3QgZG9lcyBub3QgY2FycnkgdGhpc1xuICAgICAgICAgICAgICAgIC8vIHdlIGtlZXAgdGhlIHNhbWUgc3ludGF4IGZvciByZXNwb25kKC4uLikgYXMgZm9yIEZha2VYTUxIdHRwUmVxdWVzdCB0byBlYXNlXG4gICAgICAgICAgICAgICAgLy8gdGVzdCBpbnRlZ3JhdGlvbiBhY3Jvc3MgYnJvd3NlcnNcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXR1cyA9IHR5cGVvZiBzdGF0dXMgPT09IFwibnVtYmVyXCIgPyBzdGF0dXMgOiAyMDA7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRSZXNwb25zZUJvZHkoYm9keSB8fCBcIlwiKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHNpbXVsYXRldGltZW91dDogZnVuY3Rpb24gc2ltdWxhdGV0aW1lb3V0KCkge1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzID0gMDtcbiAgICAgICAgICAgICAgICB0aGlzLmlzVGltZW91dCA9IHRydWU7XG4gICAgICAgICAgICAgICAgLy8gQWNjZXNzIHRvIHRoaXMgc2hvdWxkIGFjdHVhbGx5IHRocm93IGFuIGVycm9yXG4gICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZVRleHQgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYRG9tYWluUmVxdWVzdC5ET05FKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2lub24uZXh0ZW5kKEZha2VYRG9tYWluUmVxdWVzdCwge1xuICAgICAgICAgICAgVU5TRU5UOiAwLFxuICAgICAgICAgICAgT1BFTkVEOiAxLFxuICAgICAgICAgICAgTE9BRElORzogMyxcbiAgICAgICAgICAgIERPTkU6IDRcbiAgICAgICAgfSk7XG5cbiAgICAgICAgc2lub24udXNlRmFrZVhEb21haW5SZXF1ZXN0ID0gZnVuY3Rpb24gdXNlRmFrZVhEb21haW5SZXF1ZXN0KCkge1xuICAgICAgICAgICAgc2lub24uRmFrZVhEb21haW5SZXF1ZXN0LnJlc3RvcmUgPSBmdW5jdGlvbiByZXN0b3JlKGtlZXBPbkNyZWF0ZSkge1xuICAgICAgICAgICAgICAgIGlmICh4ZHIuc3VwcG9ydHNYRFIpIHtcbiAgICAgICAgICAgICAgICAgICAgZ2xvYmFsLlhEb21haW5SZXF1ZXN0ID0geGRyLkdsb2JhbFhEb21haW5SZXF1ZXN0O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRlbGV0ZSBzaW5vbi5GYWtlWERvbWFpblJlcXVlc3QucmVzdG9yZTtcblxuICAgICAgICAgICAgICAgIGlmIChrZWVwT25DcmVhdGUgIT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNpbm9uLkZha2VYRG9tYWluUmVxdWVzdC5vbkNyZWF0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKHhkci5zdXBwb3J0c1hEUikge1xuICAgICAgICAgICAgICAgIGdsb2JhbC5YRG9tYWluUmVxdWVzdCA9IHNpbm9uLkZha2VYRG9tYWluUmVxdWVzdDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBzaW5vbi5GYWtlWERvbWFpblJlcXVlc3Q7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uRmFrZVhEb21haW5SZXF1ZXN0ID0gRmFrZVhEb21haW5SZXF1ZXN0O1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi9jb3JlXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi4vZXh0ZW5kXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9ldmVudFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4uL2xvZ19lcnJvclwiKTtcbiAgICAgICAgbWFrZUFwaShzaW5vbik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gc2lub247XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICB9IGVsc2UgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIG1ha2VBcGkoc2lub24pOyAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4gICAgfVxufSkodHlwZW9mIGdsb2JhbCAhPT0gXCJ1bmRlZmluZWRcIiA/IGdsb2JhbCA6IHNlbGYpO1xuIiwiLyoqXG4gKiBAZGVwZW5kIGNvcmUuanNcbiAqIEBkZXBlbmQgLi4vZXh0ZW5kLmpzXG4gKiBAZGVwZW5kIGV2ZW50LmpzXG4gKiBAZGVwZW5kIC4uL2xvZ19lcnJvci5qc1xuICovXG4vKipcbiAqIEZha2UgWE1MSHR0cFJlcXVlc3Qgb2JqZWN0XG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMyBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCwgZ2xvYmFsKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBmdW5jdGlvbiBnZXRXb3JraW5nWEhSKGdsb2JhbFNjb3BlKSB7XG4gICAgICAgIHZhciBzdXBwb3J0c1hIUiA9IHR5cGVvZiBnbG9iYWxTY29wZS5YTUxIdHRwUmVxdWVzdCAhPT0gXCJ1bmRlZmluZWRcIjtcbiAgICAgICAgaWYgKHN1cHBvcnRzWEhSKSB7XG4gICAgICAgICAgICByZXR1cm4gZ2xvYmFsU2NvcGUuWE1MSHR0cFJlcXVlc3Q7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3VwcG9ydHNBY3RpdmVYID0gdHlwZW9mIGdsb2JhbFNjb3BlLkFjdGl2ZVhPYmplY3QgIT09IFwidW5kZWZpbmVkXCI7XG4gICAgICAgIGlmIChzdXBwb3J0c0FjdGl2ZVgpIHtcbiAgICAgICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBnbG9iYWxTY29wZS5BY3RpdmVYT2JqZWN0KFwiTVNYTUwyLlhNTEhUVFAuMy4wXCIpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB2YXIgc3VwcG9ydHNQcm9ncmVzcyA9IHR5cGVvZiBQcm9ncmVzc0V2ZW50ICE9PSBcInVuZGVmaW5lZFwiO1xuICAgIHZhciBzdXBwb3J0c0N1c3RvbUV2ZW50ID0gdHlwZW9mIEN1c3RvbUV2ZW50ICE9PSBcInVuZGVmaW5lZFwiO1xuICAgIHZhciBzdXBwb3J0c0Zvcm1EYXRhID0gdHlwZW9mIEZvcm1EYXRhICE9PSBcInVuZGVmaW5lZFwiO1xuICAgIHZhciBzdXBwb3J0c0FycmF5QnVmZmVyID0gdHlwZW9mIEFycmF5QnVmZmVyICE9PSBcInVuZGVmaW5lZFwiO1xuICAgIHZhciBzdXBwb3J0c0Jsb2IgPSAoZnVuY3Rpb24gKCkge1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgcmV0dXJuICEhbmV3IEJsb2IoKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgfSkoKTtcbiAgICB2YXIgc2lub25YaHIgPSB7IFhNTEh0dHBSZXF1ZXN0OiBnbG9iYWwuWE1MSHR0cFJlcXVlc3QgfTtcbiAgICBzaW5vblhoci5HbG9iYWxYTUxIdHRwUmVxdWVzdCA9IGdsb2JhbC5YTUxIdHRwUmVxdWVzdDtcbiAgICBzaW5vblhoci5HbG9iYWxBY3RpdmVYT2JqZWN0ID0gZ2xvYmFsLkFjdGl2ZVhPYmplY3Q7XG4gICAgc2lub25YaHIuc3VwcG9ydHNBY3RpdmVYID0gdHlwZW9mIHNpbm9uWGhyLkdsb2JhbEFjdGl2ZVhPYmplY3QgIT09IFwidW5kZWZpbmVkXCI7XG4gICAgc2lub25YaHIuc3VwcG9ydHNYSFIgPSB0eXBlb2Ygc2lub25YaHIuR2xvYmFsWE1MSHR0cFJlcXVlc3QgIT09IFwidW5kZWZpbmVkXCI7XG4gICAgc2lub25YaHIud29ya2luZ1hIUiA9IGdldFdvcmtpbmdYSFIoZ2xvYmFsKTtcbiAgICBzaW5vblhoci5zdXBwb3J0c0NPUlMgPSBzaW5vblhoci5zdXBwb3J0c1hIUiAmJiBcIndpdGhDcmVkZW50aWFsc1wiIGluIChuZXcgc2lub25YaHIuR2xvYmFsWE1MSHR0cFJlcXVlc3QoKSk7XG5cbiAgICB2YXIgdW5zYWZlSGVhZGVycyA9IHtcbiAgICAgICAgXCJBY2NlcHQtQ2hhcnNldFwiOiB0cnVlLFxuICAgICAgICBcIkFjY2VwdC1FbmNvZGluZ1wiOiB0cnVlLFxuICAgICAgICBDb25uZWN0aW9uOiB0cnVlLFxuICAgICAgICBcIkNvbnRlbnQtTGVuZ3RoXCI6IHRydWUsXG4gICAgICAgIENvb2tpZTogdHJ1ZSxcbiAgICAgICAgQ29va2llMjogdHJ1ZSxcbiAgICAgICAgXCJDb250ZW50LVRyYW5zZmVyLUVuY29kaW5nXCI6IHRydWUsXG4gICAgICAgIERhdGU6IHRydWUsXG4gICAgICAgIEV4cGVjdDogdHJ1ZSxcbiAgICAgICAgSG9zdDogdHJ1ZSxcbiAgICAgICAgXCJLZWVwLUFsaXZlXCI6IHRydWUsXG4gICAgICAgIFJlZmVyZXI6IHRydWUsXG4gICAgICAgIFRFOiB0cnVlLFxuICAgICAgICBUcmFpbGVyOiB0cnVlLFxuICAgICAgICBcIlRyYW5zZmVyLUVuY29kaW5nXCI6IHRydWUsXG4gICAgICAgIFVwZ3JhZGU6IHRydWUsXG4gICAgICAgIFwiVXNlci1BZ2VudFwiOiB0cnVlLFxuICAgICAgICBWaWE6IHRydWVcbiAgICB9O1xuXG4gICAgLy8gQW4gdXBsb2FkIG9iamVjdCBpcyBjcmVhdGVkIGZvciBlYWNoXG4gICAgLy8gRmFrZVhNTEh0dHBSZXF1ZXN0IGFuZCBhbGxvd3MgdXBsb2FkXG4gICAgLy8gZXZlbnRzIHRvIGJlIHNpbXVsYXRlZCB1c2luZyB1cGxvYWRQcm9ncmVzc1xuICAgIC8vIGFuZCB1cGxvYWRFcnJvci5cbiAgICBmdW5jdGlvbiBVcGxvYWRQcm9ncmVzcygpIHtcbiAgICAgICAgdGhpcy5ldmVudExpc3RlbmVycyA9IHtcbiAgICAgICAgICAgIGFib3J0OiBbXSxcbiAgICAgICAgICAgIGVycm9yOiBbXSxcbiAgICAgICAgICAgIGxvYWQ6IFtdLFxuICAgICAgICAgICAgbG9hZGVuZDogW10sXG4gICAgICAgICAgICBwcm9ncmVzczogW11cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBVcGxvYWRQcm9ncmVzcy5wcm90b3R5cGUuYWRkRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uIGFkZEV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuZXZlbnRMaXN0ZW5lcnNbZXZlbnRdLnB1c2gobGlzdGVuZXIpO1xuICAgIH07XG5cbiAgICBVcGxvYWRQcm9ncmVzcy5wcm90b3R5cGUucmVtb3ZlRXZlbnRMaXN0ZW5lciA9IGZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVyKSB7XG4gICAgICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLmV2ZW50TGlzdGVuZXJzW2V2ZW50XSB8fCBbXTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGlmIChsaXN0ZW5lcnNbaV0gPT09IGxpc3RlbmVyKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxpc3RlbmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgVXBsb2FkUHJvZ3Jlc3MucHJvdG90eXBlLmRpc3BhdGNoRXZlbnQgPSBmdW5jdGlvbiBkaXNwYXRjaEV2ZW50KGV2ZW50KSB7XG4gICAgICAgIHZhciBsaXN0ZW5lcnMgPSB0aGlzLmV2ZW50TGlzdGVuZXJzW2V2ZW50LnR5cGVdIHx8IFtdO1xuXG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsaXN0ZW5lcjsgKGxpc3RlbmVyID0gbGlzdGVuZXJzW2ldKSAhPSBudWxsOyBpKyspIHtcbiAgICAgICAgICAgIGxpc3RlbmVyKGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBOb3RlIHRoYXQgZm9yIEZha2VYTUxIdHRwUmVxdWVzdCB0byB3b3JrIHByZSBFUzVcbiAgICAvLyB3ZSBsb3NlIHNvbWUgb2YgdGhlIGFsaWdubWVudCB3aXRoIHRoZSBzcGVjLlxuICAgIC8vIFRvIGVuc3VyZSBhcyBjbG9zZSBhIG1hdGNoIGFzIHBvc3NpYmxlLFxuICAgIC8vIHNldCByZXNwb25zZVR5cGUgYmVmb3JlIGNhbGxpbmcgb3Blbiwgc2VuZCBvciByZXNwb25kO1xuICAgIGZ1bmN0aW9uIEZha2VYTUxIdHRwUmVxdWVzdCgpIHtcbiAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gRmFrZVhNTEh0dHBSZXF1ZXN0LlVOU0VOVDtcbiAgICAgICAgdGhpcy5yZXF1ZXN0SGVhZGVycyA9IHt9O1xuICAgICAgICB0aGlzLnJlcXVlc3RCb2R5ID0gbnVsbDtcbiAgICAgICAgdGhpcy5zdGF0dXMgPSAwO1xuICAgICAgICB0aGlzLnN0YXR1c1RleHQgPSBcIlwiO1xuICAgICAgICB0aGlzLnVwbG9hZCA9IG5ldyBVcGxvYWRQcm9ncmVzcygpO1xuICAgICAgICB0aGlzLnJlc3BvbnNlVHlwZSA9IFwiXCI7XG4gICAgICAgIHRoaXMucmVzcG9uc2UgPSBcIlwiO1xuICAgICAgICBpZiAoc2lub25YaHIuc3VwcG9ydHNDT1JTKSB7XG4gICAgICAgICAgICB0aGlzLndpdGhDcmVkZW50aWFscyA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHhociA9IHRoaXM7XG4gICAgICAgIHZhciBldmVudHMgPSBbXCJsb2Fkc3RhcnRcIiwgXCJsb2FkXCIsIFwiYWJvcnRcIiwgXCJlcnJvclwiLCBcImxvYWRlbmRcIl07XG5cbiAgICAgICAgZnVuY3Rpb24gYWRkRXZlbnRMaXN0ZW5lcihldmVudE5hbWUpIHtcbiAgICAgICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKGV2ZW50TmFtZSwgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgdmFyIGxpc3RlbmVyID0geGhyW1wib25cIiArIGV2ZW50TmFtZV07XG5cbiAgICAgICAgICAgICAgICBpZiAobGlzdGVuZXIgJiYgdHlwZW9mIGxpc3RlbmVyID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgbGlzdGVuZXIuY2FsbCh0aGlzLCBldmVudCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBpID0gZXZlbnRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgICAgICBhZGRFdmVudExpc3RlbmVyKGV2ZW50c1tpXSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIEZha2VYTUxIdHRwUmVxdWVzdC5vbkNyZWF0ZSA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICBGYWtlWE1MSHR0cFJlcXVlc3Qub25DcmVhdGUodGhpcyk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiB2ZXJpZnlTdGF0ZSh4aHIpIHtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlICE9PSBGYWtlWE1MSHR0cFJlcXVlc3QuT1BFTkVEKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJTlZBTElEX1NUQVRFX0VSUlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh4aHIuc2VuZEZsYWcpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIklOVkFMSURfU1RBVEVfRVJSXCIpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0SGVhZGVyKGhlYWRlcnMsIGhlYWRlcikge1xuICAgICAgICBoZWFkZXIgPSBoZWFkZXIudG9Mb3dlckNhc2UoKTtcblxuICAgICAgICBmb3IgKHZhciBoIGluIGhlYWRlcnMpIHtcbiAgICAgICAgICAgIGlmIChoLnRvTG93ZXJDYXNlKCkgPT09IGhlYWRlcikge1xuICAgICAgICAgICAgICAgIHJldHVybiBoO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgLy8gZmlsdGVyaW5nIHRvIGVuYWJsZSBhIHdoaXRlLWxpc3QgdmVyc2lvbiBvZiBTaW5vbiBGYWtlWGhyLFxuICAgIC8vIHdoZXJlIHdoaXRlbGlzdGVkIHJlcXVlc3RzIGFyZSBwYXNzZWQgdGhyb3VnaCB0byByZWFsIFhIUlxuICAgIGZ1bmN0aW9uIGVhY2goY29sbGVjdGlvbiwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKCFjb2xsZWN0aW9uKSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKHZhciBpID0gMCwgbCA9IGNvbGxlY3Rpb24ubGVuZ3RoOyBpIDwgbDsgaSArPSAxKSB7XG4gICAgICAgICAgICBjYWxsYmFjayhjb2xsZWN0aW9uW2ldKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBmdW5jdGlvbiBzb21lKGNvbGxlY3Rpb24sIGNhbGxiYWNrKSB7XG4gICAgICAgIGZvciAodmFyIGluZGV4ID0gMDsgaW5kZXggPCBjb2xsZWN0aW9uLmxlbmd0aDsgaW5kZXgrKykge1xuICAgICAgICAgICAgaWYgKGNhbGxiYWNrKGNvbGxlY3Rpb25baW5kZXhdKSA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgLy8gbGFyZ2VzdCBhcml0eSBpbiBYSFIgaXMgNSAtIFhIUiNvcGVuXG4gICAgdmFyIGFwcGx5ID0gZnVuY3Rpb24gKG9iaiwgbWV0aG9kLCBhcmdzKSB7XG4gICAgICAgIHN3aXRjaCAoYXJncy5sZW5ndGgpIHtcbiAgICAgICAgY2FzZSAwOiByZXR1cm4gb2JqW21ldGhvZF0oKTtcbiAgICAgICAgY2FzZSAxOiByZXR1cm4gb2JqW21ldGhvZF0oYXJnc1swXSk7XG4gICAgICAgIGNhc2UgMjogcmV0dXJuIG9ialttZXRob2RdKGFyZ3NbMF0sIGFyZ3NbMV0pO1xuICAgICAgICBjYXNlIDM6IHJldHVybiBvYmpbbWV0aG9kXShhcmdzWzBdLCBhcmdzWzFdLCBhcmdzWzJdKTtcbiAgICAgICAgY2FzZSA0OiByZXR1cm4gb2JqW21ldGhvZF0oYXJnc1swXSwgYXJnc1sxXSwgYXJnc1syXSwgYXJnc1szXSk7XG4gICAgICAgIGNhc2UgNTogcmV0dXJuIG9ialttZXRob2RdKGFyZ3NbMF0sIGFyZ3NbMV0sIGFyZ3NbMl0sIGFyZ3NbM10sIGFyZ3NbNF0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIEZha2VYTUxIdHRwUmVxdWVzdC5maWx0ZXJzID0gW107XG4gICAgRmFrZVhNTEh0dHBSZXF1ZXN0LmFkZEZpbHRlciA9IGZ1bmN0aW9uIGFkZEZpbHRlcihmbikge1xuICAgICAgICB0aGlzLmZpbHRlcnMucHVzaChmbik7XG4gICAgfTtcbiAgICB2YXIgSUU2UmUgPSAvTVNJRSA2LztcbiAgICBGYWtlWE1MSHR0cFJlcXVlc3QuZGVmYWtlID0gZnVuY3Rpb24gZGVmYWtlKGZha2VYaHIsIHhockFyZ3MpIHtcbiAgICAgICAgdmFyIHhociA9IG5ldyBzaW5vblhoci53b3JraW5nWEhSKCk7IC8vIGVzbGludC1kaXNhYmxlLWxpbmUgbmV3LWNhcFxuXG4gICAgICAgIGVhY2goW1xuICAgICAgICAgICAgXCJvcGVuXCIsXG4gICAgICAgICAgICBcInNldFJlcXVlc3RIZWFkZXJcIixcbiAgICAgICAgICAgIFwic2VuZFwiLFxuICAgICAgICAgICAgXCJhYm9ydFwiLFxuICAgICAgICAgICAgXCJnZXRSZXNwb25zZUhlYWRlclwiLFxuICAgICAgICAgICAgXCJnZXRBbGxSZXNwb25zZUhlYWRlcnNcIixcbiAgICAgICAgICAgIFwiYWRkRXZlbnRMaXN0ZW5lclwiLFxuICAgICAgICAgICAgXCJvdmVycmlkZU1pbWVUeXBlXCIsXG4gICAgICAgICAgICBcInJlbW92ZUV2ZW50TGlzdGVuZXJcIlxuICAgICAgICBdLCBmdW5jdGlvbiAobWV0aG9kKSB7XG4gICAgICAgICAgICBmYWtlWGhyW21ldGhvZF0gPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFwcGx5KHhociwgbWV0aG9kLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdmFyIGNvcHlBdHRycyA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgICAgICAgICBlYWNoKGFyZ3MsIGZ1bmN0aW9uIChhdHRyKSB7XG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgZmFrZVhoclthdHRyXSA9IHhoclthdHRyXTtcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICghSUU2UmUudGVzdChuYXZpZ2F0b3IudXNlckFnZW50KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgZTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIHZhciBzdGF0ZUNoYW5nZSA9IGZ1bmN0aW9uIHN0YXRlQ2hhbmdlKCkge1xuICAgICAgICAgICAgZmFrZVhoci5yZWFkeVN0YXRlID0geGhyLnJlYWR5U3RhdGU7XG4gICAgICAgICAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPj0gRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQpIHtcbiAgICAgICAgICAgICAgICBjb3B5QXR0cnMoW1wic3RhdHVzXCIsIFwic3RhdHVzVGV4dFwiXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoeGhyLnJlYWR5U3RhdGUgPj0gRmFrZVhNTEh0dHBSZXF1ZXN0LkxPQURJTkcpIHtcbiAgICAgICAgICAgICAgICBjb3B5QXR0cnMoW1wicmVzcG9uc2VUZXh0XCIsIFwicmVzcG9uc2VcIl0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlID09PSBGYWtlWE1MSHR0cFJlcXVlc3QuRE9ORSkge1xuICAgICAgICAgICAgICAgIGNvcHlBdHRycyhbXCJyZXNwb25zZVhNTFwiXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmFrZVhoci5vbnJlYWR5c3RhdGVjaGFuZ2UpIHtcbiAgICAgICAgICAgICAgICBmYWtlWGhyLm9ucmVhZHlzdGF0ZWNoYW5nZS5jYWxsKGZha2VYaHIsIHsgdGFyZ2V0OiBmYWtlWGhyIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGlmICh4aHIuYWRkRXZlbnRMaXN0ZW5lcikge1xuICAgICAgICAgICAgZm9yICh2YXIgZXZlbnQgaW4gZmFrZVhoci5ldmVudExpc3RlbmVycykge1xuICAgICAgICAgICAgICAgIGlmIChmYWtlWGhyLmV2ZW50TGlzdGVuZXJzLmhhc093blByb3BlcnR5KGV2ZW50KSkge1xuXG4gICAgICAgICAgICAgICAgICAgIC8qZXNsaW50LWRpc2FibGUgbm8tbG9vcC1mdW5jKi9cbiAgICAgICAgICAgICAgICAgICAgZWFjaChmYWtlWGhyLmV2ZW50TGlzdGVuZXJzW2V2ZW50XSwgZnVuY3Rpb24gKGhhbmRsZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBoYW5kbGVyKTtcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIC8qZXNsaW50LWVuYWJsZSBuby1sb29wLWZ1bmMqL1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHhoci5hZGRFdmVudExpc3RlbmVyKFwicmVhZHlzdGF0ZWNoYW5nZVwiLCBzdGF0ZUNoYW5nZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gc3RhdGVDaGFuZ2U7XG4gICAgICAgIH1cbiAgICAgICAgYXBwbHkoeGhyLCBcIm9wZW5cIiwgeGhyQXJncyk7XG4gICAgfTtcbiAgICBGYWtlWE1MSHR0cFJlcXVlc3QudXNlRmlsdGVycyA9IGZhbHNlO1xuXG4gICAgZnVuY3Rpb24gdmVyaWZ5UmVxdWVzdE9wZW5lZCh4aHIpIHtcbiAgICAgICAgaWYgKHhoci5yZWFkeVN0YXRlICE9PSBGYWtlWE1MSHR0cFJlcXVlc3QuT1BFTkVEKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJTlZBTElEX1NUQVRFX0VSUiAtIFwiICsgeGhyLnJlYWR5U3RhdGUpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdmVyaWZ5UmVxdWVzdFNlbnQoeGhyKSB7XG4gICAgICAgIGlmICh4aHIucmVhZHlTdGF0ZSA9PT0gRmFrZVhNTEh0dHBSZXF1ZXN0LkRPTkUpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIlJlcXVlc3QgZG9uZVwiKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHZlcmlmeUhlYWRlcnNSZWNlaXZlZCh4aHIpIHtcbiAgICAgICAgaWYgKHhoci5hc3luYyAmJiB4aHIucmVhZHlTdGF0ZSAhPT0gRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcIk5vIGhlYWRlcnMgcmVjZWl2ZWRcIik7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiB2ZXJpZnlSZXNwb25zZUJvZHlUeXBlKGJvZHkpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBib2R5ICE9PSBcInN0cmluZ1wiKSB7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSBuZXcgRXJyb3IoXCJBdHRlbXB0ZWQgdG8gcmVzcG9uZCB0byBmYWtlIFhNTEh0dHBSZXF1ZXN0IHdpdGggXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYm9keSArIFwiLCB3aGljaCBpcyBub3QgYSBzdHJpbmcuXCIpO1xuICAgICAgICAgICAgZXJyb3IubmFtZSA9IFwiSW52YWxpZEJvZHlFeGNlcHRpb25cIjtcbiAgICAgICAgICAgIHRocm93IGVycm9yO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY29udmVydFRvQXJyYXlCdWZmZXIoYm9keSkge1xuICAgICAgICB2YXIgYnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKGJvZHkubGVuZ3RoKTtcbiAgICAgICAgdmFyIHZpZXcgPSBuZXcgVWludDhBcnJheShidWZmZXIpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJvZHkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhciBjaGFyQ29kZSA9IGJvZHkuY2hhckNvZGVBdChpKTtcbiAgICAgICAgICAgIGlmIChjaGFyQ29kZSA+PSAyNTYpIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwiYXJyYXlidWZmZXIgb3IgYmxvYiByZXNwb25zZVR5cGVzIHJlcXVpcmUgYmluYXJ5IHN0cmluZywgXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJpbnZhbGlkIGNoYXJhY3RlciBcIiArIGJvZHlbaV0gKyBcIiBmb3VuZC5cIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2aWV3W2ldID0gY2hhckNvZGU7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGJ1ZmZlcjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpc1htbENvbnRlbnRUeXBlKGNvbnRlbnRUeXBlKSB7XG4gICAgICAgIHJldHVybiAhY29udGVudFR5cGUgfHwgLyh0ZXh0XFwveG1sKXwoYXBwbGljYXRpb25cXC94bWwpfChcXCt4bWwpLy50ZXN0KGNvbnRlbnRUeXBlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb252ZXJ0UmVzcG9uc2VCb2R5KHJlc3BvbnNlVHlwZSwgY29udGVudFR5cGUsIGJvZHkpIHtcbiAgICAgICAgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJcIiB8fCByZXNwb25zZVR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gYm9keTtcbiAgICAgICAgfSBlbHNlIGlmIChzdXBwb3J0c0FycmF5QnVmZmVyICYmIHJlc3BvbnNlVHlwZSA9PT0gXCJhcnJheWJ1ZmZlclwiKSB7XG4gICAgICAgICAgICByZXR1cm4gY29udmVydFRvQXJyYXlCdWZmZXIoYm9keSk7XG4gICAgICAgIH0gZWxzZSBpZiAocmVzcG9uc2VUeXBlID09PSBcImpzb25cIikge1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShib2R5KTtcbiAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4gcGFyc2luZyBmYWlsdXJlIGFzIG51bGxcbiAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChzdXBwb3J0c0Jsb2IgJiYgcmVzcG9uc2VUeXBlID09PSBcImJsb2JcIikge1xuICAgICAgICAgICAgdmFyIGJsb2JPcHRpb25zID0ge307XG4gICAgICAgICAgICBpZiAoY29udGVudFR5cGUpIHtcbiAgICAgICAgICAgICAgICBibG9iT3B0aW9ucy50eXBlID0gY29udGVudFR5cGU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gbmV3IEJsb2IoW2NvbnZlcnRUb0FycmF5QnVmZmVyKGJvZHkpXSwgYmxvYk9wdGlvbnMpO1xuICAgICAgICB9IGVsc2UgaWYgKHJlc3BvbnNlVHlwZSA9PT0gXCJkb2N1bWVudFwiKSB7XG4gICAgICAgICAgICBpZiAoaXNYbWxDb250ZW50VHlwZShjb250ZW50VHlwZSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gRmFrZVhNTEh0dHBSZXF1ZXN0LnBhcnNlWE1MKGJvZHkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCByZXNwb25zZVR5cGUgXCIgKyByZXNwb25zZVR5cGUpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNsZWFyUmVzcG9uc2UoeGhyKSB7XG4gICAgICAgIGlmICh4aHIucmVzcG9uc2VUeXBlID09PSBcIlwiIHx8IHhoci5yZXNwb25zZVR5cGUgPT09IFwidGV4dFwiKSB7XG4gICAgICAgICAgICB4aHIucmVzcG9uc2UgPSB4aHIucmVzcG9uc2VUZXh0ID0gXCJcIjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHhoci5yZXNwb25zZSA9IHhoci5yZXNwb25zZVRleHQgPSBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHhoci5yZXNwb25zZVhNTCA9IG51bGw7XG4gICAgfVxuXG4gICAgRmFrZVhNTEh0dHBSZXF1ZXN0LnBhcnNlWE1MID0gZnVuY3Rpb24gcGFyc2VYTUwodGV4dCkge1xuICAgICAgICAvLyBUcmVhdCBlbXB0eSBzdHJpbmcgYXMgcGFyc2luZyBmYWlsdXJlXG4gICAgICAgIGlmICh0ZXh0ICE9PSBcIlwiKSB7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgRE9NUGFyc2VyICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJzZXIgPSBuZXcgRE9NUGFyc2VyKCk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBwYXJzZXIucGFyc2VGcm9tU3RyaW5nKHRleHQsIFwidGV4dC94bWxcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHZhciB4bWxEb2MgPSBuZXcgd2luZG93LkFjdGl2ZVhPYmplY3QoXCJNaWNyb3NvZnQuWE1MRE9NXCIpO1xuICAgICAgICAgICAgICAgIHhtbERvYy5hc3luYyA9IFwiZmFsc2VcIjtcbiAgICAgICAgICAgICAgICB4bWxEb2MubG9hZFhNTCh0ZXh0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4geG1sRG9jO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIC8vIFVuYWJsZSB0byBwYXJzZSBYTUwgLSBubyBiaWdnaWVcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH07XG5cbiAgICBGYWtlWE1MSHR0cFJlcXVlc3Quc3RhdHVzQ29kZXMgPSB7XG4gICAgICAgIDEwMDogXCJDb250aW51ZVwiLFxuICAgICAgICAxMDE6IFwiU3dpdGNoaW5nIFByb3RvY29sc1wiLFxuICAgICAgICAyMDA6IFwiT0tcIixcbiAgICAgICAgMjAxOiBcIkNyZWF0ZWRcIixcbiAgICAgICAgMjAyOiBcIkFjY2VwdGVkXCIsXG4gICAgICAgIDIwMzogXCJOb24tQXV0aG9yaXRhdGl2ZSBJbmZvcm1hdGlvblwiLFxuICAgICAgICAyMDQ6IFwiTm8gQ29udGVudFwiLFxuICAgICAgICAyMDU6IFwiUmVzZXQgQ29udGVudFwiLFxuICAgICAgICAyMDY6IFwiUGFydGlhbCBDb250ZW50XCIsXG4gICAgICAgIDIwNzogXCJNdWx0aS1TdGF0dXNcIixcbiAgICAgICAgMzAwOiBcIk11bHRpcGxlIENob2ljZVwiLFxuICAgICAgICAzMDE6IFwiTW92ZWQgUGVybWFuZW50bHlcIixcbiAgICAgICAgMzAyOiBcIkZvdW5kXCIsXG4gICAgICAgIDMwMzogXCJTZWUgT3RoZXJcIixcbiAgICAgICAgMzA0OiBcIk5vdCBNb2RpZmllZFwiLFxuICAgICAgICAzMDU6IFwiVXNlIFByb3h5XCIsXG4gICAgICAgIDMwNzogXCJUZW1wb3JhcnkgUmVkaXJlY3RcIixcbiAgICAgICAgNDAwOiBcIkJhZCBSZXF1ZXN0XCIsXG4gICAgICAgIDQwMTogXCJVbmF1dGhvcml6ZWRcIixcbiAgICAgICAgNDAyOiBcIlBheW1lbnQgUmVxdWlyZWRcIixcbiAgICAgICAgNDAzOiBcIkZvcmJpZGRlblwiLFxuICAgICAgICA0MDQ6IFwiTm90IEZvdW5kXCIsXG4gICAgICAgIDQwNTogXCJNZXRob2QgTm90IEFsbG93ZWRcIixcbiAgICAgICAgNDA2OiBcIk5vdCBBY2NlcHRhYmxlXCIsXG4gICAgICAgIDQwNzogXCJQcm94eSBBdXRoZW50aWNhdGlvbiBSZXF1aXJlZFwiLFxuICAgICAgICA0MDg6IFwiUmVxdWVzdCBUaW1lb3V0XCIsXG4gICAgICAgIDQwOTogXCJDb25mbGljdFwiLFxuICAgICAgICA0MTA6IFwiR29uZVwiLFxuICAgICAgICA0MTE6IFwiTGVuZ3RoIFJlcXVpcmVkXCIsXG4gICAgICAgIDQxMjogXCJQcmVjb25kaXRpb24gRmFpbGVkXCIsXG4gICAgICAgIDQxMzogXCJSZXF1ZXN0IEVudGl0eSBUb28gTGFyZ2VcIixcbiAgICAgICAgNDE0OiBcIlJlcXVlc3QtVVJJIFRvbyBMb25nXCIsXG4gICAgICAgIDQxNTogXCJVbnN1cHBvcnRlZCBNZWRpYSBUeXBlXCIsXG4gICAgICAgIDQxNjogXCJSZXF1ZXN0ZWQgUmFuZ2UgTm90IFNhdGlzZmlhYmxlXCIsXG4gICAgICAgIDQxNzogXCJFeHBlY3RhdGlvbiBGYWlsZWRcIixcbiAgICAgICAgNDIyOiBcIlVucHJvY2Vzc2FibGUgRW50aXR5XCIsXG4gICAgICAgIDUwMDogXCJJbnRlcm5hbCBTZXJ2ZXIgRXJyb3JcIixcbiAgICAgICAgNTAxOiBcIk5vdCBJbXBsZW1lbnRlZFwiLFxuICAgICAgICA1MDI6IFwiQmFkIEdhdGV3YXlcIixcbiAgICAgICAgNTAzOiBcIlNlcnZpY2UgVW5hdmFpbGFibGVcIixcbiAgICAgICAgNTA0OiBcIkdhdGV3YXkgVGltZW91dFwiLFxuICAgICAgICA1MDU6IFwiSFRUUCBWZXJzaW9uIE5vdCBTdXBwb3J0ZWRcIlxuICAgIH07XG5cbiAgICBmdW5jdGlvbiBtYWtlQXBpKHNpbm9uKSB7XG4gICAgICAgIHNpbm9uLnhociA9IHNpbm9uWGhyO1xuXG4gICAgICAgIHNpbm9uLmV4dGVuZChGYWtlWE1MSHR0cFJlcXVlc3QucHJvdG90eXBlLCBzaW5vbi5FdmVudFRhcmdldCwge1xuICAgICAgICAgICAgYXN5bmM6IHRydWUsXG5cbiAgICAgICAgICAgIG9wZW46IGZ1bmN0aW9uIG9wZW4obWV0aG9kLCB1cmwsIGFzeW5jLCB1c2VybmFtZSwgcGFzc3dvcmQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLm1ldGhvZCA9IG1ldGhvZDtcbiAgICAgICAgICAgICAgICB0aGlzLnVybCA9IHVybDtcbiAgICAgICAgICAgICAgICB0aGlzLmFzeW5jID0gdHlwZW9mIGFzeW5jID09PSBcImJvb2xlYW5cIiA/IGFzeW5jIDogdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLnVzZXJuYW1lID0gdXNlcm5hbWU7XG4gICAgICAgICAgICAgICAgdGhpcy5wYXNzd29yZCA9IHBhc3N3b3JkO1xuICAgICAgICAgICAgICAgIGNsZWFyUmVzcG9uc2UodGhpcyk7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0SGVhZGVycyA9IHt9O1xuICAgICAgICAgICAgICAgIHRoaXMuc2VuZEZsYWcgPSBmYWxzZTtcblxuICAgICAgICAgICAgICAgIGlmIChGYWtlWE1MSHR0cFJlcXVlc3QudXNlRmlsdGVycyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgeGhyQXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgICAgICAgICAgICAgdmFyIGRlZmFrZSA9IHNvbWUoRmFrZVhNTEh0dHBSZXF1ZXN0LmZpbHRlcnMsIGZ1bmN0aW9uIChmaWx0ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmaWx0ZXIuYXBwbHkodGhpcywgeGhyQXJncyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZGVmYWtlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gRmFrZVhNTEh0dHBSZXF1ZXN0LmRlZmFrZSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuT1BFTkVEKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlYWR5U3RhdGVDaGFuZ2U6IGZ1bmN0aW9uIHJlYWR5U3RhdGVDaGFuZ2Uoc3RhdGUpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGUgPSBzdGF0ZTtcblxuICAgICAgICAgICAgICAgIHZhciByZWFkeVN0YXRlQ2hhbmdlRXZlbnQgPSBuZXcgc2lub24uRXZlbnQoXCJyZWFkeXN0YXRlY2hhbmdlXCIsIGZhbHNlLCBmYWxzZSwgdGhpcyk7XG4gICAgICAgICAgICAgICAgdmFyIGV2ZW50LCBwcm9ncmVzcztcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5vbnJlYWR5c3RhdGVjaGFuZ2UgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5vbnJlYWR5c3RhdGVjaGFuZ2UocmVhZHlTdGF0ZUNoYW5nZUV2ZW50KTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2lub24ubG9nRXJyb3IoXCJGYWtlIFhIUiBvbnJlYWR5c3RhdGVjaGFuZ2UgaGFuZGxlclwiLCBlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnJlYWR5U3RhdGUgPT09IEZha2VYTUxIdHRwUmVxdWVzdC5ET05FKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGVuc3VyZSBsb2FkZWQgYW5kIHRvdGFsIGFyZSBudW1iZXJzXG4gICAgICAgICAgICAgICAgICAgIHByb2dyZXNzID0ge1xuICAgICAgICAgICAgICAgICAgICAgIGxvYWRlZDogdGhpcy5wcm9ncmVzcyB8fCAwLFxuICAgICAgICAgICAgICAgICAgICAgIHRvdGFsOiB0aGlzLnByb2dyZXNzIHx8IDBcbiAgICAgICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5zdGF0dXMgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGV2ZW50ID0gdGhpcy5hYm9ydGVkID8gXCJhYm9ydFwiIDogXCJlcnJvclwiO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgZXZlbnQgPSBcImxvYWRcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmIChzdXBwb3J0c1Byb2dyZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZC5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbi5Qcm9ncmVzc0V2ZW50KFwicHJvZ3Jlc3NcIiwgcHJvZ3Jlc3MsIHRoaXMpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMudXBsb2FkLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uLlByb2dyZXNzRXZlbnQoZXZlbnQsIHByb2dyZXNzLCB0aGlzKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnVwbG9hZC5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbi5Qcm9ncmVzc0V2ZW50KFwibG9hZGVuZFwiLCBwcm9ncmVzcywgdGhpcykpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbi5Qcm9ncmVzc0V2ZW50KFwicHJvZ3Jlc3NcIiwgcHJvZ3Jlc3MsIHRoaXMpKTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KG5ldyBzaW5vbi5Qcm9ncmVzc0V2ZW50KGV2ZW50LCBwcm9ncmVzcywgdGhpcykpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uLlByb2dyZXNzRXZlbnQoXCJsb2FkZW5kXCIsIHByb2dyZXNzLCB0aGlzKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5kaXNwYXRjaEV2ZW50KHJlYWR5U3RhdGVDaGFuZ2VFdmVudCk7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBzZXRSZXF1ZXN0SGVhZGVyOiBmdW5jdGlvbiBzZXRSZXF1ZXN0SGVhZGVyKGhlYWRlciwgdmFsdWUpIHtcbiAgICAgICAgICAgICAgICB2ZXJpZnlTdGF0ZSh0aGlzKTtcblxuICAgICAgICAgICAgICAgIGlmICh1bnNhZmVIZWFkZXJzW2hlYWRlcl0gfHwgL14oU2VjLXxQcm94eS0pLy50ZXN0KGhlYWRlcikpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiUmVmdXNlZCB0byBzZXQgdW5zYWZlIGhlYWRlciBcXFwiXCIgKyBoZWFkZXIgKyBcIlxcXCJcIik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucmVxdWVzdEhlYWRlcnNbaGVhZGVyXSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzW2hlYWRlcl0gKz0gXCIsXCIgKyB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlcXVlc3RIZWFkZXJzW2hlYWRlcl0gPSB2YWx1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICAvLyBIZWxwcyB0ZXN0aW5nXG4gICAgICAgICAgICBzZXRSZXNwb25zZUhlYWRlcnM6IGZ1bmN0aW9uIHNldFJlc3BvbnNlSGVhZGVycyhoZWFkZXJzKSB7XG4gICAgICAgICAgICAgICAgdmVyaWZ5UmVxdWVzdE9wZW5lZCh0aGlzKTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbnNlSGVhZGVycyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaGVhZGVyIGluIGhlYWRlcnMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGhlYWRlcnMuaGFzT3duUHJvcGVydHkoaGVhZGVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZUhlYWRlcnNbaGVhZGVyXSA9IGhlYWRlcnNbaGVhZGVyXTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLmFzeW5jKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuSEVBREVSU19SRUNFSVZFRCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlID0gRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgLy8gQ3VycmVudGx5IHRyZWF0cyBBTEwgZGF0YSBhcyBhIERPTVN0cmluZyAoaS5lLiBubyBEb2N1bWVudClcbiAgICAgICAgICAgIHNlbmQ6IGZ1bmN0aW9uIHNlbmQoZGF0YSkge1xuICAgICAgICAgICAgICAgIHZlcmlmeVN0YXRlKHRoaXMpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCEvXihnZXR8aGVhZCkkL2kudGVzdCh0aGlzLm1ldGhvZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGNvbnRlbnRUeXBlID0gZ2V0SGVhZGVyKHRoaXMucmVxdWVzdEhlYWRlcnMsIFwiQ29udGVudC1UeXBlXCIpO1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5yZXF1ZXN0SGVhZGVyc1tjb250ZW50VHlwZV0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciB2YWx1ZSA9IHRoaXMucmVxdWVzdEhlYWRlcnNbY29udGVudFR5cGVdLnNwbGl0KFwiO1wiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnNbY29udGVudFR5cGVdID0gdmFsdWVbMF0gKyBcIjtjaGFyc2V0PXV0Zi04XCI7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoc3VwcG9ydHNGb3JtRGF0YSAmJiAhKGRhdGEgaW5zdGFuY2VvZiBGb3JtRGF0YSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnNbXCJDb250ZW50LVR5cGVcIl0gPSBcInRleHQvcGxhaW47Y2hhcnNldD11dGYtOFwiO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0Qm9keSA9IGRhdGE7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckZsYWcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB0aGlzLnNlbmRGbGFnID0gdGhpcy5hc3luYztcbiAgICAgICAgICAgICAgICBjbGVhclJlc3BvbnNlKHRoaXMpO1xuICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuT1BFTkVEKTtcblxuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdGhpcy5vblNlbmQgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uU2VuZCh0aGlzKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uLkV2ZW50KFwibG9hZHN0YXJ0XCIsIGZhbHNlLCBmYWxzZSwgdGhpcykpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgYWJvcnQ6IGZ1bmN0aW9uIGFib3J0KCkge1xuICAgICAgICAgICAgICAgIHRoaXMuYWJvcnRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgY2xlYXJSZXNwb25zZSh0aGlzKTtcbiAgICAgICAgICAgICAgICB0aGlzLmVycm9yRmxhZyA9IHRydWU7XG4gICAgICAgICAgICAgICAgdGhpcy5yZXF1ZXN0SGVhZGVycyA9IHt9O1xuICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2VIZWFkZXJzID0ge307XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yZWFkeVN0YXRlID4gRmFrZVhNTEh0dHBSZXF1ZXN0LlVOU0VOVCAmJiB0aGlzLnNlbmRGbGFnKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVhZHlTdGF0ZUNoYW5nZShGYWtlWE1MSHR0cFJlcXVlc3QuRE9ORSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2VuZEZsYWcgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aGlzLnJlYWR5U3RhdGUgPSBGYWtlWE1MSHR0cFJlcXVlc3QuVU5TRU5UO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZXJyb3I6IGZ1bmN0aW9uIGVycm9yKCkge1xuICAgICAgICAgICAgICAgIGNsZWFyUmVzcG9uc2UodGhpcyk7XG4gICAgICAgICAgICAgICAgdGhpcy5lcnJvckZsYWcgPSB0cnVlO1xuICAgICAgICAgICAgICAgIHRoaXMucmVxdWVzdEhlYWRlcnMgPSB7fTtcbiAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbnNlSGVhZGVycyA9IHt9O1xuXG4gICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5ET05FKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIGdldFJlc3BvbnNlSGVhZGVyOiBmdW5jdGlvbiBnZXRSZXNwb25zZUhlYWRlcihoZWFkZXIpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yZWFkeVN0YXRlIDwgRmFrZVhNTEh0dHBSZXF1ZXN0LkhFQURFUlNfUkVDRUlWRUQpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKC9eU2V0LUNvb2tpZTI/JC9pLnRlc3QoaGVhZGVyKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBoZWFkZXIgPSBnZXRIZWFkZXIodGhpcy5yZXNwb25zZUhlYWRlcnMsIGhlYWRlcik7XG5cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5yZXNwb25zZUhlYWRlcnNbaGVhZGVyXSB8fCBudWxsO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgZ2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbiBnZXRBbGxSZXNwb25zZUhlYWRlcnMoKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMucmVhZHlTdGF0ZSA8IEZha2VYTUxIdHRwUmVxdWVzdC5IRUFERVJTX1JFQ0VJVkVEKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHZhciBoZWFkZXJzID0gXCJcIjtcblxuICAgICAgICAgICAgICAgIGZvciAodmFyIGhlYWRlciBpbiB0aGlzLnJlc3BvbnNlSGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5yZXNwb25zZUhlYWRlcnMuaGFzT3duUHJvcGVydHkoaGVhZGVyKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgIS9eU2V0LUNvb2tpZTI/JC9pLnRlc3QoaGVhZGVyKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaGVhZGVycyArPSBoZWFkZXIgKyBcIjogXCIgKyB0aGlzLnJlc3BvbnNlSGVhZGVyc1toZWFkZXJdICsgXCJcXHJcXG5cIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBoZWFkZXJzO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgc2V0UmVzcG9uc2VCb2R5OiBmdW5jdGlvbiBzZXRSZXNwb25zZUJvZHkoYm9keSkge1xuICAgICAgICAgICAgICAgIHZlcmlmeVJlcXVlc3RTZW50KHRoaXMpO1xuICAgICAgICAgICAgICAgIHZlcmlmeUhlYWRlcnNSZWNlaXZlZCh0aGlzKTtcbiAgICAgICAgICAgICAgICB2ZXJpZnlSZXNwb25zZUJvZHlUeXBlKGJvZHkpO1xuICAgICAgICAgICAgICAgIHZhciBjb250ZW50VHlwZSA9IHRoaXMuZ2V0UmVzcG9uc2VIZWFkZXIoXCJDb250ZW50LVR5cGVcIik7XG5cbiAgICAgICAgICAgICAgICB2YXIgaXNUZXh0UmVzcG9uc2UgPSB0aGlzLnJlc3BvbnNlVHlwZSA9PT0gXCJcIiB8fCB0aGlzLnJlc3BvbnNlVHlwZSA9PT0gXCJ0ZXh0XCI7XG4gICAgICAgICAgICAgICAgY2xlYXJSZXNwb25zZSh0aGlzKTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5hc3luYykge1xuICAgICAgICAgICAgICAgICAgICB2YXIgY2h1bmtTaXplID0gdGhpcy5jaHVua1NpemUgfHwgMTA7XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmRleCA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5MT0FESU5HKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGlzVGV4dFJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5yZXNwb25zZVRleHQgPSB0aGlzLnJlc3BvbnNlICs9IGJvZHkuc3Vic3RyaW5nKGluZGV4LCBpbmRleCArIGNodW5rU2l6ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpbmRleCArPSBjaHVua1NpemU7XG4gICAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKGluZGV4IDwgYm9keS5sZW5ndGgpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2UgPSBjb252ZXJ0UmVzcG9uc2VCb2R5KHRoaXMucmVzcG9uc2VUeXBlLCBjb250ZW50VHlwZSwgYm9keSk7XG4gICAgICAgICAgICAgICAgaWYgKGlzVGV4dFJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2VUZXh0ID0gdGhpcy5yZXNwb25zZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yZXNwb25zZVR5cGUgPT09IFwiZG9jdW1lbnRcIikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJlc3BvbnNlWE1MID0gdGhpcy5yZXNwb25zZTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHRoaXMucmVzcG9uc2VUeXBlID09PSBcIlwiICYmIGlzWG1sQ29udGVudFR5cGUoY29udGVudFR5cGUpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVzcG9uc2VYTUwgPSBGYWtlWE1MSHR0cFJlcXVlc3QucGFyc2VYTUwodGhpcy5yZXNwb25zZVRleHQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB0aGlzLnByb2dyZXNzID0gYm9keS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgdGhpcy5yZWFkeVN0YXRlQ2hhbmdlKEZha2VYTUxIdHRwUmVxdWVzdC5ET05FKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHJlc3BvbmQ6IGZ1bmN0aW9uIHJlc3BvbmQoc3RhdHVzLCBoZWFkZXJzLCBib2R5KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zdGF0dXMgPSB0eXBlb2Ygc3RhdHVzID09PSBcIm51bWJlclwiID8gc3RhdHVzIDogMjAwO1xuICAgICAgICAgICAgICAgIHRoaXMuc3RhdHVzVGV4dCA9IEZha2VYTUxIdHRwUmVxdWVzdC5zdGF0dXNDb2Rlc1t0aGlzLnN0YXR1c107XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRSZXNwb25zZUhlYWRlcnMoaGVhZGVycyB8fCB7fSk7XG4gICAgICAgICAgICAgICAgdGhpcy5zZXRSZXNwb25zZUJvZHkoYm9keSB8fCBcIlwiKTtcbiAgICAgICAgICAgIH0sXG5cbiAgICAgICAgICAgIHVwbG9hZFByb2dyZXNzOiBmdW5jdGlvbiB1cGxvYWRQcm9ncmVzcyhwcm9ncmVzc0V2ZW50UmF3KSB7XG4gICAgICAgICAgICAgICAgaWYgKHN1cHBvcnRzUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGxvYWQuZGlzcGF0Y2hFdmVudChuZXcgc2lub24uUHJvZ3Jlc3NFdmVudChcInByb2dyZXNzXCIsIHByb2dyZXNzRXZlbnRSYXcpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICBkb3dubG9hZFByb2dyZXNzOiBmdW5jdGlvbiBkb3dubG9hZFByb2dyZXNzKHByb2dyZXNzRXZlbnRSYXcpIHtcbiAgICAgICAgICAgICAgICBpZiAoc3VwcG9ydHNQcm9ncmVzcykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmRpc3BhdGNoRXZlbnQobmV3IHNpbm9uLlByb2dyZXNzRXZlbnQoXCJwcm9ncmVzc1wiLCBwcm9ncmVzc0V2ZW50UmF3KSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgdXBsb2FkRXJyb3I6IGZ1bmN0aW9uIHVwbG9hZEVycm9yKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgaWYgKHN1cHBvcnRzQ3VzdG9tRXZlbnQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy51cGxvYWQuZGlzcGF0Y2hFdmVudChuZXcgc2lub24uQ3VzdG9tRXZlbnQoXCJlcnJvclwiLCB7ZGV0YWlsOiBlcnJvcn0pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHNpbm9uLmV4dGVuZChGYWtlWE1MSHR0cFJlcXVlc3QsIHtcbiAgICAgICAgICAgIFVOU0VOVDogMCxcbiAgICAgICAgICAgIE9QRU5FRDogMSxcbiAgICAgICAgICAgIEhFQURFUlNfUkVDRUlWRUQ6IDIsXG4gICAgICAgICAgICBMT0FESU5HOiAzLFxuICAgICAgICAgICAgRE9ORTogNFxuICAgICAgICB9KTtcblxuICAgICAgICBzaW5vbi51c2VGYWtlWE1MSHR0cFJlcXVlc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBGYWtlWE1MSHR0cFJlcXVlc3QucmVzdG9yZSA9IGZ1bmN0aW9uIHJlc3RvcmUoa2VlcE9uQ3JlYXRlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNpbm9uWGhyLnN1cHBvcnRzWEhSKSB7XG4gICAgICAgICAgICAgICAgICAgIGdsb2JhbC5YTUxIdHRwUmVxdWVzdCA9IHNpbm9uWGhyLkdsb2JhbFhNTEh0dHBSZXF1ZXN0O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChzaW5vblhoci5zdXBwb3J0c0FjdGl2ZVgpIHtcbiAgICAgICAgICAgICAgICAgICAgZ2xvYmFsLkFjdGl2ZVhPYmplY3QgPSBzaW5vblhoci5HbG9iYWxBY3RpdmVYT2JqZWN0O1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRlbGV0ZSBGYWtlWE1MSHR0cFJlcXVlc3QucmVzdG9yZTtcblxuICAgICAgICAgICAgICAgIGlmIChrZWVwT25DcmVhdGUgIT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIEZha2VYTUxIdHRwUmVxdWVzdC5vbkNyZWF0ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgaWYgKHNpbm9uWGhyLnN1cHBvcnRzWEhSKSB7XG4gICAgICAgICAgICAgICAgZ2xvYmFsLlhNTEh0dHBSZXF1ZXN0ID0gRmFrZVhNTEh0dHBSZXF1ZXN0O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc2lub25YaHIuc3VwcG9ydHNBY3RpdmVYKSB7XG4gICAgICAgICAgICAgICAgZ2xvYmFsLkFjdGl2ZVhPYmplY3QgPSBmdW5jdGlvbiBBY3RpdmVYT2JqZWN0KG9iaklkKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChvYmpJZCA9PT0gXCJNaWNyb3NvZnQuWE1MSFRUUFwiIHx8IC9eTXN4bWwyXFwuWE1MSFRUUC9pLnRlc3Qob2JqSWQpKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBuZXcgRmFrZVhNTEh0dHBSZXF1ZXN0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbmV3IHNpbm9uWGhyLkdsb2JhbEFjdGl2ZVhPYmplY3Qob2JqSWQpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBGYWtlWE1MSHR0cFJlcXVlc3Q7XG4gICAgICAgIH07XG5cbiAgICAgICAgc2lub24uRmFrZVhNTEh0dHBSZXF1ZXN0ID0gRmFrZVhNTEh0dHBSZXF1ZXN0O1xuICAgIH1cblxuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICB2YXIgc2lub24gPSByZXF1aXJlKFwiLi9jb3JlXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi4vZXh0ZW5kXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9ldmVudFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4uL2xvZ19lcnJvclwiKTtcbiAgICAgICAgbWFrZUFwaShzaW5vbik7XG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gc2lub247XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiwgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bmRlZlxuICAgIHR5cGVvZiBnbG9iYWwgIT09IFwidW5kZWZpbmVkXCIgPyBnbG9iYWwgOiBzZWxmXG4pKTtcbiIsIi8qKlxuICogQGRlcGVuZCB1dGlsL2NvcmUuanNcbiAqL1xuKGZ1bmN0aW9uIChzaW5vbkdsb2JhbCkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgZnVuY3Rpb24gbWFrZUFwaShzaW5vbikge1xuICAgICAgICBmdW5jdGlvbiB3YWxrSW50ZXJuYWwob2JqLCBpdGVyYXRvciwgY29udGV4dCwgb3JpZ2luYWxPYmosIHNlZW4pIHtcbiAgICAgICAgICAgIHZhciBwcm90bywgcHJvcDtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyAhPT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgLy8gV2UgZXhwbGljaXRseSB3YW50IHRvIGVudW1lcmF0ZSB0aHJvdWdoIGFsbCBvZiB0aGUgcHJvdG90eXBlJ3MgcHJvcGVydGllc1xuICAgICAgICAgICAgICAgIC8vIGluIHRoaXMgY2FzZSwgdGhlcmVmb3JlIHdlIGRlbGliZXJhdGVseSBsZWF2ZSBvdXQgYW4gb3duIHByb3BlcnR5IGNoZWNrLlxuICAgICAgICAgICAgICAgIC8qIGVzbGludC1kaXNhYmxlIGd1YXJkLWZvci1pbiAqL1xuICAgICAgICAgICAgICAgIGZvciAocHJvcCBpbiBvYmopIHtcbiAgICAgICAgICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCBvYmpbcHJvcF0sIHByb3AsIG9iaik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8qIGVzbGludC1lbmFibGUgZ3VhcmQtZm9yLWluICovXG5cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIE9iamVjdC5nZXRPd25Qcm9wZXJ0eU5hbWVzKG9iaikuZm9yRWFjaChmdW5jdGlvbiAoaykge1xuICAgICAgICAgICAgICAgIGlmIChzZWVuW2tdICE9PSB0cnVlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlZW5ba10gPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdGFyZ2V0ID0gdHlwZW9mIE9iamVjdC5nZXRPd25Qcm9wZXJ0eURlc2NyaXB0b3Iob2JqLCBrKS5nZXQgPT09IFwiZnVuY3Rpb25cIiA/XG4gICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW5hbE9iaiA6IG9iajtcbiAgICAgICAgICAgICAgICAgICAgaXRlcmF0b3IuY2FsbChjb250ZXh0LCB0YXJnZXRba10sIGssIHRhcmdldCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIHByb3RvID0gT2JqZWN0LmdldFByb3RvdHlwZU9mKG9iaik7XG4gICAgICAgICAgICBpZiAocHJvdG8pIHtcbiAgICAgICAgICAgICAgICB3YWxrSW50ZXJuYWwocHJvdG8sIGl0ZXJhdG9yLCBjb250ZXh0LCBvcmlnaW5hbE9iaiwgc2Vlbik7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICAvKiBQdWJsaWM6IHdhbGtzIHRoZSBwcm90b3R5cGUgY2hhaW4gb2YgYW4gb2JqZWN0IGFuZCBpdGVyYXRlcyBvdmVyIGV2ZXJ5IG93biBwcm9wZXJ0eVxuICAgICAgICAgKiBuYW1lIGVuY291bnRlcmVkLiBUaGUgaXRlcmF0b3IgaXMgY2FsbGVkIGluIHRoZSBzYW1lIGZhc2hpb24gdGhhdCBBcnJheS5wcm90b3R5cGUuZm9yRWFjaFxuICAgICAgICAgKiB3b3Jrcywgd2hlcmUgaXQgaXMgcGFzc2VkIHRoZSB2YWx1ZSwga2V5LCBhbmQgb3duIG9iamVjdCBhcyB0aGUgMXN0LCAybmQsIGFuZCAzcmQgcG9zaXRpb25hbFxuICAgICAgICAgKiBhcmd1bWVudCwgcmVzcGVjdGl2ZWx5LiBJbiBjYXNlcyB3aGVyZSBPYmplY3QuZ2V0T3duUHJvcGVydHlOYW1lcyBpcyBub3QgYXZhaWxhYmxlLCB3YWxrIHdpbGxcbiAgICAgICAgICogZGVmYXVsdCB0byB1c2luZyBhIHNpbXBsZSBmb3IuLmluIGxvb3AuXG4gICAgICAgICAqXG4gICAgICAgICAqIG9iaiAtIFRoZSBvYmplY3QgdG8gd2FsayB0aGUgcHJvdG90eXBlIGNoYWluIGZvci5cbiAgICAgICAgICogaXRlcmF0b3IgLSBUaGUgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIG9uIGVhY2ggcGFzcyBvZiB0aGUgd2Fsay5cbiAgICAgICAgICogY29udGV4dCAtIChPcHRpb25hbCkgV2hlbiBnaXZlbiwgdGhlIGl0ZXJhdG9yIHdpbGwgYmUgY2FsbGVkIHdpdGggdGhpcyBvYmplY3QgYXMgdGhlIHJlY2VpdmVyLlxuICAgICAgICAgKi9cbiAgICAgICAgZnVuY3Rpb24gd2FsayhvYmosIGl0ZXJhdG9yLCBjb250ZXh0KSB7XG4gICAgICAgICAgICByZXR1cm4gd2Fsa0ludGVybmFsKG9iaiwgaXRlcmF0b3IsIGNvbnRleHQsIG9iaiwge30pO1xuICAgICAgICB9XG5cbiAgICAgICAgc2lub24ud2FsayA9IHdhbGs7XG4gICAgICAgIHJldHVybiBzaW5vbi53YWxrO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvYWREZXBlbmRlbmNpZXMocmVxdWlyZSwgZXhwb3J0cywgbW9kdWxlKSB7XG4gICAgICAgIHZhciBzaW5vbiA9IHJlcXVpcmUoXCIuL3V0aWwvY29yZVwiKTtcbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBtYWtlQXBpKHNpbm9uKTtcbiAgICB9XG5cbiAgICB2YXIgaXNOb2RlID0gdHlwZW9mIG1vZHVsZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBtb2R1bGUuZXhwb3J0cyAmJiB0eXBlb2YgcmVxdWlyZSA9PT0gXCJmdW5jdGlvblwiO1xuICAgIHZhciBpc0FNRCA9IHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2YgZGVmaW5lLmFtZCA9PT0gXCJvYmplY3RcIiAmJiBkZWZpbmUuYW1kO1xuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpc05vZGUpIHtcbiAgICAgICAgbG9hZERlcGVuZGVuY2llcyhyZXF1aXJlLCBtb2R1bGUuZXhwb3J0cywgbW9kdWxlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChzaW5vbkdsb2JhbCkge1xuICAgICAgICBtYWtlQXBpKHNpbm9uR2xvYmFsKTtcbiAgICB9XG59KFxuICAgIHR5cGVvZiBzaW5vbiA9PT0gXCJvYmplY3RcIiAmJiBzaW5vbiAvLyBlc2xpbnQtZGlzYWJsZS1saW5lIG5vLXVuZGVmXG4pKTtcbiIsIigodHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQgJiYgZnVuY3Rpb24gKG0pIHtcbiAgICBkZWZpbmUoXCJmb3JtYXRpb1wiLCBbXCJzYW1zYW1cIl0sIG0pO1xufSkgfHwgKHR5cGVvZiBtb2R1bGUgPT09IFwib2JqZWN0XCIgJiYgZnVuY3Rpb24gKG0pIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IG0ocmVxdWlyZShcInNhbXNhbVwiKSk7XG59KSB8fCBmdW5jdGlvbiAobSkgeyB0aGlzLmZvcm1hdGlvID0gbSh0aGlzLnNhbXNhbSk7IH1cbikoZnVuY3Rpb24gKHNhbXNhbSkge1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIGZvcm1hdGlvID0ge1xuICAgICAgICBleGNsdWRlQ29uc3RydWN0b3JzOiBbXCJPYmplY3RcIiwgL14uJC9dLFxuICAgICAgICBxdW90ZVN0cmluZ3M6IHRydWUsXG4gICAgICAgIGxpbWl0Q2hpbGRyZW5Db3VudDogMFxuICAgIH07XG5cbiAgICB2YXIgaGFzT3duID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eTtcblxuICAgIHZhciBzcGVjaWFsT2JqZWN0cyA9IFtdO1xuICAgIGlmICh0eXBlb2YgZ2xvYmFsICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIHNwZWNpYWxPYmplY3RzLnB1c2goeyBvYmplY3Q6IGdsb2JhbCwgdmFsdWU6IFwiW29iamVjdCBnbG9iYWxdXCIgfSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2YgZG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgc3BlY2lhbE9iamVjdHMucHVzaCh7XG4gICAgICAgICAgICBvYmplY3Q6IGRvY3VtZW50LFxuICAgICAgICAgICAgdmFsdWU6IFwiW29iamVjdCBIVE1MRG9jdW1lbnRdXCJcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgIHNwZWNpYWxPYmplY3RzLnB1c2goeyBvYmplY3Q6IHdpbmRvdywgdmFsdWU6IFwiW29iamVjdCBXaW5kb3ddXCIgfSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZnVuY3Rpb25OYW1lKGZ1bmMpIHtcbiAgICAgICAgaWYgKCFmdW5jKSB7IHJldHVybiBcIlwiOyB9XG4gICAgICAgIGlmIChmdW5jLmRpc3BsYXlOYW1lKSB7IHJldHVybiBmdW5jLmRpc3BsYXlOYW1lOyB9XG4gICAgICAgIGlmIChmdW5jLm5hbWUpIHsgcmV0dXJuIGZ1bmMubmFtZTsgfVxuICAgICAgICB2YXIgbWF0Y2hlcyA9IGZ1bmMudG9TdHJpbmcoKS5tYXRjaCgvZnVuY3Rpb25cXHMrKFteXFwoXSspL20pO1xuICAgICAgICByZXR1cm4gKG1hdGNoZXMgJiYgbWF0Y2hlc1sxXSkgfHwgXCJcIjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjb25zdHJ1Y3Rvck5hbWUoZiwgb2JqZWN0KSB7XG4gICAgICAgIHZhciBuYW1lID0gZnVuY3Rpb25OYW1lKG9iamVjdCAmJiBvYmplY3QuY29uc3RydWN0b3IpO1xuICAgICAgICB2YXIgZXhjbHVkZXMgPSBmLmV4Y2x1ZGVDb25zdHJ1Y3RvcnMgfHxcbiAgICAgICAgICAgICAgICBmb3JtYXRpby5leGNsdWRlQ29uc3RydWN0b3JzIHx8IFtdO1xuXG4gICAgICAgIHZhciBpLCBsO1xuICAgICAgICBmb3IgKGkgPSAwLCBsID0gZXhjbHVkZXMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICBpZiAodHlwZW9mIGV4Y2x1ZGVzW2ldID09PSBcInN0cmluZ1wiICYmIGV4Y2x1ZGVzW2ldID09PSBuYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiXCI7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGV4Y2x1ZGVzW2ldLnRlc3QgJiYgZXhjbHVkZXNbaV0udGVzdChuYW1lKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcIlwiO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5hbWU7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaXNDaXJjdWxhcihvYmplY3QsIG9iamVjdHMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QgIT09IFwib2JqZWN0XCIpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgIHZhciBpLCBsO1xuICAgICAgICBmb3IgKGkgPSAwLCBsID0gb2JqZWN0cy5sZW5ndGg7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIGlmIChvYmplY3RzW2ldID09PSBvYmplY3QpIHsgcmV0dXJuIHRydWU7IH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYXNjaWkoZiwgb2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCkge1xuICAgICAgICBpZiAodHlwZW9mIG9iamVjdCA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgdmFyIHFzID0gZi5xdW90ZVN0cmluZ3M7XG4gICAgICAgICAgICB2YXIgcXVvdGUgPSB0eXBlb2YgcXMgIT09IFwiYm9vbGVhblwiIHx8IHFzO1xuICAgICAgICAgICAgcmV0dXJuIHByb2Nlc3NlZCB8fCBxdW90ZSA/ICdcIicgKyBvYmplY3QgKyAnXCInIDogb2JqZWN0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QgPT09IFwiZnVuY3Rpb25cIiAmJiAhKG9iamVjdCBpbnN0YW5jZW9mIFJlZ0V4cCkpIHtcbiAgICAgICAgICAgIHJldHVybiBhc2NpaS5mdW5jKG9iamVjdCk7XG4gICAgICAgIH1cblxuICAgICAgICBwcm9jZXNzZWQgPSBwcm9jZXNzZWQgfHwgW107XG5cbiAgICAgICAgaWYgKGlzQ2lyY3VsYXIob2JqZWN0LCBwcm9jZXNzZWQpKSB7IHJldHVybiBcIltDaXJjdWxhcl1cIjsgfVxuXG4gICAgICAgIGlmIChPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwob2JqZWN0KSA9PT0gXCJbb2JqZWN0IEFycmF5XVwiKSB7XG4gICAgICAgICAgICByZXR1cm4gYXNjaWkuYXJyYXkuY2FsbChmLCBvYmplY3QsIHByb2Nlc3NlZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIW9iamVjdCkgeyByZXR1cm4gU3RyaW5nKCgxL29iamVjdCkgPT09IC1JbmZpbml0eSA/IFwiLTBcIiA6IG9iamVjdCk7IH1cbiAgICAgICAgaWYgKHNhbXNhbS5pc0VsZW1lbnQob2JqZWN0KSkgeyByZXR1cm4gYXNjaWkuZWxlbWVudChvYmplY3QpOyB9XG5cbiAgICAgICAgaWYgKHR5cGVvZiBvYmplY3QudG9TdHJpbmcgPT09IFwiZnVuY3Rpb25cIiAmJlxuICAgICAgICAgICAgICAgIG9iamVjdC50b1N0cmluZyAhPT0gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZykge1xuICAgICAgICAgICAgcmV0dXJuIG9iamVjdC50b1N0cmluZygpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGksIGw7XG4gICAgICAgIGZvciAoaSA9IDAsIGwgPSBzcGVjaWFsT2JqZWN0cy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChvYmplY3QgPT09IHNwZWNpYWxPYmplY3RzW2ldLm9iamVjdCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzcGVjaWFsT2JqZWN0c1tpXS52YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBhc2NpaS5vYmplY3QuY2FsbChmLCBvYmplY3QsIHByb2Nlc3NlZCwgaW5kZW50KTtcbiAgICB9XG5cbiAgICBhc2NpaS5mdW5jID0gZnVuY3Rpb24gKGZ1bmMpIHtcbiAgICAgICAgcmV0dXJuIFwiZnVuY3Rpb24gXCIgKyBmdW5jdGlvbk5hbWUoZnVuYykgKyBcIigpIHt9XCI7XG4gICAgfTtcblxuICAgIGFzY2lpLmFycmF5ID0gZnVuY3Rpb24gKGFycmF5LCBwcm9jZXNzZWQpIHtcbiAgICAgICAgcHJvY2Vzc2VkID0gcHJvY2Vzc2VkIHx8IFtdO1xuICAgICAgICBwcm9jZXNzZWQucHVzaChhcnJheSk7XG4gICAgICAgIHZhciBwaWVjZXMgPSBbXTtcbiAgICAgICAgdmFyIGksIGw7XG4gICAgICAgIGwgPSAodGhpcy5saW1pdENoaWxkcmVuQ291bnQgPiAwKSA/IFxuICAgICAgICAgICAgTWF0aC5taW4odGhpcy5saW1pdENoaWxkcmVuQ291bnQsIGFycmF5Lmxlbmd0aCkgOiBhcnJheS5sZW5ndGg7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgcGllY2VzLnB1c2goYXNjaWkodGhpcywgYXJyYXlbaV0sIHByb2Nlc3NlZCkpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYobCA8IGFycmF5Lmxlbmd0aClcbiAgICAgICAgICAgIHBpZWNlcy5wdXNoKFwiWy4uLiBcIiArIChhcnJheS5sZW5ndGggLSBsKSArIFwiIG1vcmUgZWxlbWVudHNdXCIpO1xuXG4gICAgICAgIHJldHVybiBcIltcIiArIHBpZWNlcy5qb2luKFwiLCBcIikgKyBcIl1cIjtcbiAgICB9O1xuXG4gICAgYXNjaWkub2JqZWN0ID0gZnVuY3Rpb24gKG9iamVjdCwgcHJvY2Vzc2VkLCBpbmRlbnQpIHtcbiAgICAgICAgcHJvY2Vzc2VkID0gcHJvY2Vzc2VkIHx8IFtdO1xuICAgICAgICBwcm9jZXNzZWQucHVzaChvYmplY3QpO1xuICAgICAgICBpbmRlbnQgPSBpbmRlbnQgfHwgMDtcbiAgICAgICAgdmFyIHBpZWNlcyA9IFtdLCBwcm9wZXJ0aWVzID0gc2Ftc2FtLmtleXMob2JqZWN0KS5zb3J0KCk7XG4gICAgICAgIHZhciBsZW5ndGggPSAzO1xuICAgICAgICB2YXIgcHJvcCwgc3RyLCBvYmosIGksIGssIGw7XG4gICAgICAgIGwgPSAodGhpcy5saW1pdENoaWxkcmVuQ291bnQgPiAwKSA/IFxuICAgICAgICAgICAgTWF0aC5taW4odGhpcy5saW1pdENoaWxkcmVuQ291bnQsIHByb3BlcnRpZXMubGVuZ3RoKSA6IHByb3BlcnRpZXMubGVuZ3RoO1xuXG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBsOyArK2kpIHtcbiAgICAgICAgICAgIHByb3AgPSBwcm9wZXJ0aWVzW2ldO1xuICAgICAgICAgICAgb2JqID0gb2JqZWN0W3Byb3BdO1xuXG4gICAgICAgICAgICBpZiAoaXNDaXJjdWxhcihvYmosIHByb2Nlc3NlZCkpIHtcbiAgICAgICAgICAgICAgICBzdHIgPSBcIltDaXJjdWxhcl1cIjtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgc3RyID0gYXNjaWkodGhpcywgb2JqLCBwcm9jZXNzZWQsIGluZGVudCArIDIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBzdHIgPSAoL1xccy8udGVzdChwcm9wKSA/ICdcIicgKyBwcm9wICsgJ1wiJyA6IHByb3ApICsgXCI6IFwiICsgc3RyO1xuICAgICAgICAgICAgbGVuZ3RoICs9IHN0ci5sZW5ndGg7XG4gICAgICAgICAgICBwaWVjZXMucHVzaChzdHIpO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNvbnMgPSBjb25zdHJ1Y3Rvck5hbWUodGhpcywgb2JqZWN0KTtcbiAgICAgICAgdmFyIHByZWZpeCA9IGNvbnMgPyBcIltcIiArIGNvbnMgKyBcIl0gXCIgOiBcIlwiO1xuICAgICAgICB2YXIgaXMgPSBcIlwiO1xuICAgICAgICBmb3IgKGkgPSAwLCBrID0gaW5kZW50OyBpIDwgazsgKytpKSB7IGlzICs9IFwiIFwiOyB9XG5cbiAgICAgICAgaWYobCA8IHByb3BlcnRpZXMubGVuZ3RoKVxuICAgICAgICAgICAgcGllY2VzLnB1c2goXCJbLi4uIFwiICsgKHByb3BlcnRpZXMubGVuZ3RoIC0gbCkgKyBcIiBtb3JlIGVsZW1lbnRzXVwiKTtcblxuICAgICAgICBpZiAobGVuZ3RoICsgaW5kZW50ID4gODApIHtcbiAgICAgICAgICAgIHJldHVybiBwcmVmaXggKyBcIntcXG4gIFwiICsgaXMgKyBwaWVjZXMuam9pbihcIixcXG4gIFwiICsgaXMpICsgXCJcXG5cIiArXG4gICAgICAgICAgICAgICAgaXMgKyBcIn1cIjtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcHJlZml4ICsgXCJ7IFwiICsgcGllY2VzLmpvaW4oXCIsIFwiKSArIFwiIH1cIjtcbiAgICB9O1xuXG4gICAgYXNjaWkuZWxlbWVudCA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgICAgIHZhciB0YWdOYW1lID0gZWxlbWVudC50YWdOYW1lLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIHZhciBhdHRycyA9IGVsZW1lbnQuYXR0cmlidXRlcywgYXR0ciwgcGFpcnMgPSBbXSwgYXR0ck5hbWUsIGksIGwsIHZhbDtcblxuICAgICAgICBmb3IgKGkgPSAwLCBsID0gYXR0cnMubGVuZ3RoOyBpIDwgbDsgKytpKSB7XG4gICAgICAgICAgICBhdHRyID0gYXR0cnMuaXRlbShpKTtcbiAgICAgICAgICAgIGF0dHJOYW1lID0gYXR0ci5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLnJlcGxhY2UoXCJodG1sOlwiLCBcIlwiKTtcbiAgICAgICAgICAgIHZhbCA9IGF0dHIubm9kZVZhbHVlO1xuICAgICAgICAgICAgaWYgKGF0dHJOYW1lICE9PSBcImNvbnRlbnRlZGl0YWJsZVwiIHx8IHZhbCAhPT0gXCJpbmhlcml0XCIpIHtcbiAgICAgICAgICAgICAgICBpZiAoISF2YWwpIHsgcGFpcnMucHVzaChhdHRyTmFtZSArIFwiPVxcXCJcIiArIHZhbCArIFwiXFxcIlwiKTsgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGZvcm1hdHRlZCA9IFwiPFwiICsgdGFnTmFtZSArIChwYWlycy5sZW5ndGggPiAwID8gXCIgXCIgOiBcIlwiKTtcbiAgICAgICAgdmFyIGNvbnRlbnQgPSBlbGVtZW50LmlubmVySFRNTDtcblxuICAgICAgICBpZiAoY29udGVudC5sZW5ndGggPiAyMCkge1xuICAgICAgICAgICAgY29udGVudCA9IGNvbnRlbnQuc3Vic3RyKDAsIDIwKSArIFwiWy4uLl1cIjtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciByZXMgPSBmb3JtYXR0ZWQgKyBwYWlycy5qb2luKFwiIFwiKSArIFwiPlwiICsgY29udGVudCArXG4gICAgICAgICAgICAgICAgXCI8L1wiICsgdGFnTmFtZSArIFwiPlwiO1xuXG4gICAgICAgIHJldHVybiByZXMucmVwbGFjZSgvIGNvbnRlbnRFZGl0YWJsZT1cImluaGVyaXRcIi8sIFwiXCIpO1xuICAgIH07XG5cbiAgICBmdW5jdGlvbiBGb3JtYXRpbyhvcHRpb25zKSB7XG4gICAgICAgIGZvciAodmFyIG9wdCBpbiBvcHRpb25zKSB7XG4gICAgICAgICAgICB0aGlzW29wdF0gPSBvcHRpb25zW29wdF07XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBGb3JtYXRpby5wcm90b3R5cGUgPSB7XG4gICAgICAgIGZ1bmN0aW9uTmFtZTogZnVuY3Rpb25OYW1lLFxuXG4gICAgICAgIGNvbmZpZ3VyZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHJldHVybiBuZXcgRm9ybWF0aW8ob3B0aW9ucyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgY29uc3RydWN0b3JOYW1lOiBmdW5jdGlvbiAob2JqZWN0KSB7XG4gICAgICAgICAgICByZXR1cm4gY29uc3RydWN0b3JOYW1lKHRoaXMsIG9iamVjdCk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgYXNjaWk6IGZ1bmN0aW9uIChvYmplY3QsIHByb2Nlc3NlZCwgaW5kZW50KSB7XG4gICAgICAgICAgICByZXR1cm4gYXNjaWkodGhpcywgb2JqZWN0LCBwcm9jZXNzZWQsIGluZGVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgcmV0dXJuIEZvcm1hdGlvLnByb3RvdHlwZTtcbn0pO1xuIiwiLypnbG9iYWwgZ2xvYmFsLCB3aW5kb3cqL1xuLyoqXG4gKiBAYXV0aG9yIENocmlzdGlhbiBKb2hhbnNlbiAoY2hyaXN0aWFuQGNqb2hhbnNlbi5ubykgYW5kIGNvbnRyaWJ1dG9yc1xuICogQGxpY2Vuc2UgQlNEXG4gKlxuICogQ29weXJpZ2h0IChjKSAyMDEwLTIwMTQgQ2hyaXN0aWFuIEpvaGFuc2VuXG4gKi9cblxuKGZ1bmN0aW9uIChnbG9iYWwpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIC8vIE1ha2UgcHJvcGVydGllcyB3cml0YWJsZSBpbiBJRSwgYXMgcGVyXG4gICAgLy8gaHR0cDovL3d3dy5hZGVxdWF0ZWx5Z29vZC5jb20vUmVwbGFjaW5nLXNldFRpbWVvdXQtR2xvYmFsbHkuaHRtbFxuICAgIC8vIEpTTGludCBiZWluZyBhbmFsXG4gICAgdmFyIGdsYmwgPSBnbG9iYWw7XG5cbiAgICBnbG9iYWwuc2V0VGltZW91dCA9IGdsYmwuc2V0VGltZW91dDtcbiAgICBnbG9iYWwuY2xlYXJUaW1lb3V0ID0gZ2xibC5jbGVhclRpbWVvdXQ7XG4gICAgZ2xvYmFsLnNldEludGVydmFsID0gZ2xibC5zZXRJbnRlcnZhbDtcbiAgICBnbG9iYWwuY2xlYXJJbnRlcnZhbCA9IGdsYmwuY2xlYXJJbnRlcnZhbDtcbiAgICBnbG9iYWwuRGF0ZSA9IGdsYmwuRGF0ZTtcblxuICAgIC8vIHNldEltbWVkaWF0ZSBpcyBub3QgYSBzdGFuZGFyZCBmdW5jdGlvblxuICAgIC8vIGF2b2lkIGFkZGluZyB0aGUgcHJvcCB0byB0aGUgd2luZG93IG9iamVjdCBpZiBub3QgcHJlc2VudFxuICAgIGlmKCdzZXRJbW1lZGlhdGUnIGluIGdsb2JhbCkge1xuICAgICAgICBnbG9iYWwuc2V0SW1tZWRpYXRlID0gZ2xibC5zZXRJbW1lZGlhdGU7XG4gICAgICAgIGdsb2JhbC5jbGVhckltbWVkaWF0ZSA9IGdsYmwuY2xlYXJJbW1lZGlhdGU7XG4gICAgfVxuXG4gICAgLy8gbm9kZSBleHBlY3RzIHNldFRpbWVvdXQvc2V0SW50ZXJ2YWwgdG8gcmV0dXJuIGEgZm4gb2JqZWN0IHcvIC5yZWYoKS8udW5yZWYoKVxuICAgIC8vIGJyb3dzZXJzLCBhIG51bWJlci5cbiAgICAvLyBzZWUgaHR0cHM6Ly9naXRodWIuY29tL2Nqb2hhbnNlbi9TaW5vbi5KUy9wdWxsLzQzNlxuXG4gICAgdmFyIE5PT1AgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB1bmRlZmluZWQ7IH07XG4gICAgdmFyIHRpbWVvdXRSZXN1bHQgPSBzZXRUaW1lb3V0KE5PT1AsIDApO1xuICAgIHZhciBhZGRUaW1lclJldHVybnNPYmplY3QgPSB0eXBlb2YgdGltZW91dFJlc3VsdCA9PT0gXCJvYmplY3RcIjtcbiAgICBjbGVhclRpbWVvdXQodGltZW91dFJlc3VsdCk7XG5cbiAgICB2YXIgTmF0aXZlRGF0ZSA9IERhdGU7XG4gICAgdmFyIHVuaXF1ZVRpbWVySWQgPSAxO1xuXG4gICAgLyoqXG4gICAgICogUGFyc2Ugc3RyaW5ncyBsaWtlIFwiMDE6MTA6MDBcIiAobWVhbmluZyAxIGhvdXIsIDEwIG1pbnV0ZXMsIDAgc2Vjb25kcykgaW50b1xuICAgICAqIG51bWJlciBvZiBtaWxsaXNlY29uZHMuIFRoaXMgaXMgdXNlZCB0byBzdXBwb3J0IGh1bWFuLXJlYWRhYmxlIHN0cmluZ3MgcGFzc2VkXG4gICAgICogdG8gY2xvY2sudGljaygpXG4gICAgICovXG4gICAgZnVuY3Rpb24gcGFyc2VUaW1lKHN0cikge1xuICAgICAgICBpZiAoIXN0cikge1xuICAgICAgICAgICAgcmV0dXJuIDA7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3RyaW5ncyA9IHN0ci5zcGxpdChcIjpcIik7XG4gICAgICAgIHZhciBsID0gc3RyaW5ncy5sZW5ndGgsIGkgPSBsO1xuICAgICAgICB2YXIgbXMgPSAwLCBwYXJzZWQ7XG5cbiAgICAgICAgaWYgKGwgPiAzIHx8ICEvXihcXGRcXGQ6KXswLDJ9XFxkXFxkPyQvLnRlc3Qoc3RyKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwidGljayBvbmx5IHVuZGVyc3RhbmRzIG51bWJlcnMgYW5kICdoOm06cydcIik7XG4gICAgICAgIH1cblxuICAgICAgICB3aGlsZSAoaS0tKSB7XG4gICAgICAgICAgICBwYXJzZWQgPSBwYXJzZUludChzdHJpbmdzW2ldLCAxMCk7XG5cbiAgICAgICAgICAgIGlmIChwYXJzZWQgPj0gNjApIHtcbiAgICAgICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJJbnZhbGlkIHRpbWUgXCIgKyBzdHIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBtcyArPSBwYXJzZWQgKiBNYXRoLnBvdyg2MCwgKGwgLSBpIC0gMSkpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG1zICogMTAwMDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBVc2VkIHRvIGdyb2sgdGhlIGBub3dgIHBhcmFtZXRlciB0byBjcmVhdGVDbG9jay5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBnZXRFcG9jaChlcG9jaCkge1xuICAgICAgICBpZiAoIWVwb2NoKSB7IHJldHVybiAwOyB9XG4gICAgICAgIGlmICh0eXBlb2YgZXBvY2guZ2V0VGltZSA9PT0gXCJmdW5jdGlvblwiKSB7IHJldHVybiBlcG9jaC5nZXRUaW1lKCk7IH1cbiAgICAgICAgaWYgKHR5cGVvZiBlcG9jaCA9PT0gXCJudW1iZXJcIikgeyByZXR1cm4gZXBvY2g7IH1cbiAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihcIm5vdyBzaG91bGQgYmUgbWlsbGlzZWNvbmRzIHNpbmNlIFVOSVggZXBvY2hcIik7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gaW5SYW5nZShmcm9tLCB0bywgdGltZXIpIHtcbiAgICAgICAgcmV0dXJuIHRpbWVyICYmIHRpbWVyLmNhbGxBdCA+PSBmcm9tICYmIHRpbWVyLmNhbGxBdCA8PSB0bztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBtaXJyb3JEYXRlUHJvcGVydGllcyh0YXJnZXQsIHNvdXJjZSkge1xuICAgICAgICB2YXIgcHJvcDtcbiAgICAgICAgZm9yIChwcm9wIGluIHNvdXJjZSkge1xuICAgICAgICAgICAgaWYgKHNvdXJjZS5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgICAgIHRhcmdldFtwcm9wXSA9IHNvdXJjZVtwcm9wXTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCBzcGVjaWFsIG5vdyBpbXBsZW1lbnRhdGlvblxuICAgICAgICBpZiAoc291cmNlLm5vdykge1xuICAgICAgICAgICAgdGFyZ2V0Lm5vdyA9IGZ1bmN0aW9uIG5vdygpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGFyZ2V0LmNsb2NrLm5vdztcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkZWxldGUgdGFyZ2V0Lm5vdztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCBzcGVjaWFsIHRvU291cmNlIGltcGxlbWVudGF0aW9uXG4gICAgICAgIGlmIChzb3VyY2UudG9Tb3VyY2UpIHtcbiAgICAgICAgICAgIHRhcmdldC50b1NvdXJjZSA9IGZ1bmN0aW9uIHRvU291cmNlKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBzb3VyY2UudG9Tb3VyY2UoKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkZWxldGUgdGFyZ2V0LnRvU291cmNlO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gc2V0IHNwZWNpYWwgdG9TdHJpbmcgaW1wbGVtZW50YXRpb25cbiAgICAgICAgdGFyZ2V0LnRvU3RyaW5nID0gZnVuY3Rpb24gdG9TdHJpbmcoKSB7XG4gICAgICAgICAgICByZXR1cm4gc291cmNlLnRvU3RyaW5nKCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgdGFyZ2V0LnByb3RvdHlwZSA9IHNvdXJjZS5wcm90b3R5cGU7XG4gICAgICAgIHRhcmdldC5wYXJzZSA9IHNvdXJjZS5wYXJzZTtcbiAgICAgICAgdGFyZ2V0LlVUQyA9IHNvdXJjZS5VVEM7XG4gICAgICAgIHRhcmdldC5wcm90b3R5cGUudG9VVENTdHJpbmcgPSBzb3VyY2UucHJvdG90eXBlLnRvVVRDU3RyaW5nO1xuXG4gICAgICAgIHJldHVybiB0YXJnZXQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gY3JlYXRlRGF0ZSgpIHtcbiAgICAgICAgZnVuY3Rpb24gQ2xvY2tEYXRlKHllYXIsIG1vbnRoLCBkYXRlLCBob3VyLCBtaW51dGUsIHNlY29uZCwgbXMpIHtcbiAgICAgICAgICAgIC8vIERlZmVuc2l2ZSBhbmQgdmVyYm9zZSB0byBhdm9pZCBwb3RlbnRpYWwgaGFybSBpbiBwYXNzaW5nXG4gICAgICAgICAgICAvLyBleHBsaWNpdCB1bmRlZmluZWQgd2hlbiB1c2VyIGRvZXMgbm90IHBhc3MgYXJndW1lbnRcbiAgICAgICAgICAgIHN3aXRjaCAoYXJndW1lbnRzLmxlbmd0aCkge1xuICAgICAgICAgICAgY2FzZSAwOlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZShDbG9ja0RhdGUuY2xvY2subm93KTtcbiAgICAgICAgICAgIGNhc2UgMTpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhcik7XG4gICAgICAgICAgICBjYXNlIDI6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBOYXRpdmVEYXRlKHllYXIsIG1vbnRoKTtcbiAgICAgICAgICAgIGNhc2UgMzpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhciwgbW9udGgsIGRhdGUpO1xuICAgICAgICAgICAgY2FzZSA0OlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZSh5ZWFyLCBtb250aCwgZGF0ZSwgaG91cik7XG4gICAgICAgICAgICBjYXNlIDU6XG4gICAgICAgICAgICAgICAgcmV0dXJuIG5ldyBOYXRpdmVEYXRlKHllYXIsIG1vbnRoLCBkYXRlLCBob3VyLCBtaW51dGUpO1xuICAgICAgICAgICAgY2FzZSA2OlxuICAgICAgICAgICAgICAgIHJldHVybiBuZXcgTmF0aXZlRGF0ZSh5ZWFyLCBtb250aCwgZGF0ZSwgaG91ciwgbWludXRlLCBzZWNvbmQpO1xuICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICByZXR1cm4gbmV3IE5hdGl2ZURhdGUoeWVhciwgbW9udGgsIGRhdGUsIGhvdXIsIG1pbnV0ZSwgc2Vjb25kLCBtcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbWlycm9yRGF0ZVByb3BlcnRpZXMoQ2xvY2tEYXRlLCBOYXRpdmVEYXRlKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBhZGRUaW1lcihjbG9jaywgdGltZXIpIHtcbiAgICAgICAgaWYgKHRpbWVyLmZ1bmMgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKFwiQ2FsbGJhY2sgbXVzdCBiZSBwcm92aWRlZCB0byB0aW1lciBjYWxsc1wiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2xvY2sudGltZXJzKSB7XG4gICAgICAgICAgICBjbG9jay50aW1lcnMgPSB7fTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRpbWVyLmlkID0gdW5pcXVlVGltZXJJZCsrO1xuICAgICAgICB0aW1lci5jcmVhdGVkQXQgPSBjbG9jay5ub3c7XG4gICAgICAgIHRpbWVyLmNhbGxBdCA9IGNsb2NrLm5vdyArICh0aW1lci5kZWxheSB8fCAoY2xvY2suZHVyaW5nVGljayA/IDEgOiAwKSk7XG5cbiAgICAgICAgY2xvY2sudGltZXJzW3RpbWVyLmlkXSA9IHRpbWVyO1xuXG4gICAgICAgIGlmIChhZGRUaW1lclJldHVybnNPYmplY3QpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgaWQ6IHRpbWVyLmlkLFxuICAgICAgICAgICAgICAgIHJlZjogTk9PUCxcbiAgICAgICAgICAgICAgICB1bnJlZjogTk9PUFxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aW1lci5pZDtcbiAgICB9XG5cblxuICAgIGZ1bmN0aW9uIGNvbXBhcmVUaW1lcnMoYSwgYikge1xuICAgICAgICAvLyBTb3J0IGZpcnN0IGJ5IGFic29sdXRlIHRpbWluZ1xuICAgICAgICBpZiAoYS5jYWxsQXQgPCBiLmNhbGxBdCkge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhLmNhbGxBdCA+IGIuY2FsbEF0KSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgbmV4dCBieSBpbW1lZGlhdGUsIGltbWVkaWF0ZSB0aW1lcnMgdGFrZSBwcmVjZWRlbmNlXG4gICAgICAgIGlmIChhLmltbWVkaWF0ZSAmJiAhYi5pbW1lZGlhdGUpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIWEuaW1tZWRpYXRlICYmIGIuaW1tZWRpYXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgbmV4dCBieSBjcmVhdGlvbiB0aW1lLCBlYXJsaWVyLWNyZWF0ZWQgdGltZXJzIHRha2UgcHJlY2VkZW5jZVxuICAgICAgICBpZiAoYS5jcmVhdGVkQXQgPCBiLmNyZWF0ZWRBdCkge1xuICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICB9XG4gICAgICAgIGlmIChhLmNyZWF0ZWRBdCA+IGIuY3JlYXRlZEF0KSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNvcnQgbmV4dCBieSBpZCwgbG93ZXItaWQgdGltZXJzIHRha2UgcHJlY2VkZW5jZVxuICAgICAgICBpZiAoYS5pZCA8IGIuaWQpIHtcbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoYS5pZCA+IGIuaWQpIHtcbiAgICAgICAgICAgIHJldHVybiAxO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gQXMgdGltZXIgaWRzIGFyZSB1bmlxdWUsIG5vIGZhbGxiYWNrIGAwYCBpcyBuZWNlc3NhcnlcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBmaXJzdFRpbWVySW5SYW5nZShjbG9jaywgZnJvbSwgdG8pIHtcbiAgICAgICAgdmFyIHRpbWVycyA9IGNsb2NrLnRpbWVycyxcbiAgICAgICAgICAgIHRpbWVyID0gbnVsbCxcbiAgICAgICAgICAgIGlkLFxuICAgICAgICAgICAgaXNJblJhbmdlO1xuXG4gICAgICAgIGZvciAoaWQgaW4gdGltZXJzKSB7XG4gICAgICAgICAgICBpZiAodGltZXJzLmhhc093blByb3BlcnR5KGlkKSkge1xuICAgICAgICAgICAgICAgIGlzSW5SYW5nZSA9IGluUmFuZ2UoZnJvbSwgdG8sIHRpbWVyc1tpZF0pO1xuXG4gICAgICAgICAgICAgICAgaWYgKGlzSW5SYW5nZSAmJiAoIXRpbWVyIHx8IGNvbXBhcmVUaW1lcnModGltZXIsIHRpbWVyc1tpZF0pID09PSAxKSkge1xuICAgICAgICAgICAgICAgICAgICB0aW1lciA9IHRpbWVyc1tpZF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRpbWVyO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGNhbGxUaW1lcihjbG9jaywgdGltZXIpIHtcbiAgICAgICAgdmFyIGV4Y2VwdGlvbjtcblxuICAgICAgICBpZiAodHlwZW9mIHRpbWVyLmludGVydmFsID09PSBcIm51bWJlclwiKSB7XG4gICAgICAgICAgICBjbG9jay50aW1lcnNbdGltZXIuaWRdLmNhbGxBdCArPSB0aW1lci5pbnRlcnZhbDtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGRlbGV0ZSBjbG9jay50aW1lcnNbdGltZXIuaWRdO1xuICAgICAgICB9XG5cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgdGltZXIuZnVuYyA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICAgICAgdGltZXIuZnVuYy5hcHBseShudWxsLCB0aW1lci5hcmdzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZXZhbCh0aW1lci5mdW5jKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgZXhjZXB0aW9uID0gZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2xvY2sudGltZXJzW3RpbWVyLmlkXSkge1xuICAgICAgICAgICAgaWYgKGV4Y2VwdGlvbikge1xuICAgICAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChleGNlcHRpb24pIHtcbiAgICAgICAgICAgIHRocm93IGV4Y2VwdGlvbjtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHRpbWVyVHlwZSh0aW1lcikge1xuICAgICAgICBpZiAodGltZXIuaW1tZWRpYXRlKSB7XG4gICAgICAgICAgICByZXR1cm4gXCJJbW1lZGlhdGVcIjtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2YgdGltZXIuaW50ZXJ2YWwgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBcIkludGVydmFsXCI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gXCJUaW1lb3V0XCI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBjbGVhclRpbWVyKGNsb2NrLCB0aW1lcklkLCB0dHlwZSkge1xuICAgICAgICBpZiAoIXRpbWVySWQpIHtcbiAgICAgICAgICAgIC8vIG51bGwgYXBwZWFycyB0byBiZSBhbGxvd2VkIGluIG1vc3QgYnJvd3NlcnMsIGFuZCBhcHBlYXJzIHRvIGJlXG4gICAgICAgICAgICAvLyByZWxpZWQgdXBvbiBieSBzb21lIGxpYnJhcmllcywgbGlrZSBCb290c3RyYXAgY2Fyb3VzZWxcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghY2xvY2sudGltZXJzKSB7XG4gICAgICAgICAgICBjbG9jay50aW1lcnMgPSBbXTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGluIE5vZGUsIHRpbWVySWQgaXMgYW4gb2JqZWN0IHdpdGggLnJlZigpLy51bnJlZigpLCBhbmRcbiAgICAgICAgLy8gaXRzIC5pZCBmaWVsZCBpcyB0aGUgYWN0dWFsIHRpbWVyIGlkLlxuICAgICAgICBpZiAodHlwZW9mIHRpbWVySWQgPT09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHRpbWVySWQgPSB0aW1lcklkLmlkO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGNsb2NrLnRpbWVycy5oYXNPd25Qcm9wZXJ0eSh0aW1lcklkKSkge1xuICAgICAgICAgICAgLy8gY2hlY2sgdGhhdCB0aGUgSUQgbWF0Y2hlcyBhIHRpbWVyIG9mIHRoZSBjb3JyZWN0IHR5cGVcbiAgICAgICAgICAgIHZhciB0aW1lciA9IGNsb2NrLnRpbWVyc1t0aW1lcklkXTtcbiAgICAgICAgICAgIGlmICh0aW1lclR5cGUodGltZXIpID09PSB0dHlwZSkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBjbG9jay50aW1lcnNbdGltZXJJZF07XG4gICAgICAgICAgICB9IGVsc2Uge1xuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoXCJDYW5ub3QgY2xlYXIgdGltZXI6IHRpbWVyIGNyZWF0ZWQgd2l0aCBzZXRcIiArIHR0eXBlICsgXCIoKSBidXQgY2xlYXJlZCB3aXRoIGNsZWFyXCIgKyB0aW1lclR5cGUodGltZXIpICsgXCIoKVwiKTtcblx0XHRcdH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIHVuaW5zdGFsbChjbG9jaywgdGFyZ2V0KSB7XG4gICAgICAgIHZhciBtZXRob2QsXG4gICAgICAgICAgICBpLFxuICAgICAgICAgICAgbDtcblxuICAgICAgICBmb3IgKGkgPSAwLCBsID0gY2xvY2subWV0aG9kcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIG1ldGhvZCA9IGNsb2NrLm1ldGhvZHNbaV07XG5cbiAgICAgICAgICAgIGlmICh0YXJnZXRbbWV0aG9kXS5oYWRPd25Qcm9wZXJ0eSkge1xuICAgICAgICAgICAgICAgIHRhcmdldFttZXRob2RdID0gY2xvY2tbXCJfXCIgKyBtZXRob2RdO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGFyZ2V0W21ldGhvZF07XG4gICAgICAgICAgICAgICAgfSBjYXRjaCAoaWdub3JlKSB7fVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gUHJldmVudCBtdWx0aXBsZSBleGVjdXRpb25zIHdoaWNoIHdpbGwgY29tcGxldGVseSByZW1vdmUgdGhlc2UgcHJvcHNcbiAgICAgICAgY2xvY2subWV0aG9kcyA9IFtdO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGhpamFja01ldGhvZCh0YXJnZXQsIG1ldGhvZCwgY2xvY2spIHtcbiAgICAgICAgdmFyIHByb3A7XG5cbiAgICAgICAgY2xvY2tbbWV0aG9kXS5oYWRPd25Qcm9wZXJ0eSA9IE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh0YXJnZXQsIG1ldGhvZCk7XG4gICAgICAgIGNsb2NrW1wiX1wiICsgbWV0aG9kXSA9IHRhcmdldFttZXRob2RdO1xuXG4gICAgICAgIGlmIChtZXRob2QgPT09IFwiRGF0ZVwiKSB7XG4gICAgICAgICAgICB2YXIgZGF0ZSA9IG1pcnJvckRhdGVQcm9wZXJ0aWVzKGNsb2NrW21ldGhvZF0sIHRhcmdldFttZXRob2RdKTtcbiAgICAgICAgICAgIHRhcmdldFttZXRob2RdID0gZGF0ZTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRhcmdldFttZXRob2RdID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBjbG9ja1ttZXRob2RdLmFwcGx5KGNsb2NrLCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgZm9yIChwcm9wIGluIGNsb2NrW21ldGhvZF0pIHtcbiAgICAgICAgICAgICAgICBpZiAoY2xvY2tbbWV0aG9kXS5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgICAgICAgICB0YXJnZXRbbWV0aG9kXVtwcm9wXSA9IGNsb2NrW21ldGhvZF1bcHJvcF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgdGFyZ2V0W21ldGhvZF0uY2xvY2sgPSBjbG9jaztcbiAgICB9XG5cbiAgICB2YXIgdGltZXJzID0ge1xuICAgICAgICBzZXRUaW1lb3V0OiBzZXRUaW1lb3V0LFxuICAgICAgICBjbGVhclRpbWVvdXQ6IGNsZWFyVGltZW91dCxcbiAgICAgICAgc2V0SW1tZWRpYXRlOiBnbG9iYWwuc2V0SW1tZWRpYXRlLFxuICAgICAgICBjbGVhckltbWVkaWF0ZTogZ2xvYmFsLmNsZWFySW1tZWRpYXRlLFxuICAgICAgICBzZXRJbnRlcnZhbDogc2V0SW50ZXJ2YWwsXG4gICAgICAgIGNsZWFySW50ZXJ2YWw6IGNsZWFySW50ZXJ2YWwsXG4gICAgICAgIERhdGU6IERhdGVcbiAgICB9O1xuXG4gICAgdmFyIGtleXMgPSBPYmplY3Qua2V5cyB8fCBmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgIHZhciBrcyA9IFtdLFxuICAgICAgICAgICAga2V5O1xuXG4gICAgICAgIGZvciAoa2V5IGluIG9iaikge1xuICAgICAgICAgICAgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShrZXkpKSB7XG4gICAgICAgICAgICAgICAga3MucHVzaChrZXkpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGtzO1xuICAgIH07XG5cbiAgICBleHBvcnRzLnRpbWVycyA9IHRpbWVycztcblxuICAgIGZ1bmN0aW9uIGNyZWF0ZUNsb2NrKG5vdykge1xuICAgICAgICB2YXIgY2xvY2sgPSB7XG4gICAgICAgICAgICBub3c6IGdldEVwb2NoKG5vdyksXG4gICAgICAgICAgICB0aW1lb3V0czoge30sXG4gICAgICAgICAgICBEYXRlOiBjcmVhdGVEYXRlKClcbiAgICAgICAgfTtcblxuICAgICAgICBjbG9jay5EYXRlLmNsb2NrID0gY2xvY2s7XG5cbiAgICAgICAgY2xvY2suc2V0VGltZW91dCA9IGZ1bmN0aW9uIHNldFRpbWVvdXQoZnVuYywgdGltZW91dCkge1xuICAgICAgICAgICAgcmV0dXJuIGFkZFRpbWVyKGNsb2NrLCB7XG4gICAgICAgICAgICAgICAgZnVuYzogZnVuYyxcbiAgICAgICAgICAgICAgICBhcmdzOiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpLFxuICAgICAgICAgICAgICAgIGRlbGF5OiB0aW1lb3V0XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBjbG9jay5jbGVhclRpbWVvdXQgPSBmdW5jdGlvbiBjbGVhclRpbWVvdXQodGltZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsZWFyVGltZXIoY2xvY2ssIHRpbWVySWQsIFwiVGltZW91dFwiKTtcbiAgICAgICAgfTtcblxuICAgICAgICBjbG9jay5zZXRJbnRlcnZhbCA9IGZ1bmN0aW9uIHNldEludGVydmFsKGZ1bmMsIHRpbWVvdXQpIHtcbiAgICAgICAgICAgIHJldHVybiBhZGRUaW1lcihjbG9jaywge1xuICAgICAgICAgICAgICAgIGZ1bmM6IGZ1bmMsXG4gICAgICAgICAgICAgICAgYXJnczogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKSxcbiAgICAgICAgICAgICAgICBkZWxheTogdGltZW91dCxcbiAgICAgICAgICAgICAgICBpbnRlcnZhbDogdGltZW91dFxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgY2xvY2suY2xlYXJJbnRlcnZhbCA9IGZ1bmN0aW9uIGNsZWFySW50ZXJ2YWwodGltZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsZWFyVGltZXIoY2xvY2ssIHRpbWVySWQsIFwiSW50ZXJ2YWxcIik7XG4gICAgICAgIH07XG5cbiAgICAgICAgY2xvY2suc2V0SW1tZWRpYXRlID0gZnVuY3Rpb24gc2V0SW1tZWRpYXRlKGZ1bmMpIHtcbiAgICAgICAgICAgIHJldHVybiBhZGRUaW1lcihjbG9jaywge1xuICAgICAgICAgICAgICAgIGZ1bmM6IGZ1bmMsXG4gICAgICAgICAgICAgICAgYXJnczogQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSxcbiAgICAgICAgICAgICAgICBpbW1lZGlhdGU6IHRydWVcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNsb2NrLmNsZWFySW1tZWRpYXRlID0gZnVuY3Rpb24gY2xlYXJJbW1lZGlhdGUodGltZXJJZCkge1xuICAgICAgICAgICAgcmV0dXJuIGNsZWFyVGltZXIoY2xvY2ssIHRpbWVySWQsIFwiSW1tZWRpYXRlXCIpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGNsb2NrLnRpY2sgPSBmdW5jdGlvbiB0aWNrKG1zKSB7XG4gICAgICAgICAgICBtcyA9IHR5cGVvZiBtcyA9PT0gXCJudW1iZXJcIiA/IG1zIDogcGFyc2VUaW1lKG1zKTtcbiAgICAgICAgICAgIHZhciB0aWNrRnJvbSA9IGNsb2NrLm5vdywgdGlja1RvID0gY2xvY2subm93ICsgbXMsIHByZXZpb3VzID0gY2xvY2subm93O1xuICAgICAgICAgICAgdmFyIHRpbWVyID0gZmlyc3RUaW1lckluUmFuZ2UoY2xvY2ssIHRpY2tGcm9tLCB0aWNrVG8pO1xuICAgICAgICAgICAgdmFyIG9sZE5vdztcblxuICAgICAgICAgICAgY2xvY2suZHVyaW5nVGljayA9IHRydWU7XG5cbiAgICAgICAgICAgIHZhciBmaXJzdEV4Y2VwdGlvbjtcbiAgICAgICAgICAgIHdoaWxlICh0aW1lciAmJiB0aWNrRnJvbSA8PSB0aWNrVG8pIHtcbiAgICAgICAgICAgICAgICBpZiAoY2xvY2sudGltZXJzW3RpbWVyLmlkXSkge1xuICAgICAgICAgICAgICAgICAgICB0aWNrRnJvbSA9IGNsb2NrLm5vdyA9IHRpbWVyLmNhbGxBdDtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9sZE5vdyA9IGNsb2NrLm5vdztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxUaW1lcihjbG9jaywgdGltZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29tcGVuc2F0ZSBmb3IgYW55IHNldFN5c3RlbVRpbWUoKSBjYWxsIGR1cmluZyB0aW1lciBjYWxsYmFja1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9sZE5vdyAhPT0gY2xvY2subm93KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlja0Zyb20gKz0gY2xvY2subm93IC0gb2xkTm93O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRpY2tUbyArPSBjbG9jay5ub3cgLSBvbGROb3c7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcHJldmlvdXMgKz0gY2xvY2subm93IC0gb2xkTm93O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaXJzdEV4Y2VwdGlvbiA9IGZpcnN0RXhjZXB0aW9uIHx8IGU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB0aW1lciA9IGZpcnN0VGltZXJJblJhbmdlKGNsb2NrLCBwcmV2aW91cywgdGlja1RvKTtcbiAgICAgICAgICAgICAgICBwcmV2aW91cyA9IHRpY2tGcm9tO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBjbG9jay5kdXJpbmdUaWNrID0gZmFsc2U7XG4gICAgICAgICAgICBjbG9jay5ub3cgPSB0aWNrVG87XG5cbiAgICAgICAgICAgIGlmIChmaXJzdEV4Y2VwdGlvbikge1xuICAgICAgICAgICAgICAgIHRocm93IGZpcnN0RXhjZXB0aW9uO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gY2xvY2subm93O1xuICAgICAgICB9O1xuXG4gICAgICAgIGNsb2NrLnJlc2V0ID0gZnVuY3Rpb24gcmVzZXQoKSB7XG4gICAgICAgICAgICBjbG9jay50aW1lcnMgPSB7fTtcbiAgICAgICAgfTtcblxuICAgICAgICBjbG9jay5zZXRTeXN0ZW1UaW1lID0gZnVuY3Rpb24gc2V0U3lzdGVtVGltZShub3cpIHtcbiAgICAgICAgICAgIC8vIGRldGVybWluZSB0aW1lIGRpZmZlcmVuY2VcbiAgICAgICAgICAgIHZhciBuZXdOb3cgPSBnZXRFcG9jaChub3cpO1xuICAgICAgICAgICAgdmFyIGRpZmZlcmVuY2UgPSBuZXdOb3cgLSBjbG9jay5ub3c7XG5cbiAgICAgICAgICAgIC8vIHVwZGF0ZSAnc3lzdGVtIGNsb2NrJ1xuICAgICAgICAgICAgY2xvY2subm93ID0gbmV3Tm93O1xuXG4gICAgICAgICAgICAvLyB1cGRhdGUgdGltZXJzIGFuZCBpbnRlcnZhbHMgdG8ga2VlcCB0aGVtIHN0YWJsZVxuICAgICAgICAgICAgZm9yICh2YXIgaWQgaW4gY2xvY2sudGltZXJzKSB7XG4gICAgICAgICAgICAgICAgaWYgKGNsb2NrLnRpbWVycy5oYXNPd25Qcm9wZXJ0eShpZCkpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRpbWVyID0gY2xvY2sudGltZXJzW2lkXTtcbiAgICAgICAgICAgICAgICAgICAgdGltZXIuY3JlYXRlZEF0ICs9IGRpZmZlcmVuY2U7XG4gICAgICAgICAgICAgICAgICAgIHRpbWVyLmNhbGxBdCArPSBkaWZmZXJlbmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gY2xvY2s7XG4gICAgfVxuICAgIGV4cG9ydHMuY3JlYXRlQ2xvY2sgPSBjcmVhdGVDbG9jaztcblxuICAgIGV4cG9ydHMuaW5zdGFsbCA9IGZ1bmN0aW9uIGluc3RhbGwodGFyZ2V0LCBub3csIHRvRmFrZSkge1xuICAgICAgICB2YXIgaSxcbiAgICAgICAgICAgIGw7XG5cbiAgICAgICAgaWYgKHR5cGVvZiB0YXJnZXQgPT09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICAgIHRvRmFrZSA9IG5vdztcbiAgICAgICAgICAgIG5vdyA9IHRhcmdldDtcbiAgICAgICAgICAgIHRhcmdldCA9IG51bGw7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIXRhcmdldCkge1xuICAgICAgICAgICAgdGFyZ2V0ID0gZ2xvYmFsO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGNsb2NrID0gY3JlYXRlQ2xvY2sobm93KTtcblxuICAgICAgICBjbG9jay51bmluc3RhbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB1bmluc3RhbGwoY2xvY2ssIHRhcmdldCk7XG4gICAgICAgIH07XG5cbiAgICAgICAgY2xvY2subWV0aG9kcyA9IHRvRmFrZSB8fCBbXTtcblxuICAgICAgICBpZiAoY2xvY2subWV0aG9kcy5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgIGNsb2NrLm1ldGhvZHMgPSBrZXlzKHRpbWVycyk7XG4gICAgICAgIH1cblxuICAgICAgICBmb3IgKGkgPSAwLCBsID0gY2xvY2subWV0aG9kcy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIGhpamFja01ldGhvZCh0YXJnZXQsIGNsb2NrLm1ldGhvZHNbaV0sIGNsb2NrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjbG9jaztcbiAgICB9O1xuXG59KGdsb2JhbCB8fCB0aGlzKSk7XG4iLCIoKHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kICYmIGZ1bmN0aW9uIChtKSB7IGRlZmluZShcInNhbXNhbVwiLCBtKTsgfSkgfHxcbiAodHlwZW9mIG1vZHVsZSA9PT0gXCJvYmplY3RcIiAmJlxuICAgICAgZnVuY3Rpb24gKG0pIHsgbW9kdWxlLmV4cG9ydHMgPSBtKCk7IH0pIHx8IC8vIE5vZGVcbiBmdW5jdGlvbiAobSkgeyB0aGlzLnNhbXNhbSA9IG0oKTsgfSAvLyBCcm93c2VyIGdsb2JhbHNcbikoZnVuY3Rpb24gKCkge1xuICAgIHZhciBvID0gT2JqZWN0LnByb3RvdHlwZTtcbiAgICB2YXIgZGl2ID0gdHlwZW9mIGRvY3VtZW50ICE9PSBcInVuZGVmaW5lZFwiICYmIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJkaXZcIik7XG5cbiAgICBmdW5jdGlvbiBpc05hTih2YWx1ZSkge1xuICAgICAgICAvLyBVbmxpa2UgZ2xvYmFsIGlzTmFOLCB0aGlzIGF2b2lkcyB0eXBlIGNvZXJjaW9uXG4gICAgICAgIC8vIHR5cGVvZiBjaGVjayBhdm9pZHMgSUUgaG9zdCBvYmplY3QgaXNzdWVzLCBoYXQgdGlwIHRvXG4gICAgICAgIC8vIGxvZGFzaFxuICAgICAgICB2YXIgdmFsID0gdmFsdWU7IC8vIEpzTGludCB0aGlua3MgdmFsdWUgIT09IHZhbHVlIGlzIFwid2VpcmRcIlxuICAgICAgICByZXR1cm4gdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiICYmIHZhbHVlICE9PSB2YWw7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZ2V0Q2xhc3ModmFsdWUpIHtcbiAgICAgICAgLy8gUmV0dXJucyB0aGUgaW50ZXJuYWwgW1tDbGFzc11dIGJ5IGNhbGxpbmcgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZ1xuICAgICAgICAvLyB3aXRoIHRoZSBwcm92aWRlZCB2YWx1ZSBhcyB0aGlzLiBSZXR1cm4gdmFsdWUgaXMgYSBzdHJpbmcsIG5hbWluZyB0aGVcbiAgICAgICAgLy8gaW50ZXJuYWwgY2xhc3MsIGUuZy4gXCJBcnJheVwiXG4gICAgICAgIHJldHVybiBvLnRvU3RyaW5nLmNhbGwodmFsdWUpLnNwbGl0KC9bIFxcXV0vKVsxXTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0uaXNBcmd1bWVudHNcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iamVjdFxuICAgICAqXG4gICAgICogUmV0dXJucyBgYHRydWVgYCBpZiBgYG9iamVjdGBgIGlzIGFuIGBgYXJndW1lbnRzYGAgb2JqZWN0LFxuICAgICAqIGBgZmFsc2VgYCBvdGhlcndpc2UuXG4gICAgICovXG4gICAgZnVuY3Rpb24gaXNBcmd1bWVudHMob2JqZWN0KSB7XG4gICAgICAgIGlmIChnZXRDbGFzcyhvYmplY3QpID09PSAnQXJndW1lbnRzJykgeyByZXR1cm4gdHJ1ZTsgfVxuICAgICAgICBpZiAodHlwZW9mIG9iamVjdCAhPT0gXCJvYmplY3RcIiB8fCB0eXBlb2Ygb2JqZWN0Lmxlbmd0aCAhPT0gXCJudW1iZXJcIiB8fFxuICAgICAgICAgICAgICAgIGdldENsYXNzKG9iamVjdCkgPT09IFwiQXJyYXlcIikge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0eXBlb2Ygb2JqZWN0LmNhbGxlZSA9PSBcImZ1bmN0aW9uXCIpIHsgcmV0dXJuIHRydWU7IH1cbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgIG9iamVjdFtvYmplY3QubGVuZ3RoXSA9IDY7XG4gICAgICAgICAgICBkZWxldGUgb2JqZWN0W29iamVjdC5sZW5ndGhdO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG5hbWUgc2Ftc2FtLmlzRWxlbWVudFxuICAgICAqIEBwYXJhbSBPYmplY3Qgb2JqZWN0XG4gICAgICpcbiAgICAgKiBSZXR1cm5zIGBgdHJ1ZWBgIGlmIGBgb2JqZWN0YGAgaXMgYSBET00gZWxlbWVudCBub2RlLiBVbmxpa2VcbiAgICAgKiBVbmRlcnNjb3JlLmpzL2xvZGFzaCwgdGhpcyBmdW5jdGlvbiB3aWxsIHJldHVybiBgYGZhbHNlYGAgaWYgYGBvYmplY3RgYFxuICAgICAqIGlzIGFuICplbGVtZW50LWxpa2UqIG9iamVjdCwgaS5lLiBhIHJlZ3VsYXIgb2JqZWN0IHdpdGggYSBgYG5vZGVUeXBlYGBcbiAgICAgKiBwcm9wZXJ0eSB0aGF0IGhvbGRzIHRoZSB2YWx1ZSBgYDFgYC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0VsZW1lbnQob2JqZWN0KSB7XG4gICAgICAgIGlmICghb2JqZWN0IHx8IG9iamVjdC5ub2RlVHlwZSAhPT0gMSB8fCAhZGl2KSB7IHJldHVybiBmYWxzZTsgfVxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgb2JqZWN0LmFwcGVuZENoaWxkKGRpdik7XG4gICAgICAgICAgICBvYmplY3QucmVtb3ZlQ2hpbGQoZGl2KTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5rZXlzXG4gICAgICogQHBhcmFtIE9iamVjdCBvYmplY3RcbiAgICAgKlxuICAgICAqIFJldHVybiBhbiBhcnJheSBvZiBvd24gcHJvcGVydHkgbmFtZXMuXG4gICAgICovXG4gICAgZnVuY3Rpb24ga2V5cyhvYmplY3QpIHtcbiAgICAgICAgdmFyIGtzID0gW10sIHByb3A7XG4gICAgICAgIGZvciAocHJvcCBpbiBvYmplY3QpIHtcbiAgICAgICAgICAgIGlmIChvLmhhc093blByb3BlcnR5LmNhbGwob2JqZWN0LCBwcm9wKSkgeyBrcy5wdXNoKHByb3ApOyB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGtzO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIEBuYW1lIHNhbXNhbS5pc0RhdGVcbiAgICAgKiBAcGFyYW0gT2JqZWN0IHZhbHVlXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIHRydWUgaWYgdGhlIG9iamVjdCBpcyBhIGBgRGF0ZWBgLCBvciAqZGF0ZS1saWtlKi4gRHVjayB0eXBpbmdcbiAgICAgKiBvZiBkYXRlIG9iamVjdHMgd29yayBieSBjaGVja2luZyB0aGF0IHRoZSBvYmplY3QgaGFzIGEgYGBnZXRUaW1lYGBcbiAgICAgKiBmdW5jdGlvbiB3aG9zZSByZXR1cm4gdmFsdWUgZXF1YWxzIHRoZSByZXR1cm4gdmFsdWUgZnJvbSB0aGUgb2JqZWN0J3NcbiAgICAgKiBgYHZhbHVlT2ZgYC5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiBpc0RhdGUodmFsdWUpIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiB2YWx1ZS5nZXRUaW1lID09IFwiZnVuY3Rpb25cIiAmJlxuICAgICAgICAgICAgdmFsdWUuZ2V0VGltZSgpID09IHZhbHVlLnZhbHVlT2YoKTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0uaXNOZWdaZXJvXG4gICAgICogQHBhcmFtIE9iamVjdCB2YWx1ZVxuICAgICAqXG4gICAgICogUmV0dXJucyBgYHRydWVgYCBpZiBgYHZhbHVlYGAgaXMgYGAtMGBgLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlzTmVnWmVybyh2YWx1ZSkge1xuICAgICAgICByZXR1cm4gdmFsdWUgPT09IDAgJiYgMSAvIHZhbHVlID09PSAtSW5maW5pdHk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogQG5hbWUgc2Ftc2FtLmVxdWFsXG4gICAgICogQHBhcmFtIE9iamVjdCBvYmoxXG4gICAgICogQHBhcmFtIE9iamVjdCBvYmoyXG4gICAgICpcbiAgICAgKiBSZXR1cm5zIGBgdHJ1ZWBgIGlmIHR3byBvYmplY3RzIGFyZSBzdHJpY3RseSBlcXVhbC4gQ29tcGFyZWQgdG9cbiAgICAgKiBgYD09PWBgIHRoZXJlIGFyZSB0d28gZXhjZXB0aW9uczpcbiAgICAgKlxuICAgICAqICAgLSBOYU4gaXMgY29uc2lkZXJlZCBlcXVhbCB0byBOYU5cbiAgICAgKiAgIC0gLTAgYW5kICswIGFyZSBub3QgY29uc2lkZXJlZCBlcXVhbFxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGlkZW50aWNhbChvYmoxLCBvYmoyKSB7XG4gICAgICAgIGlmIChvYmoxID09PSBvYmoyIHx8IChpc05hTihvYmoxKSAmJiBpc05hTihvYmoyKSkpIHtcbiAgICAgICAgICAgIHJldHVybiBvYmoxICE9PSAwIHx8IGlzTmVnWmVybyhvYmoxKSA9PT0gaXNOZWdaZXJvKG9iajIpO1xuICAgICAgICB9XG4gICAgfVxuXG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0uZGVlcEVxdWFsXG4gICAgICogQHBhcmFtIE9iamVjdCBvYmoxXG4gICAgICogQHBhcmFtIE9iamVjdCBvYmoyXG4gICAgICpcbiAgICAgKiBEZWVwIGVxdWFsIGNvbXBhcmlzb24uIFR3byB2YWx1ZXMgYXJlIFwiZGVlcCBlcXVhbFwiIGlmOlxuICAgICAqXG4gICAgICogICAtIFRoZXkgYXJlIGVxdWFsLCBhY2NvcmRpbmcgdG8gc2Ftc2FtLmlkZW50aWNhbFxuICAgICAqICAgLSBUaGV5IGFyZSBib3RoIGRhdGUgb2JqZWN0cyByZXByZXNlbnRpbmcgdGhlIHNhbWUgdGltZVxuICAgICAqICAgLSBUaGV5IGFyZSBib3RoIGFycmF5cyBjb250YWluaW5nIGVsZW1lbnRzIHRoYXQgYXJlIGFsbCBkZWVwRXF1YWxcbiAgICAgKiAgIC0gVGhleSBhcmUgb2JqZWN0cyB3aXRoIHRoZSBzYW1lIHNldCBvZiBwcm9wZXJ0aWVzLCBhbmQgZWFjaCBwcm9wZXJ0eVxuICAgICAqICAgICBpbiBgYG9iajFgYCBpcyBkZWVwRXF1YWwgdG8gdGhlIGNvcnJlc3BvbmRpbmcgcHJvcGVydHkgaW4gYGBvYmoyYGBcbiAgICAgKlxuICAgICAqIFN1cHBvcnRzIGN5Y2xpYyBvYmplY3RzLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGRlZXBFcXVhbEN5Y2xpYyhvYmoxLCBvYmoyKSB7XG5cbiAgICAgICAgLy8gdXNlZCBmb3IgY3ljbGljIGNvbXBhcmlzb25cbiAgICAgICAgLy8gY29udGFpbiBhbHJlYWR5IHZpc2l0ZWQgb2JqZWN0c1xuICAgICAgICB2YXIgb2JqZWN0czEgPSBbXSxcbiAgICAgICAgICAgIG9iamVjdHMyID0gW10sXG4gICAgICAgIC8vIGNvbnRhaW4gcGF0aGVzIChwb3NpdGlvbiBpbiB0aGUgb2JqZWN0IHN0cnVjdHVyZSlcbiAgICAgICAgLy8gb2YgdGhlIGFscmVhZHkgdmlzaXRlZCBvYmplY3RzXG4gICAgICAgIC8vIGluZGV4ZXMgc2FtZSBhcyBpbiBvYmplY3RzIGFycmF5c1xuICAgICAgICAgICAgcGF0aHMxID0gW10sXG4gICAgICAgICAgICBwYXRoczIgPSBbXSxcbiAgICAgICAgLy8gY29udGFpbnMgY29tYmluYXRpb25zIG9mIGFscmVhZHkgY29tcGFyZWQgb2JqZWN0c1xuICAgICAgICAvLyBpbiB0aGUgbWFubmVyOiB7IFwiJDFbJ3JlZiddJDJbJ3JlZiddXCI6IHRydWUgfVxuICAgICAgICAgICAgY29tcGFyZWQgPSB7fTtcblxuICAgICAgICAvKipcbiAgICAgICAgICogdXNlZCB0byBjaGVjaywgaWYgdGhlIHZhbHVlIG9mIGEgcHJvcGVydHkgaXMgYW4gb2JqZWN0XG4gICAgICAgICAqIChjeWNsaWMgbG9naWMgaXMgb25seSBuZWVkZWQgZm9yIG9iamVjdHMpXG4gICAgICAgICAqIG9ubHkgbmVlZGVkIGZvciBjeWNsaWMgbG9naWNcbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIGlzT2JqZWN0KHZhbHVlKSB7XG5cbiAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmIHZhbHVlICE9PSBudWxsICYmXG4gICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBCb29sZWFuKSAmJlxuICAgICAgICAgICAgICAgICAgICAhKHZhbHVlIGluc3RhbmNlb2YgRGF0ZSkgICAgJiZcbiAgICAgICAgICAgICAgICAgICAgISh2YWx1ZSBpbnN0YW5jZW9mIE51bWJlcikgICYmXG4gICAgICAgICAgICAgICAgICAgICEodmFsdWUgaW5zdGFuY2VvZiBSZWdFeHApICAmJlxuICAgICAgICAgICAgICAgICAgICAhKHZhbHVlIGluc3RhbmNlb2YgU3RyaW5nKSkge1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8qKlxuICAgICAgICAgKiByZXR1cm5zIHRoZSBpbmRleCBvZiB0aGUgZ2l2ZW4gb2JqZWN0IGluIHRoZVxuICAgICAgICAgKiBnaXZlbiBvYmplY3RzIGFycmF5LCAtMSBpZiBub3QgY29udGFpbmVkXG4gICAgICAgICAqIG9ubHkgbmVlZGVkIGZvciBjeWNsaWMgbG9naWNcbiAgICAgICAgICovXG4gICAgICAgIGZ1bmN0aW9uIGdldEluZGV4KG9iamVjdHMsIG9iaikge1xuXG4gICAgICAgICAgICB2YXIgaTtcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCBvYmplY3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9iamVjdHNbaV0gPT09IG9iaikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiAtMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGRvZXMgdGhlIHJlY3Vyc2lvbiBmb3IgdGhlIGRlZXAgZXF1YWwgY2hlY2tcbiAgICAgICAgcmV0dXJuIChmdW5jdGlvbiBkZWVwRXF1YWwob2JqMSwgb2JqMiwgcGF0aDEsIHBhdGgyKSB7XG4gICAgICAgICAgICB2YXIgdHlwZTEgPSB0eXBlb2Ygb2JqMTtcbiAgICAgICAgICAgIHZhciB0eXBlMiA9IHR5cGVvZiBvYmoyO1xuXG4gICAgICAgICAgICAvLyA9PSBudWxsIGFsc28gbWF0Y2hlcyB1bmRlZmluZWRcbiAgICAgICAgICAgIGlmIChvYmoxID09PSBvYmoyIHx8XG4gICAgICAgICAgICAgICAgICAgIGlzTmFOKG9iajEpIHx8IGlzTmFOKG9iajIpIHx8XG4gICAgICAgICAgICAgICAgICAgIG9iajEgPT0gbnVsbCB8fCBvYmoyID09IG51bGwgfHxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTEgIT09IFwib2JqZWN0XCIgfHwgdHlwZTIgIT09IFwib2JqZWN0XCIpIHtcblxuICAgICAgICAgICAgICAgIHJldHVybiBpZGVudGljYWwob2JqMSwgb2JqMik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEVsZW1lbnRzIGFyZSBvbmx5IGVxdWFsIGlmIGlkZW50aWNhbChleHBlY3RlZCwgYWN0dWFsKVxuICAgICAgICAgICAgaWYgKGlzRWxlbWVudChvYmoxKSB8fCBpc0VsZW1lbnQob2JqMikpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgICAgICAgICAgIHZhciBpc0RhdGUxID0gaXNEYXRlKG9iajEpLCBpc0RhdGUyID0gaXNEYXRlKG9iajIpO1xuICAgICAgICAgICAgaWYgKGlzRGF0ZTEgfHwgaXNEYXRlMikge1xuICAgICAgICAgICAgICAgIGlmICghaXNEYXRlMSB8fCAhaXNEYXRlMiB8fCBvYmoxLmdldFRpbWUoKSAhPT0gb2JqMi5nZXRUaW1lKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG9iajEgaW5zdGFuY2VvZiBSZWdFeHAgJiYgb2JqMiBpbnN0YW5jZW9mIFJlZ0V4cCkge1xuICAgICAgICAgICAgICAgIGlmIChvYmoxLnRvU3RyaW5nKCkgIT09IG9iajIudG9TdHJpbmcoKSkgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGNsYXNzMSA9IGdldENsYXNzKG9iajEpO1xuICAgICAgICAgICAgdmFyIGNsYXNzMiA9IGdldENsYXNzKG9iajIpO1xuICAgICAgICAgICAgdmFyIGtleXMxID0ga2V5cyhvYmoxKTtcbiAgICAgICAgICAgIHZhciBrZXlzMiA9IGtleXMob2JqMik7XG5cbiAgICAgICAgICAgIGlmIChpc0FyZ3VtZW50cyhvYmoxKSB8fCBpc0FyZ3VtZW50cyhvYmoyKSkge1xuICAgICAgICAgICAgICAgIGlmIChvYmoxLmxlbmd0aCAhPT0gb2JqMi5sZW5ndGgpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlMSAhPT0gdHlwZTIgfHwgY2xhc3MxICE9PSBjbGFzczIgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIGtleXMxLmxlbmd0aCAhPT0ga2V5czIubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBrZXksIGksIGwsXG4gICAgICAgICAgICAgICAgLy8gZm9sbG93aW5nIHZhcnMgYXJlIHVzZWQgZm9yIHRoZSBjeWNsaWMgbG9naWNcbiAgICAgICAgICAgICAgICB2YWx1ZTEsIHZhbHVlMixcbiAgICAgICAgICAgICAgICBpc09iamVjdDEsIGlzT2JqZWN0MixcbiAgICAgICAgICAgICAgICBpbmRleDEsIGluZGV4MixcbiAgICAgICAgICAgICAgICBuZXdQYXRoMSwgbmV3UGF0aDI7XG5cbiAgICAgICAgICAgIGZvciAoaSA9IDAsIGwgPSBrZXlzMS5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBrZXlzMVtpXTtcbiAgICAgICAgICAgICAgICBpZiAoIW8uaGFzT3duUHJvcGVydHkuY2FsbChvYmoyLCBrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAvLyBTdGFydCBvZiB0aGUgY3ljbGljIGxvZ2ljXG5cbiAgICAgICAgICAgICAgICB2YWx1ZTEgPSBvYmoxW2tleV07XG4gICAgICAgICAgICAgICAgdmFsdWUyID0gb2JqMltrZXldO1xuXG4gICAgICAgICAgICAgICAgaXNPYmplY3QxID0gaXNPYmplY3QodmFsdWUxKTtcbiAgICAgICAgICAgICAgICBpc09iamVjdDIgPSBpc09iamVjdCh2YWx1ZTIpO1xuXG4gICAgICAgICAgICAgICAgLy8gZGV0ZXJtaW5lLCBpZiB0aGUgb2JqZWN0cyB3ZXJlIGFscmVhZHkgdmlzaXRlZFxuICAgICAgICAgICAgICAgIC8vIChpdCdzIGZhc3RlciB0byBjaGVjayBmb3IgaXNPYmplY3QgZmlyc3QsIHRoYW4gdG9cbiAgICAgICAgICAgICAgICAvLyBnZXQgLTEgZnJvbSBnZXRJbmRleCBmb3Igbm9uIG9iamVjdHMpXG4gICAgICAgICAgICAgICAgaW5kZXgxID0gaXNPYmplY3QxID8gZ2V0SW5kZXgob2JqZWN0czEsIHZhbHVlMSkgOiAtMTtcbiAgICAgICAgICAgICAgICBpbmRleDIgPSBpc09iamVjdDIgPyBnZXRJbmRleChvYmplY3RzMiwgdmFsdWUyKSA6IC0xO1xuXG4gICAgICAgICAgICAgICAgLy8gZGV0ZXJtaW5lIHRoZSBuZXcgcGF0aGVzIG9mIHRoZSBvYmplY3RzXG4gICAgICAgICAgICAgICAgLy8gLSBmb3Igbm9uIGN5Y2xpYyBvYmplY3RzIHRoZSBjdXJyZW50IHBhdGggd2lsbCBiZSBleHRlbmRlZFxuICAgICAgICAgICAgICAgIC8vICAgYnkgY3VycmVudCBwcm9wZXJ0eSBuYW1lXG4gICAgICAgICAgICAgICAgLy8gLSBmb3IgY3ljbGljIG9iamVjdHMgdGhlIHN0b3JlZCBwYXRoIGlzIHRha2VuXG4gICAgICAgICAgICAgICAgbmV3UGF0aDEgPSBpbmRleDEgIT09IC0xXG4gICAgICAgICAgICAgICAgICAgID8gcGF0aHMxW2luZGV4MV1cbiAgICAgICAgICAgICAgICAgICAgOiBwYXRoMSArICdbJyArIEpTT04uc3RyaW5naWZ5KGtleSkgKyAnXSc7XG4gICAgICAgICAgICAgICAgbmV3UGF0aDIgPSBpbmRleDIgIT09IC0xXG4gICAgICAgICAgICAgICAgICAgID8gcGF0aHMyW2luZGV4Ml1cbiAgICAgICAgICAgICAgICAgICAgOiBwYXRoMiArICdbJyArIEpTT04uc3RyaW5naWZ5KGtleSkgKyAnXSc7XG5cbiAgICAgICAgICAgICAgICAvLyBzdG9wIHJlY3Vyc2lvbiBpZiBjdXJyZW50IG9iamVjdHMgYXJlIGFscmVhZHkgY29tcGFyZWRcbiAgICAgICAgICAgICAgICBpZiAoY29tcGFyZWRbbmV3UGF0aDEgKyBuZXdQYXRoMl0pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gcmVtZW1iZXIgdGhlIGN1cnJlbnQgb2JqZWN0cyBhbmQgdGhlaXIgcGF0aGVzXG4gICAgICAgICAgICAgICAgaWYgKGluZGV4MSA9PT0gLTEgJiYgaXNPYmplY3QxKSB7XG4gICAgICAgICAgICAgICAgICAgIG9iamVjdHMxLnB1c2godmFsdWUxKTtcbiAgICAgICAgICAgICAgICAgICAgcGF0aHMxLnB1c2gobmV3UGF0aDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAoaW5kZXgyID09PSAtMSAmJiBpc09iamVjdDIpIHtcbiAgICAgICAgICAgICAgICAgICAgb2JqZWN0czIucHVzaCh2YWx1ZTIpO1xuICAgICAgICAgICAgICAgICAgICBwYXRoczIucHVzaChuZXdQYXRoMik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gcmVtZW1iZXIgdGhhdCB0aGUgY3VycmVudCBvYmplY3RzIGFyZSBhbHJlYWR5IGNvbXBhcmVkXG4gICAgICAgICAgICAgICAgaWYgKGlzT2JqZWN0MSAmJiBpc09iamVjdDIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29tcGFyZWRbbmV3UGF0aDEgKyBuZXdQYXRoMl0gPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIC8vIEVuZCBvZiBjeWNsaWMgbG9naWNcblxuICAgICAgICAgICAgICAgIC8vIG5laXRoZXIgdmFsdWUxIG5vciB2YWx1ZTIgaXMgYSBjeWNsZVxuICAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIHdpdGggbmV4dCBsZXZlbFxuICAgICAgICAgICAgICAgIGlmICghZGVlcEVxdWFsKHZhbHVlMSwgdmFsdWUyLCBuZXdQYXRoMSwgbmV3UGF0aDIpKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuXG4gICAgICAgIH0ob2JqMSwgb2JqMiwgJyQxJywgJyQyJykpO1xuICAgIH1cblxuICAgIHZhciBtYXRjaDtcblxuICAgIGZ1bmN0aW9uIGFycmF5Q29udGFpbnMoYXJyYXksIHN1YnNldCkge1xuICAgICAgICBpZiAoc3Vic2V0Lmxlbmd0aCA9PT0gMCkgeyByZXR1cm4gdHJ1ZTsgfVxuICAgICAgICB2YXIgaSwgbCwgaiwgaztcbiAgICAgICAgZm9yIChpID0gMCwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7ICsraSkge1xuICAgICAgICAgICAgaWYgKG1hdGNoKGFycmF5W2ldLCBzdWJzZXRbMF0pKSB7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMCwgayA9IHN1YnNldC5sZW5ndGg7IGogPCBrOyArK2opIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFtYXRjaChhcnJheVtpICsgal0sIHN1YnNldFtqXSkpIHsgcmV0dXJuIGZhbHNlOyB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBAbmFtZSBzYW1zYW0ubWF0Y2hcbiAgICAgKiBAcGFyYW0gT2JqZWN0IG9iamVjdFxuICAgICAqIEBwYXJhbSBPYmplY3QgbWF0Y2hlclxuICAgICAqXG4gICAgICogQ29tcGFyZSBhcmJpdHJhcnkgdmFsdWUgYGBvYmplY3RgYCB3aXRoIG1hdGNoZXIuXG4gICAgICovXG4gICAgbWF0Y2ggPSBmdW5jdGlvbiBtYXRjaChvYmplY3QsIG1hdGNoZXIpIHtcbiAgICAgICAgaWYgKG1hdGNoZXIgJiYgdHlwZW9mIG1hdGNoZXIudGVzdCA9PT0gXCJmdW5jdGlvblwiKSB7XG4gICAgICAgICAgICByZXR1cm4gbWF0Y2hlci50ZXN0KG9iamVjdCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mIG1hdGNoZXIgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXIob2JqZWN0KSA9PT0gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgbWF0Y2hlciA9IG1hdGNoZXIudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgIHZhciBub3ROdWxsID0gdHlwZW9mIG9iamVjdCA9PT0gXCJzdHJpbmdcIiB8fCAhIW9iamVjdDtcbiAgICAgICAgICAgIHJldHVybiBub3ROdWxsICYmXG4gICAgICAgICAgICAgICAgKFN0cmluZyhvYmplY3QpKS50b0xvd2VyQ2FzZSgpLmluZGV4T2YobWF0Y2hlcikgPj0gMDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJudW1iZXJcIikge1xuICAgICAgICAgICAgcmV0dXJuIG1hdGNoZXIgPT09IG9iamVjdDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgbWF0Y2hlciA9PT0gXCJib29sZWFuXCIpIHtcbiAgICAgICAgICAgIHJldHVybiBtYXRjaGVyID09PSBvYmplY3Q7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodHlwZW9mKG1hdGNoZXIpID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAgICAgICByZXR1cm4gdHlwZW9mKG9iamVjdCkgPT09IFwidW5kZWZpbmVkXCI7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobWF0Y2hlciA9PT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuIG9iamVjdCA9PT0gbnVsbDtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChnZXRDbGFzcyhvYmplY3QpID09PSBcIkFycmF5XCIgJiYgZ2V0Q2xhc3MobWF0Y2hlcikgPT09IFwiQXJyYXlcIikge1xuICAgICAgICAgICAgcmV0dXJuIGFycmF5Q29udGFpbnMob2JqZWN0LCBtYXRjaGVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChtYXRjaGVyICYmIHR5cGVvZiBtYXRjaGVyID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICBpZiAobWF0Y2hlciA9PT0gb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgcHJvcDtcbiAgICAgICAgICAgIGZvciAocHJvcCBpbiBtYXRjaGVyKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gb2JqZWN0W3Byb3BdO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiBvYmplY3QuZ2V0QXR0cmlidXRlID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBvYmplY3QuZ2V0QXR0cmlidXRlKHByb3ApO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAobWF0Y2hlcltwcm9wXSA9PT0gbnVsbCB8fCB0eXBlb2YgbWF0Y2hlcltwcm9wXSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHZhbHVlICE9PSBtYXRjaGVyW3Byb3BdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHR5cGVvZiAgdmFsdWUgPT09IFwidW5kZWZpbmVkXCIgfHwgIW1hdGNoKHZhbHVlLCBtYXRjaGVyW3Byb3BdKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoXCJNYXRjaGVyIHdhcyBub3QgYSBzdHJpbmcsIGEgbnVtYmVyLCBhIFwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiZnVuY3Rpb24sIGEgYm9vbGVhbiBvciBhbiBvYmplY3RcIik7XG4gICAgfTtcblxuICAgIHJldHVybiB7XG4gICAgICAgIGlzQXJndW1lbnRzOiBpc0FyZ3VtZW50cyxcbiAgICAgICAgaXNFbGVtZW50OiBpc0VsZW1lbnQsXG4gICAgICAgIGlzRGF0ZTogaXNEYXRlLFxuICAgICAgICBpc05lZ1plcm86IGlzTmVnWmVybyxcbiAgICAgICAgaWRlbnRpY2FsOiBpZGVudGljYWwsXG4gICAgICAgIGRlZXBFcXVhbDogZGVlcEVxdWFsQ3ljbGljLFxuICAgICAgICBtYXRjaDogbWF0Y2gsXG4gICAgICAgIGtleXM6IGtleXNcbiAgICB9O1xufSk7XG4iLCIvKipcbiAqIFNpbm9uIGNvcmUgdXRpbGl0aWVzLiBGb3IgaW50ZXJuYWwgdXNlIG9ubHkuXG4gKlxuICogQGF1dGhvciBDaHJpc3RpYW4gSm9oYW5zZW4gKGNocmlzdGlhbkBjam9oYW5zZW4ubm8pXG4gKiBAbGljZW5zZSBCU0RcbiAqXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTAtMjAxMyBDaHJpc3RpYW4gSm9oYW5zZW5cbiAqL1xudmFyIHNpbm9uID0gKGZ1bmN0aW9uICgpIHsgLy8gZXNsaW50LWRpc2FibGUtbGluZSBuby11bnVzZWQtdmFyc1xuICAgIFwidXNlIHN0cmljdFwiO1xuXG4gICAgdmFyIHNpbm9uTW9kdWxlO1xuICAgIHZhciBpc05vZGUgPSB0eXBlb2YgbW9kdWxlICE9PSBcInVuZGVmaW5lZFwiICYmIG1vZHVsZS5leHBvcnRzICYmIHR5cGVvZiByZXF1aXJlID09PSBcImZ1bmN0aW9uXCI7XG4gICAgdmFyIGlzQU1EID0gdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIHR5cGVvZiBkZWZpbmUuYW1kID09PSBcIm9iamVjdFwiICYmIGRlZmluZS5hbWQ7XG5cbiAgICBmdW5jdGlvbiBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIGV4cG9ydHMsIG1vZHVsZSkge1xuICAgICAgICBzaW5vbk1vZHVsZSA9IG1vZHVsZS5leHBvcnRzID0gcmVxdWlyZShcIi4vc2lub24vdXRpbC9jb3JlXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9zaW5vbi9leHRlbmRcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL3dhbGtcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL3R5cGVPZlwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vdGltZXNfaW5fd29yZHNcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL3NweVwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vY2FsbFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vYmVoYXZpb3JcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL3N0dWJcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL21vY2tcIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL2NvbGxlY3Rpb25cIik7XG4gICAgICAgIHJlcXVpcmUoXCIuL3Npbm9uL2Fzc2VydFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vc2FuZGJveFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vdGVzdFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vdGVzdF9jYXNlXCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9zaW5vbi9tYXRjaFwiKTtcbiAgICAgICAgcmVxdWlyZShcIi4vc2lub24vZm9ybWF0XCIpO1xuICAgICAgICByZXF1aXJlKFwiLi9zaW5vbi9sb2dfZXJyb3JcIik7XG4gICAgfVxuXG4gICAgaWYgKGlzQU1EKSB7XG4gICAgICAgIGRlZmluZShsb2FkRGVwZW5kZW5jaWVzKTtcbiAgICB9IGVsc2UgaWYgKGlzTm9kZSkge1xuICAgICAgICBsb2FkRGVwZW5kZW5jaWVzKHJlcXVpcmUsIG1vZHVsZS5leHBvcnRzLCBtb2R1bGUpO1xuICAgICAgICBzaW5vbk1vZHVsZSA9IG1vZHVsZS5leHBvcnRzO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHNpbm9uTW9kdWxlID0ge307XG4gICAgfVxuXG4gICAgcmV0dXJuIHNpbm9uTW9kdWxlO1xufSgpKTtcbiJdfQ== | |
class Trend { | |
constructor(database) { | |
this.database = database; | |
} | |
create() { | |
console.log('create', this.database); | |
this.database.query(); | |
} | |
} | |
var sinon = require('sinon'); | |
var Database = {query:function(){}}; | |
var database_mock = sinon.mock(Database); | |
database_mock.expects("query").once(); | |
var trend = new Trend(Database); | |
trend.create(); | |
database_mock.verify(); | |
database_mock.restore(); | |
;}, 0) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{ | |
"name": "requirebin-sketch", | |
"version": "1.0.0", | |
"dependencies": { | |
"sinon": "1.17.7" | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- contents of this file will be placed inside the <body> --> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- 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