| Server IP : 85.158.181.41 / Your IP : 216.73.217.12 Web Server : Apache System : Linux cloud9-vm129 6.1.178+1-ph #ph SMP PREEMPT_DYNAMIC Wed Jul 29 09:00:54 UTC 2026 x86_64 User : moncbefd ( 1024) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/moncbefd/www.moneta.at/admin/html/assets/javascript/ |
Upload File : |
/*!
* jQuery Migrate - v1.4.1 - 2016-05-19
* Copyright jQuery Foundation and other contributors
*/
(function( jQuery, window, undefined ) {
// See http://bugs.jquery.com/ticket/13335
// "use strict";
jQuery.migrateVersion = "1.4.1";
var warnedAbout = {};
// List of warnings already given; public read only
jQuery.migrateWarnings = [];
// Set to true to prevent console output; migrateWarnings still maintained
// jQuery.migrateMute = false;
// Show a message on the console so devs know we're active
if ( window.console && window.console.log ) {
window.console.log( "JQMIGRATE: Migrate is installed" +
( jQuery.migrateMute ? "" : " with logging active" ) +
", version " + jQuery.migrateVersion );
}
// Set to false to disable traces that appear with warnings
if ( jQuery.migrateTrace === undefined ) {
jQuery.migrateTrace = true;
}
// Forget any warnings we've already given; public
jQuery.migrateReset = function() {
warnedAbout = {};
jQuery.migrateWarnings.length = 0;
};
function migrateWarn( msg) {
var console = window.console;
if ( !warnedAbout[ msg ] ) {
warnedAbout[ msg ] = true;
jQuery.migrateWarnings.push( msg );
if ( console && console.warn && !jQuery.migrateMute ) {
console.warn( "JQMIGRATE: " + msg );
if ( jQuery.migrateTrace && console.trace ) {
console.trace();
}
}
}
}
function migrateWarnProp( obj, prop, value, msg ) {
if ( Object.defineProperty ) {
// On ES5 browsers (non-oldIE), warn if the code tries to get prop;
// allow property to be overwritten in case some other plugin wants it
try {
Object.defineProperty( obj, prop, {
configurable: true,
enumerable: true,
get: function() {
migrateWarn( msg );
return value;
},
set: function( newValue ) {
migrateWarn( msg );
value = newValue;
}
});
return;
} catch( err ) {
// IE8 is a dope about Object.defineProperty, can't warn there
}
}
// Non-ES5 (or broken) browser; just set the property
jQuery._definePropertyBroken = true;
obj[ prop ] = value;
}
if ( document.compatMode === "BackCompat" ) {
// jQuery has never supported or tested Quirks Mode
migrateWarn( "jQuery is not compatible with Quirks Mode" );
}
var attrFn = jQuery( "<input/>", { size: 1 } ).attr("size") && jQuery.attrFn,
oldAttr = jQuery.attr,
valueAttrGet = jQuery.attrHooks.value && jQuery.attrHooks.value.get ||
function() { return null; },
valueAttrSet = jQuery.attrHooks.value && jQuery.attrHooks.value.set ||
function() { return undefined; },
rnoType = /^(?:input|button)$/i,
rnoAttrNodeType = /^[238]$/,
rboolean = /^(?:autofocus|autoplay|async|checked|controls|defer|disabled|hidden|loop|multiple|open|readonly|required|scoped|selected)$/i,
ruseDefault = /^(?:checked|selected)$/i;
// jQuery.attrFn
migrateWarnProp( jQuery, "attrFn", attrFn || {}, "jQuery.attrFn is deprecated" );
jQuery.attr = function( elem, name, value, pass ) {
var lowerName = name.toLowerCase(),
nType = elem && elem.nodeType;
if ( pass ) {
// Since pass is used internally, we only warn for new jQuery
// versions where there isn't a pass arg in the formal params
if ( oldAttr.length < 4 ) {
migrateWarn("jQuery.fn.attr( props, pass ) is deprecated");
}
if ( elem && !rnoAttrNodeType.test( nType ) &&
(attrFn ? name in attrFn : jQuery.isFunction(jQuery.fn[name])) ) {
return jQuery( elem )[ name ]( value );
}
}
// Warn if user tries to set `type`, since it breaks on IE 6/7/8; by checking
// for disconnected elements we don't warn on $( "<button>", { type: "button" } ).
if ( name === "type" && value !== undefined && rnoType.test( elem.nodeName ) && elem.parentNode ) {
migrateWarn("Can't change the 'type' of an input or button in IE 6/7/8");
}
// Restore boolHook for boolean property/attribute synchronization
if ( !jQuery.attrHooks[ lowerName ] && rboolean.test( lowerName ) ) {
jQuery.attrHooks[ lowerName ] = {
get: function( elem, name ) {
// Align boolean attributes with corresponding properties
// Fall back to attribute presence where some booleans are not supported
var attrNode,
property = jQuery.prop( elem, name );
return property === true || typeof property !== "boolean" &&
( attrNode = elem.getAttributeNode(name) ) && attrNode.nodeValue !== false ?
name.toLowerCase() :
undefined;
},
set: function( elem, value, name ) {
var propName;
if ( value === false ) {
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
} else {
// value is true since we know at this point it's type boolean and not false
// Set boolean attributes to the same name and set the DOM property
propName = jQuery.propFix[ name ] || name;
if ( propName in elem ) {
// Only set the IDL specifically if it already exists on the element
elem[ propName ] = true;
}
elem.setAttribute( name, name.toLowerCase() );
}
return name;
}
};
// Warn only for attributes that can remain distinct from their properties post-1.9
if ( ruseDefault.test( lowerName ) ) {
migrateWarn( "jQuery.fn.attr('" + lowerName + "') might use property instead of attribute" );
}
}
return oldAttr.call( jQuery, elem, name, value );
};
// attrHooks: value
jQuery.attrHooks.value = {
get: function( elem, name ) {
var nodeName = ( elem.nodeName || "" ).toLowerCase();
if ( nodeName === "button" ) {
return valueAttrGet.apply( this, arguments );
}
if ( nodeName !== "input" && nodeName !== "option" ) {
migrateWarn("jQuery.fn.attr('value') no longer gets properties");
}
return name in elem ?
elem.value :
null;
},
set: function( elem, value ) {
var nodeName = ( elem.nodeName || "" ).toLowerCase();
if ( nodeName === "button" ) {
return valueAttrSet.apply( this, arguments );
}
if ( nodeName !== "input" && nodeName !== "option" ) {
migrateWarn("jQuery.fn.attr('value', val) no longer sets properties");
}
// Does not return so that setAttribute is also used
elem.value = value;
}
};
var matched, browser,
oldInit = jQuery.fn.init,
oldFind = jQuery.find,
oldParseJSON = jQuery.parseJSON,
rspaceAngle = /^\s*</,
rattrHashTest = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/,
rattrHashGlob = /\[(\s*[-\w]+\s*)([~|^$*]?=)\s*([-\w#]*?#[-\w#]*)\s*\]/g,
// Note: XSS check is done below after string is trimmed
rquickExpr = /^([^<]*)(<[\w\W]+>)([^>]*)$/;
// $(html) "looks like html" rule change
jQuery.fn.init = function( selector, context, rootjQuery ) {
var match, ret;
if ( selector && typeof selector === "string" ) {
if ( !jQuery.isPlainObject( context ) &&
(match = rquickExpr.exec( jQuery.trim( selector ) )) && match[ 0 ] ) {
// This is an HTML string according to the "old" rules; is it still?
if ( !rspaceAngle.test( selector ) ) {
migrateWarn("$(html) HTML strings must start with '<' character");
}
if ( match[ 3 ] ) {
migrateWarn("$(html) HTML text after last tag is ignored");
}
// Consistently reject any HTML-like string starting with a hash (gh-9521)
// Note that this may break jQuery 1.6.x code that otherwise would work.
if ( match[ 0 ].charAt( 0 ) === "#" ) {
migrateWarn("HTML string cannot start with a '#' character");
jQuery.error("JQMIGRATE: Invalid selector string (XSS)");
}
// Now process using loose rules; let pre-1.8 play too
// Is this a jQuery context? parseHTML expects a DOM element (#178)
if ( context && context.context && context.context.nodeType ) {
context = context.context;
}
if ( jQuery.parseHTML ) {
return oldInit.call( this,
jQuery.parseHTML( match[ 2 ], context && context.ownerDocument ||
context || document, true ), context, rootjQuery );
}
}
}
ret = oldInit.apply( this, arguments );
// Fill in selector and context properties so .live() works
if ( selector && selector.selector !== undefined ) {
// A jQuery object, copy its properties
ret.selector = selector.selector;
ret.context = selector.context;
} else {
ret.selector = typeof selector === "string" ? selector : "";
if ( selector ) {
ret.context = selector.nodeType? selector : context || document;
}
}
return ret;
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.find = function( selector ) {
var args = Array.prototype.slice.call( arguments );
// Support: PhantomJS 1.x
// String#match fails to match when used with a //g RegExp, only on some strings
if ( typeof selector === "string" && rattrHashTest.test( selector ) ) {
// The nonstandard and undocumented unquoted-hash was removed in jQuery 1.12.0
// First see if qS thinks it's a valid selector, if so avoid a false positive
try {
document.querySelector( selector );
} catch ( err1 ) {
// Didn't *look* valid to qSA, warn and try quoting what we think is the value
selector = selector.replace( rattrHashGlob, function( _, attr, op, value ) {
return "[" + attr + op + "\"" + value + "\"]";
} );
// If the regexp *may* have created an invalid selector, don't update it
// Note that there may be false alarms if selector uses jQuery extensions
try {
document.querySelector( selector );
migrateWarn( "Attribute selector with '#' must be quoted: " + args[ 0 ] );
args[ 0 ] = selector;
} catch ( err2 ) {
migrateWarn( "Attribute selector with '#' was not fixed: " + args[ 0 ] );
}
}
}
return oldFind.apply( this, args );
};
// Copy properties attached to original jQuery.find method (e.g. .attr, .isXML)
var findProp;
for ( findProp in oldFind ) {
if ( Object.prototype.hasOwnProperty.call( oldFind, findProp ) ) {
jQuery.find[ findProp ] = oldFind[ findProp ];
}
}
// Let $.parseJSON(falsy_value) return null
jQuery.parseJSON = function( json ) {
if ( !json ) {
migrateWarn("jQuery.parseJSON requires a valid JSON string");
return null;
}
return oldParseJSON.apply( this, arguments );
};
jQuery.uaMatch = function( ua ) {
ua = ua.toLowerCase();
var match = /(chrome)[ \/]([\w.]+)/.exec( ua ) ||
/(webkit)[ \/]([\w.]+)/.exec( ua ) ||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec( ua ) ||
/(msie) ([\w.]+)/.exec( ua ) ||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec( ua ) ||
[];
return {
browser: match[ 1 ] || "",
version: match[ 2 ] || "0"
};
};
// Don't clobber any existing jQuery.browser in case it's different
if ( !jQuery.browser ) {
matched = jQuery.uaMatch( navigator.userAgent );
browser = {};
if ( matched.browser ) {
browser[ matched.browser ] = true;
browser.version = matched.version;
}
// Chrome is Webkit, but Webkit is also Safari.
if ( browser.chrome ) {
browser.webkit = true;
} else if ( browser.webkit ) {
browser.safari = true;
}
jQuery.browser = browser;
}
// Warn if the code tries to get jQuery.browser
migrateWarnProp( jQuery, "browser", jQuery.browser, "jQuery.browser is deprecated" );
// jQuery.boxModel deprecated in 1.3, jQuery.support.boxModel deprecated in 1.7
jQuery.boxModel = jQuery.support.boxModel = (document.compatMode === "CSS1Compat");
migrateWarnProp( jQuery, "boxModel", jQuery.boxModel, "jQuery.boxModel is deprecated" );
migrateWarnProp( jQuery.support, "boxModel", jQuery.support.boxModel, "jQuery.support.boxModel is deprecated" );
jQuery.sub = function() {
function jQuerySub( selector, context ) {
return new jQuerySub.fn.init( selector, context );
}
jQuery.extend( true, jQuerySub, this );
jQuerySub.superclass = this;
jQuerySub.fn = jQuerySub.prototype = this();
jQuerySub.fn.constructor = jQuerySub;
jQuerySub.sub = this.sub;
jQuerySub.fn.init = function init( selector, context ) {
var instance = jQuery.fn.init.call( this, selector, context, rootjQuerySub );
return instance instanceof jQuerySub ?
instance :
jQuerySub( instance );
};
jQuerySub.fn.init.prototype = jQuerySub.fn;
var rootjQuerySub = jQuerySub(document);
migrateWarn( "jQuery.sub() is deprecated" );
return jQuerySub;
};
// The number of elements contained in the matched element set
jQuery.fn.size = function() {
migrateWarn( "jQuery.fn.size() is deprecated; use the .length property" );
return this.length;
};
var internalSwapCall = false;
// If this version of jQuery has .swap(), don't false-alarm on internal uses
if ( jQuery.swap ) {
jQuery.each( [ "height", "width", "reliableMarginRight" ], function( _, name ) {
var oldHook = jQuery.cssHooks[ name ] && jQuery.cssHooks[ name ].get;
if ( oldHook ) {
jQuery.cssHooks[ name ].get = function() {
var ret;
internalSwapCall = true;
ret = oldHook.apply( this, arguments );
internalSwapCall = false;
return ret;
};
}
});
}
jQuery.swap = function( elem, options, callback, args ) {
var ret, name,
old = {};
if ( !internalSwapCall ) {
migrateWarn( "jQuery.swap() is undocumented and deprecated" );
}
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
};
// Ensure that $.ajax gets the new parseJSON defined in core.js
jQuery.ajaxSetup({
converters: {
"text json": jQuery.parseJSON
}
});
var oldFnData = jQuery.fn.data;
jQuery.fn.data = function( name ) {
var ret, evt,
elem = this[0];
// Handles 1.7 which has this behavior and 1.8 which doesn't
if ( elem && name === "events" && arguments.length === 1 ) {
ret = jQuery.data( elem, name );
evt = jQuery._data( elem, name );
if ( ( ret === undefined || ret === evt ) && evt !== undefined ) {
migrateWarn("Use of jQuery.fn.data('events') is deprecated");
return evt;
}
}
return oldFnData.apply( this, arguments );
};
var rscriptType = /\/(java|ecma)script/i;
// Since jQuery.clean is used internally on older versions, we only shim if it's missing
if ( !jQuery.clean ) {
jQuery.clean = function( elems, context, fragment, scripts ) {
// Set context per 1.8 logic
context = context || document;
context = !context.nodeType && context[0] || context;
context = context.ownerDocument || context;
migrateWarn("jQuery.clean() is deprecated");
var i, elem, handleScript, jsTags,
ret = [];
jQuery.merge( ret, jQuery.buildFragment( elems, context ).childNodes );
// Complex logic lifted directly from jQuery 1.8
if ( fragment ) {
// Special handling of each script element
handleScript = function( elem ) {
// Check if we consider it executable
if ( !elem.type || rscriptType.test( elem.type ) ) {
// Detach the script and store it in the scripts array (if provided) or the fragment
// Return truthy to indicate that it has been handled
return scripts ?
scripts.push( elem.parentNode ? elem.parentNode.removeChild( elem ) : elem ) :
fragment.appendChild( elem );
}
};
for ( i = 0; (elem = ret[i]) != null; i++ ) {
// Check if we're done after handling an executable script
if ( !( jQuery.nodeName( elem, "script" ) && handleScript( elem ) ) ) {
// Append to fragment and handle embedded scripts
fragment.appendChild( elem );
if ( typeof elem.getElementsByTagName !== "undefined" ) {
// handleScript alters the DOM, so use jQuery.merge to ensure snapshot iteration
jsTags = jQuery.grep( jQuery.merge( [], elem.getElementsByTagName("script") ), handleScript );
// Splice the scripts into ret after their former ancestor and advance our index beyond them
ret.splice.apply( ret, [i + 1, 0].concat( jsTags ) );
i += jsTags.length;
}
}
}
}
return ret;
};
}
var eventAdd = jQuery.event.add,
eventRemove = jQuery.event.remove,
eventTrigger = jQuery.event.trigger,
oldToggle = jQuery.fn.toggle,
oldLive = jQuery.fn.live,
oldDie = jQuery.fn.die,
oldLoad = jQuery.fn.load,
ajaxEvents = "ajaxStart|ajaxStop|ajaxSend|ajaxComplete|ajaxError|ajaxSuccess",
rajaxEvent = new RegExp( "\\b(?:" + ajaxEvents + ")\\b" ),
rhoverHack = /(?:^|\s)hover(\.\S+|)\b/,
hoverHack = function( events ) {
if ( typeof( events ) !== "string" || jQuery.event.special.hover ) {
return events;
}
if ( rhoverHack.test( events ) ) {
migrateWarn("'hover' pseudo-event is deprecated, use 'mouseenter mouseleave'");
}
return events && events.replace( rhoverHack, "mouseenter$1 mouseleave$1" );
};
// Event props removed in 1.9, put them back if needed; no practical way to warn them
if ( jQuery.event.props && jQuery.event.props[ 0 ] !== "attrChange" ) {
jQuery.event.props.unshift( "attrChange", "attrName", "relatedNode", "srcElement" );
}
// Undocumented jQuery.event.handle was "deprecated" in jQuery 1.7
if ( jQuery.event.dispatch ) {
migrateWarnProp( jQuery.event, "handle", jQuery.event.dispatch, "jQuery.event.handle is undocumented and deprecated" );
}
// Support for 'hover' pseudo-event and ajax event warnings
jQuery.event.add = function( elem, types, handler, data, selector ){
if ( elem !== document && rajaxEvent.test( types ) ) {
migrateWarn( "AJAX events should be attached to document: " + types );
}
eventAdd.call( this, elem, hoverHack( types || "" ), handler, data, selector );
};
jQuery.event.remove = function( elem, types, handler, selector, mappedTypes ){
eventRemove.call( this, elem, hoverHack( types ) || "", handler, selector, mappedTypes );
};
jQuery.each( [ "load", "unload", "error" ], function( _, name ) {
jQuery.fn[ name ] = function() {
var args = Array.prototype.slice.call( arguments, 0 );
// If this is an ajax load() the first arg should be the string URL;
// technically this could also be the "Anything" arg of the event .load()
// which just goes to show why this dumb signature has been deprecated!
// jQuery custom builds that exclude the Ajax module justifiably die here.
if ( name === "load" && typeof args[ 0 ] === "string" ) {
return oldLoad.apply( this, args );
}
migrateWarn( "jQuery.fn." + name + "() is deprecated" );
args.splice( 0, 0, name );
if ( arguments.length ) {
return this.bind.apply( this, args );
}
// Use .triggerHandler here because:
// - load and unload events don't need to bubble, only applied to window or image
// - error event should not bubble to window, although it does pre-1.7
// See http://bugs.jquery.com/ticket/11820
this.triggerHandler.apply( this, args );
return this;
};
});
jQuery.fn.toggle = function( fn, fn2 ) {
// Don't mess with animation or css toggles
if ( !jQuery.isFunction( fn ) || !jQuery.isFunction( fn2 ) ) {
return oldToggle.apply( this, arguments );
}
migrateWarn("jQuery.fn.toggle(handler, handler...) is deprecated");
// Save reference to arguments for access in closure
var args = arguments,
guid = fn.guid || jQuery.guid++,
i = 0,
toggler = function( event ) {
// Figure out which function to execute
var lastToggle = ( jQuery._data( this, "lastToggle" + fn.guid ) || 0 ) % i;
jQuery._data( this, "lastToggle" + fn.guid, lastToggle + 1 );
// Make sure that clicks stop
event.preventDefault();
// and execute the function
return args[ lastToggle ].apply( this, arguments ) || false;
};
// link all the functions, so any of them can unbind this click handler
toggler.guid = guid;
while ( i < args.length ) {
args[ i++ ].guid = guid;
}
return this.click( toggler );
};
jQuery.fn.live = function( types, data, fn ) {
migrateWarn("jQuery.fn.live() is deprecated");
if ( oldLive ) {
return oldLive.apply( this, arguments );
}
jQuery( this.context ).on( types, this.selector, data, fn );
return this;
};
jQuery.fn.die = function( types, fn ) {
migrateWarn("jQuery.fn.die() is deprecated");
if ( oldDie ) {
return oldDie.apply( this, arguments );
}
jQuery( this.context ).off( types, this.selector || "**", fn );
return this;
};
// Turn global events into document-triggered events
jQuery.event.trigger = function( event, data, elem, onlyHandlers ){
if ( !elem && !rajaxEvent.test( event ) ) {
migrateWarn( "Global events are undocumented and deprecated" );
}
return eventTrigger.call( this, event, data, elem || document, onlyHandlers );
};
jQuery.each( ajaxEvents.split("|"),
function( _, name ) {
jQuery.event.special[ name ] = {
setup: function() {
var elem = this;
// The document needs no shimming; must be !== for oldIE
if ( elem !== document ) {
jQuery.event.add( document, name + "." + jQuery.guid, function() {
jQuery.event.trigger( name, Array.prototype.slice.call( arguments, 1 ), elem, true );
});
jQuery._data( this, name, jQuery.guid++ );
}
return false;
},
teardown: function() {
if ( this !== document ) {
jQuery.event.remove( document, name + "." + jQuery._data( this, name ) );
}
return false;
}
};
}
);
jQuery.event.special.ready = {
setup: function() {
if ( this === document ) {
migrateWarn( "'ready' event is deprecated" );
}
}
};
var oldSelf = jQuery.fn.andSelf || jQuery.fn.addBack,
oldFnFind = jQuery.fn.find;
jQuery.fn.andSelf = function() {
migrateWarn("jQuery.fn.andSelf() replaced by jQuery.fn.addBack()");
return oldSelf.apply( this, arguments );
};
jQuery.fn.find = function( selector ) {
var ret = oldFnFind.apply( this, arguments );
ret.context = this.context;
ret.selector = this.selector ? this.selector + " " + selector : selector;
return ret;
};
// jQuery 1.6 did not support Callbacks, do not warn there
if ( jQuery.Callbacks ) {
var oldDeferred = jQuery.Deferred,
tuples = [
// action, add listener, callbacks, .then handlers, final state
[ "resolve", "done", jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"), "resolved" ],
[ "reject", "fail", jQuery.Callbacks("once memory"),
jQuery.Callbacks("once memory"), "rejected" ],
[ "notify", "progress", jQuery.Callbacks("memory"),
jQuery.Callbacks("memory") ]
];
jQuery.Deferred = function( func ) {
var deferred = oldDeferred(),
promise = deferred.promise();
deferred.pipe = promise.pipe = function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
migrateWarn( "deferred.pipe() is deprecated" );
return jQuery.Deferred(function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
// deferred.done(function() { bind to newDefer or newDefer.resolve })
// deferred.fail(function() { bind to newDefer or newDefer.reject })
// deferred.progress(function() { bind to newDefer or newDefer.notify })
deferred[ tuple[1] ](function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && jQuery.isFunction( returned.promise ) ) {
returned.promise()
.done( newDefer.resolve )
.fail( newDefer.reject )
.progress( newDefer.notify );
} else {
newDefer[ tuple[ 0 ] + "With" ](
this === promise ? newDefer.promise() : this,
fn ? [ returned ] : arguments
);
}
});
});
fns = null;
}).promise();
};
deferred.isResolved = function() {
migrateWarn( "deferred.isResolved is deprecated" );
return deferred.state() === "resolved";
};
deferred.isRejected = function() {
migrateWarn( "deferred.isRejected is deprecated" );
return deferred.state() === "rejected";
};
if ( func ) {
func.call( deferred, deferred );
}
return deferred;
};
}
})( jQuery, window );
(function() {
var AjaxMonitor, Bar, DocumentMonitor, ElementMonitor, ElementTracker, EventLagMonitor, Evented, Events, NoTargetError, Pace, RequestIntercept, SOURCE_KEYS, Scaler, SocketRequestTracker, XHRRequestTracker, animation, avgAmplitude, bar, cancelAnimation, cancelAnimationFrame, defaultOptions, extend, extendNative, getFromDOM, getIntercept, handlePushState, ignoreStack, init, now, options, requestAnimationFrame, result, runAnimation, scalers, shouldIgnoreURL, shouldTrack, source, sources, uniScaler, _WebSocket, _XDomainRequest, _XMLHttpRequest, _i, _intercept, _len, _pushState, _ref, _ref1, _replaceState,
__slice = [].slice,
__hasProp = {}.hasOwnProperty,
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },
__indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; };
defaultOptions = {
catchupTime: 100,
initialRate: .03,
minTime: 250,
ghostTime: 100,
maxProgressPerFrame: 20,
easeFactor: 1.25,
startOnPageLoad: true,
restartOnPushState: true,
restartOnRequestAfter: 500,
target: 'body',
elements: {
checkInterval: 100,
selectors: ['body']
},
eventLag: {
minSamples: 10,
sampleCount: 3,
lagThreshold: 3
},
ajax: {
trackMethods: ['GET'],
trackWebSockets: true,
ignoreURLs: []
}
};
now = function() {
var _ref;
return (_ref = typeof performance !== "undefined" && performance !== null ? typeof performance.now === "function" ? performance.now() : void 0 : void 0) != null ? _ref : +(new Date);
};
requestAnimationFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
cancelAnimationFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
if (requestAnimationFrame == null) {
requestAnimationFrame = function(fn) {
return setTimeout(fn, 50);
};
cancelAnimationFrame = function(id) {
return clearTimeout(id);
};
}
runAnimation = function(fn) {
var last, tick;
last = now();
tick = function() {
var diff;
diff = now() - last;
if (diff >= 33) {
last = now();
return fn(diff, function() {
return requestAnimationFrame(tick);
});
} else {
return setTimeout(tick, 33 - diff);
}
};
return tick();
};
result = function() {
var args, key, obj;
obj = arguments[0], key = arguments[1], args = 3 <= arguments.length ? __slice.call(arguments, 2) : [];
if (typeof obj[key] === 'function') {
return obj[key].apply(obj, args);
} else {
return obj[key];
}
};
extend = function() {
var key, out, source, sources, val, _i, _len;
out = arguments[0], sources = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
for (_i = 0, _len = sources.length; _i < _len; _i++) {
source = sources[_i];
if (source) {
for (key in source) {
if (!__hasProp.call(source, key)) continue;
val = source[key];
if ((out[key] != null) && typeof out[key] === 'object' && (val != null) && typeof val === 'object') {
extend(out[key], val);
} else {
out[key] = val;
}
}
}
}
return out;
};
avgAmplitude = function(arr) {
var count, sum, v, _i, _len;
sum = count = 0;
for (_i = 0, _len = arr.length; _i < _len; _i++) {
v = arr[_i];
sum += Math.abs(v);
count++;
}
return sum / count;
};
getFromDOM = function(key, json) {
var data, e, el;
if (key == null) {
key = 'options';
}
if (json == null) {
json = true;
}
el = document.querySelector("[data-pace-" + key + "]");
if (!el) {
return;
}
data = el.getAttribute("data-pace-" + key);
if (!json) {
return data;
}
try {
return JSON.parse(data);
} catch (_error) {
e = _error;
return typeof console !== "undefined" && console !== null ? console.error("Error parsing inline pace options", e) : void 0;
}
};
Evented = (function() {
function Evented() {}
Evented.prototype.on = function(event, handler, ctx, once) {
var _base;
if (once == null) {
once = false;
}
if (this.bindings == null) {
this.bindings = {};
}
if ((_base = this.bindings)[event] == null) {
_base[event] = [];
}
return this.bindings[event].push({
handler: handler,
ctx: ctx,
once: once
});
};
Evented.prototype.once = function(event, handler, ctx) {
return this.on(event, handler, ctx, true);
};
Evented.prototype.off = function(event, handler) {
var i, _ref, _results;
if (((_ref = this.bindings) != null ? _ref[event] : void 0) == null) {
return;
}
if (handler == null) {
return delete this.bindings[event];
} else {
i = 0;
_results = [];
while (i < this.bindings[event].length) {
if (this.bindings[event][i].handler === handler) {
_results.push(this.bindings[event].splice(i, 1));
} else {
_results.push(i++);
}
}
return _results;
}
};
Evented.prototype.trigger = function() {
var args, ctx, event, handler, i, once, _ref, _ref1, _results;
event = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
if ((_ref = this.bindings) != null ? _ref[event] : void 0) {
i = 0;
_results = [];
while (i < this.bindings[event].length) {
_ref1 = this.bindings[event][i], handler = _ref1.handler, ctx = _ref1.ctx, once = _ref1.once;
handler.apply(ctx != null ? ctx : this, args);
if (once) {
_results.push(this.bindings[event].splice(i, 1));
} else {
_results.push(i++);
}
}
return _results;
}
};
return Evented;
})();
Pace = window.Pace || {};
window.Pace = Pace;
extend(Pace, Evented.prototype);
options = Pace.options = extend({}, defaultOptions, window.paceOptions, getFromDOM());
_ref = ['ajax', 'document', 'eventLag', 'elements'];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
source = _ref[_i];
if (options[source] === true) {
options[source] = defaultOptions[source];
}
}
NoTargetError = (function(_super) {
__extends(NoTargetError, _super);
function NoTargetError() {
_ref1 = NoTargetError.__super__.constructor.apply(this, arguments);
return _ref1;
}
return NoTargetError;
})(Error);
Bar = (function() {
function Bar() {
this.progress = 0;
}
Bar.prototype.getElement = function() {
var targetElement;
if (this.el == null) {
targetElement = document.querySelector(options.target);
if (!targetElement) {
throw new NoTargetError;
}
this.el = document.createElement('div');
this.el.className = "pace pace-active";
document.body.className = document.body.className.replace(/pace-done/g, '');
document.body.className += ' pace-running';
this.el.innerHTML = '<div class="pace-progress">\n <div class="pace-progress-inner"></div>\n</div>\n<div class="pace-activity"></div>';
if (targetElement.firstChild != null) {
targetElement.insertBefore(this.el, targetElement.firstChild);
} else {
targetElement.appendChild(this.el);
}
}
return this.el;
};
Bar.prototype.finish = function() {
var el;
el = this.getElement();
el.className = el.className.replace('pace-active', '');
el.className += ' pace-inactive';
document.body.className = document.body.className.replace('pace-running', '');
return document.body.className += ' pace-done';
};
Bar.prototype.update = function(prog) {
this.progress = prog;
return this.render();
};
Bar.prototype.destroy = function() {
try {
this.getElement().parentNode.removeChild(this.getElement());
} catch (_error) {
NoTargetError = _error;
}
return this.el = void 0;
};
Bar.prototype.render = function() {
var el, key, progressStr, transform, _j, _len1, _ref2;
if (document.querySelector(options.target) == null) {
return false;
}
el = this.getElement();
transform = "translate3d(" + this.progress + "%, 0, 0)";
_ref2 = ['webkitTransform', 'msTransform', 'transform'];
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
key = _ref2[_j];
el.children[0].style[key] = transform;
}
if (!this.lastRenderedProgress || this.lastRenderedProgress | 0 !== this.progress | 0) {
el.children[0].setAttribute('data-progress-text', "" + (this.progress | 0) + "%");
if (this.progress >= 100) {
progressStr = '99';
} else {
progressStr = this.progress < 10 ? "0" : "";
progressStr += this.progress | 0;
}
el.children[0].setAttribute('data-progress', "" + progressStr);
}
return this.lastRenderedProgress = this.progress;
};
Bar.prototype.done = function() {
return this.progress >= 100;
};
return Bar;
})();
Events = (function() {
function Events() {
this.bindings = {};
}
Events.prototype.trigger = function(name, val) {
var binding, _j, _len1, _ref2, _results;
if (this.bindings[name] != null) {
_ref2 = this.bindings[name];
_results = [];
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
binding = _ref2[_j];
_results.push(binding.call(this, val));
}
return _results;
}
};
Events.prototype.on = function(name, fn) {
var _base;
if ((_base = this.bindings)[name] == null) {
_base[name] = [];
}
return this.bindings[name].push(fn);
};
return Events;
})();
_XMLHttpRequest = window.XMLHttpRequest;
_XDomainRequest = window.XDomainRequest;
_WebSocket = window.WebSocket;
extendNative = function(to, from) {
var e, key, _results;
_results = [];
for (key in from.prototype) {
try {
if ((to[key] == null) && typeof from[key] !== 'function') {
if (typeof Object.defineProperty === 'function') {
_results.push(Object.defineProperty(to, key, {
get: function() {
return from.prototype[key];
},
configurable: true,
enumerable: true
}));
} else {
_results.push(to[key] = from.prototype[key]);
}
} else {
_results.push(void 0);
}
} catch (_error) {
e = _error;
}
}
return _results;
};
ignoreStack = [];
Pace.ignore = function() {
var args, fn, ret;
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
ignoreStack.unshift('ignore');
ret = fn.apply(null, args);
ignoreStack.shift();
return ret;
};
Pace.track = function() {
var args, fn, ret;
fn = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
ignoreStack.unshift('track');
ret = fn.apply(null, args);
ignoreStack.shift();
return ret;
};
shouldTrack = function(method) {
var _ref2;
if (method == null) {
method = 'GET';
}
if (ignoreStack[0] === 'track') {
return 'force';
}
if (!ignoreStack.length && options.ajax) {
if (method === 'socket' && options.ajax.trackWebSockets) {
return true;
} else if (_ref2 = method.toUpperCase(), __indexOf.call(options.ajax.trackMethods, _ref2) >= 0) {
return true;
}
}
return false;
};
RequestIntercept = (function(_super) {
__extends(RequestIntercept, _super);
function RequestIntercept() {
var monitorXHR,
_this = this;
RequestIntercept.__super__.constructor.apply(this, arguments);
monitorXHR = function(req) {
var _open;
_open = req.open;
return req.open = function(type, url, async) {
if (shouldTrack(type)) {
_this.trigger('request', {
type: type,
url: url,
request: req
});
}
return _open.apply(req, arguments);
};
};
window.XMLHttpRequest = function(flags) {
var req;
req = new _XMLHttpRequest(flags);
monitorXHR(req);
return req;
};
try {
extendNative(window.XMLHttpRequest, _XMLHttpRequest);
} catch (_error) {}
if (_XDomainRequest != null) {
window.XDomainRequest = function() {
var req;
req = new _XDomainRequest;
monitorXHR(req);
return req;
};
try {
extendNative(window.XDomainRequest, _XDomainRequest);
} catch (_error) {}
}
if ((_WebSocket != null) && options.ajax.trackWebSockets) {
window.WebSocket = function(url, protocols) {
var req;
if (protocols != null) {
req = new _WebSocket(url, protocols);
} else {
req = new _WebSocket(url);
}
if (shouldTrack('socket')) {
_this.trigger('request', {
type: 'socket',
url: url,
protocols: protocols,
request: req
});
}
return req;
};
try {
extendNative(window.WebSocket, _WebSocket);
} catch (_error) {}
}
}
return RequestIntercept;
})(Events);
_intercept = null;
getIntercept = function() {
if (_intercept == null) {
_intercept = new RequestIntercept;
}
return _intercept;
};
shouldIgnoreURL = function(url) {
var pattern, _j, _len1, _ref2;
_ref2 = options.ajax.ignoreURLs;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
pattern = _ref2[_j];
if (typeof pattern === 'string') {
if (url.indexOf(pattern) !== -1) {
return true;
}
} else {
if (pattern.test(url)) {
return true;
}
}
}
return false;
};
getIntercept().on('request', function(_arg) {
var after, args, request, type, url;
type = _arg.type, request = _arg.request, url = _arg.url;
if (shouldIgnoreURL(url)) {
return;
}
if (!Pace.running && (options.restartOnRequestAfter !== false || shouldTrack(type) === 'force')) {
args = arguments;
after = options.restartOnRequestAfter || 0;
if (typeof after === 'boolean') {
after = 0;
}
return setTimeout(function() {
var stillActive, _j, _len1, _ref2, _ref3, _results;
if (type === 'socket') {
stillActive = request.readyState < 2;
} else {
stillActive = (0 < (_ref2 = request.readyState) && _ref2 < 4);
}
if (stillActive) {
Pace.restart();
_ref3 = Pace.sources;
_results = [];
for (_j = 0, _len1 = _ref3.length; _j < _len1; _j++) {
source = _ref3[_j];
if (source instanceof AjaxMonitor) {
source.watch.apply(source, args);
break;
} else {
_results.push(void 0);
}
}
return _results;
}
}, after);
}
});
AjaxMonitor = (function() {
function AjaxMonitor() {
var _this = this;
this.elements = [];
getIntercept().on('request', function() {
return _this.watch.apply(_this, arguments);
});
}
AjaxMonitor.prototype.watch = function(_arg) {
var request, tracker, type, url;
type = _arg.type, request = _arg.request, url = _arg.url;
if (shouldIgnoreURL(url)) {
return;
}
if (type === 'socket') {
tracker = new SocketRequestTracker(request);
} else {
tracker = new XHRRequestTracker(request);
}
return this.elements.push(tracker);
};
return AjaxMonitor;
})();
XHRRequestTracker = (function() {
function XHRRequestTracker(request) {
var event, size, _j, _len1, _onreadystatechange, _ref2,
_this = this;
this.progress = 0;
if (window.ProgressEvent != null) {
size = null;
request.addEventListener('progress', function(evt) {
if (evt.lengthComputable) {
return _this.progress = 100 * evt.loaded / evt.total;
} else {
return _this.progress = _this.progress + (100 - _this.progress) / 2;
}
}, false);
_ref2 = ['load', 'abort', 'timeout', 'error'];
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
event = _ref2[_j];
request.addEventListener(event, function() {
return _this.progress = 100;
}, false);
}
} else {
_onreadystatechange = request.onreadystatechange;
request.onreadystatechange = function() {
var _ref3;
if ((_ref3 = request.readyState) === 0 || _ref3 === 4) {
_this.progress = 100;
} else if (request.readyState === 3) {
_this.progress = 50;
}
return typeof _onreadystatechange === "function" ? _onreadystatechange.apply(null, arguments) : void 0;
};
}
}
return XHRRequestTracker;
})();
SocketRequestTracker = (function() {
function SocketRequestTracker(request) {
var event, _j, _len1, _ref2,
_this = this;
this.progress = 0;
_ref2 = ['error', 'open'];
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
event = _ref2[_j];
request.addEventListener(event, function() {
return _this.progress = 100;
}, false);
}
}
return SocketRequestTracker;
})();
ElementMonitor = (function() {
function ElementMonitor(options) {
var selector, _j, _len1, _ref2;
if (options == null) {
options = {};
}
this.elements = [];
if (options.selectors == null) {
options.selectors = [];
}
_ref2 = options.selectors;
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
selector = _ref2[_j];
this.elements.push(new ElementTracker(selector));
}
}
return ElementMonitor;
})();
ElementTracker = (function() {
function ElementTracker(selector) {
this.selector = selector;
this.progress = 0;
this.check();
}
ElementTracker.prototype.check = function() {
var _this = this;
if (document.querySelector(this.selector)) {
return this.done();
} else {
return setTimeout((function() {
return _this.check();
}), options.elements.checkInterval);
}
};
ElementTracker.prototype.done = function() {
return this.progress = 100;
};
return ElementTracker;
})();
DocumentMonitor = (function() {
DocumentMonitor.prototype.states = {
loading: 0,
interactive: 50,
complete: 100
};
function DocumentMonitor() {
var _onreadystatechange, _ref2,
_this = this;
this.progress = (_ref2 = this.states[document.readyState]) != null ? _ref2 : 100;
_onreadystatechange = document.onreadystatechange;
document.onreadystatechange = function() {
if (_this.states[document.readyState] != null) {
_this.progress = _this.states[document.readyState];
}
return typeof _onreadystatechange === "function" ? _onreadystatechange.apply(null, arguments) : void 0;
};
}
return DocumentMonitor;
})();
EventLagMonitor = (function() {
function EventLagMonitor() {
var avg, interval, last, points, samples,
_this = this;
this.progress = 0;
avg = 0;
samples = [];
points = 0;
last = now();
interval = setInterval(function() {
var diff;
diff = now() - last - 50;
last = now();
samples.push(diff);
if (samples.length > options.eventLag.sampleCount) {
samples.shift();
}
avg = avgAmplitude(samples);
if (++points >= options.eventLag.minSamples && avg < options.eventLag.lagThreshold) {
_this.progress = 100;
return clearInterval(interval);
} else {
return _this.progress = 100 * (3 / (avg + 3));
}
}, 50);
}
return EventLagMonitor;
})();
Scaler = (function() {
function Scaler(source) {
this.source = source;
this.last = this.sinceLastUpdate = 0;
this.rate = options.initialRate;
this.catchup = 0;
this.progress = this.lastProgress = 0;
if (this.source != null) {
this.progress = result(this.source, 'progress');
}
}
Scaler.prototype.tick = function(frameTime, val) {
var scaling;
if (val == null) {
val = result(this.source, 'progress');
}
if (val >= 100) {
this.done = true;
}
if (val === this.last) {
this.sinceLastUpdate += frameTime;
} else {
if (this.sinceLastUpdate) {
this.rate = (val - this.last) / this.sinceLastUpdate;
}
this.catchup = (val - this.progress) / options.catchupTime;
this.sinceLastUpdate = 0;
this.last = val;
}
if (val > this.progress) {
this.progress += this.catchup * frameTime;
}
scaling = 1 - Math.pow(this.progress / 100, options.easeFactor);
this.progress += scaling * this.rate * frameTime;
this.progress = Math.min(this.lastProgress + options.maxProgressPerFrame, this.progress);
this.progress = Math.max(0, this.progress);
this.progress = Math.min(100, this.progress);
this.lastProgress = this.progress;
return this.progress;
};
return Scaler;
})();
sources = null;
scalers = null;
bar = null;
uniScaler = null;
animation = null;
cancelAnimation = null;
Pace.running = false;
handlePushState = function() {
if (options.restartOnPushState) {
return Pace.restart();
}
};
if (window.history.pushState != null) {
_pushState = window.history.pushState;
window.history.pushState = function() {
handlePushState();
return _pushState.apply(window.history, arguments);
};
}
if (window.history.replaceState != null) {
_replaceState = window.history.replaceState;
window.history.replaceState = function() {
handlePushState();
return _replaceState.apply(window.history, arguments);
};
}
SOURCE_KEYS = {
ajax: AjaxMonitor,
elements: ElementMonitor,
document: DocumentMonitor,
eventLag: EventLagMonitor
};
(init = function() {
var type, _j, _k, _len1, _len2, _ref2, _ref3, _ref4;
Pace.sources = sources = [];
_ref2 = ['ajax', 'elements', 'document', 'eventLag'];
for (_j = 0, _len1 = _ref2.length; _j < _len1; _j++) {
type = _ref2[_j];
if (options[type] !== false) {
sources.push(new SOURCE_KEYS[type](options[type]));
}
}
_ref4 = (_ref3 = options.extraSources) != null ? _ref3 : [];
for (_k = 0, _len2 = _ref4.length; _k < _len2; _k++) {
source = _ref4[_k];
sources.push(new source(options));
}
Pace.bar = bar = new Bar;
scalers = [];
return uniScaler = new Scaler;
})();
Pace.stop = function() {
Pace.trigger('stop');
Pace.running = false;
bar.destroy();
cancelAnimation = true;
if (animation != null) {
if (typeof cancelAnimationFrame === "function") {
cancelAnimationFrame(animation);
}
animation = null;
}
return init();
};
Pace.restart = function() {
Pace.trigger('restart');
Pace.stop();
return Pace.start();
};
Pace.go = function() {
var start;
Pace.running = true;
bar.render();
start = now();
cancelAnimation = false;
return animation = runAnimation(function(frameTime, enqueueNextFrame) {
var avg, count, done, element, elements, i, j, remaining, scaler, scalerList, sum, _j, _k, _len1, _len2, _ref2;
remaining = 100 - bar.progress;
count = sum = 0;
done = true;
for (i = _j = 0, _len1 = sources.length; _j < _len1; i = ++_j) {
source = sources[i];
scalerList = scalers[i] != null ? scalers[i] : scalers[i] = [];
elements = (_ref2 = source.elements) != null ? _ref2 : [source];
for (j = _k = 0, _len2 = elements.length; _k < _len2; j = ++_k) {
element = elements[j];
scaler = scalerList[j] != null ? scalerList[j] : scalerList[j] = new Scaler(element);
done &= scaler.done;
if (scaler.done) {
continue;
}
count++;
sum += scaler.tick(frameTime);
}
}
avg = sum / count;
bar.update(uniScaler.tick(frameTime, avg));
if (bar.done() || done || cancelAnimation) {
bar.update(100);
Pace.trigger('done');
return setTimeout(function() {
bar.finish();
Pace.running = false;
return Pace.trigger('hide');
}, Math.max(options.ghostTime, Math.max(options.minTime - (now() - start), 0)));
} else {
return enqueueNextFrame();
}
});
};
Pace.start = function(_options) {
extend(options, _options);
Pace.running = true;
try {
bar.render();
} catch (_error) {
NoTargetError = _error;
}
if (!document.querySelector('.pace')) {
return setTimeout(Pace.start, 50);
} else {
Pace.trigger('start');
return Pace.go();
}
};
if (typeof define === 'function' && define.amd) {
define(['pace'], function() {
return Pace;
});
} else if (typeof exports === 'object') {
module.exports = Pace;
} else {
if (options.startOnPageLoad) {
Pace.start();
}
}
}).call(this);
(function(root, factory) {
// `root` does not resolve to the global window object in a Browserified
// bundle, so a direct reference to that object is used instead.
var _srcDoc = window.srcDoc;
if (typeof define === "function" && define.amd) {
define(['exports'], function(exports) {
factory(exports, _srcDoc);
root.srcDoc = exports;
});
} else if (typeof exports === "object") {
factory(exports, _srcDoc);
} else {
root.srcDoc = {};
factory(root.srcDoc, _srcDoc);
}
})(this, function(exports, _srcDoc) {
var idx, iframes;
var isCompliant = !!("srcdoc" in document.createElement("iframe"));
var implementations = {
compliant: function( iframe, content ) {
if (content) {
iframe.setAttribute("srcdoc", content);
}
},
legacy: function( iframe, content ) {
var jsUrl;
if (!iframe || !iframe.getAttribute) {
return;
}
if (!content) {
content = iframe.getAttribute("srcdoc");
} else {
iframe.setAttribute("srcdoc", content);
}
if (content) {
// The value returned by a script-targeted URL will be used as
// the iFrame's content. Create such a URL which returns the
// iFrame element's `srcdoc` attribute.
jsUrl = "javascript: window.frameElement.getAttribute('srcdoc');";
iframe.setAttribute("src", jsUrl);
// Explicitly set the iFrame's window.location for
// compatability with IE9, which does not react to changes in
// the `src` attribute when it is a `javascript:` URL, for
// some reason
if (iframe.contentWindow) {
iframe.contentWindow.location = jsUrl;
}
}
}
};
var srcDoc = exports;
// Assume the best
srcDoc.set = implementations.compliant;
srcDoc.noConflict = function() {
window.srcDoc = _srcDoc;
return srcDoc;
};
// If the browser supports srcdoc, no shimming is necessary
if (isCompliant) {
return;
}
srcDoc.set = implementations.legacy;
// Automatically shim any iframes already present in the document
iframes = document.getElementsByTagName("iframe");
idx = iframes.length;
while (idx--) {
srcDoc.set( iframes[idx] );
}
});
/*! jQuery UI - v1.12.1 - 2016-09-14
* http://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery" ], factory );
} else {
// Browser globals
factory( jQuery );
}
}(function( $ ) {
$.ui = $.ui || {};
var version = $.ui.version = "1.12.1";
/*!
* jQuery UI Widget 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Widget
//>>group: Core
//>>description: Provides a factory for creating stateful widgets with a common API.
//>>docs: http://api.jqueryui.com/jQuery.widget/
//>>demos: http://jqueryui.com/widget/
var widgetUuid = 0;
var widgetSlice = Array.prototype.slice;
$.cleanData = ( function( orig ) {
return function( elems ) {
var events, elem, i;
for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
try {
// Only trigger remove when necessary to save time
events = $._data( elem, "events" );
if ( events && events.remove ) {
$( elem ).triggerHandler( "remove" );
}
// Http://bugs.jquery.com/ticket/8235
} catch ( e ) {}
}
orig( elems );
};
} )( $.cleanData );
$.widget = function( name, base, prototype ) {
var existingConstructor, constructor, basePrototype;
// ProxiedPrototype allows the provided prototype to remain unmodified
// so that it can be used as a mixin for multiple widgets (#8876)
var proxiedPrototype = {};
var namespace = name.split( "." )[ 0 ];
name = name.split( "." )[ 1 ];
var fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
if ( $.isArray( prototype ) ) {
prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
}
// Create selector for plugin
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
return !!$.data( elem, fullName );
};
$[ namespace ] = $[ namespace ] || {};
existingConstructor = $[ namespace ][ name ];
constructor = $[ namespace ][ name ] = function( options, element ) {
// Allow instantiation without "new" keyword
if ( !this._createWidget ) {
return new constructor( options, element );
}
// Allow instantiation without initializing for simple inheritance
// must use "new" keyword (the code above always passes args)
if ( arguments.length ) {
this._createWidget( options, element );
}
};
// Extend with the existing constructor to carry over any static properties
$.extend( constructor, existingConstructor, {
version: prototype.version,
// Copy the object used to create the prototype in case we need to
// redefine the widget later
_proto: $.extend( {}, prototype ),
// Track widgets that inherit from this widget in case this widget is
// redefined after a widget inherits from it
_childConstructors: []
} );
basePrototype = new base();
// We need to make the options hash a property directly on the new instance
// otherwise we'll modify the options hash on the prototype that we're
// inheriting from
basePrototype.options = $.widget.extend( {}, basePrototype.options );
$.each( prototype, function( prop, value ) {
if ( !$.isFunction( value ) ) {
proxiedPrototype[ prop ] = value;
return;
}
proxiedPrototype[ prop ] = ( function() {
function _super() {
return base.prototype[ prop ].apply( this, arguments );
}
function _superApply( args ) {
return base.prototype[ prop ].apply( this, args );
}
return function() {
var __super = this._super;
var __superApply = this._superApply;
var returnValue;
this._super = _super;
this._superApply = _superApply;
returnValue = value.apply( this, arguments );
this._super = __super;
this._superApply = __superApply;
return returnValue;
};
} )();
} );
constructor.prototype = $.widget.extend( basePrototype, {
// TODO: remove support for widgetEventPrefix
// always use the name + a colon as the prefix, e.g., draggable:start
// don't prefix for widgets that aren't DOM-based
widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
}, proxiedPrototype, {
constructor: constructor,
namespace: namespace,
widgetName: name,
widgetFullName: fullName
} );
// If this widget is being redefined then we need to find all widgets that
// are inheriting from it and redefine all of them so that they inherit from
// the new version of this widget. We're essentially trying to replace one
// level in the prototype chain.
if ( existingConstructor ) {
$.each( existingConstructor._childConstructors, function( i, child ) {
var childPrototype = child.prototype;
// Redefine the child widget using the same prototype that was
// originally used, but inherit from the new version of the base
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
child._proto );
} );
// Remove the list of existing child constructors from the old constructor
// so the old child constructors can be garbage collected
delete existingConstructor._childConstructors;
} else {
base._childConstructors.push( constructor );
}
$.widget.bridge( name, constructor );
return constructor;
};
$.widget.extend = function( target ) {
var input = widgetSlice.call( arguments, 1 );
var inputIndex = 0;
var inputLength = input.length;
var key;
var value;
for ( ; inputIndex < inputLength; inputIndex++ ) {
for ( key in input[ inputIndex ] ) {
value = input[ inputIndex ][ key ];
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
// Clone objects
if ( $.isPlainObject( value ) ) {
target[ key ] = $.isPlainObject( target[ key ] ) ?
$.widget.extend( {}, target[ key ], value ) :
// Don't extend strings, arrays, etc. with objects
$.widget.extend( {}, value );
// Copy everything else by reference
} else {
target[ key ] = value;
}
}
}
}
return target;
};
$.widget.bridge = function( name, object ) {
var fullName = object.prototype.widgetFullName || name;
$.fn[ name ] = function( options ) {
var isMethodCall = typeof options === "string";
var args = widgetSlice.call( arguments, 1 );
var returnValue = this;
if ( isMethodCall ) {
// If this is an empty collection, we need to have the instance method
// return undefined instead of the jQuery instance
if ( !this.length && options === "instance" ) {
returnValue = undefined;
} else {
this.each( function() {
var methodValue;
var instance = $.data( this, fullName );
if ( options === "instance" ) {
returnValue = instance;
return false;
}
if ( !instance ) {
return $.error( "cannot call methods on " + name +
" prior to initialization; " +
"attempted to call method '" + options + "'" );
}
if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
return $.error( "no such method '" + options + "' for " + name +
" widget instance" );
}
methodValue = instance[ options ].apply( instance, args );
if ( methodValue !== instance && methodValue !== undefined ) {
returnValue = methodValue && methodValue.jquery ?
returnValue.pushStack( methodValue.get() ) :
methodValue;
return false;
}
} );
}
} else {
// Allow multiple hashes to be passed on init
if ( args.length ) {
options = $.widget.extend.apply( null, [ options ].concat( args ) );
}
this.each( function() {
var instance = $.data( this, fullName );
if ( instance ) {
instance.option( options || {} );
if ( instance._init ) {
instance._init();
}
} else {
$.data( this, fullName, new object( options, this ) );
}
} );
}
return returnValue;
};
};
$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];
$.Widget.prototype = {
widgetName: "widget",
widgetEventPrefix: "",
defaultElement: "<div>",
options: {
classes: {},
disabled: false,
// Callbacks
create: null
},
_createWidget: function( options, element ) {
element = $( element || this.defaultElement || this )[ 0 ];
this.element = $( element );
this.uuid = widgetUuid++;
this.eventNamespace = "." + this.widgetName + this.uuid;
this.bindings = $();
this.hoverable = $();
this.focusable = $();
this.classesElementLookup = {};
if ( element !== this ) {
$.data( element, this.widgetFullName, this );
this._on( true, this.element, {
remove: function( event ) {
if ( event.target === element ) {
this.destroy();
}
}
} );
this.document = $( element.style ?
// Element within the document
element.ownerDocument :
// Element is window or document
element.document || element );
this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
}
this.options = $.widget.extend( {},
this.options,
this._getCreateOptions(),
options );
this._create();
if ( this.options.disabled ) {
this._setOptionDisabled( this.options.disabled );
}
this._trigger( "create", null, this._getCreateEventData() );
this._init();
},
_getCreateOptions: function() {
return {};
},
_getCreateEventData: $.noop,
_create: $.noop,
_init: $.noop,
destroy: function() {
var that = this;
this._destroy();
$.each( this.classesElementLookup, function( key, value ) {
that._removeClass( value, key );
} );
// We can probably remove the unbind calls in 2.0
// all event bindings should go through this._on()
this.element
.off( this.eventNamespace )
.removeData( this.widgetFullName );
this.widget()
.off( this.eventNamespace )
.removeAttr( "aria-disabled" );
// Clean up events and states
this.bindings.off( this.eventNamespace );
},
_destroy: $.noop,
widget: function() {
return this.element;
},
option: function( key, value ) {
var options = key;
var parts;
var curOption;
var i;
if ( arguments.length === 0 ) {
// Don't return a reference to the internal hash
return $.widget.extend( {}, this.options );
}
if ( typeof key === "string" ) {
// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
options = {};
parts = key.split( "." );
key = parts.shift();
if ( parts.length ) {
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
for ( i = 0; i < parts.length - 1; i++ ) {
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
curOption = curOption[ parts[ i ] ];
}
key = parts.pop();
if ( arguments.length === 1 ) {
return curOption[ key ] === undefined ? null : curOption[ key ];
}
curOption[ key ] = value;
} else {
if ( arguments.length === 1 ) {
return this.options[ key ] === undefined ? null : this.options[ key ];
}
options[ key ] = value;
}
}
this._setOptions( options );
return this;
},
_setOptions: function( options ) {
var key;
for ( key in options ) {
this._setOption( key, options[ key ] );
}
return this;
},
_setOption: function( key, value ) {
if ( key === "classes" ) {
this._setOptionClasses( value );
}
this.options[ key ] = value;
if ( key === "disabled" ) {
this._setOptionDisabled( value );
}
return this;
},
_setOptionClasses: function( value ) {
var classKey, elements, currentElements;
for ( classKey in value ) {
currentElements = this.classesElementLookup[ classKey ];
if ( value[ classKey ] === this.options.classes[ classKey ] ||
!currentElements ||
!currentElements.length ) {
continue;
}
// We are doing this to create a new jQuery object because the _removeClass() call
// on the next line is going to destroy the reference to the current elements being
// tracked. We need to save a copy of this collection so that we can add the new classes
// below.
elements = $( currentElements.get() );
this._removeClass( currentElements, classKey );
// We don't use _addClass() here, because that uses this.options.classes
// for generating the string of classes. We want to use the value passed in from
// _setOption(), this is the new value of the classes option which was passed to
// _setOption(). We pass this value directly to _classes().
elements.addClass( this._classes( {
element: elements,
keys: classKey,
classes: value,
add: true
} ) );
}
},
_setOptionDisabled: function( value ) {
this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
// If the widget is becoming disabled, then nothing is interactive
if ( value ) {
this._removeClass( this.hoverable, null, "ui-state-hover" );
this._removeClass( this.focusable, null, "ui-state-focus" );
}
},
enable: function() {
return this._setOptions( { disabled: false } );
},
disable: function() {
return this._setOptions( { disabled: true } );
},
_classes: function( options ) {
var full = [];
var that = this;
options = $.extend( {
element: this.element,
classes: this.options.classes || {}
}, options );
function processClassString( classes, checkOption ) {
var current, i;
for ( i = 0; i < classes.length; i++ ) {
current = that.classesElementLookup[ classes[ i ] ] || $();
if ( options.add ) {
current = $( $.unique( current.get().concat( options.element.get() ) ) );
} else {
current = $( current.not( options.element ).get() );
}
that.classesElementLookup[ classes[ i ] ] = current;
full.push( classes[ i ] );
if ( checkOption && options.classes[ classes[ i ] ] ) {
full.push( options.classes[ classes[ i ] ] );
}
}
}
this._on( options.element, {
"remove": "_untrackClassesElement"
} );
if ( options.keys ) {
processClassString( options.keys.match( /\S+/g ) || [], true );
}
if ( options.extra ) {
processClassString( options.extra.match( /\S+/g ) || [] );
}
return full.join( " " );
},
_untrackClassesElement: function( event ) {
var that = this;
$.each( that.classesElementLookup, function( key, value ) {
if ( $.inArray( event.target, value ) !== -1 ) {
that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
}
} );
},
_removeClass: function( element, keys, extra ) {
return this._toggleClass( element, keys, extra, false );
},
_addClass: function( element, keys, extra ) {
return this._toggleClass( element, keys, extra, true );
},
_toggleClass: function( element, keys, extra, add ) {
add = ( typeof add === "boolean" ) ? add : extra;
var shift = ( typeof element === "string" || element === null ),
options = {
extra: shift ? keys : extra,
keys: shift ? element : keys,
element: shift ? this.element : element,
add: add
};
options.element.toggleClass( this._classes( options ), add );
return this;
},
_on: function( suppressDisabledCheck, element, handlers ) {
var delegateElement;
var instance = this;
// No suppressDisabledCheck flag, shuffle arguments
if ( typeof suppressDisabledCheck !== "boolean" ) {
handlers = element;
element = suppressDisabledCheck;
suppressDisabledCheck = false;
}
// No element argument, shuffle and use this.element
if ( !handlers ) {
handlers = element;
element = this.element;
delegateElement = this.widget();
} else {
element = delegateElement = $( element );
this.bindings = this.bindings.add( element );
}
$.each( handlers, function( event, handler ) {
function handlerProxy() {
// Allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
if ( !suppressDisabledCheck &&
( instance.options.disabled === true ||
$( this ).hasClass( "ui-state-disabled" ) ) ) {
return;
}
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
// Copy the guid so direct unbinding works
if ( typeof handler !== "string" ) {
handlerProxy.guid = handler.guid =
handler.guid || handlerProxy.guid || $.guid++;
}
var match = event.match( /^([\w:-]*)\s*(.*)$/ );
var eventName = match[ 1 ] + instance.eventNamespace;
var selector = match[ 2 ];
if ( selector ) {
delegateElement.on( eventName, selector, handlerProxy );
} else {
element.on( eventName, handlerProxy );
}
} );
},
_off: function( element, eventName ) {
eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
this.eventNamespace;
element.off( eventName ).off( eventName );
// Clear the stack to avoid memory leaks (#10056)
this.bindings = $( this.bindings.not( element ).get() );
this.focusable = $( this.focusable.not( element ).get() );
this.hoverable = $( this.hoverable.not( element ).get() );
},
_delay: function( handler, delay ) {
function handlerProxy() {
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
var instance = this;
return setTimeout( handlerProxy, delay || 0 );
},
_hoverable: function( element ) {
this.hoverable = this.hoverable.add( element );
this._on( element, {
mouseenter: function( event ) {
this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
},
mouseleave: function( event ) {
this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
}
} );
},
_focusable: function( element ) {
this.focusable = this.focusable.add( element );
this._on( element, {
focusin: function( event ) {
this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
},
focusout: function( event ) {
this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
}
} );
},
_trigger: function( type, event, data ) {
var prop, orig;
var callback = this.options[ type ];
data = data || {};
event = $.Event( event );
event.type = ( type === this.widgetEventPrefix ?
type :
this.widgetEventPrefix + type ).toLowerCase();
// The original event may come from any element
// so we need to reset the target on the new event
event.target = this.element[ 0 ];
// Copy original event properties over to the new event
orig = event.originalEvent;
if ( orig ) {
for ( prop in orig ) {
if ( !( prop in event ) ) {
event[ prop ] = orig[ prop ];
}
}
}
this.element.trigger( event, data );
return !( $.isFunction( callback ) &&
callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
event.isDefaultPrevented() );
}
};
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
if ( typeof options === "string" ) {
options = { effect: options };
}
var hasOptions;
var effectName = !options ?
method :
options === true || typeof options === "number" ?
defaultEffect :
options.effect || defaultEffect;
options = options || {};
if ( typeof options === "number" ) {
options = { duration: options };
}
hasOptions = !$.isEmptyObject( options );
options.complete = callback;
if ( options.delay ) {
element.delay( options.delay );
}
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
element[ method ]( options );
} else if ( effectName !== method && element[ effectName ] ) {
element[ effectName ]( options.duration, options.easing, callback );
} else {
element.queue( function( next ) {
$( this )[ method ]();
if ( callback ) {
callback.call( element[ 0 ] );
}
next();
} );
}
};
} );
var widget = $.widget;
/*!
* jQuery UI Position 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/position/
*/
//>>label: Position
//>>group: Core
//>>description: Positions elements relative to other elements.
//>>docs: http://api.jqueryui.com/position/
//>>demos: http://jqueryui.com/position/
( function() {
var cachedScrollbarWidth,
max = Math.max,
abs = Math.abs,
rhorizontal = /left|center|right/,
rvertical = /top|center|bottom/,
roffset = /[\+\-]\d+(\.[\d]+)?%?/,
rposition = /^\w+/,
rpercent = /%$/,
_position = $.fn.position;
function getOffsets( offsets, width, height ) {
return [
parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
];
}
function parseCss( element, property ) {
return parseInt( $.css( element, property ), 10 ) || 0;
}
function getDimensions( elem ) {
var raw = elem[ 0 ];
if ( raw.nodeType === 9 ) {
return {
width: elem.width(),
height: elem.height(),
offset: { top: 0, left: 0 }
};
}
if ( $.isWindow( raw ) ) {
return {
width: elem.width(),
height: elem.height(),
offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
};
}
if ( raw.preventDefault ) {
return {
width: 0,
height: 0,
offset: { top: raw.pageY, left: raw.pageX }
};
}
return {
width: elem.outerWidth(),
height: elem.outerHeight(),
offset: elem.offset()
};
}
$.position = {
scrollbarWidth: function() {
if ( cachedScrollbarWidth !== undefined ) {
return cachedScrollbarWidth;
}
var w1, w2,
div = $( "<div " +
"style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
"<div style='height:100px;width:auto;'></div></div>" ),
innerDiv = div.children()[ 0 ];
$( "body" ).append( div );
w1 = innerDiv.offsetWidth;
div.css( "overflow", "scroll" );
w2 = innerDiv.offsetWidth;
if ( w1 === w2 ) {
w2 = div[ 0 ].clientWidth;
}
div.remove();
return ( cachedScrollbarWidth = w1 - w2 );
},
getScrollInfo: function( within ) {
var overflowX = within.isWindow || within.isDocument ? "" :
within.element.css( "overflow-x" ),
overflowY = within.isWindow || within.isDocument ? "" :
within.element.css( "overflow-y" ),
hasOverflowX = overflowX === "scroll" ||
( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
hasOverflowY = overflowY === "scroll" ||
( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
return {
width: hasOverflowY ? $.position.scrollbarWidth() : 0,
height: hasOverflowX ? $.position.scrollbarWidth() : 0
};
},
getWithinInfo: function( element ) {
var withinElement = $( element || window ),
isWindow = $.isWindow( withinElement[ 0 ] ),
isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
hasOffset = !isWindow && !isDocument;
return {
element: withinElement,
isWindow: isWindow,
isDocument: isDocument,
offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
scrollLeft: withinElement.scrollLeft(),
scrollTop: withinElement.scrollTop(),
width: withinElement.outerWidth(),
height: withinElement.outerHeight()
};
}
};
$.fn.position = function( options ) {
if ( !options || !options.of ) {
return _position.apply( this, arguments );
}
// Make a copy, we don't want to modify arguments
options = $.extend( {}, options );
var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
target = $( options.of ),
within = $.position.getWithinInfo( options.within ),
scrollInfo = $.position.getScrollInfo( within ),
collision = ( options.collision || "flip" ).split( " " ),
offsets = {};
dimensions = getDimensions( target );
if ( target[ 0 ].preventDefault ) {
// Force left top to allow flipping
options.at = "left top";
}
targetWidth = dimensions.width;
targetHeight = dimensions.height;
targetOffset = dimensions.offset;
// Clone to reuse original targetOffset later
basePosition = $.extend( {}, targetOffset );
// Force my and at to have valid horizontal and vertical positions
// if a value is missing or invalid, it will be converted to center
$.each( [ "my", "at" ], function() {
var pos = ( options[ this ] || "" ).split( " " ),
horizontalOffset,
verticalOffset;
if ( pos.length === 1 ) {
pos = rhorizontal.test( pos[ 0 ] ) ?
pos.concat( [ "center" ] ) :
rvertical.test( pos[ 0 ] ) ?
[ "center" ].concat( pos ) :
[ "center", "center" ];
}
pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
// Calculate offsets
horizontalOffset = roffset.exec( pos[ 0 ] );
verticalOffset = roffset.exec( pos[ 1 ] );
offsets[ this ] = [
horizontalOffset ? horizontalOffset[ 0 ] : 0,
verticalOffset ? verticalOffset[ 0 ] : 0
];
// Reduce to just the positions without the offsets
options[ this ] = [
rposition.exec( pos[ 0 ] )[ 0 ],
rposition.exec( pos[ 1 ] )[ 0 ]
];
} );
// Normalize collision option
if ( collision.length === 1 ) {
collision[ 1 ] = collision[ 0 ];
}
if ( options.at[ 0 ] === "right" ) {
basePosition.left += targetWidth;
} else if ( options.at[ 0 ] === "center" ) {
basePosition.left += targetWidth / 2;
}
if ( options.at[ 1 ] === "bottom" ) {
basePosition.top += targetHeight;
} else if ( options.at[ 1 ] === "center" ) {
basePosition.top += targetHeight / 2;
}
atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
basePosition.left += atOffset[ 0 ];
basePosition.top += atOffset[ 1 ];
return this.each( function() {
var collisionPosition, using,
elem = $( this ),
elemWidth = elem.outerWidth(),
elemHeight = elem.outerHeight(),
marginLeft = parseCss( this, "marginLeft" ),
marginTop = parseCss( this, "marginTop" ),
collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
scrollInfo.width,
collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
scrollInfo.height,
position = $.extend( {}, basePosition ),
myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
if ( options.my[ 0 ] === "right" ) {
position.left -= elemWidth;
} else if ( options.my[ 0 ] === "center" ) {
position.left -= elemWidth / 2;
}
if ( options.my[ 1 ] === "bottom" ) {
position.top -= elemHeight;
} else if ( options.my[ 1 ] === "center" ) {
position.top -= elemHeight / 2;
}
position.left += myOffset[ 0 ];
position.top += myOffset[ 1 ];
collisionPosition = {
marginLeft: marginLeft,
marginTop: marginTop
};
$.each( [ "left", "top" ], function( i, dir ) {
if ( $.ui.position[ collision[ i ] ] ) {
$.ui.position[ collision[ i ] ][ dir ]( position, {
targetWidth: targetWidth,
targetHeight: targetHeight,
elemWidth: elemWidth,
elemHeight: elemHeight,
collisionPosition: collisionPosition,
collisionWidth: collisionWidth,
collisionHeight: collisionHeight,
offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
my: options.my,
at: options.at,
within: within,
elem: elem
} );
}
} );
if ( options.using ) {
// Adds feedback as second argument to using callback, if present
using = function( props ) {
var left = targetOffset.left - position.left,
right = left + targetWidth - elemWidth,
top = targetOffset.top - position.top,
bottom = top + targetHeight - elemHeight,
feedback = {
target: {
element: target,
left: targetOffset.left,
top: targetOffset.top,
width: targetWidth,
height: targetHeight
},
element: {
element: elem,
left: position.left,
top: position.top,
width: elemWidth,
height: elemHeight
},
horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
};
if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
feedback.horizontal = "center";
}
if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
feedback.vertical = "middle";
}
if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
feedback.important = "horizontal";
} else {
feedback.important = "vertical";
}
options.using.call( this, props, feedback );
};
}
elem.offset( $.extend( position, { using: using } ) );
} );
};
$.ui.position = {
fit: {
left: function( position, data ) {
var within = data.within,
withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
outerWidth = within.width,
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
overLeft = withinOffset - collisionPosLeft,
overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
newOverRight;
// Element is wider than within
if ( data.collisionWidth > outerWidth ) {
// Element is initially over the left side of within
if ( overLeft > 0 && overRight <= 0 ) {
newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
withinOffset;
position.left += overLeft - newOverRight;
// Element is initially over right side of within
} else if ( overRight > 0 && overLeft <= 0 ) {
position.left = withinOffset;
// Element is initially over both left and right sides of within
} else {
if ( overLeft > overRight ) {
position.left = withinOffset + outerWidth - data.collisionWidth;
} else {
position.left = withinOffset;
}
}
// Too far left -> align with left edge
} else if ( overLeft > 0 ) {
position.left += overLeft;
// Too far right -> align with right edge
} else if ( overRight > 0 ) {
position.left -= overRight;
// Adjust based on position and margin
} else {
position.left = max( position.left - collisionPosLeft, position.left );
}
},
top: function( position, data ) {
var within = data.within,
withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
outerHeight = data.within.height,
collisionPosTop = position.top - data.collisionPosition.marginTop,
overTop = withinOffset - collisionPosTop,
overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
newOverBottom;
// Element is taller than within
if ( data.collisionHeight > outerHeight ) {
// Element is initially over the top of within
if ( overTop > 0 && overBottom <= 0 ) {
newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
withinOffset;
position.top += overTop - newOverBottom;
// Element is initially over bottom of within
} else if ( overBottom > 0 && overTop <= 0 ) {
position.top = withinOffset;
// Element is initially over both top and bottom of within
} else {
if ( overTop > overBottom ) {
position.top = withinOffset + outerHeight - data.collisionHeight;
} else {
position.top = withinOffset;
}
}
// Too far up -> align with top
} else if ( overTop > 0 ) {
position.top += overTop;
// Too far down -> align with bottom edge
} else if ( overBottom > 0 ) {
position.top -= overBottom;
// Adjust based on position and margin
} else {
position.top = max( position.top - collisionPosTop, position.top );
}
}
},
flip: {
left: function( position, data ) {
var within = data.within,
withinOffset = within.offset.left + within.scrollLeft,
outerWidth = within.width,
offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
overLeft = collisionPosLeft - offsetLeft,
overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
myOffset = data.my[ 0 ] === "left" ?
-data.elemWidth :
data.my[ 0 ] === "right" ?
data.elemWidth :
0,
atOffset = data.at[ 0 ] === "left" ?
data.targetWidth :
data.at[ 0 ] === "right" ?
-data.targetWidth :
0,
offset = -2 * data.offset[ 0 ],
newOverRight,
newOverLeft;
if ( overLeft < 0 ) {
newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
outerWidth - withinOffset;
if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
position.left += myOffset + atOffset + offset;
}
} else if ( overRight > 0 ) {
newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
atOffset + offset - offsetLeft;
if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
position.left += myOffset + atOffset + offset;
}
}
},
top: function( position, data ) {
var within = data.within,
withinOffset = within.offset.top + within.scrollTop,
outerHeight = within.height,
offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
collisionPosTop = position.top - data.collisionPosition.marginTop,
overTop = collisionPosTop - offsetTop,
overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
top = data.my[ 1 ] === "top",
myOffset = top ?
-data.elemHeight :
data.my[ 1 ] === "bottom" ?
data.elemHeight :
0,
atOffset = data.at[ 1 ] === "top" ?
data.targetHeight :
data.at[ 1 ] === "bottom" ?
-data.targetHeight :
0,
offset = -2 * data.offset[ 1 ],
newOverTop,
newOverBottom;
if ( overTop < 0 ) {
newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
outerHeight - withinOffset;
if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
position.top += myOffset + atOffset + offset;
}
} else if ( overBottom > 0 ) {
newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
offset - offsetTop;
if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
position.top += myOffset + atOffset + offset;
}
}
}
},
flipfit: {
left: function() {
$.ui.position.flip.left.apply( this, arguments );
$.ui.position.fit.left.apply( this, arguments );
},
top: function() {
$.ui.position.flip.top.apply( this, arguments );
$.ui.position.fit.top.apply( this, arguments );
}
}
};
} )();
var position = $.ui.position;
/*!
* jQuery UI :data 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :data Selector
//>>group: Core
//>>description: Selects elements which have data stored under the specified key.
//>>docs: http://api.jqueryui.com/data-selector/
var data = $.extend( $.expr[ ":" ], {
data: $.expr.createPseudo ?
$.expr.createPseudo( function( dataName ) {
return function( elem ) {
return !!$.data( elem, dataName );
};
} ) :
// Support: jQuery <1.8
function( elem, i, match ) {
return !!$.data( elem, match[ 3 ] );
}
} );
/*!
* jQuery UI Disable Selection 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: disableSelection
//>>group: Core
//>>description: Disable selection of text content within the set of matched elements.
//>>docs: http://api.jqueryui.com/disableSelection/
// This file is deprecated
var disableSelection = $.fn.extend( {
disableSelection: ( function() {
var eventType = "onselectstart" in document.createElement( "div" ) ?
"selectstart" :
"mousedown";
return function() {
return this.on( eventType + ".ui-disableSelection", function( event ) {
event.preventDefault();
} );
};
} )(),
enableSelection: function() {
return this.off( ".ui-disableSelection" );
}
} );
/*!
* jQuery UI Effects 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Effects Core
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/category/effects-core/
//>>demos: http://jqueryui.com/effect/
var dataSpace = "ui-effects-",
dataSpaceStyle = "ui-effects-style",
dataSpaceAnimated = "ui-effects-animated",
// Create a local jQuery because jQuery Color relies on it and the
// global may not exist with AMD and a custom build (#10199)
jQuery = $;
$.effects = {
effect: {}
};
/*!
* jQuery Color Animations v2.1.2
* https://github.com/jquery/jquery-color
*
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* Date: Wed Jan 16 08:47:09 2013 -0600
*/
( function( jQuery, undefined ) {
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
// Plusequals test for += 100 -= 100
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
// A set of RE's that can match strings and generate color tuples.
stringParsers = [ {
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ],
execResult[ 3 ],
execResult[ 4 ]
];
}
}, {
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ] * 2.55,
execResult[ 2 ] * 2.55,
execResult[ 3 ] * 2.55,
execResult[ 4 ]
];
}
}, {
// This regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ], 16 )
];
}
}, {
// This regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
];
}
}, {
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
space: "hsla",
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ] / 100,
execResult[ 3 ] / 100,
execResult[ 4 ]
];
}
} ],
// JQuery.Color( )
color = jQuery.Color = function( color, green, blue, alpha ) {
return new jQuery.Color.fn.parse( color, green, blue, alpha );
},
spaces = {
rgba: {
props: {
red: {
idx: 0,
type: "byte"
},
green: {
idx: 1,
type: "byte"
},
blue: {
idx: 2,
type: "byte"
}
}
},
hsla: {
props: {
hue: {
idx: 0,
type: "degrees"
},
saturation: {
idx: 1,
type: "percent"
},
lightness: {
idx: 2,
type: "percent"
}
}
}
},
propTypes = {
"byte": {
floor: true,
max: 255
},
"percent": {
max: 1
},
"degrees": {
mod: 360,
floor: true
}
},
support = color.support = {},
// Element for support tests
supportElem = jQuery( "<p>" )[ 0 ],
// Colors = jQuery.Color.names
colors,
// Local aliases of functions called often
each = jQuery.each;
// Determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
// Define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
space.cache = "_" + spaceName;
space.props.alpha = {
idx: 3,
type: "percent",
def: 1
};
} );
function clamp( value, prop, allowEmpty ) {
var type = propTypes[ prop.type ] || {};
if ( value == null ) {
return ( allowEmpty || !prop.def ) ? null : prop.def;
}
// ~~ is an short way of doing floor for positive numbers
value = type.floor ? ~~value : parseFloat( value );
// IE will pass in empty strings as value for alpha,
// which will hit this case
if ( isNaN( value ) ) {
return prop.def;
}
if ( type.mod ) {
// We add mod before modding to make sure that negatives values
// get converted properly: -10 -> 350
return ( value + type.mod ) % type.mod;
}
// For now all property types without mod have min and max
return 0 > value ? 0 : type.max < value ? type.max : value;
}
function stringParse( string ) {
var inst = color(),
rgba = inst._rgba = [];
string = string.toLowerCase();
each( stringParsers, function( i, parser ) {
var parsed,
match = parser.re.exec( string ),
values = match && parser.parse( match ),
spaceName = parser.space || "rgba";
if ( values ) {
parsed = inst[ spaceName ]( values );
// If this was an rgba parse the assignment might happen twice
// oh well....
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
rgba = inst._rgba = parsed._rgba;
// Exit each( stringParsers ) here because we matched
return false;
}
} );
// Found a stringParser that handled it
if ( rgba.length ) {
// If this came from a parsed string, force "transparent" when alpha is 0
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
if ( rgba.join() === "0,0,0,0" ) {
jQuery.extend( rgba, colors.transparent );
}
return inst;
}
// Named colors
return colors[ string ];
}
color.fn = jQuery.extend( color.prototype, {
parse: function( red, green, blue, alpha ) {
if ( red === undefined ) {
this._rgba = [ null, null, null, null ];
return this;
}
if ( red.jquery || red.nodeType ) {
red = jQuery( red ).css( green );
green = undefined;
}
var inst = this,
type = jQuery.type( red ),
rgba = this._rgba = [];
// More than 1 argument specified - assume ( red, green, blue, alpha )
if ( green !== undefined ) {
red = [ red, green, blue, alpha ];
type = "array";
}
if ( type === "string" ) {
return this.parse( stringParse( red ) || colors._default );
}
if ( type === "array" ) {
each( spaces.rgba.props, function( key, prop ) {
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
} );
return this;
}
if ( type === "object" ) {
if ( red instanceof color ) {
each( spaces, function( spaceName, space ) {
if ( red[ space.cache ] ) {
inst[ space.cache ] = red[ space.cache ].slice();
}
} );
} else {
each( spaces, function( spaceName, space ) {
var cache = space.cache;
each( space.props, function( key, prop ) {
// If the cache doesn't exist, and we know how to convert
if ( !inst[ cache ] && space.to ) {
// If the value was null, we don't need to copy it
// if the key was alpha, we don't need to copy it either
if ( key === "alpha" || red[ key ] == null ) {
return;
}
inst[ cache ] = space.to( inst._rgba );
}
// This is the only case where we allow nulls for ALL properties.
// call clamp with alwaysAllowEmpty
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
} );
// Everything defined but alpha?
if ( inst[ cache ] &&
jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
// Use the default of 1
inst[ cache ][ 3 ] = 1;
if ( space.from ) {
inst._rgba = space.from( inst[ cache ] );
}
}
} );
}
return this;
}
},
is: function( compare ) {
var is = color( compare ),
same = true,
inst = this;
each( spaces, function( _, space ) {
var localCache,
isCache = is[ space.cache ];
if ( isCache ) {
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
each( space.props, function( _, prop ) {
if ( isCache[ prop.idx ] != null ) {
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
return same;
}
} );
}
return same;
} );
return same;
},
_space: function() {
var used = [],
inst = this;
each( spaces, function( spaceName, space ) {
if ( inst[ space.cache ] ) {
used.push( spaceName );
}
} );
return used.pop();
},
transition: function( other, distance ) {
var end = color( other ),
spaceName = end._space(),
space = spaces[ spaceName ],
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
start = startColor[ space.cache ] || space.to( startColor._rgba ),
result = start.slice();
end = end[ space.cache ];
each( space.props, function( key, prop ) {
var index = prop.idx,
startValue = start[ index ],
endValue = end[ index ],
type = propTypes[ prop.type ] || {};
// If null, don't override start value
if ( endValue === null ) {
return;
}
// If null - use end
if ( startValue === null ) {
result[ index ] = endValue;
} else {
if ( type.mod ) {
if ( endValue - startValue > type.mod / 2 ) {
startValue += type.mod;
} else if ( startValue - endValue > type.mod / 2 ) {
startValue -= type.mod;
}
}
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
}
} );
return this[ spaceName ]( result );
},
blend: function( opaque ) {
// If we are already opaque - return ourself
if ( this._rgba[ 3 ] === 1 ) {
return this;
}
var rgb = this._rgba.slice(),
a = rgb.pop(),
blend = color( opaque )._rgba;
return color( jQuery.map( rgb, function( v, i ) {
return ( 1 - a ) * blend[ i ] + a * v;
} ) );
},
toRgbaString: function() {
var prefix = "rgba(",
rgba = jQuery.map( this._rgba, function( v, i ) {
return v == null ? ( i > 2 ? 1 : 0 ) : v;
} );
if ( rgba[ 3 ] === 1 ) {
rgba.pop();
prefix = "rgb(";
}
return prefix + rgba.join() + ")";
},
toHslaString: function() {
var prefix = "hsla(",
hsla = jQuery.map( this.hsla(), function( v, i ) {
if ( v == null ) {
v = i > 2 ? 1 : 0;
}
// Catch 1 and 2
if ( i && i < 3 ) {
v = Math.round( v * 100 ) + "%";
}
return v;
} );
if ( hsla[ 3 ] === 1 ) {
hsla.pop();
prefix = "hsl(";
}
return prefix + hsla.join() + ")";
},
toHexString: function( includeAlpha ) {
var rgba = this._rgba.slice(),
alpha = rgba.pop();
if ( includeAlpha ) {
rgba.push( ~~( alpha * 255 ) );
}
return "#" + jQuery.map( rgba, function( v ) {
// Default to 0 when nulls exist
v = ( v || 0 ).toString( 16 );
return v.length === 1 ? "0" + v : v;
} ).join( "" );
},
toString: function() {
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
}
} );
color.fn.parse.prototype = color.fn;
// Hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
function hue2rgb( p, q, h ) {
h = ( h + 1 ) % 1;
if ( h * 6 < 1 ) {
return p + ( q - p ) * h * 6;
}
if ( h * 2 < 1 ) {
return q;
}
if ( h * 3 < 2 ) {
return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
}
return p;
}
spaces.hsla.to = function( rgba ) {
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
return [ null, null, null, rgba[ 3 ] ];
}
var r = rgba[ 0 ] / 255,
g = rgba[ 1 ] / 255,
b = rgba[ 2 ] / 255,
a = rgba[ 3 ],
max = Math.max( r, g, b ),
min = Math.min( r, g, b ),
diff = max - min,
add = max + min,
l = add * 0.5,
h, s;
if ( min === max ) {
h = 0;
} else if ( r === max ) {
h = ( 60 * ( g - b ) / diff ) + 360;
} else if ( g === max ) {
h = ( 60 * ( b - r ) / diff ) + 120;
} else {
h = ( 60 * ( r - g ) / diff ) + 240;
}
// Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
if ( diff === 0 ) {
s = 0;
} else if ( l <= 0.5 ) {
s = diff / add;
} else {
s = diff / ( 2 - add );
}
return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
};
spaces.hsla.from = function( hsla ) {
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
return [ null, null, null, hsla[ 3 ] ];
}
var h = hsla[ 0 ] / 360,
s = hsla[ 1 ],
l = hsla[ 2 ],
a = hsla[ 3 ],
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
p = 2 * l - q;
return [
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Math.round( hue2rgb( p, q, h ) * 255 ),
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
a
];
};
each( spaces, function( spaceName, space ) {
var props = space.props,
cache = space.cache,
to = space.to,
from = space.from;
// Makes rgba() and hsla()
color.fn[ spaceName ] = function( value ) {
// Generate a cache for this space if it doesn't exist
if ( to && !this[ cache ] ) {
this[ cache ] = to( this._rgba );
}
if ( value === undefined ) {
return this[ cache ].slice();
}
var ret,
type = jQuery.type( value ),
arr = ( type === "array" || type === "object" ) ? value : arguments,
local = this[ cache ].slice();
each( props, function( key, prop ) {
var val = arr[ type === "object" ? key : prop.idx ];
if ( val == null ) {
val = local[ prop.idx ];
}
local[ prop.idx ] = clamp( val, prop );
} );
if ( from ) {
ret = color( from( local ) );
ret[ cache ] = local;
return ret;
} else {
return color( local );
}
};
// Makes red() green() blue() alpha() hue() saturation() lightness()
each( props, function( key, prop ) {
// Alpha is included in more than one space
if ( color.fn[ key ] ) {
return;
}
color.fn[ key ] = function( value ) {
var vtype = jQuery.type( value ),
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
local = this[ fn ](),
cur = local[ prop.idx ],
match;
if ( vtype === "undefined" ) {
return cur;
}
if ( vtype === "function" ) {
value = value.call( this, cur );
vtype = jQuery.type( value );
}
if ( value == null && prop.empty ) {
return this;
}
if ( vtype === "string" ) {
match = rplusequals.exec( value );
if ( match ) {
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
}
}
local[ prop.idx ] = value;
return this[ fn ]( local );
};
} );
} );
// Add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
var hooks = hook.split( " " );
each( hooks, function( i, hook ) {
jQuery.cssHooks[ hook ] = {
set: function( elem, value ) {
var parsed, curElem,
backgroundColor = "";
if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
( parsed = stringParse( value ) ) ) ) {
value = color( parsed || value );
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
while (
( backgroundColor === "" || backgroundColor === "transparent" ) &&
curElem && curElem.style
) {
try {
backgroundColor = jQuery.css( curElem, "backgroundColor" );
curElem = curElem.parentNode;
} catch ( e ) {
}
}
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
backgroundColor :
"_default" );
}
value = value.toRgbaString();
}
try {
elem.style[ hook ] = value;
} catch ( e ) {
// Wrapped to prevent IE from throwing errors on "invalid" values like
// 'auto' or 'inherit'
}
}
};
jQuery.fx.step[ hook ] = function( fx ) {
if ( !fx.colorInit ) {
fx.start = color( fx.elem, hook );
fx.end = color( fx.end );
fx.colorInit = true;
}
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
};
} );
};
color.hook( stepHooks );
jQuery.cssHooks.borderColor = {
expand: function( value ) {
var expanded = {};
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
expanded[ "border" + part + "Color" ] = value;
} );
return expanded;
}
};
// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {
// 4.1. Basic color keywords
aqua: "#00ffff",
black: "#000000",
blue: "#0000ff",
fuchsia: "#ff00ff",
gray: "#808080",
green: "#008000",
lime: "#00ff00",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
purple: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
teal: "#008080",
white: "#ffffff",
yellow: "#ffff00",
// 4.2.3. "transparent" color keyword
transparent: [ null, null, null, 0 ],
_default: "#ffffff"
};
} )( jQuery );
/******************************************************************************/
/****************************** CLASS ANIMATIONS ******************************/
/******************************************************************************/
( function() {
var classAnimationActions = [ "add", "remove", "toggle" ],
shorthandStyles = {
border: 1,
borderBottom: 1,
borderColor: 1,
borderLeft: 1,
borderRight: 1,
borderTop: 1,
borderWidth: 1,
margin: 1,
padding: 1
};
$.each(
[ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
function( _, prop ) {
$.fx.step[ prop ] = function( fx ) {
if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
jQuery.style( fx.elem, prop, fx.end );
fx.setAttr = true;
}
};
}
);
function getElementStyles( elem ) {
var key, len,
style = elem.ownerDocument.defaultView ?
elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
elem.currentStyle,
styles = {};
if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
len = style.length;
while ( len-- ) {
key = style[ len ];
if ( typeof style[ key ] === "string" ) {
styles[ $.camelCase( key ) ] = style[ key ];
}
}
// Support: Opera, IE <9
} else {
for ( key in style ) {
if ( typeof style[ key ] === "string" ) {
styles[ key ] = style[ key ];
}
}
}
return styles;
}
function styleDifference( oldStyle, newStyle ) {
var diff = {},
name, value;
for ( name in newStyle ) {
value = newStyle[ name ];
if ( oldStyle[ name ] !== value ) {
if ( !shorthandStyles[ name ] ) {
if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
diff[ name ] = value;
}
}
}
}
return diff;
}
// Support: jQuery <1.8
if ( !$.fn.addBack ) {
$.fn.addBack = function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
};
}
$.effects.animateClass = function( value, duration, easing, callback ) {
var o = $.speed( duration, easing, callback );
return this.queue( function() {
var animated = $( this ),
baseClass = animated.attr( "class" ) || "",
applyClassChange,
allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
// Map the animated objects to store the original styles.
allAnimations = allAnimations.map( function() {
var el = $( this );
return {
el: el,
start: getElementStyles( this )
};
} );
// Apply class change
applyClassChange = function() {
$.each( classAnimationActions, function( i, action ) {
if ( value[ action ] ) {
animated[ action + "Class" ]( value[ action ] );
}
} );
};
applyClassChange();
// Map all animated objects again - calculate new styles and diff
allAnimations = allAnimations.map( function() {
this.end = getElementStyles( this.el[ 0 ] );
this.diff = styleDifference( this.start, this.end );
return this;
} );
// Apply original class
animated.attr( "class", baseClass );
// Map all animated objects again - this time collecting a promise
allAnimations = allAnimations.map( function() {
var styleInfo = this,
dfd = $.Deferred(),
opts = $.extend( {}, o, {
queue: false,
complete: function() {
dfd.resolve( styleInfo );
}
} );
this.el.animate( this.diff, opts );
return dfd.promise();
} );
// Once all animations have completed:
$.when.apply( $, allAnimations.get() ).done( function() {
// Set the final class
applyClassChange();
// For each animated element,
// clear all css properties that were animated
$.each( arguments, function() {
var el = this.el;
$.each( this.diff, function( key ) {
el.css( key, "" );
} );
} );
// This is guarnteed to be there if you use jQuery.speed()
// it also handles dequeuing the next anim...
o.complete.call( animated[ 0 ] );
} );
} );
};
$.fn.extend( {
addClass: ( function( orig ) {
return function( classNames, speed, easing, callback ) {
return speed ?
$.effects.animateClass.call( this,
{ add: classNames }, speed, easing, callback ) :
orig.apply( this, arguments );
};
} )( $.fn.addClass ),
removeClass: ( function( orig ) {
return function( classNames, speed, easing, callback ) {
return arguments.length > 1 ?
$.effects.animateClass.call( this,
{ remove: classNames }, speed, easing, callback ) :
orig.apply( this, arguments );
};
} )( $.fn.removeClass ),
toggleClass: ( function( orig ) {
return function( classNames, force, speed, easing, callback ) {
if ( typeof force === "boolean" || force === undefined ) {
if ( !speed ) {
// Without speed parameter
return orig.apply( this, arguments );
} else {
return $.effects.animateClass.call( this,
( force ? { add: classNames } : { remove: classNames } ),
speed, easing, callback );
}
} else {
// Without force parameter
return $.effects.animateClass.call( this,
{ toggle: classNames }, force, speed, easing );
}
};
} )( $.fn.toggleClass ),
switchClass: function( remove, add, speed, easing, callback ) {
return $.effects.animateClass.call( this, {
add: add,
remove: remove
}, speed, easing, callback );
}
} );
} )();
/******************************************************************************/
/*********************************** EFFECTS **********************************/
/******************************************************************************/
( function() {
if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
$.expr.filters.animated = ( function( orig ) {
return function( elem ) {
return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
};
} )( $.expr.filters.animated );
}
if ( $.uiBackCompat !== false ) {
$.extend( $.effects, {
// Saves a set of properties in a data storage
save: function( element, set ) {
var i = 0, length = set.length;
for ( ; i < length; i++ ) {
if ( set[ i ] !== null ) {
element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
}
}
},
// Restores a set of previously saved properties from a data storage
restore: function( element, set ) {
var val, i = 0, length = set.length;
for ( ; i < length; i++ ) {
if ( set[ i ] !== null ) {
val = element.data( dataSpace + set[ i ] );
element.css( set[ i ], val );
}
}
},
setMode: function( el, mode ) {
if ( mode === "toggle" ) {
mode = el.is( ":hidden" ) ? "show" : "hide";
}
return mode;
},
// Wraps the element around a wrapper that copies position properties
createWrapper: function( element ) {
// If the element is already wrapped, return it
if ( element.parent().is( ".ui-effects-wrapper" ) ) {
return element.parent();
}
// Wrap the element
var props = {
width: element.outerWidth( true ),
height: element.outerHeight( true ),
"float": element.css( "float" )
},
wrapper = $( "<div></div>" )
.addClass( "ui-effects-wrapper" )
.css( {
fontSize: "100%",
background: "transparent",
border: "none",
margin: 0,
padding: 0
} ),
// Store the size in case width/height are defined in % - Fixes #5245
size = {
width: element.width(),
height: element.height()
},
active = document.activeElement;
// Support: Firefox
// Firefox incorrectly exposes anonymous content
// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
try {
active.id;
} catch ( e ) {
active = document.body;
}
element.wrap( wrapper );
// Fixes #7595 - Elements lose focus when wrapped.
if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
$( active ).trigger( "focus" );
}
// Hotfix for jQuery 1.4 since some change in wrap() seems to actually
// lose the reference to the wrapped element
wrapper = element.parent();
// Transfer positioning properties to the wrapper
if ( element.css( "position" ) === "static" ) {
wrapper.css( { position: "relative" } );
element.css( { position: "relative" } );
} else {
$.extend( props, {
position: element.css( "position" ),
zIndex: element.css( "z-index" )
} );
$.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
props[ pos ] = element.css( pos );
if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
props[ pos ] = "auto";
}
} );
element.css( {
position: "relative",
top: 0,
left: 0,
right: "auto",
bottom: "auto"
} );
}
element.css( size );
return wrapper.css( props ).show();
},
removeWrapper: function( element ) {
var active = document.activeElement;
if ( element.parent().is( ".ui-effects-wrapper" ) ) {
element.parent().replaceWith( element );
// Fixes #7595 - Elements lose focus when wrapped.
if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
$( active ).trigger( "focus" );
}
}
return element;
}
} );
}
$.extend( $.effects, {
version: "1.12.1",
define: function( name, mode, effect ) {
if ( !effect ) {
effect = mode;
mode = "effect";
}
$.effects.effect[ name ] = effect;
$.effects.effect[ name ].mode = mode;
return effect;
},
scaledDimensions: function( element, percent, direction ) {
if ( percent === 0 ) {
return {
height: 0,
width: 0,
outerHeight: 0,
outerWidth: 0
};
}
var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
return {
height: element.height() * y,
width: element.width() * x,
outerHeight: element.outerHeight() * y,
outerWidth: element.outerWidth() * x
};
},
clipToBox: function( animation ) {
return {
width: animation.clip.right - animation.clip.left,
height: animation.clip.bottom - animation.clip.top,
left: animation.clip.left,
top: animation.clip.top
};
},
// Injects recently queued functions to be first in line (after "inprogress")
unshift: function( element, queueLength, count ) {
var queue = element.queue();
if ( queueLength > 1 ) {
queue.splice.apply( queue,
[ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
}
element.dequeue();
},
saveStyle: function( element ) {
element.data( dataSpaceStyle, element[ 0 ].style.cssText );
},
restoreStyle: function( element ) {
element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
element.removeData( dataSpaceStyle );
},
mode: function( element, mode ) {
var hidden = element.is( ":hidden" );
if ( mode === "toggle" ) {
mode = hidden ? "show" : "hide";
}
if ( hidden ? mode === "hide" : mode === "show" ) {
mode = "none";
}
return mode;
},
// Translates a [top,left] array into a baseline value
getBaseline: function( origin, original ) {
var y, x;
switch ( origin[ 0 ] ) {
case "top":
y = 0;
break;
case "middle":
y = 0.5;
break;
case "bottom":
y = 1;
break;
default:
y = origin[ 0 ] / original.height;
}
switch ( origin[ 1 ] ) {
case "left":
x = 0;
break;
case "center":
x = 0.5;
break;
case "right":
x = 1;
break;
default:
x = origin[ 1 ] / original.width;
}
return {
x: x,
y: y
};
},
// Creates a placeholder element so that the original element can be made absolute
createPlaceholder: function( element ) {
var placeholder,
cssPosition = element.css( "position" ),
position = element.position();
// Lock in margins first to account for form elements, which
// will change margin if you explicitly set height
// see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
// Support: Safari
element.css( {
marginTop: element.css( "marginTop" ),
marginBottom: element.css( "marginBottom" ),
marginLeft: element.css( "marginLeft" ),
marginRight: element.css( "marginRight" )
} )
.outerWidth( element.outerWidth() )
.outerHeight( element.outerHeight() );
if ( /^(static|relative)/.test( cssPosition ) ) {
cssPosition = "absolute";
placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
// Convert inline to inline block to account for inline elements
// that turn to inline block based on content (like img)
display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
"inline-block" :
"block",
visibility: "hidden",
// Margins need to be set to account for margin collapse
marginTop: element.css( "marginTop" ),
marginBottom: element.css( "marginBottom" ),
marginLeft: element.css( "marginLeft" ),
marginRight: element.css( "marginRight" ),
"float": element.css( "float" )
} )
.outerWidth( element.outerWidth() )
.outerHeight( element.outerHeight() )
.addClass( "ui-effects-placeholder" );
element.data( dataSpace + "placeholder", placeholder );
}
element.css( {
position: cssPosition,
left: position.left,
top: position.top
} );
return placeholder;
},
removePlaceholder: function( element ) {
var dataKey = dataSpace + "placeholder",
placeholder = element.data( dataKey );
if ( placeholder ) {
placeholder.remove();
element.removeData( dataKey );
}
},
// Removes a placeholder if it exists and restores
// properties that were modified during placeholder creation
cleanUp: function( element ) {
$.effects.restoreStyle( element );
$.effects.removePlaceholder( element );
},
setTransition: function( element, list, factor, value ) {
value = value || {};
$.each( list, function( i, x ) {
var unit = element.cssUnit( x );
if ( unit[ 0 ] > 0 ) {
value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
}
} );
return value;
}
} );
// Return an effect options object for the given parameters:
function _normalizeArguments( effect, options, speed, callback ) {
// Allow passing all options as the first parameter
if ( $.isPlainObject( effect ) ) {
options = effect;
effect = effect.effect;
}
// Convert to an object
effect = { effect: effect };
// Catch (effect, null, ...)
if ( options == null ) {
options = {};
}
// Catch (effect, callback)
if ( $.isFunction( options ) ) {
callback = options;
speed = null;
options = {};
}
// Catch (effect, speed, ?)
if ( typeof options === "number" || $.fx.speeds[ options ] ) {
callback = speed;
speed = options;
options = {};
}
// Catch (effect, options, callback)
if ( $.isFunction( speed ) ) {
callback = speed;
speed = null;
}
// Add options to effect
if ( options ) {
$.extend( effect, options );
}
speed = speed || options.duration;
effect.duration = $.fx.off ? 0 :
typeof speed === "number" ? speed :
speed in $.fx.speeds ? $.fx.speeds[ speed ] :
$.fx.speeds._default;
effect.complete = callback || options.complete;
return effect;
}
function standardAnimationOption( option ) {
// Valid standard speeds (nothing, number, named speed)
if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
return true;
}
// Invalid strings - treat as "normal" speed
if ( typeof option === "string" && !$.effects.effect[ option ] ) {
return true;
}
// Complete callback
if ( $.isFunction( option ) ) {
return true;
}
// Options hash (but not naming an effect)
if ( typeof option === "object" && !option.effect ) {
return true;
}
// Didn't match any standard API
return false;
}
$.fn.extend( {
effect: function( /* effect, options, speed, callback */ ) {
var args = _normalizeArguments.apply( this, arguments ),
effectMethod = $.effects.effect[ args.effect ],
defaultMode = effectMethod.mode,
queue = args.queue,
queueName = queue || "fx",
complete = args.complete,
mode = args.mode,
modes = [],
prefilter = function( next ) {
var el = $( this ),
normalizedMode = $.effects.mode( el, mode ) || defaultMode;
// Sentinel for duck-punching the :animated psuedo-selector
el.data( dataSpaceAnimated, true );
// Save effect mode for later use,
// we can't just call $.effects.mode again later,
// as the .show() below destroys the initial state
modes.push( normalizedMode );
// See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
if ( defaultMode && ( normalizedMode === "show" ||
( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
el.show();
}
if ( !defaultMode || normalizedMode !== "none" ) {
$.effects.saveStyle( el );
}
if ( $.isFunction( next ) ) {
next();
}
};
if ( $.fx.off || !effectMethod ) {
// Delegate to the original method (e.g., .show()) if possible
if ( mode ) {
return this[ mode ]( args.duration, complete );
} else {
return this.each( function() {
if ( complete ) {
complete.call( this );
}
} );
}
}
function run( next ) {
var elem = $( this );
function cleanup() {
elem.removeData( dataSpaceAnimated );
$.effects.cleanUp( elem );
if ( args.mode === "hide" ) {
elem.hide();
}
done();
}
function done() {
if ( $.isFunction( complete ) ) {
complete.call( elem[ 0 ] );
}
if ( $.isFunction( next ) ) {
next();
}
}
// Override mode option on a per element basis,
// as toggle can be either show or hide depending on element state
args.mode = modes.shift();
if ( $.uiBackCompat !== false && !defaultMode ) {
if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
// Call the core method to track "olddisplay" properly
elem[ mode ]();
done();
} else {
effectMethod.call( elem[ 0 ], args, done );
}
} else {
if ( args.mode === "none" ) {
// Call the core method to track "olddisplay" properly
elem[ mode ]();
done();
} else {
effectMethod.call( elem[ 0 ], args, cleanup );
}
}
}
// Run prefilter on all elements first to ensure that
// any showing or hiding happens before placeholder creation,
// which ensures that any layout changes are correctly captured.
return queue === false ?
this.each( prefilter ).each( run ) :
this.queue( queueName, prefilter ).queue( queueName, run );
},
show: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "show";
return this.effect.call( this, args );
}
};
} )( $.fn.show ),
hide: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "hide";
return this.effect.call( this, args );
}
};
} )( $.fn.hide ),
toggle: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "toggle";
return this.effect.call( this, args );
}
};
} )( $.fn.toggle ),
cssUnit: function( key ) {
var style = this.css( key ),
val = [];
$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
if ( style.indexOf( unit ) > 0 ) {
val = [ parseFloat( style ), unit ];
}
} );
return val;
},
cssClip: function( clipObj ) {
if ( clipObj ) {
return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
clipObj.bottom + "px " + clipObj.left + "px)" );
}
return parseClip( this.css( "clip" ), this );
},
transfer: function( options, done ) {
var element = $( this ),
target = $( options.to ),
targetFixed = target.css( "position" ) === "fixed",
body = $( "body" ),
fixTop = targetFixed ? body.scrollTop() : 0,
fixLeft = targetFixed ? body.scrollLeft() : 0,
endPosition = target.offset(),
animation = {
top: endPosition.top - fixTop,
left: endPosition.left - fixLeft,
height: target.innerHeight(),
width: target.innerWidth()
},
startPosition = element.offset(),
transfer = $( "<div class='ui-effects-transfer'></div>" )
.appendTo( "body" )
.addClass( options.className )
.css( {
top: startPosition.top - fixTop,
left: startPosition.left - fixLeft,
height: element.innerHeight(),
width: element.innerWidth(),
position: targetFixed ? "fixed" : "absolute"
} )
.animate( animation, options.duration, options.easing, function() {
transfer.remove();
if ( $.isFunction( done ) ) {
done();
}
} );
}
} );
function parseClip( str, element ) {
var outerWidth = element.outerWidth(),
outerHeight = element.outerHeight(),
clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
return {
top: parseFloat( values[ 1 ] ) || 0,
right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
left: parseFloat( values[ 4 ] ) || 0
};
}
$.fx.step.clip = function( fx ) {
if ( !fx.clipInit ) {
fx.start = $( fx.elem ).cssClip();
if ( typeof fx.end === "string" ) {
fx.end = parseClip( fx.end, fx.elem );
}
fx.clipInit = true;
}
$( fx.elem ).cssClip( {
top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
} );
};
} )();
/******************************************************************************/
/*********************************** EASING ***********************************/
/******************************************************************************/
( function() {
// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
var baseEasings = {};
$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
baseEasings[ name ] = function( p ) {
return Math.pow( p, i + 2 );
};
} );
$.extend( baseEasings, {
Sine: function( p ) {
return 1 - Math.cos( p * Math.PI / 2 );
},
Circ: function( p ) {
return 1 - Math.sqrt( 1 - p * p );
},
Elastic: function( p ) {
return p === 0 || p === 1 ? p :
-Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
},
Back: function( p ) {
return p * p * ( 3 * p - 2 );
},
Bounce: function( p ) {
var pow2,
bounce = 4;
while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
}
} );
$.each( baseEasings, function( name, easeIn ) {
$.easing[ "easeIn" + name ] = easeIn;
$.easing[ "easeOut" + name ] = function( p ) {
return 1 - easeIn( 1 - p );
};
$.easing[ "easeInOut" + name ] = function( p ) {
return p < 0.5 ?
easeIn( p * 2 ) / 2 :
1 - easeIn( p * -2 + 2 ) / 2;
};
} );
} )();
var effect = $.effects;
/*!
* jQuery UI Effects Blind 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Blind Effect
//>>group: Effects
//>>description: Blinds the element.
//>>docs: http://api.jqueryui.com/blind-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
var map = {
up: [ "bottom", "top" ],
vertical: [ "bottom", "top" ],
down: [ "top", "bottom" ],
left: [ "right", "left" ],
horizontal: [ "right", "left" ],
right: [ "left", "right" ]
},
element = $( this ),
direction = options.direction || "up",
start = element.cssClip(),
animate = { clip: $.extend( {}, start ) },
placeholder = $.effects.createPlaceholder( element );
animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
if ( options.mode === "show" ) {
element.cssClip( animate.clip );
if ( placeholder ) {
placeholder.css( $.effects.clipToBox( animate ) );
}
animate.clip = start;
}
if ( placeholder ) {
placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
}
element.animate( animate, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Bounce 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Bounce Effect
//>>group: Effects
//>>description: Bounces an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/bounce-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
var upAnim, downAnim, refValue,
element = $( this ),
// Defaults:
mode = options.mode,
hide = mode === "hide",
show = mode === "show",
direction = options.direction || "up",
distance = options.distance,
times = options.times || 5,
// Number of internal animations
anims = times * 2 + ( show || hide ? 1 : 0 ),
speed = options.duration / anims,
easing = options.easing,
// Utility:
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
motion = ( direction === "up" || direction === "left" ),
i = 0,
queuelen = element.queue().length;
$.effects.createPlaceholder( element );
refValue = element.css( ref );
// Default distance for the BIGGEST bounce is the outer Distance / 3
if ( !distance ) {
distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
}
if ( show ) {
downAnim = { opacity: 1 };
downAnim[ ref ] = refValue;
// If we are showing, force opacity 0 and set the initial position
// then do the "first" animation
element
.css( "opacity", 0 )
.css( ref, motion ? -distance * 2 : distance * 2 )
.animate( downAnim, speed, easing );
}
// Start at the smallest distance if we are hiding
if ( hide ) {
distance = distance / Math.pow( 2, times - 1 );
}
downAnim = {};
downAnim[ ref ] = refValue;
// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
for ( ; i < times; i++ ) {
upAnim = {};
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
element
.animate( upAnim, speed, easing )
.animate( downAnim, speed, easing );
distance = hide ? distance * 2 : distance / 2;
}
// Last Bounce when Hiding
if ( hide ) {
upAnim = { opacity: 0 };
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
element.animate( upAnim, speed, easing );
}
element.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Clip 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Clip Effect
//>>group: Effects
//>>description: Clips the element on and off like an old TV.
//>>docs: http://api.jqueryui.com/clip-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
var start,
animate = {},
element = $( this ),
direction = options.direction || "vertical",
both = direction === "both",
horizontal = both || direction === "horizontal",
vertical = both || direction === "vertical";
start = element.cssClip();
animate.clip = {
top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
right: horizontal ? ( start.right - start.left ) / 2 : start.right,
bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
left: horizontal ? ( start.right - start.left ) / 2 : start.left
};
$.effects.createPlaceholder( element );
if ( options.mode === "show" ) {
element.cssClip( animate.clip );
animate.clip = start;
}
element.animate( animate, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Drop 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Drop Effect
//>>group: Effects
//>>description: Moves an element in one direction and hides it at the same time.
//>>docs: http://api.jqueryui.com/drop-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
var distance,
element = $( this ),
mode = options.mode,
show = mode === "show",
direction = options.direction || "left",
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
animation = {
opacity: 0
};
$.effects.createPlaceholder( element );
distance = options.distance ||
element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
animation[ ref ] = motion + distance;
if ( show ) {
element.css( animation );
animation[ ref ] = oppositeMotion + distance;
animation.opacity = 1;
}
// Animate
element.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Explode 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Explode Effect
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/explode-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
var i, j, left, top, mx, my,
rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
cells = rows,
element = $( this ),
mode = options.mode,
show = mode === "show",
// Show and then visibility:hidden the element before calculating offset
offset = element.show().css( "visibility", "hidden" ).offset(),
// Width and height of a piece
width = Math.ceil( element.outerWidth() / cells ),
height = Math.ceil( element.outerHeight() / rows ),
pieces = [];
// Children animate complete:
function childComplete() {
pieces.push( this );
if ( pieces.length === rows * cells ) {
animComplete();
}
}
// Clone the element for each row and cell.
for ( i = 0; i < rows; i++ ) { // ===>
top = offset.top + i * height;
my = i - ( rows - 1 ) / 2;
for ( j = 0; j < cells; j++ ) { // |||
left = offset.left + j * width;
mx = j - ( cells - 1 ) / 2;
// Create a clone of the now hidden main element that will be absolute positioned
// within a wrapper div off the -left and -top equal to size of our pieces
element
.clone()
.appendTo( "body" )
.wrap( "<div></div>" )
.css( {
position: "absolute",
visibility: "visible",
left: -j * width,
top: -i * height
} )
// Select the wrapper - make it overflow: hidden and absolute positioned based on
// where the original was located +left and +top equal to the size of pieces
.parent()
.addClass( "ui-effects-explode" )
.css( {
position: "absolute",
overflow: "hidden",
width: width,
height: height,
left: left + ( show ? mx * width : 0 ),
top: top + ( show ? my * height : 0 ),
opacity: show ? 0 : 1
} )
.animate( {
left: left + ( show ? 0 : mx * width ),
top: top + ( show ? 0 : my * height ),
opacity: show ? 1 : 0
}, options.duration || 500, options.easing, childComplete );
}
}
function animComplete() {
element.css( {
visibility: "visible"
} );
$( pieces ).remove();
done();
}
} );
/*!
* jQuery UI Effects Fade 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Fade Effect
//>>group: Effects
//>>description: Fades the element.
//>>docs: http://api.jqueryui.com/fade-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
var show = options.mode === "show";
$( this )
.css( "opacity", show ? 0 : 1 )
.animate( {
opacity: show ? 1 : 0
}, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Fold 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Fold Effect
//>>group: Effects
//>>description: Folds an element first horizontally and then vertically.
//>>docs: http://api.jqueryui.com/fold-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
// Create element
var element = $( this ),
mode = options.mode,
show = mode === "show",
hide = mode === "hide",
size = options.size || 15,
percent = /([0-9]+)%/.exec( size ),
horizFirst = !!options.horizFirst,
ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
duration = options.duration / 2,
placeholder = $.effects.createPlaceholder( element ),
start = element.cssClip(),
animation1 = { clip: $.extend( {}, start ) },
animation2 = { clip: $.extend( {}, start ) },
distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
queuelen = element.queue().length;
if ( percent ) {
size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
}
animation1.clip[ ref[ 0 ] ] = size;
animation2.clip[ ref[ 0 ] ] = size;
animation2.clip[ ref[ 1 ] ] = 0;
if ( show ) {
element.cssClip( animation2.clip );
if ( placeholder ) {
placeholder.css( $.effects.clipToBox( animation2 ) );
}
animation2.clip = start;
}
// Animate
element
.queue( function( next ) {
if ( placeholder ) {
placeholder
.animate( $.effects.clipToBox( animation1 ), duration, options.easing )
.animate( $.effects.clipToBox( animation2 ), duration, options.easing );
}
next();
} )
.animate( animation1, duration, options.easing )
.animate( animation2, duration, options.easing )
.queue( done );
$.effects.unshift( element, queuelen, 4 );
} );
/*!
* jQuery UI Effects Highlight 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Highlight Effect
//>>group: Effects
//>>description: Highlights the background of an element in a defined color for a custom duration.
//>>docs: http://api.jqueryui.com/highlight-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
var element = $( this ),
animation = {
backgroundColor: element.css( "backgroundColor" )
};
if ( options.mode === "hide" ) {
animation.opacity = 0;
}
$.effects.saveStyle( element );
element
.css( {
backgroundImage: "none",
backgroundColor: options.color || "#ffff99"
} )
.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Size 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Size Effect
//>>group: Effects
//>>description: Resize an element to a specified width and height.
//>>docs: http://api.jqueryui.com/size-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectSize = $.effects.define( "size", function( options, done ) {
// Create element
var baseline, factor, temp,
element = $( this ),
// Copy for children
cProps = [ "fontSize" ],
vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
// Set options
mode = options.mode,
restore = mode !== "effect",
scale = options.scale || "both",
origin = options.origin || [ "middle", "center" ],
position = element.css( "position" ),
pos = element.position(),
original = $.effects.scaledDimensions( element ),
from = options.from || original,
to = options.to || $.effects.scaledDimensions( element, 0 );
$.effects.createPlaceholder( element );
if ( mode === "show" ) {
temp = from;
from = to;
to = temp;
}
// Set scaling factor
factor = {
from: {
y: from.height / original.height,
x: from.width / original.width
},
to: {
y: to.height / original.height,
x: to.width / original.width
}
};
// Scale the css box
if ( scale === "box" || scale === "both" ) {
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
from = $.effects.setTransition( element, vProps, factor.from.y, from );
to = $.effects.setTransition( element, vProps, factor.to.y, to );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
from = $.effects.setTransition( element, hProps, factor.from.x, from );
to = $.effects.setTransition( element, hProps, factor.to.x, to );
}
}
// Scale the content
if ( scale === "content" || scale === "both" ) {
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
from = $.effects.setTransition( element, cProps, factor.from.y, from );
to = $.effects.setTransition( element, cProps, factor.to.y, to );
}
}
// Adjust the position properties based on the provided origin points
if ( origin ) {
baseline = $.effects.getBaseline( origin, original );
from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
}
element.css( from );
// Animate the children if desired
if ( scale === "content" || scale === "both" ) {
vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
// Only animate children with width attributes specified
// TODO: is this right? should we include anything with css width specified as well
element.find( "*[width]" ).each( function() {
var child = $( this ),
childOriginal = $.effects.scaledDimensions( child ),
childFrom = {
height: childOriginal.height * factor.from.y,
width: childOriginal.width * factor.from.x,
outerHeight: childOriginal.outerHeight * factor.from.y,
outerWidth: childOriginal.outerWidth * factor.from.x
},
childTo = {
height: childOriginal.height * factor.to.y,
width: childOriginal.width * factor.to.x,
outerHeight: childOriginal.height * factor.to.y,
outerWidth: childOriginal.width * factor.to.x
};
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
}
if ( restore ) {
$.effects.saveStyle( child );
}
// Animate children
child.css( childFrom );
child.animate( childTo, options.duration, options.easing, function() {
// Restore children
if ( restore ) {
$.effects.restoreStyle( child );
}
} );
} );
}
// Animate
element.animate( to, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: function() {
var offset = element.offset();
if ( to.opacity === 0 ) {
element.css( "opacity", from.opacity );
}
if ( !restore ) {
element
.css( "position", position === "static" ? "relative" : position )
.offset( offset );
// Need to save style here so that automatic style restoration
// doesn't restore to the original styles from before the animation.
$.effects.saveStyle( element );
}
done();
}
} );
} );
/*!
* jQuery UI Effects Scale 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Scale Effect
//>>group: Effects
//>>description: Grows or shrinks an element and its content.
//>>docs: http://api.jqueryui.com/scale-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
// Create element
var el = $( this ),
mode = options.mode,
percent = parseInt( options.percent, 10 ) ||
( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
newOptions = $.extend( true, {
from: $.effects.scaledDimensions( el ),
to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
origin: options.origin || [ "middle", "center" ]
}, options );
// Fade option to support puff
if ( options.fade ) {
newOptions.from.opacity = 1;
newOptions.to.opacity = 0;
}
$.effects.effect.size.call( this, newOptions, done );
} );
/*!
* jQuery UI Effects Puff 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Puff Effect
//>>group: Effects
//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
//>>docs: http://api.jqueryui.com/puff-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
var newOptions = $.extend( true, {}, options, {
fade: true,
percent: parseInt( options.percent, 10 ) || 150
} );
$.effects.effect.scale.call( this, newOptions, done );
} );
/*!
* jQuery UI Effects Pulsate 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Pulsate Effect
//>>group: Effects
//>>description: Pulsates an element n times by changing the opacity to zero and back.
//>>docs: http://api.jqueryui.com/pulsate-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
var element = $( this ),
mode = options.mode,
show = mode === "show",
hide = mode === "hide",
showhide = show || hide,
// Showing or hiding leaves off the "last" animation
anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
duration = options.duration / anims,
animateTo = 0,
i = 1,
queuelen = element.queue().length;
if ( show || !element.is( ":visible" ) ) {
element.css( "opacity", 0 ).show();
animateTo = 1;
}
// Anims - 1 opacity "toggles"
for ( ; i < anims; i++ ) {
element.animate( { opacity: animateTo }, duration, options.easing );
animateTo = 1 - animateTo;
}
element.animate( { opacity: animateTo }, duration, options.easing );
element.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Shake 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Shake Effect
//>>group: Effects
//>>description: Shakes an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/shake-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
var i = 1,
element = $( this ),
direction = options.direction || "left",
distance = options.distance || 20,
times = options.times || 3,
anims = times * 2 + 1,
speed = Math.round( options.duration / anims ),
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
positiveMotion = ( direction === "up" || direction === "left" ),
animation = {},
animation1 = {},
animation2 = {},
queuelen = element.queue().length;
$.effects.createPlaceholder( element );
// Animation
animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
// Animate
element.animate( animation, speed, options.easing );
// Shakes
for ( ; i < times; i++ ) {
element
.animate( animation1, speed, options.easing )
.animate( animation2, speed, options.easing );
}
element
.animate( animation1, speed, options.easing )
.animate( animation, speed / 2, options.easing )
.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Slide 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Slide Effect
//>>group: Effects
//>>description: Slides an element in and out of the viewport.
//>>docs: http://api.jqueryui.com/slide-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
var startClip, startRef,
element = $( this ),
map = {
up: [ "bottom", "top" ],
down: [ "top", "bottom" ],
left: [ "right", "left" ],
right: [ "left", "right" ]
},
mode = options.mode,
direction = options.direction || "left",
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
positiveMotion = ( direction === "up" || direction === "left" ),
distance = options.distance ||
element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
animation = {};
$.effects.createPlaceholder( element );
startClip = element.cssClip();
startRef = element.position()[ ref ];
// Define hide animation
animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
animation.clip = element.cssClip();
animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
// Reverse the animation if we're showing
if ( mode === "show" ) {
element.cssClip( animation.clip );
element.css( ref, animation[ ref ] );
animation.clip = startClip;
animation[ ref ] = startRef;
}
// Actually animate
element.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Transfer 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Transfer Effect
//>>group: Effects
//>>description: Displays a transfer effect from one element to another.
//>>docs: http://api.jqueryui.com/transfer-effect/
//>>demos: http://jqueryui.com/effect/
var effect;
if ( $.uiBackCompat !== false ) {
effect = $.effects.define( "transfer", function( options, done ) {
$( this ).transfer( options, done );
} );
}
var effectsEffectTransfer = effect;
/*!
* jQuery UI Focusable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :focusable Selector
//>>group: Core
//>>description: Selects elements which can be focused.
//>>docs: http://api.jqueryui.com/focusable-selector/
// Selectors
$.ui.focusable = function( element, hasTabindex ) {
var map, mapName, img, focusableIfVisible, fieldset,
nodeName = element.nodeName.toLowerCase();
if ( "area" === nodeName ) {
map = element.parentNode;
mapName = map.name;
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
return false;
}
img = $( "img[usemap='#" + mapName + "']" );
return img.length > 0 && img.is( ":visible" );
}
if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
focusableIfVisible = !element.disabled;
if ( focusableIfVisible ) {
// Form controls within a disabled fieldset are disabled.
// However, controls within the fieldset's legend do not get disabled.
// Since controls generally aren't placed inside legends, we skip
// this portion of the check.
fieldset = $( element ).closest( "fieldset" )[ 0 ];
if ( fieldset ) {
focusableIfVisible = !fieldset.disabled;
}
}
} else if ( "a" === nodeName ) {
focusableIfVisible = element.href || hasTabindex;
} else {
focusableIfVisible = hasTabindex;
}
return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
};
// Support: IE 8 only
// IE 8 doesn't resolve inherit to visible/hidden for computed values
function visible( element ) {
var visibility = element.css( "visibility" );
while ( visibility === "inherit" ) {
element = element.parent();
visibility = element.css( "visibility" );
}
return visibility !== "hidden";
}
$.extend( $.expr[ ":" ], {
focusable: function( element ) {
return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
}
} );
var focusable = $.ui.focusable;
// Support: IE8 Only
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
// with a string, so we need to find the proper form.
var form = $.fn.form = function() {
return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
};
/*!
* jQuery UI Form Reset Mixin 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Form Reset Mixin
//>>group: Core
//>>description: Refresh input widgets when their form is reset
//>>docs: http://api.jqueryui.com/form-reset-mixin/
var formResetMixin = $.ui.formResetMixin = {
_formResetHandler: function() {
var form = $( this );
// Wait for the form reset to actually happen before refreshing
setTimeout( function() {
var instances = form.data( "ui-form-reset-instances" );
$.each( instances, function() {
this.refresh();
} );
} );
},
_bindFormResetHandler: function() {
this.form = this.element.form();
if ( !this.form.length ) {
return;
}
var instances = this.form.data( "ui-form-reset-instances" ) || [];
if ( !instances.length ) {
// We don't use _on() here because we use a single event handler per form
this.form.on( "reset.ui-form-reset", this._formResetHandler );
}
instances.push( this );
this.form.data( "ui-form-reset-instances", instances );
},
_unbindFormResetHandler: function() {
if ( !this.form.length ) {
return;
}
var instances = this.form.data( "ui-form-reset-instances" );
instances.splice( $.inArray( this, instances ), 1 );
if ( instances.length ) {
this.form.data( "ui-form-reset-instances", instances );
} else {
this.form
.removeData( "ui-form-reset-instances" )
.off( "reset.ui-form-reset" );
}
}
};
/*!
* jQuery UI Support for jQuery core 1.7.x 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
*/
//>>label: jQuery 1.7 Support
//>>group: Core
//>>description: Support version 1.7.x of jQuery core
// Support: jQuery 1.7 only
// Not a great way to check versions, but since we only support 1.7+ and only
// need to detect <1.8, this is a simple check that should suffice. Checking
// for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
// and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
// 1.7 anymore). See #11197 for why we're not using feature detection.
if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
// Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
// Unlike jQuery Core 1.8+, these only support numeric values to set the
// dimensions in pixels
$.each( [ "Width", "Height" ], function( i, name ) {
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
type = name.toLowerCase(),
orig = {
innerWidth: $.fn.innerWidth,
innerHeight: $.fn.innerHeight,
outerWidth: $.fn.outerWidth,
outerHeight: $.fn.outerHeight
};
function reduce( elem, size, border, margin ) {
$.each( side, function() {
size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
if ( border ) {
size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
}
if ( margin ) {
size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
}
} );
return size;
}
$.fn[ "inner" + name ] = function( size ) {
if ( size === undefined ) {
return orig[ "inner" + name ].call( this );
}
return this.each( function() {
$( this ).css( type, reduce( this, size ) + "px" );
} );
};
$.fn[ "outer" + name ] = function( size, margin ) {
if ( typeof size !== "number" ) {
return orig[ "outer" + name ].call( this, size );
}
return this.each( function() {
$( this ).css( type, reduce( this, size, true, margin ) + "px" );
} );
};
} );
$.fn.addBack = function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
};
}
;
/*!
* jQuery UI Keycode 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Keycode
//>>group: Core
//>>description: Provide keycodes as keynames
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
var keycode = $.ui.keyCode = {
BACKSPACE: 8,
COMMA: 188,
DELETE: 46,
DOWN: 40,
END: 35,
ENTER: 13,
ESCAPE: 27,
HOME: 36,
LEFT: 37,
PAGE_DOWN: 34,
PAGE_UP: 33,
PERIOD: 190,
RIGHT: 39,
SPACE: 32,
TAB: 9,
UP: 38
};
// Internal use only
var escapeSelector = $.ui.escapeSelector = ( function() {
var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
return function( selector ) {
return selector.replace( selectorEscape, "\\$1" );
};
} )();
/*!
* jQuery UI Labels 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: labels
//>>group: Core
//>>description: Find all the labels associated with a given input
//>>docs: http://api.jqueryui.com/labels/
var labels = $.fn.labels = function() {
var ancestor, selector, id, labels, ancestors;
// Check control.labels first
if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
return this.pushStack( this[ 0 ].labels );
}
// Support: IE <= 11, FF <= 37, Android <= 2.3 only
// Above browsers do not support control.labels. Everything below is to support them
// as well as document fragments. control.labels does not work on document fragments
labels = this.eq( 0 ).parents( "label" );
// Look for the label based on the id
id = this.attr( "id" );
if ( id ) {
// We don't search against the document in case the element
// is disconnected from the DOM
ancestor = this.eq( 0 ).parents().last();
// Get a full set of top level ancestors
ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
// Create a selector for the label based on the id
selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
labels = labels.add( ancestors.find( selector ).addBack( selector ) );
}
// Return whatever we have found for labels
return this.pushStack( labels );
};
/*!
* jQuery UI Scroll Parent 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: scrollParent
//>>group: Core
//>>description: Get the closest ancestor element that is scrollable.
//>>docs: http://api.jqueryui.com/scrollParent/
var scrollParent = $.fn.scrollParent = function( includeHidden ) {
var position = this.css( "position" ),
excludeStaticParent = position === "absolute",
overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
scrollParent = this.parents().filter( function() {
var parent = $( this );
if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
return false;
}
return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
parent.css( "overflow-x" ) );
} ).eq( 0 );
return position === "fixed" || !scrollParent.length ?
$( this[ 0 ].ownerDocument || document ) :
scrollParent;
};
/*!
* jQuery UI Tabbable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :tabbable Selector
//>>group: Core
//>>description: Selects elements which can be tabbed to.
//>>docs: http://api.jqueryui.com/tabbable-selector/
var tabbable = $.extend( $.expr[ ":" ], {
tabbable: function( element ) {
var tabIndex = $.attr( element, "tabindex" ),
hasTabindex = tabIndex != null;
return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
}
} );
/*!
* jQuery UI Unique ID 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: uniqueId
//>>group: Core
//>>description: Functions to generate and remove uniqueId's
//>>docs: http://api.jqueryui.com/uniqueId/
var uniqueId = $.fn.extend( {
uniqueId: ( function() {
var uuid = 0;
return function() {
return this.each( function() {
if ( !this.id ) {
this.id = "ui-id-" + ( ++uuid );
}
} );
};
} )(),
removeUniqueId: function() {
return this.each( function() {
if ( /^ui-id-\d+$/.test( this.id ) ) {
$( this ).removeAttr( "id" );
}
} );
}
} );
/*!
* jQuery UI Accordion 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Accordion
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/accordion/
//>>demos: http://jqueryui.com/accordion/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/accordion.css
//>>css.theme: ../../themes/base/theme.css
var widgetsAccordion = $.widget( "ui.accordion", {
version: "1.12.1",
options: {
active: 0,
animate: {},
classes: {
"ui-accordion-header": "ui-corner-top",
"ui-accordion-header-collapsed": "ui-corner-all",
"ui-accordion-content": "ui-corner-bottom"
},
collapsible: false,
event: "click",
header: "> li > :first-child, > :not(li):even",
heightStyle: "auto",
icons: {
activeHeader: "ui-icon-triangle-1-s",
header: "ui-icon-triangle-1-e"
},
// Callbacks
activate: null,
beforeActivate: null
},
hideProps: {
borderTopWidth: "hide",
borderBottomWidth: "hide",
paddingTop: "hide",
paddingBottom: "hide",
height: "hide"
},
showProps: {
borderTopWidth: "show",
borderBottomWidth: "show",
paddingTop: "show",
paddingBottom: "show",
height: "show"
},
_create: function() {
var options = this.options;
this.prevShow = this.prevHide = $();
this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
this.element.attr( "role", "tablist" );
// Don't allow collapsible: false and active: false / null
if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
options.active = 0;
}
this._processPanels();
// handle negative values
if ( options.active < 0 ) {
options.active += this.headers.length;
}
this._refresh();
},
_getCreateEventData: function() {
return {
header: this.active,
panel: !this.active.length ? $() : this.active.next()
};
},
_createIcons: function() {
var icon, children,
icons = this.options.icons;
if ( icons ) {
icon = $( "<span>" );
this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
icon.prependTo( this.headers );
children = this.active.children( ".ui-accordion-header-icon" );
this._removeClass( children, icons.header )
._addClass( children, null, icons.activeHeader )
._addClass( this.headers, "ui-accordion-icons" );
}
},
_destroyIcons: function() {
this._removeClass( this.headers, "ui-accordion-icons" );
this.headers.children( ".ui-accordion-header-icon" ).remove();
},
_destroy: function() {
var contents;
// Clean up main element
this.element.removeAttr( "role" );
// Clean up headers
this.headers
.removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
.removeUniqueId();
this._destroyIcons();
// Clean up content panels
contents = this.headers.next()
.css( "display", "" )
.removeAttr( "role aria-hidden aria-labelledby" )
.removeUniqueId();
if ( this.options.heightStyle !== "content" ) {
contents.css( "height", "" );
}
},
_setOption: function( key, value ) {
if ( key === "active" ) {
// _activate() will handle invalid values and update this.options
this._activate( value );
return;
}
if ( key === "event" ) {
if ( this.options.event ) {
this._off( this.headers, this.options.event );
}
this._setupEvents( value );
}
this._super( key, value );
// Setting collapsible: false while collapsed; open first panel
if ( key === "collapsible" && !value && this.options.active === false ) {
this._activate( 0 );
}
if ( key === "icons" ) {
this._destroyIcons();
if ( value ) {
this._createIcons();
}
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", value );
// Support: IE8 Only
// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
// so we need to add the disabled class to the headers and panels
this._toggleClass( null, "ui-state-disabled", !!value );
this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
!!value );
},
_keydown: function( event ) {
if ( event.altKey || event.ctrlKey ) {
return;
}
var keyCode = $.ui.keyCode,
length = this.headers.length,
currentIndex = this.headers.index( event.target ),
toFocus = false;
switch ( event.keyCode ) {
case keyCode.RIGHT:
case keyCode.DOWN:
toFocus = this.headers[ ( currentIndex + 1 ) % length ];
break;
case keyCode.LEFT:
case keyCode.UP:
toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
break;
case keyCode.SPACE:
case keyCode.ENTER:
this._eventHandler( event );
break;
case keyCode.HOME:
toFocus = this.headers[ 0 ];
break;
case keyCode.END:
toFocus = this.headers[ length - 1 ];
break;
}
if ( toFocus ) {
$( event.target ).attr( "tabIndex", -1 );
$( toFocus ).attr( "tabIndex", 0 );
$( toFocus ).trigger( "focus" );
event.preventDefault();
}
},
_panelKeyDown: function( event ) {
if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
$( event.currentTarget ).prev().trigger( "focus" );
}
},
refresh: function() {
var options = this.options;
this._processPanels();
// Was collapsed or no panel
if ( ( options.active === false && options.collapsible === true ) ||
!this.headers.length ) {
options.active = false;
this.active = $();
// active false only when collapsible is true
} else if ( options.active === false ) {
this._activate( 0 );
// was active, but active panel is gone
} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
// all remaining panel are disabled
if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
options.active = false;
this.active = $();
// activate previous panel
} else {
this._activate( Math.max( 0, options.active - 1 ) );
}
// was active, active panel still exists
} else {
// make sure active index is correct
options.active = this.headers.index( this.active );
}
this._destroyIcons();
this._refresh();
},
_processPanels: function() {
var prevHeaders = this.headers,
prevPanels = this.panels;
this.headers = this.element.find( this.options.header );
this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
"ui-state-default" );
this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
// Avoid memory leaks (#10056)
if ( prevPanels ) {
this._off( prevHeaders.not( this.headers ) );
this._off( prevPanels.not( this.panels ) );
}
},
_refresh: function() {
var maxHeight,
options = this.options,
heightStyle = options.heightStyle,
parent = this.element.parent();
this.active = this._findActive( options.active );
this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
._removeClass( this.active, "ui-accordion-header-collapsed" );
this._addClass( this.active.next(), "ui-accordion-content-active" );
this.active.next().show();
this.headers
.attr( "role", "tab" )
.each( function() {
var header = $( this ),
headerId = header.uniqueId().attr( "id" ),
panel = header.next(),
panelId = panel.uniqueId().attr( "id" );
header.attr( "aria-controls", panelId );
panel.attr( "aria-labelledby", headerId );
} )
.next()
.attr( "role", "tabpanel" );
this.headers
.not( this.active )
.attr( {
"aria-selected": "false",
"aria-expanded": "false",
tabIndex: -1
} )
.next()
.attr( {
"aria-hidden": "true"
} )
.hide();
// Make sure at least one header is in the tab order
if ( !this.active.length ) {
this.headers.eq( 0 ).attr( "tabIndex", 0 );
} else {
this.active.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} )
.next()
.attr( {
"aria-hidden": "false"
} );
}
this._createIcons();
this._setupEvents( options.event );
if ( heightStyle === "fill" ) {
maxHeight = parent.height();
this.element.siblings( ":visible" ).each( function() {
var elem = $( this ),
position = elem.css( "position" );
if ( position === "absolute" || position === "fixed" ) {
return;
}
maxHeight -= elem.outerHeight( true );
} );
this.headers.each( function() {
maxHeight -= $( this ).outerHeight( true );
} );
this.headers.next()
.each( function() {
$( this ).height( Math.max( 0, maxHeight -
$( this ).innerHeight() + $( this ).height() ) );
} )
.css( "overflow", "auto" );
} else if ( heightStyle === "auto" ) {
maxHeight = 0;
this.headers.next()
.each( function() {
var isVisible = $( this ).is( ":visible" );
if ( !isVisible ) {
$( this ).show();
}
maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
if ( !isVisible ) {
$( this ).hide();
}
} )
.height( maxHeight );
}
},
_activate: function( index ) {
var active = this._findActive( index )[ 0 ];
// Trying to activate the already active panel
if ( active === this.active[ 0 ] ) {
return;
}
// Trying to collapse, simulate a click on the currently active header
active = active || this.active[ 0 ];
this._eventHandler( {
target: active,
currentTarget: active,
preventDefault: $.noop
} );
},
_findActive: function( selector ) {
return typeof selector === "number" ? this.headers.eq( selector ) : $();
},
_setupEvents: function( event ) {
var events = {
keydown: "_keydown"
};
if ( event ) {
$.each( event.split( " " ), function( index, eventName ) {
events[ eventName ] = "_eventHandler";
} );
}
this._off( this.headers.add( this.headers.next() ) );
this._on( this.headers, events );
this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
this._hoverable( this.headers );
this._focusable( this.headers );
},
_eventHandler: function( event ) {
var activeChildren, clickedChildren,
options = this.options,
active = this.active,
clicked = $( event.currentTarget ),
clickedIsActive = clicked[ 0 ] === active[ 0 ],
collapsing = clickedIsActive && options.collapsible,
toShow = collapsing ? $() : clicked.next(),
toHide = active.next(),
eventData = {
oldHeader: active,
oldPanel: toHide,
newHeader: collapsing ? $() : clicked,
newPanel: toShow
};
event.preventDefault();
if (
// click on active header, but not collapsible
( clickedIsActive && !options.collapsible ) ||
// allow canceling activation
( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
return;
}
options.active = collapsing ? false : this.headers.index( clicked );
// When the call to ._toggle() comes after the class changes
// it causes a very odd bug in IE 8 (see #6720)
this.active = clickedIsActive ? $() : clicked;
this._toggle( eventData );
// Switch classes
// corner classes on the previously active header stay after the animation
this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
if ( options.icons ) {
activeChildren = active.children( ".ui-accordion-header-icon" );
this._removeClass( activeChildren, null, options.icons.activeHeader )
._addClass( activeChildren, null, options.icons.header );
}
if ( !clickedIsActive ) {
this._removeClass( clicked, "ui-accordion-header-collapsed" )
._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
if ( options.icons ) {
clickedChildren = clicked.children( ".ui-accordion-header-icon" );
this._removeClass( clickedChildren, null, options.icons.header )
._addClass( clickedChildren, null, options.icons.activeHeader );
}
this._addClass( clicked.next(), "ui-accordion-content-active" );
}
},
_toggle: function( data ) {
var toShow = data.newPanel,
toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
// Handle activating a panel during the animation for another activation
this.prevShow.add( this.prevHide ).stop( true, true );
this.prevShow = toShow;
this.prevHide = toHide;
if ( this.options.animate ) {
this._animate( toShow, toHide, data );
} else {
toHide.hide();
toShow.show();
this._toggleComplete( data );
}
toHide.attr( {
"aria-hidden": "true"
} );
toHide.prev().attr( {
"aria-selected": "false",
"aria-expanded": "false"
} );
// if we're switching panels, remove the old header from the tab order
// if we're opening from collapsed state, remove the previous header from the tab order
// if we're collapsing, then keep the collapsing header in the tab order
if ( toShow.length && toHide.length ) {
toHide.prev().attr( {
"tabIndex": -1,
"aria-expanded": "false"
} );
} else if ( toShow.length ) {
this.headers.filter( function() {
return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
} )
.attr( "tabIndex", -1 );
}
toShow
.attr( "aria-hidden", "false" )
.prev()
.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
},
_animate: function( toShow, toHide, data ) {
var total, easing, duration,
that = this,
adjust = 0,
boxSizing = toShow.css( "box-sizing" ),
down = toShow.length &&
( !toHide.length || ( toShow.index() < toHide.index() ) ),
animate = this.options.animate || {},
options = down && animate.down || animate,
complete = function() {
that._toggleComplete( data );
};
if ( typeof options === "number" ) {
duration = options;
}
if ( typeof options === "string" ) {
easing = options;
}
// fall back from options to animation in case of partial down settings
easing = easing || options.easing || animate.easing;
duration = duration || options.duration || animate.duration;
if ( !toHide.length ) {
return toShow.animate( this.showProps, duration, easing, complete );
}
if ( !toShow.length ) {
return toHide.animate( this.hideProps, duration, easing, complete );
}
total = toShow.show().outerHeight();
toHide.animate( this.hideProps, {
duration: duration,
easing: easing,
step: function( now, fx ) {
fx.now = Math.round( now );
}
} );
toShow
.hide()
.animate( this.showProps, {
duration: duration,
easing: easing,
complete: complete,
step: function( now, fx ) {
fx.now = Math.round( now );
if ( fx.prop !== "height" ) {
if ( boxSizing === "content-box" ) {
adjust += fx.now;
}
} else if ( that.options.heightStyle !== "content" ) {
fx.now = Math.round( total - toHide.outerHeight() - adjust );
adjust = 0;
}
}
} );
},
_toggleComplete: function( data ) {
var toHide = data.oldPanel,
prev = toHide.prev();
this._removeClass( toHide, "ui-accordion-content-active" );
this._removeClass( prev, "ui-accordion-header-active" )
._addClass( prev, "ui-accordion-header-collapsed" );
// Work around for rendering bug in IE (#5421)
if ( toHide.length ) {
toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
}
this._trigger( "activate", null, data );
}
} );
var safeActiveElement = $.ui.safeActiveElement = function( document ) {
var activeElement;
// Support: IE 9 only
// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
try {
activeElement = document.activeElement;
} catch ( error ) {
activeElement = document.body;
}
// Support: IE 9 - 11 only
// IE may return null instead of an element
// Interestingly, this only seems to occur when NOT in an iframe
if ( !activeElement ) {
activeElement = document.body;
}
// Support: IE 11 only
// IE11 returns a seemingly empty object in some cases when accessing
// document.activeElement from an <iframe>
if ( !activeElement.nodeName ) {
activeElement = document.body;
}
return activeElement;
};
/*!
* jQuery UI Menu 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Menu
//>>group: Widgets
//>>description: Creates nestable menus.
//>>docs: http://api.jqueryui.com/menu/
//>>demos: http://jqueryui.com/menu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/menu.css
//>>css.theme: ../../themes/base/theme.css
var widgetsMenu = $.widget( "ui.menu", {
version: "1.12.1",
defaultElement: "<ul>",
delay: 300,
options: {
icons: {
submenu: "ui-icon-caret-1-e"
},
items: "> *",
menus: "ul",
position: {
my: "left top",
at: "right top"
},
role: "menu",
// Callbacks
blur: null,
focus: null,
select: null
},
_create: function() {
this.activeMenu = this.element;
// Flag used to prevent firing of the click handler
// as the event bubbles up through nested menus
this.mouseHandled = false;
this.element
.uniqueId()
.attr( {
role: this.options.role,
tabIndex: 0
} );
this._addClass( "ui-menu", "ui-widget ui-widget-content" );
this._on( {
// Prevent focus from sticking to links inside menu after clicking
// them (focus should always stay on UL during navigation).
"mousedown .ui-menu-item": function( event ) {
event.preventDefault();
},
"click .ui-menu-item": function( event ) {
var target = $( event.target );
var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
this.select( event );
// Only set the mouseHandled flag if the event will bubble, see #9469.
if ( !event.isPropagationStopped() ) {
this.mouseHandled = true;
}
// Open submenu on click
if ( target.has( ".ui-menu" ).length ) {
this.expand( event );
} else if ( !this.element.is( ":focus" ) &&
active.closest( ".ui-menu" ).length ) {
// Redirect focus to the menu
this.element.trigger( "focus", [ true ] );
// If the active item is on the top level, let it stay active.
// Otherwise, blur the active item since it is no longer visible.
if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
clearTimeout( this.timer );
}
}
}
},
"mouseenter .ui-menu-item": function( event ) {
// Ignore mouse events while typeahead is active, see #10458.
// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
// is over an item in the menu
if ( this.previousFilter ) {
return;
}
var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
target = $( event.currentTarget );
// Ignore bubbled events on parent items, see #11641
if ( actualTarget[ 0 ] !== target[ 0 ] ) {
return;
}
// Remove ui-state-active class from siblings of the newly focused menu item
// to avoid a jump caused by adjacent elements both having a class with a border
this._removeClass( target.siblings().children( ".ui-state-active" ),
null, "ui-state-active" );
this.focus( event, target );
},
mouseleave: "collapseAll",
"mouseleave .ui-menu": "collapseAll",
focus: function( event, keepActiveItem ) {
// If there's already an active item, keep it active
// If not, activate the first item
var item = this.active || this.element.find( this.options.items ).eq( 0 );
if ( !keepActiveItem ) {
this.focus( event, item );
}
},
blur: function( event ) {
this._delay( function() {
var notContained = !$.contains(
this.element[ 0 ],
$.ui.safeActiveElement( this.document[ 0 ] )
);
if ( notContained ) {
this.collapseAll( event );
}
} );
},
keydown: "_keydown"
} );
this.refresh();
// Clicks outside of a menu collapse any open menus
this._on( this.document, {
click: function( event ) {
if ( this._closeOnDocumentClick( event ) ) {
this.collapseAll( event );
}
// Reset the mouseHandled flag
this.mouseHandled = false;
}
} );
},
_destroy: function() {
var items = this.element.find( ".ui-menu-item" )
.removeAttr( "role aria-disabled" ),
submenus = items.children( ".ui-menu-item-wrapper" )
.removeUniqueId()
.removeAttr( "tabIndex role aria-haspopup" );
// Destroy (sub)menus
this.element
.removeAttr( "aria-activedescendant" )
.find( ".ui-menu" ).addBack()
.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
"tabIndex" )
.removeUniqueId()
.show();
submenus.children().each( function() {
var elem = $( this );
if ( elem.data( "ui-menu-submenu-caret" ) ) {
elem.remove();
}
} );
},
_keydown: function( event ) {
var match, prev, character, skip,
preventDefault = true;
switch ( event.keyCode ) {
case $.ui.keyCode.PAGE_UP:
this.previousPage( event );
break;
case $.ui.keyCode.PAGE_DOWN:
this.nextPage( event );
break;
case $.ui.keyCode.HOME:
this._move( "first", "first", event );
break;
case $.ui.keyCode.END:
this._move( "last", "last", event );
break;
case $.ui.keyCode.UP:
this.previous( event );
break;
case $.ui.keyCode.DOWN:
this.next( event );
break;
case $.ui.keyCode.LEFT:
this.collapse( event );
break;
case $.ui.keyCode.RIGHT:
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
this.expand( event );
}
break;
case $.ui.keyCode.ENTER:
case $.ui.keyCode.SPACE:
this._activate( event );
break;
case $.ui.keyCode.ESCAPE:
this.collapse( event );
break;
default:
preventDefault = false;
prev = this.previousFilter || "";
skip = false;
// Support number pad values
character = event.keyCode >= 96 && event.keyCode <= 105 ?
( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
clearTimeout( this.filterTimer );
if ( character === prev ) {
skip = true;
} else {
character = prev + character;
}
match = this._filterMenuItems( character );
match = skip && match.index( this.active.next() ) !== -1 ?
this.active.nextAll( ".ui-menu-item" ) :
match;
// If no matches on the current filter, reset to the last character pressed
// to move down the menu to the first item that starts with that character
if ( !match.length ) {
character = String.fromCharCode( event.keyCode );
match = this._filterMenuItems( character );
}
if ( match.length ) {
this.focus( event, match );
this.previousFilter = character;
this.filterTimer = this._delay( function() {
delete this.previousFilter;
}, 1000 );
} else {
delete this.previousFilter;
}
}
if ( preventDefault ) {
event.preventDefault();
}
},
_activate: function( event ) {
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
if ( this.active.children( "[aria-haspopup='true']" ).length ) {
this.expand( event );
} else {
this.select( event );
}
}
},
refresh: function() {
var menus, items, newSubmenus, newItems, newWrappers,
that = this,
icon = this.options.icons.submenu,
submenus = this.element.find( this.options.menus );
this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
// Initialize nested menus
newSubmenus = submenus.filter( ":not(.ui-menu)" )
.hide()
.attr( {
role: this.options.role,
"aria-hidden": "true",
"aria-expanded": "false"
} )
.each( function() {
var menu = $( this ),
item = menu.prev(),
submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
item
.attr( "aria-haspopup", "true" )
.prepend( submenuCaret );
menu.attr( "aria-labelledby", item.attr( "id" ) );
} );
this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
menus = submenus.add( this.element );
items = menus.find( this.options.items );
// Initialize menu-items containing spaces and/or dashes only as dividers
items.not( ".ui-menu-item" ).each( function() {
var item = $( this );
if ( that._isDivider( item ) ) {
that._addClass( item, "ui-menu-divider", "ui-widget-content" );
}
} );
// Don't refresh list items that are already adapted
newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
newWrappers = newItems.children()
.not( ".ui-menu" )
.uniqueId()
.attr( {
tabIndex: -1,
role: this._itemRole()
} );
this._addClass( newItems, "ui-menu-item" )
._addClass( newWrappers, "ui-menu-item-wrapper" );
// Add aria-disabled attribute to any disabled menu item
items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
// If the active item has been removed, blur the menu
if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
this.blur();
}
},
_itemRole: function() {
return {
menu: "menuitem",
listbox: "option"
}[ this.options.role ];
},
_setOption: function( key, value ) {
if ( key === "icons" ) {
var icons = this.element.find( ".ui-menu-icon" );
this._removeClass( icons, null, this.options.icons.submenu )
._addClass( icons, null, value.submenu );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", String( value ) );
this._toggleClass( null, "ui-state-disabled", !!value );
},
focus: function( event, item ) {
var nested, focused, activeParent;
this.blur( event, event && event.type === "focus" );
this._scrollIntoView( item );
this.active = item.first();
focused = this.active.children( ".ui-menu-item-wrapper" );
this._addClass( focused, null, "ui-state-active" );
// Only update aria-activedescendant if there's a role
// otherwise we assume focus is managed elsewhere
if ( this.options.role ) {
this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
}
// Highlight active parent menu item, if any
activeParent = this.active
.parent()
.closest( ".ui-menu-item" )
.children( ".ui-menu-item-wrapper" );
this._addClass( activeParent, null, "ui-state-active" );
if ( event && event.type === "keydown" ) {
this._close();
} else {
this.timer = this._delay( function() {
this._close();
}, this.delay );
}
nested = item.children( ".ui-menu" );
if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
this._startOpening( nested );
}
this.activeMenu = item.parent();
this._trigger( "focus", event, { item: item } );
},
_scrollIntoView: function( item ) {
var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
if ( this._hasScroll() ) {
borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
scroll = this.activeMenu.scrollTop();
elementHeight = this.activeMenu.height();
itemHeight = item.outerHeight();
if ( offset < 0 ) {
this.activeMenu.scrollTop( scroll + offset );
} else if ( offset + itemHeight > elementHeight ) {
this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
}
}
},
blur: function( event, fromFocus ) {
if ( !fromFocus ) {
clearTimeout( this.timer );
}
if ( !this.active ) {
return;
}
this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
null, "ui-state-active" );
this._trigger( "blur", event, { item: this.active } );
this.active = null;
},
_startOpening: function( submenu ) {
clearTimeout( this.timer );
// Don't open if already open fixes a Firefox bug that caused a .5 pixel
// shift in the submenu position when mousing over the caret icon
if ( submenu.attr( "aria-hidden" ) !== "true" ) {
return;
}
this.timer = this._delay( function() {
this._close();
this._open( submenu );
}, this.delay );
},
_open: function( submenu ) {
var position = $.extend( {
of: this.active
}, this.options.position );
clearTimeout( this.timer );
this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
.hide()
.attr( "aria-hidden", "true" );
submenu
.show()
.removeAttr( "aria-hidden" )
.attr( "aria-expanded", "true" )
.position( position );
},
collapseAll: function( event, all ) {
clearTimeout( this.timer );
this.timer = this._delay( function() {
// If we were passed an event, look for the submenu that contains the event
var currentMenu = all ? this.element :
$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
// If we found no valid submenu ancestor, use the main menu to close all
// sub menus anyway
if ( !currentMenu.length ) {
currentMenu = this.element;
}
this._close( currentMenu );
this.blur( event );
// Work around active item staying active after menu is blurred
this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
this.activeMenu = currentMenu;
}, this.delay );
},
// With no arguments, closes the currently active menu - if nothing is active
// it closes all menus. If passed an argument, it will search for menus BELOW
_close: function( startMenu ) {
if ( !startMenu ) {
startMenu = this.active ? this.active.parent() : this.element;
}
startMenu.find( ".ui-menu" )
.hide()
.attr( "aria-hidden", "true" )
.attr( "aria-expanded", "false" );
},
_closeOnDocumentClick: function( event ) {
return !$( event.target ).closest( ".ui-menu" ).length;
},
_isDivider: function( item ) {
// Match hyphen, em dash, en dash
return !/[^\-\u2014\u2013\s]/.test( item.text() );
},
collapse: function( event ) {
var newItem = this.active &&
this.active.parent().closest( ".ui-menu-item", this.element );
if ( newItem && newItem.length ) {
this._close();
this.focus( event, newItem );
}
},
expand: function( event ) {
var newItem = this.active &&
this.active
.children( ".ui-menu " )
.find( this.options.items )
.first();
if ( newItem && newItem.length ) {
this._open( newItem.parent() );
// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
this._delay( function() {
this.focus( event, newItem );
} );
}
},
next: function( event ) {
this._move( "next", "first", event );
},
previous: function( event ) {
this._move( "prev", "last", event );
},
isFirstItem: function() {
return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
},
isLastItem: function() {
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
},
_move: function( direction, filter, event ) {
var next;
if ( this.active ) {
if ( direction === "first" || direction === "last" ) {
next = this.active
[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
.eq( -1 );
} else {
next = this.active
[ direction + "All" ]( ".ui-menu-item" )
.eq( 0 );
}
}
if ( !next || !next.length || !this.active ) {
next = this.activeMenu.find( this.options.items )[ filter ]();
}
this.focus( event, next );
},
nextPage: function( event ) {
var item, base, height;
if ( !this.active ) {
this.next( event );
return;
}
if ( this.isLastItem() ) {
return;
}
if ( this._hasScroll() ) {
base = this.active.offset().top;
height = this.element.height();
this.active.nextAll( ".ui-menu-item" ).each( function() {
item = $( this );
return item.offset().top - base - height < 0;
} );
this.focus( event, item );
} else {
this.focus( event, this.activeMenu.find( this.options.items )
[ !this.active ? "first" : "last" ]() );
}
},
previousPage: function( event ) {
var item, base, height;
if ( !this.active ) {
this.next( event );
return;
}
if ( this.isFirstItem() ) {
return;
}
if ( this._hasScroll() ) {
base = this.active.offset().top;
height = this.element.height();
this.active.prevAll( ".ui-menu-item" ).each( function() {
item = $( this );
return item.offset().top - base + height > 0;
} );
this.focus( event, item );
} else {
this.focus( event, this.activeMenu.find( this.options.items ).first() );
}
},
_hasScroll: function() {
return this.element.outerHeight() < this.element.prop( "scrollHeight" );
},
select: function( event ) {
// TODO: It should never be possible to not have an active item at this
// point, but the tests don't trigger mouseenter before click.
this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
var ui = { item: this.active };
if ( !this.active.has( ".ui-menu" ).length ) {
this.collapseAll( event, true );
}
this._trigger( "select", event, ui );
},
_filterMenuItems: function( character ) {
var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
regex = new RegExp( "^" + escapedCharacter, "i" );
return this.activeMenu
.find( this.options.items )
// Only match on items, not dividers or other content (#10571)
.filter( ".ui-menu-item" )
.filter( function() {
return regex.test(
$.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
} );
}
} );
/*!
* jQuery UI Autocomplete 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Autocomplete
//>>group: Widgets
//>>description: Lists suggested words as the user is typing.
//>>docs: http://api.jqueryui.com/autocomplete/
//>>demos: http://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.autocomplete", {
version: "1.12.1",
defaultElement: "<input>",
options: {
appendTo: null,
autoFocus: false,
delay: 300,
minLength: 1,
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
source: null,
// Callbacks
change: null,
close: null,
focus: null,
open: null,
response: null,
search: null,
select: null
},
requestIndex: 0,
pending: 0,
_create: function() {
// Some browsers only repeat keydown events, not keypress events,
// so we use the suppressKeyPress flag to determine if we've already
// handled the keydown event. #7269
// Unfortunately the code for & in keypress is the same as the up arrow,
// so we use the suppressKeyPressRepeat flag to avoid handling keypress
// events when we know the keydown event was used to modify the
// search term. #7799
var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
nodeName = this.element[ 0 ].nodeName.toLowerCase(),
isTextarea = nodeName === "textarea",
isInput = nodeName === "input";
// Textareas are always multi-line
// Inputs are always single-line, even if inside a contentEditable element
// IE also treats inputs as contentEditable
// All other element types are determined by whether or not they're contentEditable
this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
this.isNewMenu = true;
this._addClass( "ui-autocomplete-input" );
this.element.attr( "autocomplete", "off" );
this._on( this.element, {
keydown: function( event ) {
if ( this.element.prop( "readOnly" ) ) {
suppressKeyPress = true;
suppressInput = true;
suppressKeyPressRepeat = true;
return;
}
suppressKeyPress = false;
suppressInput = false;
suppressKeyPressRepeat = false;
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.PAGE_UP:
suppressKeyPress = true;
this._move( "previousPage", event );
break;
case keyCode.PAGE_DOWN:
suppressKeyPress = true;
this._move( "nextPage", event );
break;
case keyCode.UP:
suppressKeyPress = true;
this._keyEvent( "previous", event );
break;
case keyCode.DOWN:
suppressKeyPress = true;
this._keyEvent( "next", event );
break;
case keyCode.ENTER:
// when menu is open and has focus
if ( this.menu.active ) {
// #6055 - Opera still allows the keypress to occur
// which causes forms to submit
suppressKeyPress = true;
event.preventDefault();
this.menu.select( event );
}
break;
case keyCode.TAB:
if ( this.menu.active ) {
this.menu.select( event );
}
break;
case keyCode.ESCAPE:
if ( this.menu.element.is( ":visible" ) ) {
if ( !this.isMultiLine ) {
this._value( this.term );
}
this.close( event );
// Different browsers have different default behavior for escape
// Single press can mean undo or clear
// Double press in IE means clear the whole form
event.preventDefault();
}
break;
default:
suppressKeyPressRepeat = true;
// search timeout should be triggered before the input value is changed
this._searchTimeout( event );
break;
}
},
keypress: function( event ) {
if ( suppressKeyPress ) {
suppressKeyPress = false;
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
event.preventDefault();
}
return;
}
if ( suppressKeyPressRepeat ) {
return;
}
// Replicate some key handlers to allow them to repeat in Firefox and Opera
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.PAGE_UP:
this._move( "previousPage", event );
break;
case keyCode.PAGE_DOWN:
this._move( "nextPage", event );
break;
case keyCode.UP:
this._keyEvent( "previous", event );
break;
case keyCode.DOWN:
this._keyEvent( "next", event );
break;
}
},
input: function( event ) {
if ( suppressInput ) {
suppressInput = false;
event.preventDefault();
return;
}
this._searchTimeout( event );
},
focus: function() {
this.selectedItem = null;
this.previous = this._value();
},
blur: function( event ) {
if ( this.cancelBlur ) {
delete this.cancelBlur;
return;
}
clearTimeout( this.searching );
this.close( event );
this._change( event );
}
} );
this._initSource();
this.menu = $( "<ul>" )
.appendTo( this._appendTo() )
.menu( {
// disable ARIA support, the live region takes care of that
role: null
} )
.hide()
.menu( "instance" );
this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
this._on( this.menu.element, {
mousedown: function( event ) {
// prevent moving focus out of the text field
event.preventDefault();
// IE doesn't prevent moving focus even with event.preventDefault()
// so we set a flag to know when we should ignore the blur event
this.cancelBlur = true;
this._delay( function() {
delete this.cancelBlur;
// Support: IE 8 only
// Right clicking a menu item or selecting text from the menu items will
// result in focus moving out of the input. However, we've already received
// and ignored the blur event because of the cancelBlur flag set above. So
// we restore focus to ensure that the menu closes properly based on the user's
// next actions.
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
this.element.trigger( "focus" );
}
} );
},
menufocus: function( event, ui ) {
var label, item;
// support: Firefox
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
if ( this.isNewMenu ) {
this.isNewMenu = false;
if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
this.menu.blur();
this.document.one( "mousemove", function() {
$( event.target ).trigger( event.originalEvent );
} );
return;
}
}
item = ui.item.data( "ui-autocomplete-item" );
if ( false !== this._trigger( "focus", event, { item: item } ) ) {
// use value to match what will end up in the input, if it was a key event
if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
this._value( item.value );
}
}
// Announce the value in the liveRegion
label = ui.item.attr( "aria-label" ) || item.value;
if ( label && $.trim( label ).length ) {
this.liveRegion.children().hide();
$( "<div>" ).text( label ).appendTo( this.liveRegion );
}
},
menuselect: function( event, ui ) {
var item = ui.item.data( "ui-autocomplete-item" ),
previous = this.previous;
// Only trigger when focus was lost (click on menu)
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
this.element.trigger( "focus" );
this.previous = previous;
// #6109 - IE triggers two focus events and the second
// is asynchronous, so we need to reset the previous
// term synchronously and asynchronously :-(
this._delay( function() {
this.previous = previous;
this.selectedItem = item;
} );
}
if ( false !== this._trigger( "select", event, { item: item } ) ) {
this._value( item.value );
}
// reset the term after the select event
// this allows custom select handling to work properly
this.term = this._value();
this.close( event );
this.selectedItem = item;
}
} );
this.liveRegion = $( "<div>", {
role: "status",
"aria-live": "assertive",
"aria-relevant": "additions"
} )
.appendTo( this.document[ 0 ].body );
this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
// Turning off autocomplete prevents the browser from remembering the
// value when navigating through history, so we re-enable autocomplete
// if the page is unloaded before the widget is destroyed. #7790
this._on( this.window, {
beforeunload: function() {
this.element.removeAttr( "autocomplete" );
}
} );
},
_destroy: function() {
clearTimeout( this.searching );
this.element.removeAttr( "autocomplete" );
this.menu.element.remove();
this.liveRegion.remove();
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "source" ) {
this._initSource();
}
if ( key === "appendTo" ) {
this.menu.element.appendTo( this._appendTo() );
}
if ( key === "disabled" && value && this.xhr ) {
this.xhr.abort();
}
},
_isEventTargetInWidget: function( event ) {
var menuElement = this.menu.element[ 0 ];
return event.target === this.element[ 0 ] ||
event.target === menuElement ||
$.contains( menuElement, event.target );
},
_closeOnClickOutside: function( event ) {
if ( !this._isEventTargetInWidget( event ) ) {
this.close();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element ) {
element = element.jquery || element.nodeType ?
$( element ) :
this.document.find( element ).eq( 0 );
}
if ( !element || !element[ 0 ] ) {
element = this.element.closest( ".ui-front, dialog" );
}
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_initSource: function() {
var array, url,
that = this;
if ( $.isArray( this.options.source ) ) {
array = this.options.source;
this.source = function( request, response ) {
response( $.ui.autocomplete.filter( array, request.term ) );
};
} else if ( typeof this.options.source === "string" ) {
url = this.options.source;
this.source = function( request, response ) {
if ( that.xhr ) {
that.xhr.abort();
}
that.xhr = $.ajax( {
url: url,
data: request,
dataType: "json",
success: function( data ) {
response( data );
},
error: function() {
response( [] );
}
} );
};
} else {
this.source = this.options.source;
}
},
_searchTimeout: function( event ) {
clearTimeout( this.searching );
this.searching = this._delay( function() {
// Search if the value has changed, or if the user retypes the same value (see #7434)
var equalValues = this.term === this._value(),
menuVisible = this.menu.element.is( ":visible" ),
modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
this.selectedItem = null;
this.search( null, event );
}
}, this.options.delay );
},
search: function( value, event ) {
value = value != null ? value : this._value();
// Always save the actual value, not the one passed as an argument
this.term = this._value();
if ( value.length < this.options.minLength ) {
return this.close( event );
}
if ( this._trigger( "search", event ) === false ) {
return;
}
return this._search( value );
},
_search: function( value ) {
this.pending++;
this._addClass( "ui-autocomplete-loading" );
this.cancelSearch = false;
this.source( { term: value }, this._response() );
},
_response: function() {
var index = ++this.requestIndex;
return $.proxy( function( content ) {
if ( index === this.requestIndex ) {
this.__response( content );
}
this.pending--;
if ( !this.pending ) {
this._removeClass( "ui-autocomplete-loading" );
}
}, this );
},
__response: function( content ) {
if ( content ) {
content = this._normalize( content );
}
this._trigger( "response", null, { content: content } );
if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
this._suggest( content );
this._trigger( "open" );
} else {
// use ._close() instead of .close() so we don't cancel future searches
this._close();
}
},
close: function( event ) {
this.cancelSearch = true;
this._close( event );
},
_close: function( event ) {
// Remove the handler that closes the menu on outside clicks
this._off( this.document, "mousedown" );
if ( this.menu.element.is( ":visible" ) ) {
this.menu.element.hide();
this.menu.blur();
this.isNewMenu = true;
this._trigger( "close", event );
}
},
_change: function( event ) {
if ( this.previous !== this._value() ) {
this._trigger( "change", event, { item: this.selectedItem } );
}
},
_normalize: function( items ) {
// assume all items have the right format when the first item is complete
if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
return items;
}
return $.map( items, function( item ) {
if ( typeof item === "string" ) {
return {
label: item,
value: item
};
}
return $.extend( {}, item, {
label: item.label || item.value,
value: item.value || item.label
} );
} );
},
_suggest: function( items ) {
var ul = this.menu.element.empty();
this._renderMenu( ul, items );
this.isNewMenu = true;
this.menu.refresh();
// Size and position menu
ul.show();
this._resizeMenu();
ul.position( $.extend( {
of: this.element
}, this.options.position ) );
if ( this.options.autoFocus ) {
this.menu.next();
}
// Listen for interactions outside of the widget (#6642)
this._on( this.document, {
mousedown: "_closeOnClickOutside"
} );
},
_resizeMenu: function() {
var ul = this.menu.element;
ul.outerWidth( Math.max(
// Firefox wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping (#7513)
ul.width( "" ).outerWidth() + 1,
this.element.outerWidth()
) );
},
_renderMenu: function( ul, items ) {
var that = this;
$.each( items, function( index, item ) {
that._renderItemData( ul, item );
} );
},
_renderItemData: function( ul, item ) {
return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
},
_renderItem: function( ul, item ) {
return $( "<li>" )
.append( $( "<div>" ).text( item.label ) )
.appendTo( ul );
},
_move: function( direction, event ) {
if ( !this.menu.element.is( ":visible" ) ) {
this.search( null, event );
return;
}
if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
this.menu.isLastItem() && /^next/.test( direction ) ) {
if ( !this.isMultiLine ) {
this._value( this.term );
}
this.menu.blur();
return;
}
this.menu[ direction ]( event );
},
widget: function() {
return this.menu.element;
},
_value: function() {
return this.valueMethod.apply( this.element, arguments );
},
_keyEvent: function( keyEvent, event ) {
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
this._move( keyEvent, event );
// Prevents moving cursor to beginning/end of the text field in some browsers
event.preventDefault();
}
},
// Support: Chrome <=50
// We should be able to just use this.element.prop( "isContentEditable" )
// but hidden elements always report false in Chrome.
// https://code.google.com/p/chromium/issues/detail?id=313082
_isContentEditable: function( element ) {
if ( !element.length ) {
return false;
}
var editable = element.prop( "contentEditable" );
if ( editable === "inherit" ) {
return this._isContentEditable( element.parent() );
}
return editable === "true";
}
} );
$.extend( $.ui.autocomplete, {
escapeRegex: function( value ) {
return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
},
filter: function( array, term ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
return $.grep( array, function( value ) {
return matcher.test( value.label || value.value || value );
} );
}
} );
// Live region extension, adding a `messages` option
// NOTE: This is an experimental API. We are still investigating
// a full solution for string manipulation and internationalization.
$.widget( "ui.autocomplete", $.ui.autocomplete, {
options: {
messages: {
noResults: "No search results.",
results: function( amount ) {
return amount + ( amount > 1 ? " results are" : " result is" ) +
" available, use up and down arrow keys to navigate.";
}
}
},
__response: function( content ) {
var message;
this._superApply( arguments );
if ( this.options.disabled || this.cancelSearch ) {
return;
}
if ( content && content.length ) {
message = this.options.messages.results( content.length );
} else {
message = this.options.messages.noResults;
}
this.liveRegion.children().hide();
$( "<div>" ).text( message ).appendTo( this.liveRegion );
}
} );
var widgetsAutocomplete = $.ui.autocomplete;
/*!
* jQuery UI Controlgroup 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css
var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
var widgetsControlgroup = $.widget( "ui.controlgroup", {
version: "1.12.1",
defaultElement: "<div>",
options: {
direction: "horizontal",
disabled: null,
onlyVisible: true,
items: {
"button": "input[type=button], input[type=submit], input[type=reset], button, a",
"controlgroupLabel": ".ui-controlgroup-label",
"checkboxradio": "input[type='checkbox'], input[type='radio']",
"selectmenu": "select",
"spinner": ".ui-spinner-input"
}
},
_create: function() {
this._enhance();
},
// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
_enhance: function() {
this.element.attr( "role", "toolbar" );
this.refresh();
},
_destroy: function() {
this._callChildMethod( "destroy" );
this.childWidgets.removeData( "ui-controlgroup-data" );
this.element.removeAttr( "role" );
if ( this.options.items.controlgroupLabel ) {
this.element
.find( this.options.items.controlgroupLabel )
.find( ".ui-controlgroup-label-contents" )
.contents().unwrap();
}
},
_initWidgets: function() {
var that = this,
childWidgets = [];
// First we iterate over each of the items options
$.each( this.options.items, function( widget, selector ) {
var labels;
var options = {};
// Make sure the widget has a selector set
if ( !selector ) {
return;
}
if ( widget === "controlgroupLabel" ) {
labels = that.element.find( selector );
labels.each( function() {
var element = $( this );
if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
return;
}
element.contents()
.wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
} );
that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
childWidgets = childWidgets.concat( labels.get() );
return;
}
// Make sure the widget actually exists
if ( !$.fn[ widget ] ) {
return;
}
// We assume everything is in the middle to start because we can't determine
// first / last elements until all enhancments are done.
if ( that[ "_" + widget + "Options" ] ) {
options = that[ "_" + widget + "Options" ]( "middle" );
} else {
options = { classes: {} };
}
// Find instances of this widget inside controlgroup and init them
that.element
.find( selector )
.each( function() {
var element = $( this );
var instance = element[ widget ]( "instance" );
// We need to clone the default options for this type of widget to avoid
// polluting the variable options which has a wider scope than a single widget.
var instanceOptions = $.widget.extend( {}, options );
// If the button is the child of a spinner ignore it
// TODO: Find a more generic solution
if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
return;
}
// Create the widget if it doesn't exist
if ( !instance ) {
instance = element[ widget ]()[ widget ]( "instance" );
}
if ( instance ) {
instanceOptions.classes =
that._resolveClassesValues( instanceOptions.classes, instance );
}
element[ widget ]( instanceOptions );
// Store an instance of the controlgroup to be able to reference
// from the outermost element for changing options and refresh
var widgetElement = element[ widget ]( "widget" );
$.data( widgetElement[ 0 ], "ui-controlgroup-data",
instance ? instance : element[ widget ]( "instance" ) );
childWidgets.push( widgetElement[ 0 ] );
} );
} );
this.childWidgets = $( $.unique( childWidgets ) );
this._addClass( this.childWidgets, "ui-controlgroup-item" );
},
_callChildMethod: function( method ) {
this.childWidgets.each( function() {
var element = $( this ),
data = element.data( "ui-controlgroup-data" );
if ( data && data[ method ] ) {
data[ method ]();
}
} );
},
_updateCornerClass: function( element, position ) {
var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
var add = this._buildSimpleOptions( position, "label" ).classes.label;
this._removeClass( element, null, remove );
this._addClass( element, null, add );
},
_buildSimpleOptions: function( position, key ) {
var direction = this.options.direction === "vertical";
var result = {
classes: {}
};
result.classes[ key ] = {
"middle": "",
"first": "ui-corner-" + ( direction ? "top" : "left" ),
"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
"only": "ui-corner-all"
}[ position ];
return result;
},
_spinnerOptions: function( position ) {
var options = this._buildSimpleOptions( position, "ui-spinner" );
options.classes[ "ui-spinner-up" ] = "";
options.classes[ "ui-spinner-down" ] = "";
return options;
},
_buttonOptions: function( position ) {
return this._buildSimpleOptions( position, "ui-button" );
},
_checkboxradioOptions: function( position ) {
return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
},
_selectmenuOptions: function( position ) {
var direction = this.options.direction === "vertical";
return {
width: direction ? "auto" : false,
classes: {
middle: {
"ui-selectmenu-button-open": "",
"ui-selectmenu-button-closed": ""
},
first: {
"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
},
last: {
"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
},
only: {
"ui-selectmenu-button-open": "ui-corner-top",
"ui-selectmenu-button-closed": "ui-corner-all"
}
}[ position ]
};
},
_resolveClassesValues: function( classes, instance ) {
var result = {};
$.each( classes, function( key ) {
var current = instance.options.classes[ key ] || "";
current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
} );
return result;
},
_setOption: function( key, value ) {
if ( key === "direction" ) {
this._removeClass( "ui-controlgroup-" + this.options.direction );
}
this._super( key, value );
if ( key === "disabled" ) {
this._callChildMethod( value ? "disable" : "enable" );
return;
}
this.refresh();
},
refresh: function() {
var children,
that = this;
this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
if ( this.options.direction === "horizontal" ) {
this._addClass( null, "ui-helper-clearfix" );
}
this._initWidgets();
children = this.childWidgets;
// We filter here because we need to track all childWidgets not just the visible ones
if ( this.options.onlyVisible ) {
children = children.filter( ":visible" );
}
if ( children.length ) {
// We do this last because we need to make sure all enhancment is done
// before determining first and last
$.each( [ "first", "last" ], function( index, value ) {
var instance = children[ value ]().data( "ui-controlgroup-data" );
if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
var options = that[ "_" + instance.widgetName + "Options" ](
children.length === 1 ? "only" : value
);
options.classes = that._resolveClassesValues( options.classes, instance );
instance.element[ instance.widgetName ]( options );
} else {
that._updateCornerClass( children[ value ](), value );
}
} );
// Finally call the refresh method on each of the child widgets.
this._callChildMethod( "refresh" );
}
}
} );
/*!
* jQuery UI Checkboxradio 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Checkboxradio
//>>group: Widgets
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
//>>docs: http://api.jqueryui.com/checkboxradio/
//>>demos: http://jqueryui.com/checkboxradio/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.structure: ../../themes/base/checkboxradio.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
version: "1.12.1",
options: {
disabled: null,
label: null,
icon: true,
classes: {
"ui-checkboxradio-label": "ui-corner-all",
"ui-checkboxradio-icon": "ui-corner-all"
}
},
_getCreateOptions: function() {
var disabled, labels;
var that = this;
var options = this._super() || {};
// We read the type here, because it makes more sense to throw a element type error first,
// rather then the error for lack of a label. Often if its the wrong type, it
// won't have a label (e.g. calling on a div, btn, etc)
this._readType();
labels = this.element.labels();
// If there are multiple labels, use the last one
this.label = $( labels[ labels.length - 1 ] );
if ( !this.label.length ) {
$.error( "No label found for checkboxradio widget" );
}
this.originalLabel = "";
// We need to get the label text but this may also need to make sure it does not contain the
// input itself.
this.label.contents().not( this.element[ 0 ] ).each( function() {
// The label contents could be text, html, or a mix. We concat each element to get a
// string representation of the label, without the input as part of it.
that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
} );
// Set the label option if we found label text
if ( this.originalLabel ) {
options.label = this.originalLabel;
}
disabled = this.element[ 0 ].disabled;
if ( disabled != null ) {
options.disabled = disabled;
}
return options;
},
_create: function() {
var checked = this.element[ 0 ].checked;
this._bindFormResetHandler();
if ( this.options.disabled == null ) {
this.options.disabled = this.element[ 0 ].disabled;
}
this._setOption( "disabled", this.options.disabled );
this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
if ( this.type === "radio" ) {
this._addClass( this.label, "ui-checkboxradio-radio-label" );
}
if ( this.options.label && this.options.label !== this.originalLabel ) {
this._updateLabel();
} else if ( this.originalLabel ) {
this.options.label = this.originalLabel;
}
this._enhance();
if ( checked ) {
this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
if ( this.icon ) {
this._addClass( this.icon, null, "ui-state-hover" );
}
}
this._on( {
change: "_toggleClasses",
focus: function() {
this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
},
blur: function() {
this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
}
} );
},
_readType: function() {
var nodeName = this.element[ 0 ].nodeName.toLowerCase();
this.type = this.element[ 0 ].type;
if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
$.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
" and element.type=" + this.type );
}
},
// Support jQuery Mobile enhanced option
_enhance: function() {
this._updateIcon( this.element[ 0 ].checked );
},
widget: function() {
return this.label;
},
_getRadioGroup: function() {
var group;
var name = this.element[ 0 ].name;
var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
if ( !name ) {
return $( [] );
}
if ( this.form.length ) {
group = $( this.form[ 0 ].elements ).filter( nameSelector );
} else {
// Not inside a form, check all inputs that also are not inside a form
group = $( nameSelector ).filter( function() {
return $( this ).form().length === 0;
} );
}
return group.not( this.element );
},
_toggleClasses: function() {
var checked = this.element[ 0 ].checked;
this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
if ( this.options.icon && this.type === "checkbox" ) {
this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
._toggleClass( this.icon, null, "ui-icon-blank", !checked );
}
if ( this.type === "radio" ) {
this._getRadioGroup()
.each( function() {
var instance = $( this ).checkboxradio( "instance" );
if ( instance ) {
instance._removeClass( instance.label,
"ui-checkboxradio-checked", "ui-state-active" );
}
} );
}
},
_destroy: function() {
this._unbindFormResetHandler();
if ( this.icon ) {
this.icon.remove();
this.iconSpace.remove();
}
},
_setOption: function( key, value ) {
// We don't allow the value to be set to nothing
if ( key === "label" && !value ) {
return;
}
this._super( key, value );
if ( key === "disabled" ) {
this._toggleClass( this.label, null, "ui-state-disabled", value );
this.element[ 0 ].disabled = value;
// Don't refresh when setting disabled
return;
}
this.refresh();
},
_updateIcon: function( checked ) {
var toAdd = "ui-icon ui-icon-background ";
if ( this.options.icon ) {
if ( !this.icon ) {
this.icon = $( "<span>" );
this.iconSpace = $( "<span> </span>" );
this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
}
if ( this.type === "checkbox" ) {
toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
} else {
toAdd += "ui-icon-blank";
}
this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
if ( !checked ) {
this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
}
this.icon.prependTo( this.label ).after( this.iconSpace );
} else if ( this.icon !== undefined ) {
this.icon.remove();
this.iconSpace.remove();
delete this.icon;
}
},
_updateLabel: function() {
// Remove the contents of the label ( minus the icon, icon space, and input )
var contents = this.label.contents().not( this.element[ 0 ] );
if ( this.icon ) {
contents = contents.not( this.icon[ 0 ] );
}
if ( this.iconSpace ) {
contents = contents.not( this.iconSpace[ 0 ] );
}
contents.remove();
this.label.append( this.options.label );
},
refresh: function() {
var checked = this.element[ 0 ].checked,
isDisabled = this.element[ 0 ].disabled;
this._updateIcon( checked );
this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
if ( this.options.label !== null ) {
this._updateLabel();
}
if ( isDisabled !== this.options.disabled ) {
this._setOptions( { "disabled": isDisabled } );
}
}
} ] );
var widgetsCheckboxradio = $.ui.checkboxradio;
/*!
* jQuery UI Button 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Button
//>>group: Widgets
//>>description: Enhances a form with themeable buttons.
//>>docs: http://api.jqueryui.com/button/
//>>demos: http://jqueryui.com/button/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.button", {
version: "1.12.1",
defaultElement: "<button>",
options: {
classes: {
"ui-button": "ui-corner-all"
},
disabled: null,
icon: null,
iconPosition: "beginning",
label: null,
showLabel: true
},
_getCreateOptions: function() {
var disabled,
// This is to support cases like in jQuery Mobile where the base widget does have
// an implementation of _getCreateOptions
options = this._super() || {};
this.isInput = this.element.is( "input" );
disabled = this.element[ 0 ].disabled;
if ( disabled != null ) {
options.disabled = disabled;
}
this.originalLabel = this.isInput ? this.element.val() : this.element.html();
if ( this.originalLabel ) {
options.label = this.originalLabel;
}
return options;
},
_create: function() {
if ( !this.option.showLabel & !this.options.icon ) {
this.options.showLabel = true;
}
// We have to check the option again here even though we did in _getCreateOptions,
// because null may have been passed on init which would override what was set in
// _getCreateOptions
if ( this.options.disabled == null ) {
this.options.disabled = this.element[ 0 ].disabled || false;
}
this.hasTitle = !!this.element.attr( "title" );
// Check to see if the label needs to be set or if its already correct
if ( this.options.label && this.options.label !== this.originalLabel ) {
if ( this.isInput ) {
this.element.val( this.options.label );
} else {
this.element.html( this.options.label );
}
}
this._addClass( "ui-button", "ui-widget" );
this._setOption( "disabled", this.options.disabled );
this._enhance();
if ( this.element.is( "a" ) ) {
this._on( {
"keyup": function( event ) {
if ( event.keyCode === $.ui.keyCode.SPACE ) {
event.preventDefault();
// Support: PhantomJS <= 1.9, IE 8 Only
// If a native click is available use it so we actually cause navigation
// otherwise just trigger a click event
if ( this.element[ 0 ].click ) {
this.element[ 0 ].click();
} else {
this.element.trigger( "click" );
}
}
}
} );
}
},
_enhance: function() {
if ( !this.element.is( "button" ) ) {
this.element.attr( "role", "button" );
}
if ( this.options.icon ) {
this._updateIcon( "icon", this.options.icon );
this._updateTooltip();
}
},
_updateTooltip: function() {
this.title = this.element.attr( "title" );
if ( !this.options.showLabel && !this.title ) {
this.element.attr( "title", this.options.label );
}
},
_updateIcon: function( option, value ) {
var icon = option !== "iconPosition",
position = icon ? this.options.iconPosition : value,
displayBlock = position === "top" || position === "bottom";
// Create icon
if ( !this.icon ) {
this.icon = $( "<span>" );
this._addClass( this.icon, "ui-button-icon", "ui-icon" );
if ( !this.options.showLabel ) {
this._addClass( "ui-button-icon-only" );
}
} else if ( icon ) {
// If we are updating the icon remove the old icon class
this._removeClass( this.icon, null, this.options.icon );
}
// If we are updating the icon add the new icon class
if ( icon ) {
this._addClass( this.icon, null, value );
}
this._attachIcon( position );
// If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
// the iconSpace if there is one.
if ( displayBlock ) {
this._addClass( this.icon, null, "ui-widget-icon-block" );
if ( this.iconSpace ) {
this.iconSpace.remove();
}
} else {
// Position is beginning or end so remove the ui-widget-icon-block class and add the
// space if it does not exist
if ( !this.iconSpace ) {
this.iconSpace = $( "<span> </span>" );
this._addClass( this.iconSpace, "ui-button-icon-space" );
}
this._removeClass( this.icon, null, "ui-wiget-icon-block" );
this._attachIconSpace( position );
}
},
_destroy: function() {
this.element.removeAttr( "role" );
if ( this.icon ) {
this.icon.remove();
}
if ( this.iconSpace ) {
this.iconSpace.remove();
}
if ( !this.hasTitle ) {
this.element.removeAttr( "title" );
}
},
_attachIconSpace: function( iconPosition ) {
this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
},
_attachIcon: function( iconPosition ) {
this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
},
_setOptions: function( options ) {
var newShowLabel = options.showLabel === undefined ?
this.options.showLabel :
options.showLabel,
newIcon = options.icon === undefined ? this.options.icon : options.icon;
if ( !newShowLabel && !newIcon ) {
options.showLabel = true;
}
this._super( options );
},
_setOption: function( key, value ) {
if ( key === "icon" ) {
if ( value ) {
this._updateIcon( key, value );
} else if ( this.icon ) {
this.icon.remove();
if ( this.iconSpace ) {
this.iconSpace.remove();
}
}
}
if ( key === "iconPosition" ) {
this._updateIcon( key, value );
}
// Make sure we can't end up with a button that has neither text nor icon
if ( key === "showLabel" ) {
this._toggleClass( "ui-button-icon-only", null, !value );
this._updateTooltip();
}
if ( key === "label" ) {
if ( this.isInput ) {
this.element.val( value );
} else {
// If there is an icon, append it, else nothing then append the value
// this avoids removal of the icon when setting label text
this.element.html( value );
if ( this.icon ) {
this._attachIcon( this.options.iconPosition );
this._attachIconSpace( this.options.iconPosition );
}
}
}
this._super( key, value );
if ( key === "disabled" ) {
this._toggleClass( null, "ui-state-disabled", value );
this.element[ 0 ].disabled = value;
if ( value ) {
this.element.blur();
}
}
},
refresh: function() {
// Make sure to only check disabled if its an element that supports this otherwise
// check for the disabled class to determine state
var isDisabled = this.element.is( "input, button" ) ?
this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
if ( isDisabled !== this.options.disabled ) {
this._setOptions( { disabled: isDisabled } );
}
this._updateTooltip();
}
} );
// DEPRECATED
if ( $.uiBackCompat !== false ) {
// Text and Icons options
$.widget( "ui.button", $.ui.button, {
options: {
text: true,
icons: {
primary: null,
secondary: null
}
},
_create: function() {
if ( this.options.showLabel && !this.options.text ) {
this.options.showLabel = this.options.text;
}
if ( !this.options.showLabel && this.options.text ) {
this.options.text = this.options.showLabel;
}
if ( !this.options.icon && ( this.options.icons.primary ||
this.options.icons.secondary ) ) {
if ( this.options.icons.primary ) {
this.options.icon = this.options.icons.primary;
} else {
this.options.icon = this.options.icons.secondary;
this.options.iconPosition = "end";
}
} else if ( this.options.icon ) {
this.options.icons.primary = this.options.icon;
}
this._super();
},
_setOption: function( key, value ) {
if ( key === "text" ) {
this._super( "showLabel", value );
return;
}
if ( key === "showLabel" ) {
this.options.text = value;
}
if ( key === "icon" ) {
this.options.icons.primary = value;
}
if ( key === "icons" ) {
if ( value.primary ) {
this._super( "icon", value.primary );
this._super( "iconPosition", "beginning" );
} else if ( value.secondary ) {
this._super( "icon", value.secondary );
this._super( "iconPosition", "end" );
}
}
this._superApply( arguments );
}
} );
$.fn.button = ( function( orig ) {
return function() {
if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
( this.length && this[ 0 ].tagName === "INPUT" && (
this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
) ) ) {
return orig.apply( this, arguments );
}
if ( !$.ui.checkboxradio ) {
$.error( "Checkboxradio widget missing" );
}
if ( arguments.length === 0 ) {
return this.checkboxradio( {
"icon": false
} );
}
return this.checkboxradio.apply( this, arguments );
};
} )( $.fn.button );
$.fn.buttonset = function() {
if ( !$.ui.controlgroup ) {
$.error( "Controlgroup widget missing" );
}
if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
return this.controlgroup.apply( this,
[ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
}
if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
}
if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
arguments[ 0 ].items = {
button: arguments[ 0 ].items
};
}
return this.controlgroup.apply( this, arguments );
};
}
var widgetsButton = $.ui.button;
// jscs:disable maximumLineLength
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
/*!
* jQuery UI Datepicker 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Datepicker
//>>group: Widgets
//>>description: Displays a calendar from an input or inline for selecting dates.
//>>docs: http://api.jqueryui.com/datepicker/
//>>demos: http://jqueryui.com/datepicker/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/datepicker.css
//>>css.theme: ../../themes/base/theme.css
$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
var datepicker_instActive;
function datepicker_getZindex( elem ) {
var position, value;
while ( elem.length && elem[ 0 ] !== document ) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned
position = elem.css( "position" );
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
value = parseInt( elem.css( "zIndex" ), 10 );
if ( !isNaN( value ) && value !== 0 ) {
return value;
}
}
elem = elem.parent();
}
return 0;
}
/* Date picker manager.
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
Settings for (groups of) date pickers are maintained in an instance object,
allowing multiple different settings on the same page. */
function Datepicker() {
this._curInst = null; // The current instance in use
this._keyEvent = false; // If the last event was a key event
this._disabledInputs = []; // List of date picker inputs that have been disabled
this._datepickerShowing = false; // True if the popup picker is showing , false if not
this._inDialog = false; // True if showing within a "dialog", false if not
this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
this._appendClass = "ui-datepicker-append"; // The name of the append marker class
this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
this.regional = []; // Available regional settings, indexed by language code
this.regional[ "" ] = { // Default regional settings
closeText: "Done", // Display text for close link
prevText: "Prev", // Display text for previous month link
nextText: "Next", // Display text for next month link
currentText: "Today", // Display text for current month link
monthNames: [ "January","February","March","April","May","June",
"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
weekHeader: "Wk", // Column header for week of the year
dateFormat: "mm/dd/yy", // See format options on parseDate
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
isRTL: false, // True if right-to-left language, false if left-to-right
showMonthAfterYear: false, // True if the year select precedes month, false for month then year
yearSuffix: "" // Additional text to append to the year in the month headers
};
this._defaults = { // Global defaults for all the date picker instances
showOn: "focus", // "focus" for popup on focus,
// "button" for trigger button, or "both" for either
showAnim: "fadeIn", // Name of jQuery animation for popup
showOptions: {}, // Options for enhanced animations
defaultDate: null, // Used when field is blank: actual date,
// +/-number for offset from today, null for today
appendText: "", // Display text following the input box, e.g. showing the format
buttonText: "...", // Text for trigger button
buttonImage: "", // URL for trigger button image
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
hideIfNoPrevNext: false, // True to hide next/previous month links
// if not applicable, false to just disable them
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
gotoCurrent: false, // True if today link goes back to current selection instead
changeMonth: false, // True if month can be selected directly, false if only prev/next
changeYear: false, // True if year can be selected directly, false if only prev/next
yearRange: "c-10:c+10", // Range of years to display in drop-down,
// either relative to today's year (-nn:+nn), relative to currently displayed year
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
showOtherMonths: false, // True to show dates in other months, false to leave blank
selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
showWeek: false, // True to show week of the year, false to not show it
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
// takes a Date and returns the number of the week for it
shortYearCutoff: "+10", // Short year values < this are in the current century,
// > this are in the previous century,
// string value starting with "+" for current year + value
minDate: null, // The earliest selectable date, or null for no limit
maxDate: null, // The latest selectable date, or null for no limit
duration: "fast", // Duration of display/closure
beforeShowDay: null, // Function that takes a date and returns an array with
// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
// [2] = cell title (optional), e.g. $.datepicker.noWeekends
beforeShow: null, // Function that takes an input field and
// returns a set of custom settings for the date picker
onSelect: null, // Define a callback function when a date is selected
onChangeMonthYear: null, // Define a callback function when the month or year is changed
onClose: null, // Define a callback function when the datepicker is closed
numberOfMonths: 1, // Number of months to show at a time
showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
stepMonths: 1, // Number of months to step back/forward
stepBigMonths: 12, // Number of months to step back/forward for the big links
altField: "", // Selector for an alternate field to store selected dates into
altFormat: "", // The date format to use for the alternate field
constrainInput: true, // The input is constrained by the current date format
showButtonPanel: false, // True to show button panel, false to not show it
autoSize: false, // True to size the input for the date format, false to leave as is
disabled: false // The initial disabled state
};
$.extend( this._defaults, this.regional[ "" ] );
this.regional.en = $.extend( true, {}, this.regional[ "" ] );
this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
}
$.extend( Datepicker.prototype, {
/* Class name added to elements to indicate already configured with a date picker. */
markerClassName: "hasDatepicker",
//Keep track of the maximum number of rows displayed (see #7043)
maxRows: 4,
// TODO rename to "widget" when switching to widget factory
_widgetDatepicker: function() {
return this.dpDiv;
},
/* Override the default settings for all instances of the date picker.
* @param settings object - the new settings to use as defaults (anonymous object)
* @return the manager object
*/
setDefaults: function( settings ) {
datepicker_extendRemove( this._defaults, settings || {} );
return this;
},
/* Attach the date picker to a jQuery selection.
* @param target element - the target input field or division or span
* @param settings object - the new settings to use for this date picker instance (anonymous)
*/
_attachDatepicker: function( target, settings ) {
var nodeName, inline, inst;
nodeName = target.nodeName.toLowerCase();
inline = ( nodeName === "div" || nodeName === "span" );
if ( !target.id ) {
this.uuid += 1;
target.id = "dp" + this.uuid;
}
inst = this._newInst( $( target ), inline );
inst.settings = $.extend( {}, settings || {} );
if ( nodeName === "input" ) {
this._connectDatepicker( target, inst );
} else if ( inline ) {
this._inlineDatepicker( target, inst );
}
},
/* Create a new instance object. */
_newInst: function( target, inline ) {
var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
return { id: id, input: target, // associated target
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
drawMonth: 0, drawYear: 0, // month being drawn
inline: inline, // is datepicker inline or not
dpDiv: ( !inline ? this.dpDiv : // presentation div
datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
},
/* Attach the date picker to an input field. */
_connectDatepicker: function( target, inst ) {
var input = $( target );
inst.append = $( [] );
inst.trigger = $( [] );
if ( input.hasClass( this.markerClassName ) ) {
return;
}
this._attachments( input, inst );
input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
this._autoSize( inst );
$.data( target, "datepicker", inst );
//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
if ( inst.settings.disabled ) {
this._disableDatepicker( target );
}
},
/* Make attachments based on settings. */
_attachments: function( input, inst ) {
var showOn, buttonText, buttonImage,
appendText = this._get( inst, "appendText" ),
isRTL = this._get( inst, "isRTL" );
if ( inst.append ) {
inst.append.remove();
}
if ( appendText ) {
inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
input[ isRTL ? "before" : "after" ]( inst.append );
}
input.off( "focus", this._showDatepicker );
if ( inst.trigger ) {
inst.trigger.remove();
}
showOn = this._get( inst, "showOn" );
if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
input.on( "focus", this._showDatepicker );
}
if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
buttonText = this._get( inst, "buttonText" );
buttonImage = this._get( inst, "buttonImage" );
inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
$( "<img/>" ).addClass( this._triggerClass ).
attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
$( "<button type='button'></button>" ).addClass( this._triggerClass ).
html( !buttonImage ? buttonText : $( "<img/>" ).attr(
{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
input[ isRTL ? "before" : "after" ]( inst.trigger );
inst.trigger.on( "click", function() {
if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
$.datepicker._hideDatepicker();
} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
$.datepicker._hideDatepicker();
$.datepicker._showDatepicker( input[ 0 ] );
} else {
$.datepicker._showDatepicker( input[ 0 ] );
}
return false;
} );
}
},
/* Apply the maximum length for the date format. */
_autoSize: function( inst ) {
if ( this._get( inst, "autoSize" ) && !inst.inline ) {
var findMax, max, maxI, i,
date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
dateFormat = this._get( inst, "dateFormat" );
if ( dateFormat.match( /[DM]/ ) ) {
findMax = function( names ) {
max = 0;
maxI = 0;
for ( i = 0; i < names.length; i++ ) {
if ( names[ i ].length > max ) {
max = names[ i ].length;
maxI = i;
}
}
return maxI;
};
date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
"monthNames" : "monthNamesShort" ) ) ) );
date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
}
inst.input.attr( "size", this._formatDate( inst, date ).length );
}
},
/* Attach an inline date picker to a div. */
_inlineDatepicker: function( target, inst ) {
var divSpan = $( target );
if ( divSpan.hasClass( this.markerClassName ) ) {
return;
}
divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
$.data( target, "datepicker", inst );
this._setDate( inst, this._getDefaultDate( inst ), true );
this._updateDatepicker( inst );
this._updateAlternate( inst );
//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
if ( inst.settings.disabled ) {
this._disableDatepicker( target );
}
// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
inst.dpDiv.css( "display", "block" );
},
/* Pop-up the date picker in a "dialog" box.
* @param input element - ignored
* @param date string or Date - the initial date to display
* @param onSelect function - the function to call when a date is selected
* @param settings object - update the dialog date picker instance's settings (anonymous object)
* @param pos int[2] - coordinates for the dialog's position within the screen or
* event - with x/y coordinates or
* leave empty for default (screen centre)
* @return the manager object
*/
_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
var id, browserWidth, browserHeight, scrollX, scrollY,
inst = this._dialogInst; // internal instance
if ( !inst ) {
this.uuid += 1;
id = "dp" + this.uuid;
this._dialogInput = $( "<input type='text' id='" + id +
"' style='position: absolute; top: -100px; width: 0px;'/>" );
this._dialogInput.on( "keydown", this._doKeyDown );
$( "body" ).append( this._dialogInput );
inst = this._dialogInst = this._newInst( this._dialogInput, false );
inst.settings = {};
$.data( this._dialogInput[ 0 ], "datepicker", inst );
}
datepicker_extendRemove( inst.settings, settings || {} );
date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
this._dialogInput.val( date );
this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
if ( !this._pos ) {
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
scrollY = document.documentElement.scrollTop || document.body.scrollTop;
this._pos = // should use actual width/height below
[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
}
// Move input on screen for focus, but hidden behind dialog
this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
inst.settings.onSelect = onSelect;
this._inDialog = true;
this.dpDiv.addClass( this._dialogClass );
this._showDatepicker( this._dialogInput[ 0 ] );
if ( $.blockUI ) {
$.blockUI( this.dpDiv );
}
$.data( this._dialogInput[ 0 ], "datepicker", inst );
return this;
},
/* Detach a datepicker from its control.
* @param target element - the target input field or division or span
*/
_destroyDatepicker: function( target ) {
var nodeName,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
$.removeData( target, "datepicker" );
if ( nodeName === "input" ) {
inst.append.remove();
inst.trigger.remove();
$target.removeClass( this.markerClassName ).
off( "focus", this._showDatepicker ).
off( "keydown", this._doKeyDown ).
off( "keypress", this._doKeyPress ).
off( "keyup", this._doKeyUp );
} else if ( nodeName === "div" || nodeName === "span" ) {
$target.removeClass( this.markerClassName ).empty();
}
if ( datepicker_instActive === inst ) {
datepicker_instActive = null;
}
},
/* Enable the date picker to a jQuery selection.
* @param target element - the target input field or division or span
*/
_enableDatepicker: function( target ) {
var nodeName, inline,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
if ( nodeName === "input" ) {
target.disabled = false;
inst.trigger.filter( "button" ).
each( function() { this.disabled = false; } ).end().
filter( "img" ).css( { opacity: "1.0", cursor: "" } );
} else if ( nodeName === "div" || nodeName === "span" ) {
inline = $target.children( "." + this._inlineClass );
inline.children().removeClass( "ui-state-disabled" );
inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
prop( "disabled", false );
}
this._disabledInputs = $.map( this._disabledInputs,
function( value ) { return ( value === target ? null : value ); } ); // delete entry
},
/* Disable the date picker to a jQuery selection.
* @param target element - the target input field or division or span
*/
_disableDatepicker: function( target ) {
var nodeName, inline,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
if ( nodeName === "input" ) {
target.disabled = true;
inst.trigger.filter( "button" ).
each( function() { this.disabled = true; } ).end().
filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
} else if ( nodeName === "div" || nodeName === "span" ) {
inline = $target.children( "." + this._inlineClass );
inline.children().addClass( "ui-state-disabled" );
inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
prop( "disabled", true );
}
this._disabledInputs = $.map( this._disabledInputs,
function( value ) { return ( value === target ? null : value ); } ); // delete entry
this._disabledInputs[ this._disabledInputs.length ] = target;
},
/* Is the first field in a jQuery collection disabled as a datepicker?
* @param target element - the target input field or division or span
* @return boolean - true if disabled, false if enabled
*/
_isDisabledDatepicker: function( target ) {
if ( !target ) {
return false;
}
for ( var i = 0; i < this._disabledInputs.length; i++ ) {
if ( this._disabledInputs[ i ] === target ) {
return true;
}
}
return false;
},
/* Retrieve the instance data for the target control.
* @param target element - the target input field or division or span
* @return object - the associated instance data
* @throws error if a jQuery problem getting data
*/
_getInst: function( target ) {
try {
return $.data( target, "datepicker" );
}
catch ( err ) {
throw "Missing instance data for this datepicker";
}
},
/* Update or retrieve the settings for a date picker attached to an input field or division.
* @param target element - the target input field or division or span
* @param name object - the new settings to update or
* string - the name of the setting to change or retrieve,
* when retrieving also "all" for all instance settings or
* "defaults" for all global defaults
* @param value any - the new value for the setting
* (omit if above is an object or to retrieve a value)
*/
_optionDatepicker: function( target, name, value ) {
var settings, date, minDate, maxDate,
inst = this._getInst( target );
if ( arguments.length === 2 && typeof name === "string" ) {
return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
this._get( inst, name ) ) : null ) );
}
settings = name || {};
if ( typeof name === "string" ) {
settings = {};
settings[ name ] = value;
}
if ( inst ) {
if ( this._curInst === inst ) {
this._hideDatepicker();
}
date = this._getDateDatepicker( target, true );
minDate = this._getMinMaxDate( inst, "min" );
maxDate = this._getMinMaxDate( inst, "max" );
datepicker_extendRemove( inst.settings, settings );
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
inst.settings.minDate = this._formatDate( inst, minDate );
}
if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
inst.settings.maxDate = this._formatDate( inst, maxDate );
}
if ( "disabled" in settings ) {
if ( settings.disabled ) {
this._disableDatepicker( target );
} else {
this._enableDatepicker( target );
}
}
this._attachments( $( target ), inst );
this._autoSize( inst );
this._setDate( inst, date );
this._updateAlternate( inst );
this._updateDatepicker( inst );
}
},
// Change method deprecated
_changeDatepicker: function( target, name, value ) {
this._optionDatepicker( target, name, value );
},
/* Redraw the date picker attached to an input field or division.
* @param target element - the target input field or division or span
*/
_refreshDatepicker: function( target ) {
var inst = this._getInst( target );
if ( inst ) {
this._updateDatepicker( inst );
}
},
/* Set the dates for a jQuery selection.
* @param target element - the target input field or division or span
* @param date Date - the new date
*/
_setDateDatepicker: function( target, date ) {
var inst = this._getInst( target );
if ( inst ) {
this._setDate( inst, date );
this._updateDatepicker( inst );
this._updateAlternate( inst );
}
},
/* Get the date(s) for the first entry in a jQuery selection.
* @param target element - the target input field or division or span
* @param noDefault boolean - true if no default date is to be used
* @return Date - the current date
*/
_getDateDatepicker: function( target, noDefault ) {
var inst = this._getInst( target );
if ( inst && !inst.inline ) {
this._setDateFromField( inst, noDefault );
}
return ( inst ? this._getDate( inst ) : null );
},
/* Handle keystrokes. */
_doKeyDown: function( event ) {
var onSelect, dateStr, sel,
inst = $.datepicker._getInst( event.target ),
handled = true,
isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
inst._keyEvent = true;
if ( $.datepicker._datepickerShowing ) {
switch ( event.keyCode ) {
case 9: $.datepicker._hideDatepicker();
handled = false;
break; // hide on tab out
case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
$.datepicker._currentClass + ")", inst.dpDiv );
if ( sel[ 0 ] ) {
$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
}
onSelect = $.datepicker._get( inst, "onSelect" );
if ( onSelect ) {
dateStr = $.datepicker._formatDate( inst );
// Trigger custom callback
onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
} else {
$.datepicker._hideDatepicker();
}
return false; // don't submit the form
case 27: $.datepicker._hideDatepicker();
break; // hide on escape
case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
-$.datepicker._get( inst, "stepBigMonths" ) :
-$.datepicker._get( inst, "stepMonths" ) ), "M" );
break; // previous month/year on page up/+ ctrl
case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
+$.datepicker._get( inst, "stepBigMonths" ) :
+$.datepicker._get( inst, "stepMonths" ) ), "M" );
break; // next month/year on page down/+ ctrl
case 35: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._clearDate( event.target );
}
handled = event.ctrlKey || event.metaKey;
break; // clear on ctrl or command +end
case 36: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._gotoToday( event.target );
}
handled = event.ctrlKey || event.metaKey;
break; // current on ctrl or command +home
case 37: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
}
handled = event.ctrlKey || event.metaKey;
// -1 day on ctrl or command +left
if ( event.originalEvent.altKey ) {
$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
-$.datepicker._get( inst, "stepBigMonths" ) :
-$.datepicker._get( inst, "stepMonths" ) ), "M" );
}
// next month/year on alt +left on Mac
break;
case 38: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, -7, "D" );
}
handled = event.ctrlKey || event.metaKey;
break; // -1 week on ctrl or command +up
case 39: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
}
handled = event.ctrlKey || event.metaKey;
// +1 day on ctrl or command +right
if ( event.originalEvent.altKey ) {
$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
+$.datepicker._get( inst, "stepBigMonths" ) :
+$.datepicker._get( inst, "stepMonths" ) ), "M" );
}
// next month/year on alt +right
break;
case 40: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, +7, "D" );
}
handled = event.ctrlKey || event.metaKey;
break; // +1 week on ctrl or command +down
default: handled = false;
}
} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
$.datepicker._showDatepicker( this );
} else {
handled = false;
}
if ( handled ) {
event.preventDefault();
event.stopPropagation();
}
},
/* Filter entered characters - based on date format. */
_doKeyPress: function( event ) {
var chars, chr,
inst = $.datepicker._getInst( event.target );
if ( $.datepicker._get( inst, "constrainInput" ) ) {
chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
}
},
/* Synchronise manual entry and field/alternate field. */
_doKeyUp: function( event ) {
var date,
inst = $.datepicker._getInst( event.target );
if ( inst.input.val() !== inst.lastVal ) {
try {
date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
( inst.input ? inst.input.val() : null ),
$.datepicker._getFormatConfig( inst ) );
if ( date ) { // only if valid
$.datepicker._setDateFromField( inst );
$.datepicker._updateAlternate( inst );
$.datepicker._updateDatepicker( inst );
}
}
catch ( err ) {
}
}
return true;
},
/* Pop-up the date picker for a given input field.
* If false returned from beforeShow event handler do not show.
* @param input element - the input field attached to the date picker or
* event - if triggered by focus
*/
_showDatepicker: function( input ) {
input = input.target || input;
if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
input = $( "input", input.parentNode )[ 0 ];
}
if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
return;
}
var inst, beforeShow, beforeShowSettings, isFixed,
offset, showAnim, duration;
inst = $.datepicker._getInst( input );
if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
$.datepicker._curInst.dpDiv.stop( true, true );
if ( inst && $.datepicker._datepickerShowing ) {
$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
}
}
beforeShow = $.datepicker._get( inst, "beforeShow" );
beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
if ( beforeShowSettings === false ) {
return;
}
datepicker_extendRemove( inst.settings, beforeShowSettings );
inst.lastVal = null;
$.datepicker._lastInput = input;
$.datepicker._setDateFromField( inst );
if ( $.datepicker._inDialog ) { // hide cursor
input.value = "";
}
if ( !$.datepicker._pos ) { // position below input
$.datepicker._pos = $.datepicker._findPos( input );
$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
}
isFixed = false;
$( input ).parents().each( function() {
isFixed |= $( this ).css( "position" ) === "fixed";
return !isFixed;
} );
offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
$.datepicker._pos = null;
//to avoid flashes on Firefox
inst.dpDiv.empty();
// determine sizing offscreen
inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
$.datepicker._updateDatepicker( inst );
// fix width for dynamic number of date pickers
// and adjust position before showing
offset = $.datepicker._checkOffset( inst, offset, isFixed );
inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
left: offset.left + "px", top: offset.top + "px" } );
if ( !inst.inline ) {
showAnim = $.datepicker._get( inst, "showAnim" );
duration = $.datepicker._get( inst, "duration" );
inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
$.datepicker._datepickerShowing = true;
if ( $.effects && $.effects.effect[ showAnim ] ) {
inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
} else {
inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
}
if ( $.datepicker._shouldFocusInput( inst ) ) {
inst.input.trigger( "focus" );
}
$.datepicker._curInst = inst;
}
},
/* Generate the date picker content. */
_updateDatepicker: function( inst ) {
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
datepicker_instActive = inst; // for delegate hover events
inst.dpDiv.empty().append( this._generateHTML( inst ) );
this._attachHandlers( inst );
var origyearshtml,
numMonths = this._getNumberOfMonths( inst ),
cols = numMonths[ 1 ],
width = 17,
activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
if ( activeCell.length > 0 ) {
datepicker_handleMouseover.apply( activeCell.get( 0 ) );
}
inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
if ( cols > 1 ) {
inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
}
inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
"Class" ]( "ui-datepicker-multi" );
inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
"Class" ]( "ui-datepicker-rtl" );
if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
inst.input.trigger( "focus" );
}
// Deffered render of the years select (to avoid flashes on Firefox)
if ( inst.yearshtml ) {
origyearshtml = inst.yearshtml;
setTimeout( function() {
//assure that inst.yearshtml didn't change.
if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
}
origyearshtml = inst.yearshtml = null;
}, 0 );
}
},
// #6694 - don't focus the input if it's already focused
// this breaks the change event in IE
// Support: IE and jQuery <1.9
_shouldFocusInput: function( inst ) {
return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
},
/* Check positioning to remain on screen. */
_checkOffset: function( inst, offset, isFixed ) {
var dpWidth = inst.dpDiv.outerWidth(),
dpHeight = inst.dpDiv.outerHeight(),
inputWidth = inst.input ? inst.input.outerWidth() : 0,
inputHeight = inst.input ? inst.input.outerHeight() : 0,
viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
// Now check if datepicker is showing outside window viewport - move to a better place if so.
offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
Math.abs( dpHeight + inputHeight ) : 0 );
return offset;
},
/* Find an object's position on the screen. */
_findPos: function( obj ) {
var position,
inst = this._getInst( obj ),
isRTL = this._get( inst, "isRTL" );
while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
}
position = $( obj ).offset();
return [ position.left, position.top ];
},
/* Hide the date picker from view.
* @param input element - the input field attached to the date picker
*/
_hideDatepicker: function( input ) {
var showAnim, duration, postProcess, onClose,
inst = this._curInst;
if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
return;
}
if ( this._datepickerShowing ) {
showAnim = this._get( inst, "showAnim" );
duration = this._get( inst, "duration" );
postProcess = function() {
$.datepicker._tidyDialog( inst );
};
// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
} else {
inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
}
if ( !showAnim ) {
postProcess();
}
this._datepickerShowing = false;
onClose = this._get( inst, "onClose" );
if ( onClose ) {
onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
}
this._lastInput = null;
if ( this._inDialog ) {
this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
if ( $.blockUI ) {
$.unblockUI();
$( "body" ).append( this.dpDiv );
}
}
this._inDialog = false;
}
},
/* Tidy up after a dialog display. */
_tidyDialog: function( inst ) {
inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
},
/* Close date picker if clicked elsewhere. */
_checkExternalClick: function( event ) {
if ( !$.datepicker._curInst ) {
return;
}
var $target = $( event.target ),
inst = $.datepicker._getInst( $target[ 0 ] );
if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
!$target.hasClass( $.datepicker.markerClassName ) &&
!$target.closest( "." + $.datepicker._triggerClass ).length &&
$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
$.datepicker._hideDatepicker();
}
},
/* Adjust one of the date sub-fields. */
_adjustDate: function( id, offset, period ) {
var target = $( id ),
inst = this._getInst( target[ 0 ] );
if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
return;
}
this._adjustInstDate( inst, offset +
( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
period );
this._updateDatepicker( inst );
},
/* Action for current link. */
_gotoToday: function( id ) {
var date,
target = $( id ),
inst = this._getInst( target[ 0 ] );
if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
inst.selectedDay = inst.currentDay;
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
inst.drawYear = inst.selectedYear = inst.currentYear;
} else {
date = new Date();
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
}
this._notifyChange( inst );
this._adjustDate( target );
},
/* Action for selecting a new month/year. */
_selectMonthYear: function( id, select, period ) {
var target = $( id ),
inst = this._getInst( target[ 0 ] );
inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
parseInt( select.options[ select.selectedIndex ].value, 10 );
this._notifyChange( inst );
this._adjustDate( target );
},
/* Action for selecting a day. */
_selectDay: function( id, month, year, td ) {
var inst,
target = $( id );
if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
return;
}
inst = this._getInst( target[ 0 ] );
inst.selectedDay = inst.currentDay = $( "a", td ).html();
inst.selectedMonth = inst.currentMonth = month;
inst.selectedYear = inst.currentYear = year;
this._selectDate( id, this._formatDate( inst,
inst.currentDay, inst.currentMonth, inst.currentYear ) );
},
/* Erase the input field and hide the date picker. */
_clearDate: function( id ) {
var target = $( id );
this._selectDate( target, "" );
},
/* Update the input field with the selected date. */
_selectDate: function( id, dateStr ) {
var onSelect,
target = $( id ),
inst = this._getInst( target[ 0 ] );
dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
if ( inst.input ) {
inst.input.val( dateStr );
}
this._updateAlternate( inst );
onSelect = this._get( inst, "onSelect" );
if ( onSelect ) {
onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
} else if ( inst.input ) {
inst.input.trigger( "change" ); // fire the change event
}
if ( inst.inline ) {
this._updateDatepicker( inst );
} else {
this._hideDatepicker();
this._lastInput = inst.input[ 0 ];
if ( typeof( inst.input[ 0 ] ) !== "object" ) {
inst.input.trigger( "focus" ); // restore focus
}
this._lastInput = null;
}
},
/* Update any alternate field to synchronise with the main field. */
_updateAlternate: function( inst ) {
var altFormat, date, dateStr,
altField = this._get( inst, "altField" );
if ( altField ) { // update alternate field too
altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
date = this._getDate( inst );
dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
$( altField ).val( dateStr );
}
},
/* Set as beforeShowDay function to prevent selection of weekends.
* @param date Date - the date to customise
* @return [boolean, string] - is this date selectable?, what is its CSS class?
*/
noWeekends: function( date ) {
var day = date.getDay();
return [ ( day > 0 && day < 6 ), "" ];
},
/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
* @param date Date - the date to get the week for
* @return number - the number of the week within the year that contains this date
*/
iso8601Week: function( date ) {
var time,
checkDate = new Date( date.getTime() );
// Find Thursday of this week starting on Monday
checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
time = checkDate.getTime();
checkDate.setMonth( 0 ); // Compare with Jan 1
checkDate.setDate( 1 );
return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
},
/* Parse a string value into a date object.
* See formatDate below for the possible formats.
*
* @param format string - the expected format of the date
* @param value string - the date in the above format
* @param settings Object - attributes include:
* shortYearCutoff number - the cutoff year for determining the century (optional)
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
* dayNames string[7] - names of the days from Sunday (optional)
* monthNamesShort string[12] - abbreviated names of the months (optional)
* monthNames string[12] - names of the months (optional)
* @return Date - the extracted date value or null if value is blank
*/
parseDate: function( format, value, settings ) {
if ( format == null || value == null ) {
throw "Invalid arguments";
}
value = ( typeof value === "object" ? value.toString() : value + "" );
if ( value === "" ) {
return null;
}
var iFormat, dim, extra,
iValue = 0,
shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
year = -1,
month = -1,
day = -1,
doy = -1,
literal = false,
date,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
},
// Extract a number from the string value
getNumber = function( match ) {
var isDoubled = lookAhead( match ),
size = ( match === "@" ? 14 : ( match === "!" ? 20 :
( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
minSize = ( match === "y" ? size : 1 ),
digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
num = value.substring( iValue ).match( digits );
if ( !num ) {
throw "Missing number at position " + iValue;
}
iValue += num[ 0 ].length;
return parseInt( num[ 0 ], 10 );
},
// Extract a name from the string value and convert to an index
getName = function( match, shortNames, longNames ) {
var index = -1,
names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
return [ [ k, v ] ];
} ).sort( function( a, b ) {
return -( a[ 1 ].length - b[ 1 ].length );
} );
$.each( names, function( i, pair ) {
var name = pair[ 1 ];
if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
index = pair[ 0 ];
iValue += name.length;
return false;
}
} );
if ( index !== -1 ) {
return index + 1;
} else {
throw "Unknown name at position " + iValue;
}
},
// Confirm that a literal character matches the string value
checkLiteral = function() {
if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
throw "Unexpected literal at position " + iValue;
}
iValue++;
};
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
checkLiteral();
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d":
day = getNumber( "d" );
break;
case "D":
getName( "D", dayNamesShort, dayNames );
break;
case "o":
doy = getNumber( "o" );
break;
case "m":
month = getNumber( "m" );
break;
case "M":
month = getName( "M", monthNamesShort, monthNames );
break;
case "y":
year = getNumber( "y" );
break;
case "@":
date = new Date( getNumber( "@" ) );
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
break;
case "!":
date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
break;
case "'":
if ( lookAhead( "'" ) ) {
checkLiteral();
} else {
literal = true;
}
break;
default:
checkLiteral();
}
}
}
if ( iValue < value.length ) {
extra = value.substr( iValue );
if ( !/^\s+/.test( extra ) ) {
throw "Extra/unparsed characters found in date: " + extra;
}
}
if ( year === -1 ) {
year = new Date().getFullYear();
} else if ( year < 100 ) {
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
( year <= shortYearCutoff ? 0 : -100 );
}
if ( doy > -1 ) {
month = 1;
day = doy;
do {
dim = this._getDaysInMonth( year, month - 1 );
if ( day <= dim ) {
break;
}
month++;
day -= dim;
} while ( true );
}
date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
throw "Invalid date"; // E.g. 31/02/00
}
return date;
},
/* Standard date formats. */
ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
COOKIE: "D, dd M yy",
ISO_8601: "yy-mm-dd",
RFC_822: "D, d M y",
RFC_850: "DD, dd-M-y",
RFC_1036: "D, d M y",
RFC_1123: "D, d M yy",
RFC_2822: "D, d M yy",
RSS: "D, d M y", // RFC 822
TICKS: "!",
TIMESTAMP: "@",
W3C: "yy-mm-dd", // ISO 8601
_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
/* Format a date object into a string value.
* The format can be combinations of the following:
* d - day of month (no leading zero)
* dd - day of month (two digit)
* o - day of year (no leading zeros)
* oo - day of year (three digit)
* D - day name short
* DD - day name long
* m - month of year (no leading zero)
* mm - month of year (two digit)
* M - month name short
* MM - month name long
* y - year (two digit)
* yy - year (four digit)
* @ - Unix timestamp (ms since 01/01/1970)
* ! - Windows ticks (100ns since 01/01/0001)
* "..." - literal text
* '' - single quote
*
* @param format string - the desired format of the date
* @param date Date - the date value to format
* @param settings Object - attributes include:
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
* dayNames string[7] - names of the days from Sunday (optional)
* monthNamesShort string[12] - abbreviated names of the months (optional)
* monthNames string[12] - names of the months (optional)
* @return string - the date in the above format
*/
formatDate: function( format, date, settings ) {
if ( !date ) {
return "";
}
var iFormat,
dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
},
// Format a number, with leading zero if necessary
formatNumber = function( match, value, len ) {
var num = "" + value;
if ( lookAhead( match ) ) {
while ( num.length < len ) {
num = "0" + num;
}
}
return num;
},
// Format a name, short or long as requested
formatName = function( match, value, shortNames, longNames ) {
return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
},
output = "",
literal = false;
if ( date ) {
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
output += format.charAt( iFormat );
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d":
output += formatNumber( "d", date.getDate(), 2 );
break;
case "D":
output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
break;
case "o":
output += formatNumber( "o",
Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
break;
case "m":
output += formatNumber( "m", date.getMonth() + 1, 2 );
break;
case "M":
output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
break;
case "y":
output += ( lookAhead( "y" ) ? date.getFullYear() :
( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
break;
case "@":
output += date.getTime();
break;
case "!":
output += date.getTime() * 10000 + this._ticksTo1970;
break;
case "'":
if ( lookAhead( "'" ) ) {
output += "'";
} else {
literal = true;
}
break;
default:
output += format.charAt( iFormat );
}
}
}
}
return output;
},
/* Extract all possible characters from the date format. */
_possibleChars: function( format ) {
var iFormat,
chars = "",
literal = false,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
};
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
chars += format.charAt( iFormat );
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d": case "m": case "y": case "@":
chars += "0123456789";
break;
case "D": case "M":
return null; // Accept anything
case "'":
if ( lookAhead( "'" ) ) {
chars += "'";
} else {
literal = true;
}
break;
default:
chars += format.charAt( iFormat );
}
}
}
return chars;
},
/* Get a setting value, defaulting if necessary. */
_get: function( inst, name ) {
return inst.settings[ name ] !== undefined ?
inst.settings[ name ] : this._defaults[ name ];
},
/* Parse existing date and initialise date picker. */
_setDateFromField: function( inst, noDefault ) {
if ( inst.input.val() === inst.lastVal ) {
return;
}
var dateFormat = this._get( inst, "dateFormat" ),
dates = inst.lastVal = inst.input ? inst.input.val() : null,
defaultDate = this._getDefaultDate( inst ),
date = defaultDate,
settings = this._getFormatConfig( inst );
try {
date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
} catch ( event ) {
dates = ( noDefault ? "" : dates );
}
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
inst.currentDay = ( dates ? date.getDate() : 0 );
inst.currentMonth = ( dates ? date.getMonth() : 0 );
inst.currentYear = ( dates ? date.getFullYear() : 0 );
this._adjustInstDate( inst );
},
/* Retrieve the default date shown on opening. */
_getDefaultDate: function( inst ) {
return this._restrictMinMax( inst,
this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
},
/* A date may be specified as an exact value or a relative one. */
_determineDate: function( inst, date, defaultDate ) {
var offsetNumeric = function( offset ) {
var date = new Date();
date.setDate( date.getDate() + offset );
return date;
},
offsetString = function( offset ) {
try {
return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
offset, $.datepicker._getFormatConfig( inst ) );
}
catch ( e ) {
// Ignore
}
var date = ( offset.toLowerCase().match( /^c/ ) ?
$.datepicker._getDate( inst ) : null ) || new Date(),
year = date.getFullYear(),
month = date.getMonth(),
day = date.getDate(),
pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
matches = pattern.exec( offset );
while ( matches ) {
switch ( matches[ 2 ] || "d" ) {
case "d" : case "D" :
day += parseInt( matches[ 1 ], 10 ); break;
case "w" : case "W" :
day += parseInt( matches[ 1 ], 10 ) * 7; break;
case "m" : case "M" :
month += parseInt( matches[ 1 ], 10 );
day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
break;
case "y": case "Y" :
year += parseInt( matches[ 1 ], 10 );
day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
break;
}
matches = pattern.exec( offset );
}
return new Date( year, month, day );
},
newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
if ( newDate ) {
newDate.setHours( 0 );
newDate.setMinutes( 0 );
newDate.setSeconds( 0 );
newDate.setMilliseconds( 0 );
}
return this._daylightSavingAdjust( newDate );
},
/* Handle switch to/from daylight saving.
* Hours may be non-zero on daylight saving cut-over:
* > 12 when midnight changeover, but then cannot generate
* midnight datetime, so jump to 1AM, otherwise reset.
* @param date (Date) the date to check
* @return (Date) the corrected date
*/
_daylightSavingAdjust: function( date ) {
if ( !date ) {
return null;
}
date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
return date;
},
/* Set the date(s) directly. */
_setDate: function( inst, date, noChange ) {
var clear = !date,
origMonth = inst.selectedMonth,
origYear = inst.selectedYear,
newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
inst.selectedDay = inst.currentDay = newDate.getDate();
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
this._notifyChange( inst );
}
this._adjustInstDate( inst );
if ( inst.input ) {
inst.input.val( clear ? "" : this._formatDate( inst ) );
}
},
/* Retrieve the date(s) directly. */
_getDate: function( inst ) {
var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
this._daylightSavingAdjust( new Date(
inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
return startDate;
},
/* Attach the onxxx handlers. These are declared statically so
* they work with static code transformers like Caja.
*/
_attachHandlers: function( inst ) {
var stepMonths = this._get( inst, "stepMonths" ),
id = "#" + inst.id.replace( /\\\\/g, "\\" );
inst.dpDiv.find( "[data-handler]" ).map( function() {
var handler = {
prev: function() {
$.datepicker._adjustDate( id, -stepMonths, "M" );
},
next: function() {
$.datepicker._adjustDate( id, +stepMonths, "M" );
},
hide: function() {
$.datepicker._hideDatepicker();
},
today: function() {
$.datepicker._gotoToday( id );
},
selectDay: function() {
$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
return false;
},
selectMonth: function() {
$.datepicker._selectMonthYear( id, this, "M" );
return false;
},
selectYear: function() {
$.datepicker._selectMonthYear( id, this, "Y" );
return false;
}
};
$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
} );
},
/* Generate the HTML for the current state of the date picker. */
_generateHTML: function( inst ) {
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
tempDate = new Date(),
today = this._daylightSavingAdjust(
new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
isRTL = this._get( inst, "isRTL" ),
showButtonPanel = this._get( inst, "showButtonPanel" ),
hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
numMonths = this._getNumberOfMonths( inst ),
showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
stepMonths = this._get( inst, "stepMonths" ),
isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
drawMonth = inst.drawMonth - showCurrentAtPos,
drawYear = inst.drawYear;
if ( drawMonth < 0 ) {
drawMonth += 12;
drawYear--;
}
if ( maxDate ) {
maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
drawMonth--;
if ( drawMonth < 0 ) {
drawMonth = 11;
drawYear--;
}
}
}
inst.drawMonth = drawMonth;
inst.drawYear = drawYear;
prevText = this._get( inst, "prevText" );
prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
this._getFormatConfig( inst ) ) );
prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
nextText = this._get( inst, "nextText" );
nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
this._getFormatConfig( inst ) ) );
next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
currentText = this._get( inst, "currentText" );
gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
currentText = ( !navigationAsDateFormat ? currentText :
this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
this._get( inst, "closeText" ) + "</button>" : "" );
buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
showWeek = this._get( inst, "showWeek" );
dayNames = this._get( inst, "dayNames" );
dayNamesMin = this._get( inst, "dayNamesMin" );
monthNames = this._get( inst, "monthNames" );
monthNamesShort = this._get( inst, "monthNamesShort" );
beforeShowDay = this._get( inst, "beforeShowDay" );
showOtherMonths = this._get( inst, "showOtherMonths" );
selectOtherMonths = this._get( inst, "selectOtherMonths" );
defaultDate = this._getDefaultDate( inst );
html = "";
for ( row = 0; row < numMonths[ 0 ]; row++ ) {
group = "";
this.maxRows = 4;
for ( col = 0; col < numMonths[ 1 ]; col++ ) {
selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
cornerClass = " ui-corner-all";
calender = "";
if ( isMultiMonth ) {
calender += "<div class='ui-datepicker-group";
if ( numMonths[ 1 ] > 1 ) {
switch ( col ) {
case 0: calender += " ui-datepicker-group-first";
cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
}
}
calender += "'>";
}
calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
"</div><table class='ui-datepicker-calendar'><thead>" +
"<tr>";
thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
for ( dow = 0; dow < 7; dow++ ) { // days of the week
day = ( dow + firstDay ) % 7;
thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
}
calender += thead + "</tr></thead><tbody>";
daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
}
leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
this.maxRows = numRows;
printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
calender += "<tr>";
tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
for ( dow = 0; dow < 7; dow++ ) { // create date picker days
daySettings = ( beforeShowDay ?
beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
otherMonth = ( printDate.getMonth() !== drawMonth );
unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
tbody += "<td class='" +
( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
// or defaultDate is current printedDate and defaultDate is selectedDate
" " + this._dayOverClass : "" ) + // highlight selected day
( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title
( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
( otherMonth && !showOtherMonths ? " " : // display for other months
( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
printDate.setDate( printDate.getDate() + 1 );
printDate = this._daylightSavingAdjust( printDate );
}
calender += tbody + "</tr>";
}
drawMonth++;
if ( drawMonth > 11 ) {
drawMonth = 0;
drawYear++;
}
calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
group += calender;
}
html += group;
}
html += buttonPanel;
inst._keyEvent = false;
return html;
},
/* Generate the month and year header. */
_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
secondary, monthNames, monthNamesShort ) {
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
changeMonth = this._get( inst, "changeMonth" ),
changeYear = this._get( inst, "changeYear" ),
showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
html = "<div class='ui-datepicker-title'>",
monthHtml = "";
// Month selection
if ( secondary || !changeMonth ) {
monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
} else {
inMinYear = ( minDate && minDate.getFullYear() === drawYear );
inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
for ( month = 0; month < 12; month++ ) {
if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
monthHtml += "<option value='" + month + "'" +
( month === drawMonth ? " selected='selected'" : "" ) +
">" + monthNamesShort[ month ] + "</option>";
}
}
monthHtml += "</select>";
}
if ( !showMonthAfterYear ) {
html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" );
}
// Year selection
if ( !inst.yearshtml ) {
inst.yearshtml = "";
if ( secondary || !changeYear ) {
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
} else {
// determine range of years to display
years = this._get( inst, "yearRange" ).split( ":" );
thisYear = new Date().getFullYear();
determineYear = function( value ) {
var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
parseInt( value, 10 ) ) );
return ( isNaN( year ) ? thisYear : year );
};
year = determineYear( years[ 0 ] );
endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
for ( ; year <= endYear; year++ ) {
inst.yearshtml += "<option value='" + year + "'" +
( year === drawYear ? " selected='selected'" : "" ) +
">" + year + "</option>";
}
inst.yearshtml += "</select>";
html += inst.yearshtml;
inst.yearshtml = null;
}
}
html += this._get( inst, "yearSuffix" );
if ( showMonthAfterYear ) {
html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml;
}
html += "</div>"; // Close datepicker_header
return html;
},
/* Adjust one of the date sub-fields. */
_adjustInstDate: function( inst, offset, period ) {
var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
if ( period === "M" || period === "Y" ) {
this._notifyChange( inst );
}
},
/* Ensure a date is within any min/max bounds. */
_restrictMinMax: function( inst, date ) {
var minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
newDate = ( minDate && date < minDate ? minDate : date );
return ( maxDate && newDate > maxDate ? maxDate : newDate );
},
/* Notify change of month/year. */
_notifyChange: function( inst ) {
var onChange = this._get( inst, "onChangeMonthYear" );
if ( onChange ) {
onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
}
},
/* Determine the number of months to show. */
_getNumberOfMonths: function( inst ) {
var numMonths = this._get( inst, "numberOfMonths" );
return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
},
/* Determine the current maximum date - ensure no time components are set. */
_getMinMaxDate: function( inst, minMax ) {
return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
},
/* Find the number of days in a given month. */
_getDaysInMonth: function( year, month ) {
return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
},
/* Find the day of the week of the first of a month. */
_getFirstDayOfMonth: function( year, month ) {
return new Date( year, month, 1 ).getDay();
},
/* Determines if we should allow a "next/prev" month display change. */
_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
var numMonths = this._getNumberOfMonths( inst ),
date = this._daylightSavingAdjust( new Date( curYear,
curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
if ( offset < 0 ) {
date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
}
return this._isInRange( inst, date );
},
/* Is the given date in the accepted range? */
_isInRange: function( inst, date ) {
var yearSplit, currentYear,
minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
minYear = null,
maxYear = null,
years = this._get( inst, "yearRange" );
if ( years ) {
yearSplit = years.split( ":" );
currentYear = new Date().getFullYear();
minYear = parseInt( yearSplit[ 0 ], 10 );
maxYear = parseInt( yearSplit[ 1 ], 10 );
if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
minYear += currentYear;
}
if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
maxYear += currentYear;
}
}
return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
( !maxDate || date.getTime() <= maxDate.getTime() ) &&
( !minYear || date.getFullYear() >= minYear ) &&
( !maxYear || date.getFullYear() <= maxYear ) );
},
/* Provide the configuration settings for formatting/parsing. */
_getFormatConfig: function( inst ) {
var shortYearCutoff = this._get( inst, "shortYearCutoff" );
shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
return { shortYearCutoff: shortYearCutoff,
dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
},
/* Format the given date for display. */
_formatDate: function( inst, day, month, year ) {
if ( !day ) {
inst.currentDay = inst.selectedDay;
inst.currentMonth = inst.selectedMonth;
inst.currentYear = inst.selectedYear;
}
var date = ( day ? ( typeof day === "object" ? day :
this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
}
} );
/*
* Bind hover events for datepicker elements.
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
* Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
*/
function datepicker_bindHover( dpDiv ) {
var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
return dpDiv.on( "mouseout", selector, function() {
$( this ).removeClass( "ui-state-hover" );
if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
$( this ).removeClass( "ui-datepicker-prev-hover" );
}
if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
$( this ).removeClass( "ui-datepicker-next-hover" );
}
} )
.on( "mouseover", selector, datepicker_handleMouseover );
}
function datepicker_handleMouseover() {
if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
$( this ).addClass( "ui-state-hover" );
if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
$( this ).addClass( "ui-datepicker-prev-hover" );
}
if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
$( this ).addClass( "ui-datepicker-next-hover" );
}
}
}
/* jQuery extend now ignores nulls! */
function datepicker_extendRemove( target, props ) {
$.extend( target, props );
for ( var name in props ) {
if ( props[ name ] == null ) {
target[ name ] = props[ name ];
}
}
return target;
}
/* Invoke the datepicker functionality.
@param options string - a command, optionally followed by additional parameters or
Object - settings for attaching new datepicker functionality
@return jQuery object */
$.fn.datepicker = function( options ) {
/* Verify an empty collection wasn't passed - Fixes #6976 */
if ( !this.length ) {
return this;
}
/* Initialise the date picker. */
if ( !$.datepicker.initialized ) {
$( document ).on( "mousedown", $.datepicker._checkExternalClick );
$.datepicker.initialized = true;
}
/* Append datepicker main container to body if not exist. */
if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
$( "body" ).append( $.datepicker.dpDiv );
}
var otherArgs = Array.prototype.slice.call( arguments, 1 );
if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
return $.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
}
if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
return $.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
}
return this.each( function() {
typeof options === "string" ?
$.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this ].concat( otherArgs ) ) :
$.datepicker._attachDatepicker( this, options );
} );
};
$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.12.1";
var widgetsDatepicker = $.datepicker;
// This file is deprecated
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
/*!
* jQuery UI Mouse 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Mouse
//>>group: Widgets
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
//>>docs: http://api.jqueryui.com/mouse/
var mouseHandled = false;
$( document ).on( "mouseup", function() {
mouseHandled = false;
} );
var widgetsMouse = $.widget( "ui.mouse", {
version: "1.12.1",
options: {
cancel: "input, textarea, button, select, option",
distance: 1,
delay: 0
},
_mouseInit: function() {
var that = this;
this.element
.on( "mousedown." + this.widgetName, function( event ) {
return that._mouseDown( event );
} )
.on( "click." + this.widgetName, function( event ) {
if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
$.removeData( event.target, that.widgetName + ".preventClickEvent" );
event.stopImmediatePropagation();
return false;
}
} );
this.started = false;
},
// TODO: make sure destroying one instance of mouse doesn't mess with
// other instances of mouse
_mouseDestroy: function() {
this.element.off( "." + this.widgetName );
if ( this._mouseMoveDelegate ) {
this.document
.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
}
},
_mouseDown: function( event ) {
// don't let more than one widget handle mouseStart
if ( mouseHandled ) {
return;
}
this._mouseMoved = false;
// We may have missed mouseup (out of window)
( this._mouseStarted && this._mouseUp( event ) );
this._mouseDownEvent = event;
var that = this,
btnIsLeft = ( event.which === 1 ),
// event.target.nodeName works around a bug in IE 8 with
// disabled inputs (#7620)
elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
$( event.target ).closest( this.options.cancel ).length : false );
if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
return true;
}
this.mouseDelayMet = !this.options.delay;
if ( !this.mouseDelayMet ) {
this._mouseDelayTimer = setTimeout( function() {
that.mouseDelayMet = true;
}, this.options.delay );
}
if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
this._mouseStarted = ( this._mouseStart( event ) !== false );
if ( !this._mouseStarted ) {
event.preventDefault();
return true;
}
}
// Click event may never have fired (Gecko & Opera)
if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
$.removeData( event.target, this.widgetName + ".preventClickEvent" );
}
// These delegates are required to keep context
this._mouseMoveDelegate = function( event ) {
return that._mouseMove( event );
};
this._mouseUpDelegate = function( event ) {
return that._mouseUp( event );
};
this.document
.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.on( "mouseup." + this.widgetName, this._mouseUpDelegate );
event.preventDefault();
mouseHandled = true;
return true;
},
_mouseMove: function( event ) {
// Only check for mouseups outside the document if you've moved inside the document
// at least once. This prevents the firing of mouseup in the case of IE<9, which will
// fire a mousemove event if content is placed under the cursor. See #7778
// Support: IE <9
if ( this._mouseMoved ) {
// IE mouseup check - mouseup happened when mouse was out of window
if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
!event.button ) {
return this._mouseUp( event );
// Iframe mouseup check - mouseup occurred in another document
} else if ( !event.which ) {
// Support: Safari <=8 - 9
// Safari sets which to 0 if you press any of the following keys
// during a drag (#14461)
if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
this.ignoreMissingWhich = true;
} else if ( !this.ignoreMissingWhich ) {
return this._mouseUp( event );
}
}
}
if ( event.which || event.button ) {
this._mouseMoved = true;
}
if ( this._mouseStarted ) {
this._mouseDrag( event );
return event.preventDefault();
}
if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
this._mouseStarted =
( this._mouseStart( this._mouseDownEvent, event ) !== false );
( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
}
return !this._mouseStarted;
},
_mouseUp: function( event ) {
this.document
.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
if ( this._mouseStarted ) {
this._mouseStarted = false;
if ( event.target === this._mouseDownEvent.target ) {
$.data( event.target, this.widgetName + ".preventClickEvent", true );
}
this._mouseStop( event );
}
if ( this._mouseDelayTimer ) {
clearTimeout( this._mouseDelayTimer );
delete this._mouseDelayTimer;
}
this.ignoreMissingWhich = false;
mouseHandled = false;
event.preventDefault();
},
_mouseDistanceMet: function( event ) {
return ( Math.max(
Math.abs( this._mouseDownEvent.pageX - event.pageX ),
Math.abs( this._mouseDownEvent.pageY - event.pageY )
) >= this.options.distance
);
},
_mouseDelayMet: function( /* event */ ) {
return this.mouseDelayMet;
},
// These are placeholder methods, to be overriden by extending plugin
_mouseStart: function( /* event */ ) {},
_mouseDrag: function( /* event */ ) {},
_mouseStop: function( /* event */ ) {},
_mouseCapture: function( /* event */ ) { return true; }
} );
// $.ui.plugin is deprecated. Use $.widget() extensions instead.
var plugin = $.ui.plugin = {
add: function( module, option, set ) {
var i,
proto = $.ui[ module ].prototype;
for ( i in set ) {
proto.plugins[ i ] = proto.plugins[ i ] || [];
proto.plugins[ i ].push( [ option, set[ i ] ] );
}
},
call: function( instance, name, args, allowDisconnected ) {
var i,
set = instance.plugins[ name ];
if ( !set ) {
return;
}
if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
return;
}
for ( i = 0; i < set.length; i++ ) {
if ( instance.options[ set[ i ][ 0 ] ] ) {
set[ i ][ 1 ].apply( instance.element, args );
}
}
}
};
var safeBlur = $.ui.safeBlur = function( element ) {
// Support: IE9 - 10 only
// If the <body> is blurred, IE will switch windows, see #9420
if ( element && element.nodeName.toLowerCase() !== "body" ) {
$( element ).trigger( "blur" );
}
};
/*!
* jQuery UI Draggable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Draggable
//>>group: Interactions
//>>description: Enables dragging functionality for any element.
//>>docs: http://api.jqueryui.com/draggable/
//>>demos: http://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css
$.widget( "ui.draggable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "drag",
options: {
addClasses: true,
appendTo: "parent",
axis: false,
connectToSortable: false,
containment: false,
cursor: "auto",
cursorAt: false,
grid: false,
handle: false,
helper: "original",
iframeFix: false,
opacity: false,
refreshPositions: false,
revert: false,
revertDuration: 500,
scope: "default",
scroll: true,
scrollSensitivity: 20,
scrollSpeed: 20,
snap: false,
snapMode: "both",
snapTolerance: 20,
stack: false,
zIndex: false,
// Callbacks
drag: null,
start: null,
stop: null
},
_create: function() {
if ( this.options.helper === "original" ) {
this._setPositionRelative();
}
if ( this.options.addClasses ) {
this._addClass( "ui-draggable" );
}
this._setHandleClassName();
this._mouseInit();
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "handle" ) {
this._removeHandleClassName();
this._setHandleClassName();
}
},
_destroy: function() {
if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
this.destroyOnClear = true;
return;
}
this._removeHandleClassName();
this._mouseDestroy();
},
_mouseCapture: function( event ) {
var o = this.options;
// Among others, prevent a drag on a resizable-handle
if ( this.helper || o.disabled ||
$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
return false;
}
//Quit if we're not on a valid handle
this.handle = this._getHandle( event );
if ( !this.handle ) {
return false;
}
this._blurActiveElement( event );
this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
return true;
},
_blockFrames: function( selector ) {
this.iframeBlocks = this.document.find( selector ).map( function() {
var iframe = $( this );
return $( "<div>" )
.css( "position", "absolute" )
.appendTo( iframe.parent() )
.outerWidth( iframe.outerWidth() )
.outerHeight( iframe.outerHeight() )
.offset( iframe.offset() )[ 0 ];
} );
},
_unblockFrames: function() {
if ( this.iframeBlocks ) {
this.iframeBlocks.remove();
delete this.iframeBlocks;
}
},
_blurActiveElement: function( event ) {
var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
target = $( event.target );
// Don't blur if the event occurred on an element that is within
// the currently focused element
// See #10527, #12472
if ( target.closest( activeElement ).length ) {
return;
}
// Blur any element that currently has focus, see #4261
$.ui.safeBlur( activeElement );
},
_mouseStart: function( event ) {
var o = this.options;
//Create and append the visible helper
this.helper = this._createHelper( event );
this._addClass( this.helper, "ui-draggable-dragging" );
//Cache the helper size
this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable
if ( $.ui.ddmanager ) {
$.ui.ddmanager.current = this;
}
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Store the helper's css position
this.cssPosition = this.helper.css( "position" );
this.scrollParent = this.helper.scrollParent( true );
this.offsetParent = this.helper.offsetParent();
this.hasFixedAncestor = this.helper.parents().filter( function() {
return $( this ).css( "position" ) === "fixed";
} ).length > 0;
//The element's absolute position on the page minus margins
this.positionAbs = this.element.offset();
this._refreshOffsets( event );
//Generate the original position
this.originalPosition = this.position = this._generatePosition( event, false );
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
//Set a containment if given in the options
this._setContainment();
//Trigger event + callbacks
if ( this._trigger( "start", event ) === false ) {
this._clear();
return false;
}
//Recache the helper size
this._cacheHelperProportions();
//Prepare the droppable offsets
if ( $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
// Execute the drag once - this causes the helper not to be visible before getting its
// correct position
this._mouseDrag( event, true );
// If the ddmanager is used for droppables, inform the manager that dragging has started
// (see #5003)
if ( $.ui.ddmanager ) {
$.ui.ddmanager.dragStart( this, event );
}
return true;
},
_refreshOffsets: function( event ) {
this.offset = {
top: this.positionAbs.top - this.margins.top,
left: this.positionAbs.left - this.margins.left,
scroll: false,
parent: this._getParentOffset(),
relative: this._getRelativeOffset()
};
this.offset.click = {
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
};
},
_mouseDrag: function( event, noPropagation ) {
// reset any necessary cached properties (see #5009)
if ( this.hasFixedAncestor ) {
this.offset.parent = this._getParentOffset();
}
//Compute the helpers position
this.position = this._generatePosition( event, true );
this.positionAbs = this._convertPositionTo( "absolute" );
//Call plugins and callbacks and use the resulting position if something is returned
if ( !noPropagation ) {
var ui = this._uiHash();
if ( this._trigger( "drag", event, ui ) === false ) {
this._mouseUp( new $.Event( "mouseup", event ) );
return false;
}
this.position = ui.position;
}
this.helper[ 0 ].style.left = this.position.left + "px";
this.helper[ 0 ].style.top = this.position.top + "px";
if ( $.ui.ddmanager ) {
$.ui.ddmanager.drag( this, event );
}
return false;
},
_mouseStop: function( event ) {
//If we are using droppables, inform the manager about the drop
var that = this,
dropped = false;
if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
dropped = $.ui.ddmanager.drop( this, event );
}
//if a drop comes from outside (a sortable)
if ( this.dropped ) {
dropped = this.dropped;
this.dropped = false;
}
if ( ( this.options.revert === "invalid" && !dropped ) ||
( this.options.revert === "valid" && dropped ) ||
this.options.revert === true || ( $.isFunction( this.options.revert ) &&
this.options.revert.call( this.element, dropped ) )
) {
$( this.helper ).animate(
this.originalPosition,
parseInt( this.options.revertDuration, 10 ),
function() {
if ( that._trigger( "stop", event ) !== false ) {
that._clear();
}
}
);
} else {
if ( this._trigger( "stop", event ) !== false ) {
this._clear();
}
}
return false;
},
_mouseUp: function( event ) {
this._unblockFrames();
// If the ddmanager is used for droppables, inform the manager that dragging has stopped
// (see #5003)
if ( $.ui.ddmanager ) {
$.ui.ddmanager.dragStop( this, event );
}
// Only need to focus if the event occurred on the draggable itself, see #10527
if ( this.handleElement.is( event.target ) ) {
// The interaction is over; whether or not the click resulted in a drag,
// focus the element
this.element.trigger( "focus" );
}
return $.ui.mouse.prototype._mouseUp.call( this, event );
},
cancel: function() {
if ( this.helper.is( ".ui-draggable-dragging" ) ) {
this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
} else {
this._clear();
}
return this;
},
_getHandle: function( event ) {
return this.options.handle ?
!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
true;
},
_setHandleClassName: function() {
this.handleElement = this.options.handle ?
this.element.find( this.options.handle ) : this.element;
this._addClass( this.handleElement, "ui-draggable-handle" );
},
_removeHandleClassName: function() {
this._removeClass( this.handleElement, "ui-draggable-handle" );
},
_createHelper: function( event ) {
var o = this.options,
helperIsFunction = $.isFunction( o.helper ),
helper = helperIsFunction ?
$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
( o.helper === "clone" ?
this.element.clone().removeAttr( "id" ) :
this.element );
if ( !helper.parents( "body" ).length ) {
helper.appendTo( ( o.appendTo === "parent" ?
this.element[ 0 ].parentNode :
o.appendTo ) );
}
// Http://bugs.jqueryui.com/ticket/9446
// a helper function can return the original element
// which wouldn't have been set to relative in _create
if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
this._setPositionRelative();
}
if ( helper[ 0 ] !== this.element[ 0 ] &&
!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
helper.css( "position", "absolute" );
}
return helper;
},
_setPositionRelative: function() {
if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
this.element[ 0 ].style.position = "relative";
}
},
_adjustOffsetFromHelper: function( obj ) {
if ( typeof obj === "string" ) {
obj = obj.split( " " );
}
if ( $.isArray( obj ) ) {
obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
}
if ( "left" in obj ) {
this.offset.click.left = obj.left + this.margins.left;
}
if ( "right" in obj ) {
this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
}
if ( "top" in obj ) {
this.offset.click.top = obj.top + this.margins.top;
}
if ( "bottom" in obj ) {
this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
}
},
_isRootNode: function( element ) {
return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
},
_getParentOffset: function() {
//Get the offsetParent and cache its position
var po = this.offsetParent.offset(),
document = this.document[ 0 ];
// This is a special case where we need to modify a offset calculated on start, since the
// following happened:
// 1. The position of the helper is absolute, so it's position is calculated based on the
// next positioned parent
// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
// the document, which means that the scroll is included in the initial calculation of the
// offset of the parent, and never recalculated upon drag
if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
po.left += this.scrollParent.scrollLeft();
po.top += this.scrollParent.scrollTop();
}
if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
po = { top: 0, left: 0 };
}
return {
top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
};
},
_getRelativeOffset: function() {
if ( this.cssPosition !== "relative" ) {
return { top: 0, left: 0 };
}
var p = this.element.position(),
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
return {
top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
};
},
_cacheMargins: function() {
this.margins = {
left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
};
},
_cacheHelperProportions: function() {
this.helperProportions = {
width: this.helper.outerWidth(),
height: this.helper.outerHeight()
};
},
_setContainment: function() {
var isUserScrollable, c, ce,
o = this.options,
document = this.document[ 0 ];
this.relativeContainer = null;
if ( !o.containment ) {
this.containment = null;
return;
}
if ( o.containment === "window" ) {
this.containment = [
$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
$( window ).scrollLeft() + $( window ).width() -
this.helperProportions.width - this.margins.left,
$( window ).scrollTop() +
( $( window ).height() || document.body.parentNode.scrollHeight ) -
this.helperProportions.height - this.margins.top
];
return;
}
if ( o.containment === "document" ) {
this.containment = [
0,
0,
$( document ).width() - this.helperProportions.width - this.margins.left,
( $( document ).height() || document.body.parentNode.scrollHeight ) -
this.helperProportions.height - this.margins.top
];
return;
}
if ( o.containment.constructor === Array ) {
this.containment = o.containment;
return;
}
if ( o.containment === "parent" ) {
o.containment = this.helper[ 0 ].parentNode;
}
c = $( o.containment );
ce = c[ 0 ];
if ( !ce ) {
return;
}
isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
this.containment = [
( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
this.helperProportions.width -
this.margins.left -
this.margins.right,
( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
this.helperProportions.height -
this.margins.top -
this.margins.bottom
];
this.relativeContainer = c;
},
_convertPositionTo: function( d, pos ) {
if ( !pos ) {
pos = this.position;
}
var mod = d === "absolute" ? 1 : -1,
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
return {
top: (
// The absolute mouse position
pos.top +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top * mod -
( ( this.cssPosition === "fixed" ?
-this.offset.scroll.top :
( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
),
left: (
// The absolute mouse position
pos.left +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left * mod -
( ( this.cssPosition === "fixed" ?
-this.offset.scroll.left :
( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
)
};
},
_generatePosition: function( event, constrainPosition ) {
var containment, co, top, left,
o = this.options,
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
pageX = event.pageX,
pageY = event.pageY;
// Cache the scroll
if ( !scrollIsRootNode || !this.offset.scroll ) {
this.offset.scroll = {
top: this.scrollParent.scrollTop(),
left: this.scrollParent.scrollLeft()
};
}
/*
* - Position constraining -
* Constrain the position to a mix of grid, containment.
*/
// If we are not dragging yet, we won't check for options
if ( constrainPosition ) {
if ( this.containment ) {
if ( this.relativeContainer ) {
co = this.relativeContainer.offset();
containment = [
this.containment[ 0 ] + co.left,
this.containment[ 1 ] + co.top,
this.containment[ 2 ] + co.left,
this.containment[ 3 ] + co.top
];
} else {
containment = this.containment;
}
if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
pageX = containment[ 0 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
pageY = containment[ 1 ] + this.offset.click.top;
}
if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
pageX = containment[ 2 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
pageY = containment[ 3 ] + this.offset.click.top;
}
}
if ( o.grid ) {
//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
// argument errors in IE (see ticket #6950)
top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
top - this.offset.click.top > containment[ 3 ] ) ?
top :
( ( top - this.offset.click.top >= containment[ 1 ] ) ?
top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
left = o.grid[ 0 ] ? this.originalPageX +
Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
this.originalPageX;
pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
left - this.offset.click.left > containment[ 2 ] ) ?
left :
( ( left - this.offset.click.left >= containment[ 0 ] ) ?
left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
}
if ( o.axis === "y" ) {
pageX = this.originalPageX;
}
if ( o.axis === "x" ) {
pageY = this.originalPageY;
}
}
return {
top: (
// The absolute mouse position
pageY -
// Click offset (relative to the element)
this.offset.click.top -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top +
( this.cssPosition === "fixed" ?
-this.offset.scroll.top :
( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
),
left: (
// The absolute mouse position
pageX -
// Click offset (relative to the element)
this.offset.click.left -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left +
( this.cssPosition === "fixed" ?
-this.offset.scroll.left :
( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
)
};
},
_clear: function() {
this._removeClass( this.helper, "ui-draggable-dragging" );
if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
this.helper.remove();
}
this.helper = null;
this.cancelHelperRemoval = false;
if ( this.destroyOnClear ) {
this.destroy();
}
},
// From now on bulk stuff - mainly helpers
_trigger: function( type, event, ui ) {
ui = ui || this._uiHash();
$.ui.plugin.call( this, type, [ event, ui, this ], true );
// Absolute position and offset (see #6884 ) have to be recalculated after plugins
if ( /^(drag|start|stop)/.test( type ) ) {
this.positionAbs = this._convertPositionTo( "absolute" );
ui.offset = this.positionAbs;
}
return $.Widget.prototype._trigger.call( this, type, event, ui );
},
plugins: {},
_uiHash: function() {
return {
helper: this.helper,
position: this.position,
originalPosition: this.originalPosition,
offset: this.positionAbs
};
}
} );
$.ui.plugin.add( "draggable", "connectToSortable", {
start: function( event, ui, draggable ) {
var uiSortable = $.extend( {}, ui, {
item: draggable.element
} );
draggable.sortables = [];
$( draggable.options.connectToSortable ).each( function() {
var sortable = $( this ).sortable( "instance" );
if ( sortable && !sortable.options.disabled ) {
draggable.sortables.push( sortable );
// RefreshPositions is called at drag start to refresh the containerCache
// which is used in drag. This ensures it's initialized and synchronized
// with any changes that might have happened on the page since initialization.
sortable.refreshPositions();
sortable._trigger( "activate", event, uiSortable );
}
} );
},
stop: function( event, ui, draggable ) {
var uiSortable = $.extend( {}, ui, {
item: draggable.element
} );
draggable.cancelHelperRemoval = false;
$.each( draggable.sortables, function() {
var sortable = this;
if ( sortable.isOver ) {
sortable.isOver = 0;
// Allow this sortable to handle removing the helper
draggable.cancelHelperRemoval = true;
sortable.cancelHelperRemoval = false;
// Use _storedCSS To restore properties in the sortable,
// as this also handles revert (#9675) since the draggable
// may have modified them in unexpected ways (#8809)
sortable._storedCSS = {
position: sortable.placeholder.css( "position" ),
top: sortable.placeholder.css( "top" ),
left: sortable.placeholder.css( "left" )
};
sortable._mouseStop( event );
// Once drag has ended, the sortable should return to using
// its original helper, not the shared helper from draggable
sortable.options.helper = sortable.options._helper;
} else {
// Prevent this Sortable from removing the helper.
// However, don't set the draggable to remove the helper
// either as another connected Sortable may yet handle the removal.
sortable.cancelHelperRemoval = true;
sortable._trigger( "deactivate", event, uiSortable );
}
} );
},
drag: function( event, ui, draggable ) {
$.each( draggable.sortables, function() {
var innermostIntersecting = false,
sortable = this;
// Copy over variables that sortable's _intersectsWith uses
sortable.positionAbs = draggable.positionAbs;
sortable.helperProportions = draggable.helperProportions;
sortable.offset.click = draggable.offset.click;
if ( sortable._intersectsWith( sortable.containerCache ) ) {
innermostIntersecting = true;
$.each( draggable.sortables, function() {
// Copy over variables that sortable's _intersectsWith uses
this.positionAbs = draggable.positionAbs;
this.helperProportions = draggable.helperProportions;
this.offset.click = draggable.offset.click;
if ( this !== sortable &&
this._intersectsWith( this.containerCache ) &&
$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
innermostIntersecting = false;
}
return innermostIntersecting;
} );
}
if ( innermostIntersecting ) {
// If it intersects, we use a little isOver variable and set it once,
// so that the move-in stuff gets fired only once.
if ( !sortable.isOver ) {
sortable.isOver = 1;
// Store draggable's parent in case we need to reappend to it later.
draggable._parent = ui.helper.parent();
sortable.currentItem = ui.helper
.appendTo( sortable.element )
.data( "ui-sortable-item", true );
// Store helper option to later restore it
sortable.options._helper = sortable.options.helper;
sortable.options.helper = function() {
return ui.helper[ 0 ];
};
// Fire the start events of the sortable with our passed browser event,
// and our own helper (so it doesn't create a new one)
event.target = sortable.currentItem[ 0 ];
sortable._mouseCapture( event, true );
sortable._mouseStart( event, true, true );
// Because the browser event is way off the new appended portlet,
// modify necessary variables to reflect the changes
sortable.offset.click.top = draggable.offset.click.top;
sortable.offset.click.left = draggable.offset.click.left;
sortable.offset.parent.left -= draggable.offset.parent.left -
sortable.offset.parent.left;
sortable.offset.parent.top -= draggable.offset.parent.top -
sortable.offset.parent.top;
draggable._trigger( "toSortable", event );
// Inform draggable that the helper is in a valid drop zone,
// used solely in the revert option to handle "valid/invalid".
draggable.dropped = sortable.element;
// Need to refreshPositions of all sortables in the case that
// adding to one sortable changes the location of the other sortables (#9675)
$.each( draggable.sortables, function() {
this.refreshPositions();
} );
// Hack so receive/update callbacks work (mostly)
draggable.currentItem = draggable.element;
sortable.fromOutside = draggable;
}
if ( sortable.currentItem ) {
sortable._mouseDrag( event );
// Copy the sortable's position because the draggable's can potentially reflect
// a relative position, while sortable is always absolute, which the dragged
// element has now become. (#8809)
ui.position = sortable.position;
}
} else {
// If it doesn't intersect with the sortable, and it intersected before,
// we fake the drag stop of the sortable, but make sure it doesn't remove
// the helper by using cancelHelperRemoval.
if ( sortable.isOver ) {
sortable.isOver = 0;
sortable.cancelHelperRemoval = true;
// Calling sortable's mouseStop would trigger a revert,
// so revert must be temporarily false until after mouseStop is called.
sortable.options._revert = sortable.options.revert;
sortable.options.revert = false;
sortable._trigger( "out", event, sortable._uiHash( sortable ) );
sortable._mouseStop( event, true );
// Restore sortable behaviors that were modfied
// when the draggable entered the sortable area (#9481)
sortable.options.revert = sortable.options._revert;
sortable.options.helper = sortable.options._helper;
if ( sortable.placeholder ) {
sortable.placeholder.remove();
}
// Restore and recalculate the draggable's offset considering the sortable
// may have modified them in unexpected ways. (#8809, #10669)
ui.helper.appendTo( draggable._parent );
draggable._refreshOffsets( event );
ui.position = draggable._generatePosition( event, true );
draggable._trigger( "fromSortable", event );
// Inform draggable that the helper is no longer in a valid drop zone
draggable.dropped = false;
// Need to refreshPositions of all sortables just in case removing
// from one sortable changes the location of other sortables (#9675)
$.each( draggable.sortables, function() {
this.refreshPositions();
} );
}
}
} );
}
} );
$.ui.plugin.add( "draggable", "cursor", {
start: function( event, ui, instance ) {
var t = $( "body" ),
o = instance.options;
if ( t.css( "cursor" ) ) {
o._cursor = t.css( "cursor" );
}
t.css( "cursor", o.cursor );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._cursor ) {
$( "body" ).css( "cursor", o._cursor );
}
}
} );
$.ui.plugin.add( "draggable", "opacity", {
start: function( event, ui, instance ) {
var t = $( ui.helper ),
o = instance.options;
if ( t.css( "opacity" ) ) {
o._opacity = t.css( "opacity" );
}
t.css( "opacity", o.opacity );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._opacity ) {
$( ui.helper ).css( "opacity", o._opacity );
}
}
} );
$.ui.plugin.add( "draggable", "scroll", {
start: function( event, ui, i ) {
if ( !i.scrollParentNotHidden ) {
i.scrollParentNotHidden = i.helper.scrollParent( false );
}
if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
i.overflowOffset = i.scrollParentNotHidden.offset();
}
},
drag: function( event, ui, i ) {
var o = i.options,
scrolled = false,
scrollParent = i.scrollParentNotHidden[ 0 ],
document = i.document[ 0 ];
if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
if ( !o.axis || o.axis !== "x" ) {
if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
o.scrollSensitivity ) {
scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
}
}
if ( !o.axis || o.axis !== "y" ) {
if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
o.scrollSensitivity ) {
scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
}
}
} else {
if ( !o.axis || o.axis !== "x" ) {
if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
o.scrollSensitivity ) {
scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
}
}
if ( !o.axis || o.axis !== "y" ) {
if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
scrolled = $( document ).scrollLeft(
$( document ).scrollLeft() - o.scrollSpeed
);
} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
o.scrollSensitivity ) {
scrolled = $( document ).scrollLeft(
$( document ).scrollLeft() + o.scrollSpeed
);
}
}
}
if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( i, event );
}
}
} );
$.ui.plugin.add( "draggable", "snap", {
start: function( event, ui, i ) {
var o = i.options;
i.snapElements = [];
$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
.each( function() {
var $t = $( this ),
$o = $t.offset();
if ( this !== i.element[ 0 ] ) {
i.snapElements.push( {
item: this,
width: $t.outerWidth(), height: $t.outerHeight(),
top: $o.top, left: $o.left
} );
}
} );
},
drag: function( event, ui, inst ) {
var ts, bs, ls, rs, l, r, t, b, i, first,
o = inst.options,
d = o.snapTolerance,
x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
l = inst.snapElements[ i ].left - inst.margins.left;
r = l + inst.snapElements[ i ].width;
t = inst.snapElements[ i ].top - inst.margins.top;
b = t + inst.snapElements[ i ].height;
if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
!$.contains( inst.snapElements[ i ].item.ownerDocument,
inst.snapElements[ i ].item ) ) {
if ( inst.snapElements[ i ].snapping ) {
( inst.options.snap.release &&
inst.options.snap.release.call(
inst.element,
event,
$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
) );
}
inst.snapElements[ i ].snapping = false;
continue;
}
if ( o.snapMode !== "inner" ) {
ts = Math.abs( t - y2 ) <= d;
bs = Math.abs( b - y1 ) <= d;
ls = Math.abs( l - x2 ) <= d;
rs = Math.abs( r - x1 ) <= d;
if ( ts ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: t - inst.helperProportions.height,
left: 0
} ).top;
}
if ( bs ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: b,
left: 0
} ).top;
}
if ( ls ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: l - inst.helperProportions.width
} ).left;
}
if ( rs ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: r
} ).left;
}
}
first = ( ts || bs || ls || rs );
if ( o.snapMode !== "outer" ) {
ts = Math.abs( t - y1 ) <= d;
bs = Math.abs( b - y2 ) <= d;
ls = Math.abs( l - x1 ) <= d;
rs = Math.abs( r - x2 ) <= d;
if ( ts ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: t,
left: 0
} ).top;
}
if ( bs ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: b - inst.helperProportions.height,
left: 0
} ).top;
}
if ( ls ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: l
} ).left;
}
if ( rs ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: r - inst.helperProportions.width
} ).left;
}
}
if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
( inst.options.snap.snap &&
inst.options.snap.snap.call(
inst.element,
event,
$.extend( inst._uiHash(), {
snapItem: inst.snapElements[ i ].item
} ) ) );
}
inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
}
}
} );
$.ui.plugin.add( "draggable", "stack", {
start: function( event, ui, instance ) {
var min,
o = instance.options,
group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
} );
if ( !group.length ) { return; }
min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
$( group ).each( function( i ) {
$( this ).css( "zIndex", min + i );
} );
this.css( "zIndex", ( min + group.length ) );
}
} );
$.ui.plugin.add( "draggable", "zIndex", {
start: function( event, ui, instance ) {
var t = $( ui.helper ),
o = instance.options;
if ( t.css( "zIndex" ) ) {
o._zIndex = t.css( "zIndex" );
}
t.css( "zIndex", o.zIndex );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._zIndex ) {
$( ui.helper ).css( "zIndex", o._zIndex );
}
}
} );
var widgetsDraggable = $.ui.draggable;
/*!
* jQuery UI Resizable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.resizable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "resize",
options: {
alsoResize: false,
animate: false,
animateDuration: "slow",
animateEasing: "swing",
aspectRatio: false,
autoHide: false,
classes: {
"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
},
containment: false,
ghost: false,
grid: false,
handles: "e,s,se",
helper: false,
maxHeight: null,
maxWidth: null,
minHeight: 10,
minWidth: 10,
// See #7960
zIndex: 90,
// Callbacks
resize: null,
start: null,
stop: null
},
_num: function( value ) {
return parseFloat( value ) || 0;
},
_isNumber: function( value ) {
return !isNaN( parseFloat( value ) );
},
_hasScroll: function( el, a ) {
if ( $( el ).css( "overflow" ) === "hidden" ) {
return false;
}
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
has = false;
if ( el[ scroll ] > 0 ) {
return true;
}
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
// set the scroll
el[ scroll ] = 1;
has = ( el[ scroll ] > 0 );
el[ scroll ] = 0;
return has;
},
_create: function() {
var margins,
o = this.options,
that = this;
this._addClass( "ui-resizable" );
$.extend( this, {
_aspectRatio: !!( o.aspectRatio ),
aspectRatio: o.aspectRatio,
originalElement: this.element,
_proportionallyResizeElements: [],
_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
} );
// Wrap the element if it cannot hold child nodes
if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
this.element.wrap(
$( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
position: this.element.css( "position" ),
width: this.element.outerWidth(),
height: this.element.outerHeight(),
top: this.element.css( "top" ),
left: this.element.css( "left" )
} )
);
this.element = this.element.parent().data(
"ui-resizable", this.element.resizable( "instance" )
);
this.elementIsWrapper = true;
margins = {
marginTop: this.originalElement.css( "marginTop" ),
marginRight: this.originalElement.css( "marginRight" ),
marginBottom: this.originalElement.css( "marginBottom" ),
marginLeft: this.originalElement.css( "marginLeft" )
};
this.element.css( margins );
this.originalElement.css( "margin", 0 );
// support: Safari
// Prevent Safari textarea resize
this.originalResizeStyle = this.originalElement.css( "resize" );
this.originalElement.css( "resize", "none" );
this._proportionallyResizeElements.push( this.originalElement.css( {
position: "static",
zoom: 1,
display: "block"
} ) );
// Support: IE9
// avoid IE jump (hard set the margin)
this.originalElement.css( margins );
this._proportionallyResize();
}
this._setupHandles();
if ( o.autoHide ) {
$( this.element )
.on( "mouseenter", function() {
if ( o.disabled ) {
return;
}
that._removeClass( "ui-resizable-autohide" );
that._handles.show();
} )
.on( "mouseleave", function() {
if ( o.disabled ) {
return;
}
if ( !that.resizing ) {
that._addClass( "ui-resizable-autohide" );
that._handles.hide();
}
} );
}
this._mouseInit();
},
_destroy: function() {
this._mouseDestroy();
var wrapper,
_destroy = function( exp ) {
$( exp )
.removeData( "resizable" )
.removeData( "ui-resizable" )
.off( ".resizable" )
.find( ".ui-resizable-handle" )
.remove();
};
// TODO: Unwrap at same DOM position
if ( this.elementIsWrapper ) {
_destroy( this.element );
wrapper = this.element;
this.originalElement.css( {
position: wrapper.css( "position" ),
width: wrapper.outerWidth(),
height: wrapper.outerHeight(),
top: wrapper.css( "top" ),
left: wrapper.css( "left" )
} ).insertAfter( wrapper );
wrapper.remove();
}
this.originalElement.css( "resize", this.originalResizeStyle );
_destroy( this.originalElement );
return this;
},
_setOption: function( key, value ) {
this._super( key, value );
switch ( key ) {
case "handles":
this._removeHandles();
this._setupHandles();
break;
default:
break;
}
},
_setupHandles: function() {
var o = this.options, handle, i, n, hname, axis, that = this;
this.handles = o.handles ||
( !$( ".ui-resizable-handle", this.element ).length ?
"e,s,se" : {
n: ".ui-resizable-n",
e: ".ui-resizable-e",
s: ".ui-resizable-s",
w: ".ui-resizable-w",
se: ".ui-resizable-se",
sw: ".ui-resizable-sw",
ne: ".ui-resizable-ne",
nw: ".ui-resizable-nw"
} );
this._handles = $();
if ( this.handles.constructor === String ) {
if ( this.handles === "all" ) {
this.handles = "n,e,s,w,se,sw,ne,nw";
}
n = this.handles.split( "," );
this.handles = {};
for ( i = 0; i < n.length; i++ ) {
handle = $.trim( n[ i ] );
hname = "ui-resizable-" + handle;
axis = $( "<div>" );
this._addClass( axis, "ui-resizable-handle " + hname );
axis.css( { zIndex: o.zIndex } );
this.handles[ handle ] = ".ui-resizable-" + handle;
this.element.append( axis );
}
}
this._renderAxis = function( target ) {
var i, axis, padPos, padWrapper;
target = target || this.element;
for ( i in this.handles ) {
if ( this.handles[ i ].constructor === String ) {
this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
this.handles[ i ] = $( this.handles[ i ] );
this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
}
if ( this.elementIsWrapper &&
this.originalElement[ 0 ]
.nodeName
.match( /^(textarea|input|select|button)$/i ) ) {
axis = $( this.handles[ i ], this.element );
padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
axis.outerHeight() :
axis.outerWidth();
padPos = [ "padding",
/ne|nw|n/.test( i ) ? "Top" :
/se|sw|s/.test( i ) ? "Bottom" :
/^e$/.test( i ) ? "Right" : "Left" ].join( "" );
target.css( padPos, padWrapper );
this._proportionallyResize();
}
this._handles = this._handles.add( this.handles[ i ] );
}
};
// TODO: make renderAxis a prototype function
this._renderAxis( this.element );
this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
this._handles.disableSelection();
this._handles.on( "mouseover", function() {
if ( !that.resizing ) {
if ( this.className ) {
axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
}
that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
}
} );
if ( o.autoHide ) {
this._handles.hide();
this._addClass( "ui-resizable-autohide" );
}
},
_removeHandles: function() {
this._handles.remove();
},
_mouseCapture: function( event ) {
var i, handle,
capture = false;
for ( i in this.handles ) {
handle = $( this.handles[ i ] )[ 0 ];
if ( handle === event.target || $.contains( handle, event.target ) ) {
capture = true;
}
}
return !this.options.disabled && capture;
},
_mouseStart: function( event ) {
var curleft, curtop, cursor,
o = this.options,
el = this.element;
this.resizing = true;
this._renderProxy();
curleft = this._num( this.helper.css( "left" ) );
curtop = this._num( this.helper.css( "top" ) );
if ( o.containment ) {
curleft += $( o.containment ).scrollLeft() || 0;
curtop += $( o.containment ).scrollTop() || 0;
}
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
this.size = this._helper ? {
width: this.helper.width(),
height: this.helper.height()
} : {
width: el.width(),
height: el.height()
};
this.originalSize = this._helper ? {
width: el.outerWidth(),
height: el.outerHeight()
} : {
width: el.width(),
height: el.height()
};
this.sizeDiff = {
width: el.outerWidth() - el.width(),
height: el.outerHeight() - el.height()
};
this.originalPosition = { left: curleft, top: curtop };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
o.aspectRatio :
( ( this.originalSize.width / this.originalSize.height ) || 1 );
cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
this._addClass( "ui-resizable-resizing" );
this._propagate( "start", event );
return true;
},
_mouseDrag: function( event ) {
var data, props,
smp = this.originalMousePosition,
a = this.axis,
dx = ( event.pageX - smp.left ) || 0,
dy = ( event.pageY - smp.top ) || 0,
trigger = this._change[ a ];
this._updatePrevProperties();
if ( !trigger ) {
return false;
}
data = trigger.apply( this, [ event, dx, dy ] );
this._updateVirtualBoundaries( event.shiftKey );
if ( this._aspectRatio || event.shiftKey ) {
data = this._updateRatio( data, event );
}
data = this._respectSize( data, event );
this._updateCache( data );
this._propagate( "resize", event );
props = this._applyChanges();
if ( !this._helper && this._proportionallyResizeElements.length ) {
this._proportionallyResize();
}
if ( !$.isEmptyObject( props ) ) {
this._updatePrevProperties();
this._trigger( "resize", event, this.ui() );
this._applyChanges();
}
return false;
},
_mouseStop: function( event ) {
this.resizing = false;
var pr, ista, soffseth, soffsetw, s, left, top,
o = this.options, that = this;
if ( this._helper ) {
pr = this._proportionallyResizeElements;
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
soffsetw = ista ? 0 : that.sizeDiff.width;
s = {
width: ( that.helper.width() - soffsetw ),
height: ( that.helper.height() - soffseth )
};
left = ( parseFloat( that.element.css( "left" ) ) +
( that.position.left - that.originalPosition.left ) ) || null;
top = ( parseFloat( that.element.css( "top" ) ) +
( that.position.top - that.originalPosition.top ) ) || null;
if ( !o.animate ) {
this.element.css( $.extend( s, { top: top, left: left } ) );
}
that.helper.height( that.size.height );
that.helper.width( that.size.width );
if ( this._helper && !o.animate ) {
this._proportionallyResize();
}
}
$( "body" ).css( "cursor", "auto" );
this._removeClass( "ui-resizable-resizing" );
this._propagate( "stop", event );
if ( this._helper ) {
this.helper.remove();
}
return false;
},
_updatePrevProperties: function() {
this.prevPosition = {
top: this.position.top,
left: this.position.left
};
this.prevSize = {
width: this.size.width,
height: this.size.height
};
},
_applyChanges: function() {
var props = {};
if ( this.position.top !== this.prevPosition.top ) {
props.top = this.position.top + "px";
}
if ( this.position.left !== this.prevPosition.left ) {
props.left = this.position.left + "px";
}
if ( this.size.width !== this.prevSize.width ) {
props.width = this.size.width + "px";
}
if ( this.size.height !== this.prevSize.height ) {
props.height = this.size.height + "px";
}
this.helper.css( props );
return props;
},
_updateVirtualBoundaries: function( forceAspectRatio ) {
var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
o = this.options;
b = {
minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
};
if ( this._aspectRatio || forceAspectRatio ) {
pMinWidth = b.minHeight * this.aspectRatio;
pMinHeight = b.minWidth / this.aspectRatio;
pMaxWidth = b.maxHeight * this.aspectRatio;
pMaxHeight = b.maxWidth / this.aspectRatio;
if ( pMinWidth > b.minWidth ) {
b.minWidth = pMinWidth;
}
if ( pMinHeight > b.minHeight ) {
b.minHeight = pMinHeight;
}
if ( pMaxWidth < b.maxWidth ) {
b.maxWidth = pMaxWidth;
}
if ( pMaxHeight < b.maxHeight ) {
b.maxHeight = pMaxHeight;
}
}
this._vBoundaries = b;
},
_updateCache: function( data ) {
this.offset = this.helper.offset();
if ( this._isNumber( data.left ) ) {
this.position.left = data.left;
}
if ( this._isNumber( data.top ) ) {
this.position.top = data.top;
}
if ( this._isNumber( data.height ) ) {
this.size.height = data.height;
}
if ( this._isNumber( data.width ) ) {
this.size.width = data.width;
}
},
_updateRatio: function( data ) {
var cpos = this.position,
csize = this.size,
a = this.axis;
if ( this._isNumber( data.height ) ) {
data.width = ( data.height * this.aspectRatio );
} else if ( this._isNumber( data.width ) ) {
data.height = ( data.width / this.aspectRatio );
}
if ( a === "sw" ) {
data.left = cpos.left + ( csize.width - data.width );
data.top = null;
}
if ( a === "nw" ) {
data.top = cpos.top + ( csize.height - data.height );
data.left = cpos.left + ( csize.width - data.width );
}
return data;
},
_respectSize: function( data ) {
var o = this._vBoundaries,
a = this.axis,
ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
dw = this.originalPosition.left + this.originalSize.width,
dh = this.originalPosition.top + this.originalSize.height,
cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
if ( isminw ) {
data.width = o.minWidth;
}
if ( isminh ) {
data.height = o.minHeight;
}
if ( ismaxw ) {
data.width = o.maxWidth;
}
if ( ismaxh ) {
data.height = o.maxHeight;
}
if ( isminw && cw ) {
data.left = dw - o.minWidth;
}
if ( ismaxw && cw ) {
data.left = dw - o.maxWidth;
}
if ( isminh && ch ) {
data.top = dh - o.minHeight;
}
if ( ismaxh && ch ) {
data.top = dh - o.maxHeight;
}
// Fixing jump error on top/left - bug #2330
if ( !data.width && !data.height && !data.left && data.top ) {
data.top = null;
} else if ( !data.width && !data.height && !data.top && data.left ) {
data.left = null;
}
return data;
},
_getPaddingPlusBorderDimensions: function( element ) {
var i = 0,
widths = [],
borders = [
element.css( "borderTopWidth" ),
element.css( "borderRightWidth" ),
element.css( "borderBottomWidth" ),
element.css( "borderLeftWidth" )
],
paddings = [
element.css( "paddingTop" ),
element.css( "paddingRight" ),
element.css( "paddingBottom" ),
element.css( "paddingLeft" )
];
for ( ; i < 4; i++ ) {
widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
}
return {
height: widths[ 0 ] + widths[ 2 ],
width: widths[ 1 ] + widths[ 3 ]
};
},
_proportionallyResize: function() {
if ( !this._proportionallyResizeElements.length ) {
return;
}
var prel,
i = 0,
element = this.helper || this.element;
for ( ; i < this._proportionallyResizeElements.length; i++ ) {
prel = this._proportionallyResizeElements[ i ];
// TODO: Seems like a bug to cache this.outerDimensions
// considering that we are in a loop.
if ( !this.outerDimensions ) {
this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
}
prel.css( {
height: ( element.height() - this.outerDimensions.height ) || 0,
width: ( element.width() - this.outerDimensions.width ) || 0
} );
}
},
_renderProxy: function() {
var el = this.element, o = this.options;
this.elementOffset = el.offset();
if ( this._helper ) {
this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
this._addClass( this.helper, this._helper );
this.helper.css( {
width: this.element.outerWidth(),
height: this.element.outerHeight(),
position: "absolute",
left: this.elementOffset.left + "px",
top: this.elementOffset.top + "px",
zIndex: ++o.zIndex //TODO: Don't modify option
} );
this.helper
.appendTo( "body" )
.disableSelection();
} else {
this.helper = this.element;
}
},
_change: {
e: function( event, dx ) {
return { width: this.originalSize.width + dx };
},
w: function( event, dx ) {
var cs = this.originalSize, sp = this.originalPosition;
return { left: sp.left + dx, width: cs.width - dx };
},
n: function( event, dx, dy ) {
var cs = this.originalSize, sp = this.originalPosition;
return { top: sp.top + dy, height: cs.height - dy };
},
s: function( event, dx, dy ) {
return { height: this.originalSize.height + dy };
},
se: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
},
sw: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
},
ne: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
},
nw: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
}
},
_propagate: function( n, event ) {
$.ui.plugin.call( this, n, [ event, this.ui() ] );
( n !== "resize" && this._trigger( n, event, this.ui() ) );
},
plugins: {},
ui: function() {
return {
originalElement: this.originalElement,
element: this.element,
helper: this.helper,
position: this.position,
size: this.size,
originalSize: this.originalSize,
originalPosition: this.originalPosition
};
}
} );
/*
* Resizable Extensions
*/
$.ui.plugin.add( "resizable", "animate", {
stop: function( event ) {
var that = $( this ).resizable( "instance" ),
o = that.options,
pr = that._proportionallyResizeElements,
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
soffsetw = ista ? 0 : that.sizeDiff.width,
style = {
width: ( that.size.width - soffsetw ),
height: ( that.size.height - soffseth )
},
left = ( parseFloat( that.element.css( "left" ) ) +
( that.position.left - that.originalPosition.left ) ) || null,
top = ( parseFloat( that.element.css( "top" ) ) +
( that.position.top - that.originalPosition.top ) ) || null;
that.element.animate(
$.extend( style, top && left ? { top: top, left: left } : {} ), {
duration: o.animateDuration,
easing: o.animateEasing,
step: function() {
var data = {
width: parseFloat( that.element.css( "width" ) ),
height: parseFloat( that.element.css( "height" ) ),
top: parseFloat( that.element.css( "top" ) ),
left: parseFloat( that.element.css( "left" ) )
};
if ( pr && pr.length ) {
$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
}
// Propagating resize, and updating values for each animation step
that._updateCache( data );
that._propagate( "resize", event );
}
}
);
}
} );
$.ui.plugin.add( "resizable", "containment", {
start: function() {
var element, p, co, ch, cw, width, height,
that = $( this ).resizable( "instance" ),
o = that.options,
el = that.element,
oc = o.containment,
ce = ( oc instanceof $ ) ?
oc.get( 0 ) :
( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
if ( !ce ) {
return;
}
that.containerElement = $( ce );
if ( /document/.test( oc ) || oc === document ) {
that.containerOffset = {
left: 0,
top: 0
};
that.containerPosition = {
left: 0,
top: 0
};
that.parentData = {
element: $( document ),
left: 0,
top: 0,
width: $( document ).width(),
height: $( document ).height() || document.body.parentNode.scrollHeight
};
} else {
element = $( ce );
p = [];
$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
p[ i ] = that._num( element.css( "padding" + name ) );
} );
that.containerOffset = element.offset();
that.containerPosition = element.position();
that.containerSize = {
height: ( element.innerHeight() - p[ 3 ] ),
width: ( element.innerWidth() - p[ 1 ] )
};
co = that.containerOffset;
ch = that.containerSize.height;
cw = that.containerSize.width;
width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
that.parentData = {
element: ce,
left: co.left,
top: co.top,
width: width,
height: height
};
}
},
resize: function( event ) {
var woset, hoset, isParent, isOffsetRelative,
that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cp = that.position,
pRatio = that._aspectRatio || event.shiftKey,
cop = {
top: 0,
left: 0
},
ce = that.containerElement,
continueResize = true;
if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
cop = co;
}
if ( cp.left < ( that._helper ? co.left : 0 ) ) {
that.size.width = that.size.width +
( that._helper ?
( that.position.left - co.left ) :
( that.position.left - cop.left ) );
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
that.position.left = o.helper ? co.left : 0;
}
if ( cp.top < ( that._helper ? co.top : 0 ) ) {
that.size.height = that.size.height +
( that._helper ?
( that.position.top - co.top ) :
that.position.top );
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
that.position.top = that._helper ? co.top : 0;
}
isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
if ( isParent && isOffsetRelative ) {
that.offset.left = that.parentData.left + that.position.left;
that.offset.top = that.parentData.top + that.position.top;
} else {
that.offset.left = that.element.offset().left;
that.offset.top = that.element.offset().top;
}
woset = Math.abs( that.sizeDiff.width +
( that._helper ?
that.offset.left - cop.left :
( that.offset.left - co.left ) ) );
hoset = Math.abs( that.sizeDiff.height +
( that._helper ?
that.offset.top - cop.top :
( that.offset.top - co.top ) ) );
if ( woset + that.size.width >= that.parentData.width ) {
that.size.width = that.parentData.width - woset;
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
}
if ( hoset + that.size.height >= that.parentData.height ) {
that.size.height = that.parentData.height - hoset;
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
}
if ( !continueResize ) {
that.position.left = that.prevPosition.left;
that.position.top = that.prevPosition.top;
that.size.width = that.prevSize.width;
that.size.height = that.prevSize.height;
}
},
stop: function() {
var that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cop = that.containerPosition,
ce = that.containerElement,
helper = $( that.helper ),
ho = helper.offset(),
w = helper.outerWidth() - that.sizeDiff.width,
h = helper.outerHeight() - that.sizeDiff.height;
if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
} );
}
if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
} );
}
}
} );
$.ui.plugin.add( "resizable", "alsoResize", {
start: function() {
var that = $( this ).resizable( "instance" ),
o = that.options;
$( o.alsoResize ).each( function() {
var el = $( this );
el.data( "ui-resizable-alsoresize", {
width: parseFloat( el.width() ), height: parseFloat( el.height() ),
left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
} );
} );
},
resize: function( event, ui ) {
var that = $( this ).resizable( "instance" ),
o = that.options,
os = that.originalSize,
op = that.originalPosition,
delta = {
height: ( that.size.height - os.height ) || 0,
width: ( that.size.width - os.width ) || 0,
top: ( that.position.top - op.top ) || 0,
left: ( that.position.left - op.left ) || 0
};
$( o.alsoResize ).each( function() {
var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
css = el.parents( ui.originalElement[ 0 ] ).length ?
[ "width", "height" ] :
[ "width", "height", "top", "left" ];
$.each( css, function( i, prop ) {
var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
if ( sum && sum >= 0 ) {
style[ prop ] = sum || null;
}
} );
el.css( style );
} );
},
stop: function() {
$( this ).removeData( "ui-resizable-alsoresize" );
}
} );
$.ui.plugin.add( "resizable", "ghost", {
start: function() {
var that = $( this ).resizable( "instance" ), cs = that.size;
that.ghost = that.originalElement.clone();
that.ghost.css( {
opacity: 0.25,
display: "block",
position: "relative",
height: cs.height,
width: cs.width,
margin: 0,
left: 0,
top: 0
} );
that._addClass( that.ghost, "ui-resizable-ghost" );
// DEPRECATED
// TODO: remove after 1.12
if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
// Ghost option
that.ghost.addClass( this.options.ghost );
}
that.ghost.appendTo( that.helper );
},
resize: function() {
var that = $( this ).resizable( "instance" );
if ( that.ghost ) {
that.ghost.css( {
position: "relative",
height: that.size.height,
width: that.size.width
} );
}
},
stop: function() {
var that = $( this ).resizable( "instance" );
if ( that.ghost && that.helper ) {
that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
}
}
} );
$.ui.plugin.add( "resizable", "grid", {
resize: function() {
var outerDimensions,
that = $( this ).resizable( "instance" ),
o = that.options,
cs = that.size,
os = that.originalSize,
op = that.originalPosition,
a = that.axis,
grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
gridX = ( grid[ 0 ] || 1 ),
gridY = ( grid[ 1 ] || 1 ),
ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
newWidth = os.width + ox,
newHeight = os.height + oy,
isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
isMinHeight = o.minHeight && ( o.minHeight > newHeight );
o.grid = grid;
if ( isMinWidth ) {
newWidth += gridX;
}
if ( isMinHeight ) {
newHeight += gridY;
}
if ( isMaxWidth ) {
newWidth -= gridX;
}
if ( isMaxHeight ) {
newHeight -= gridY;
}
if ( /^(se|s|e)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
} else if ( /^(ne)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.top = op.top - oy;
} else if ( /^(sw)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.left = op.left - ox;
} else {
if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
outerDimensions = that._getPaddingPlusBorderDimensions( this );
}
if ( newHeight - gridY > 0 ) {
that.size.height = newHeight;
that.position.top = op.top - oy;
} else {
newHeight = gridY - outerDimensions.height;
that.size.height = newHeight;
that.position.top = op.top + os.height - newHeight;
}
if ( newWidth - gridX > 0 ) {
that.size.width = newWidth;
that.position.left = op.left - ox;
} else {
newWidth = gridX - outerDimensions.width;
that.size.width = newWidth;
that.position.left = op.left + os.width - newWidth;
}
}
}
} );
var widgetsResizable = $.ui.resizable;
/*!
* jQuery UI Dialog 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Dialog
//>>group: Widgets
//>>description: Displays customizable dialog windows.
//>>docs: http://api.jqueryui.com/dialog/
//>>demos: http://jqueryui.com/dialog/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/dialog.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.dialog", {
version: "1.12.1",
options: {
appendTo: "body",
autoOpen: true,
buttons: [],
classes: {
"ui-dialog": "ui-corner-all",
"ui-dialog-titlebar": "ui-corner-all"
},
closeOnEscape: true,
closeText: "Close",
draggable: true,
hide: null,
height: "auto",
maxHeight: null,
maxWidth: null,
minHeight: 150,
minWidth: 150,
modal: false,
position: {
my: "center",
at: "center",
of: window,
collision: "fit",
// Ensure the titlebar is always visible
using: function( pos ) {
var topOffset = $( this ).css( pos ).offset().top;
if ( topOffset < 0 ) {
$( this ).css( "top", pos.top - topOffset );
}
}
},
resizable: true,
show: null,
title: null,
width: 300,
// Callbacks
beforeClose: null,
close: null,
drag: null,
dragStart: null,
dragStop: null,
focus: null,
open: null,
resize: null,
resizeStart: null,
resizeStop: null
},
sizeRelatedOptions: {
buttons: true,
height: true,
maxHeight: true,
maxWidth: true,
minHeight: true,
minWidth: true,
width: true
},
resizableRelatedOptions: {
maxHeight: true,
maxWidth: true,
minHeight: true,
minWidth: true
},
_create: function() {
this.originalCss = {
display: this.element[ 0 ].style.display,
width: this.element[ 0 ].style.width,
minHeight: this.element[ 0 ].style.minHeight,
maxHeight: this.element[ 0 ].style.maxHeight,
height: this.element[ 0 ].style.height
};
this.originalPosition = {
parent: this.element.parent(),
index: this.element.parent().children().index( this.element )
};
this.originalTitle = this.element.attr( "title" );
if ( this.options.title == null && this.originalTitle != null ) {
this.options.title = this.originalTitle;
}
// Dialogs can't be disabled
if ( this.options.disabled ) {
this.options.disabled = false;
}
this._createWrapper();
this.element
.show()
.removeAttr( "title" )
.appendTo( this.uiDialog );
this._addClass( "ui-dialog-content", "ui-widget-content" );
this._createTitlebar();
this._createButtonPane();
if ( this.options.draggable && $.fn.draggable ) {
this._makeDraggable();
}
if ( this.options.resizable && $.fn.resizable ) {
this._makeResizable();
}
this._isOpen = false;
this._trackFocus();
},
_init: function() {
if ( this.options.autoOpen ) {
this.open();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element && ( element.jquery || element.nodeType ) ) {
return $( element );
}
return this.document.find( element || "body" ).eq( 0 );
},
_destroy: function() {
var next,
originalPosition = this.originalPosition;
this._untrackInstance();
this._destroyOverlay();
this.element
.removeUniqueId()
.css( this.originalCss )
// Without detaching first, the following becomes really slow
.detach();
this.uiDialog.remove();
if ( this.originalTitle ) {
this.element.attr( "title", this.originalTitle );
}
next = originalPosition.parent.children().eq( originalPosition.index );
// Don't try to place the dialog next to itself (#8613)
if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
next.before( this.element );
} else {
originalPosition.parent.append( this.element );
}
},
widget: function() {
return this.uiDialog;
},
disable: $.noop,
enable: $.noop,
close: function( event ) {
var that = this;
if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
return;
}
this._isOpen = false;
this._focusedElement = null;
this._destroyOverlay();
this._untrackInstance();
if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
// Hiding a focused element doesn't trigger blur in WebKit
// so in case we have nothing to focus on, explicitly blur the active element
// https://bugs.webkit.org/show_bug.cgi?id=47182
$.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
}
this._hide( this.uiDialog, this.options.hide, function() {
that._trigger( "close", event );
} );
},
isOpen: function() {
return this._isOpen;
},
moveToTop: function() {
this._moveToTop();
},
_moveToTop: function( event, silent ) {
var moved = false,
zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
return +$( this ).css( "z-index" );
} ).get(),
zIndexMax = Math.max.apply( null, zIndices );
if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
this.uiDialog.css( "z-index", zIndexMax + 1 );
moved = true;
}
if ( moved && !silent ) {
this._trigger( "focus", event );
}
return moved;
},
open: function() {
var that = this;
if ( this._isOpen ) {
if ( this._moveToTop() ) {
this._focusTabbable();
}
return;
}
this._isOpen = true;
this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
this._size();
this._position();
this._createOverlay();
this._moveToTop( null, true );
// Ensure the overlay is moved to the top with the dialog, but only when
// opening. The overlay shouldn't move after the dialog is open so that
// modeless dialogs opened after the modal dialog stack properly.
if ( this.overlay ) {
this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
}
this._show( this.uiDialog, this.options.show, function() {
that._focusTabbable();
that._trigger( "focus" );
} );
// Track the dialog immediately upon openening in case a focus event
// somehow occurs outside of the dialog before an element inside the
// dialog is focused (#10152)
this._makeFocusTarget();
this._trigger( "open" );
},
_focusTabbable: function() {
// Set focus to the first match:
// 1. An element that was focused previously
// 2. First element inside the dialog matching [autofocus]
// 3. Tabbable element inside the content element
// 4. Tabbable element inside the buttonpane
// 5. The close button
// 6. The dialog itself
var hasFocus = this._focusedElement;
if ( !hasFocus ) {
hasFocus = this.element.find( "[autofocus]" );
}
if ( !hasFocus.length ) {
hasFocus = this.element.find( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialog;
}
hasFocus.eq( 0 ).trigger( "focus" );
},
_keepFocus: function( event ) {
function checkFocus() {
var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
isActive = this.uiDialog[ 0 ] === activeElement ||
$.contains( this.uiDialog[ 0 ], activeElement );
if ( !isActive ) {
this._focusTabbable();
}
}
event.preventDefault();
checkFocus.call( this );
// support: IE
// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
// so we check again later
this._delay( checkFocus );
},
_createWrapper: function() {
this.uiDialog = $( "<div>" )
.hide()
.attr( {
// Setting tabIndex makes the div focusable
tabIndex: -1,
role: "dialog"
} )
.appendTo( this._appendTo() );
this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
this._on( this.uiDialog, {
keydown: function( event ) {
if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
event.keyCode === $.ui.keyCode.ESCAPE ) {
event.preventDefault();
this.close( event );
return;
}
// Prevent tabbing out of dialogs
if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
return;
}
var tabbables = this.uiDialog.find( ":tabbable" ),
first = tabbables.filter( ":first" ),
last = tabbables.filter( ":last" );
if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
!event.shiftKey ) {
this._delay( function() {
first.trigger( "focus" );
} );
event.preventDefault();
} else if ( ( event.target === first[ 0 ] ||
event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
this._delay( function() {
last.trigger( "focus" );
} );
event.preventDefault();
}
},
mousedown: function( event ) {
if ( this._moveToTop( event ) ) {
this._focusTabbable();
}
}
} );
// We assume that any existing aria-describedby attribute means
// that the dialog content is marked up properly
// otherwise we brute force the content as the description
if ( !this.element.find( "[aria-describedby]" ).length ) {
this.uiDialog.attr( {
"aria-describedby": this.element.uniqueId().attr( "id" )
} );
}
},
_createTitlebar: function() {
var uiDialogTitle;
this.uiDialogTitlebar = $( "<div>" );
this._addClass( this.uiDialogTitlebar,
"ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
this._on( this.uiDialogTitlebar, {
mousedown: function( event ) {
// Don't prevent click on close button (#8838)
// Focusing a dialog that is partially scrolled out of view
// causes the browser to scroll it into view, preventing the click event
if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
// Dialog isn't getting focus when dragging (#8063)
this.uiDialog.trigger( "focus" );
}
}
} );
// Support: IE
// Use type="button" to prevent enter keypresses in textboxes from closing the
// dialog in IE (#9312)
this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
.button( {
label: $( "<a>" ).text( this.options.closeText ).html(),
icon: "ui-icon-closethick",
showLabel: false
} )
.appendTo( this.uiDialogTitlebar );
this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
this._on( this.uiDialogTitlebarClose, {
click: function( event ) {
event.preventDefault();
this.close( event );
}
} );
uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
this._addClass( uiDialogTitle, "ui-dialog-title" );
this._title( uiDialogTitle );
this.uiDialogTitlebar.prependTo( this.uiDialog );
this.uiDialog.attr( {
"aria-labelledby": uiDialogTitle.attr( "id" )
} );
},
_title: function( title ) {
if ( this.options.title ) {
title.text( this.options.title );
} else {
title.html( " " );
}
},
_createButtonPane: function() {
this.uiDialogButtonPane = $( "<div>" );
this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
"ui-widget-content ui-helper-clearfix" );
this.uiButtonSet = $( "<div>" )
.appendTo( this.uiDialogButtonPane );
this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
this._createButtons();
},
_createButtons: function() {
var that = this,
buttons = this.options.buttons;
// If we already have a button pane, remove it
this.uiDialogButtonPane.remove();
this.uiButtonSet.empty();
if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
this._removeClass( this.uiDialog, "ui-dialog-buttons" );
return;
}
$.each( buttons, function( name, props ) {
var click, buttonOptions;
props = $.isFunction( props ) ?
{ click: props, text: name } :
props;
// Default to a non-submitting button
props = $.extend( { type: "button" }, props );
// Change the context for the click callback to be the main element
click = props.click;
buttonOptions = {
icon: props.icon,
iconPosition: props.iconPosition,
showLabel: props.showLabel,
// Deprecated options
icons: props.icons,
text: props.text
};
delete props.click;
delete props.icon;
delete props.iconPosition;
delete props.showLabel;
// Deprecated options
delete props.icons;
if ( typeof props.text === "boolean" ) {
delete props.text;
}
$( "<button></button>", props )
.button( buttonOptions )
.appendTo( that.uiButtonSet )
.on( "click", function() {
click.apply( that.element[ 0 ], arguments );
} );
} );
this._addClass( this.uiDialog, "ui-dialog-buttons" );
this.uiDialogButtonPane.appendTo( this.uiDialog );
},
_makeDraggable: function() {
var that = this,
options = this.options;
function filteredUi( ui ) {
return {
position: ui.position,
offset: ui.offset
};
}
this.uiDialog.draggable( {
cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
handle: ".ui-dialog-titlebar",
containment: "document",
start: function( event, ui ) {
that._addClass( $( this ), "ui-dialog-dragging" );
that._blockFrames();
that._trigger( "dragStart", event, filteredUi( ui ) );
},
drag: function( event, ui ) {
that._trigger( "drag", event, filteredUi( ui ) );
},
stop: function( event, ui ) {
var left = ui.offset.left - that.document.scrollLeft(),
top = ui.offset.top - that.document.scrollTop();
options.position = {
my: "left top",
at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
"top" + ( top >= 0 ? "+" : "" ) + top,
of: that.window
};
that._removeClass( $( this ), "ui-dialog-dragging" );
that._unblockFrames();
that._trigger( "dragStop", event, filteredUi( ui ) );
}
} );
},
_makeResizable: function() {
var that = this,
options = this.options,
handles = options.resizable,
// .ui-resizable has position: relative defined in the stylesheet
// but dialogs have to use absolute or fixed positioning
position = this.uiDialog.css( "position" ),
resizeHandles = typeof handles === "string" ?
handles :
"n,e,s,w,se,sw,ne,nw";
function filteredUi( ui ) {
return {
originalPosition: ui.originalPosition,
originalSize: ui.originalSize,
position: ui.position,
size: ui.size
};
}
this.uiDialog.resizable( {
cancel: ".ui-dialog-content",
containment: "document",
alsoResize: this.element,
maxWidth: options.maxWidth,
maxHeight: options.maxHeight,
minWidth: options.minWidth,
minHeight: this._minHeight(),
handles: resizeHandles,
start: function( event, ui ) {
that._addClass( $( this ), "ui-dialog-resizing" );
that._blockFrames();
that._trigger( "resizeStart", event, filteredUi( ui ) );
},
resize: function( event, ui ) {
that._trigger( "resize", event, filteredUi( ui ) );
},
stop: function( event, ui ) {
var offset = that.uiDialog.offset(),
left = offset.left - that.document.scrollLeft(),
top = offset.top - that.document.scrollTop();
options.height = that.uiDialog.height();
options.width = that.uiDialog.width();
options.position = {
my: "left top",
at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
"top" + ( top >= 0 ? "+" : "" ) + top,
of: that.window
};
that._removeClass( $( this ), "ui-dialog-resizing" );
that._unblockFrames();
that._trigger( "resizeStop", event, filteredUi( ui ) );
}
} )
.css( "position", position );
},
_trackFocus: function() {
this._on( this.widget(), {
focusin: function( event ) {
this._makeFocusTarget();
this._focusedElement = $( event.target );
}
} );
},
_makeFocusTarget: function() {
this._untrackInstance();
this._trackingInstances().unshift( this );
},
_untrackInstance: function() {
var instances = this._trackingInstances(),
exists = $.inArray( this, instances );
if ( exists !== -1 ) {
instances.splice( exists, 1 );
}
},
_trackingInstances: function() {
var instances = this.document.data( "ui-dialog-instances" );
if ( !instances ) {
instances = [];
this.document.data( "ui-dialog-instances", instances );
}
return instances;
},
_minHeight: function() {
var options = this.options;
return options.height === "auto" ?
options.minHeight :
Math.min( options.minHeight, options.height );
},
_position: function() {
// Need to show the dialog to get the actual offset in the position plugin
var isVisible = this.uiDialog.is( ":visible" );
if ( !isVisible ) {
this.uiDialog.show();
}
this.uiDialog.position( this.options.position );
if ( !isVisible ) {
this.uiDialog.hide();
}
},
_setOptions: function( options ) {
var that = this,
resize = false,
resizableOptions = {};
$.each( options, function( key, value ) {
that._setOption( key, value );
if ( key in that.sizeRelatedOptions ) {
resize = true;
}
if ( key in that.resizableRelatedOptions ) {
resizableOptions[ key ] = value;
}
} );
if ( resize ) {
this._size();
this._position();
}
if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", resizableOptions );
}
},
_setOption: function( key, value ) {
var isDraggable, isResizable,
uiDialog = this.uiDialog;
if ( key === "disabled" ) {
return;
}
this._super( key, value );
if ( key === "appendTo" ) {
this.uiDialog.appendTo( this._appendTo() );
}
if ( key === "buttons" ) {
this._createButtons();
}
if ( key === "closeText" ) {
this.uiDialogTitlebarClose.button( {
// Ensure that we always pass a string
label: $( "<a>" ).text( "" + this.options.closeText ).html()
} );
}
if ( key === "draggable" ) {
isDraggable = uiDialog.is( ":data(ui-draggable)" );
if ( isDraggable && !value ) {
uiDialog.draggable( "destroy" );
}
if ( !isDraggable && value ) {
this._makeDraggable();
}
}
if ( key === "position" ) {
this._position();
}
if ( key === "resizable" ) {
// currently resizable, becoming non-resizable
isResizable = uiDialog.is( ":data(ui-resizable)" );
if ( isResizable && !value ) {
uiDialog.resizable( "destroy" );
}
// Currently resizable, changing handles
if ( isResizable && typeof value === "string" ) {
uiDialog.resizable( "option", "handles", value );
}
// Currently non-resizable, becoming resizable
if ( !isResizable && value !== false ) {
this._makeResizable();
}
}
if ( key === "title" ) {
this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
}
},
_size: function() {
// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
// divs will both have width and height set, so we need to reset them
var nonContentHeight, minContentHeight, maxContentHeight,
options = this.options;
// Reset content sizing
this.element.show().css( {
width: "auto",
minHeight: 0,
maxHeight: "none",
height: 0
} );
if ( options.minWidth > options.width ) {
options.width = options.minWidth;
}
// Reset wrapper sizing
// determine the height of all the non-content elements
nonContentHeight = this.uiDialog.css( {
height: "auto",
width: options.width
} )
.outerHeight();
minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
maxContentHeight = typeof options.maxHeight === "number" ?
Math.max( 0, options.maxHeight - nonContentHeight ) :
"none";
if ( options.height === "auto" ) {
this.element.css( {
minHeight: minContentHeight,
maxHeight: maxContentHeight,
height: "auto"
} );
} else {
this.element.height( Math.max( 0, options.height - nonContentHeight ) );
}
if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
}
},
_blockFrames: function() {
this.iframeBlocks = this.document.find( "iframe" ).map( function() {
var iframe = $( this );
return $( "<div>" )
.css( {
position: "absolute",
width: iframe.outerWidth(),
height: iframe.outerHeight()
} )
.appendTo( iframe.parent() )
.offset( iframe.offset() )[ 0 ];
} );
},
_unblockFrames: function() {
if ( this.iframeBlocks ) {
this.iframeBlocks.remove();
delete this.iframeBlocks;
}
},
_allowInteraction: function( event ) {
if ( $( event.target ).closest( ".ui-dialog" ).length ) {
return true;
}
// TODO: Remove hack when datepicker implements
// the .ui-front logic (#8989)
return !!$( event.target ).closest( ".ui-datepicker" ).length;
},
_createOverlay: function() {
if ( !this.options.modal ) {
return;
}
// We use a delay in case the overlay is created from an
// event that we're going to be cancelling (#2804)
var isOpening = true;
this._delay( function() {
isOpening = false;
} );
if ( !this.document.data( "ui-dialog-overlays" ) ) {
// Prevent use of anchors and inputs
// Using _on() for an event handler shared across many instances is
// safe because the dialogs stack and must be closed in reverse order
this._on( this.document, {
focusin: function( event ) {
if ( isOpening ) {
return;
}
if ( !this._allowInteraction( event ) ) {
event.preventDefault();
this._trackingInstances()[ 0 ]._focusTabbable();
}
}
} );
}
this.overlay = $( "<div>" )
.appendTo( this._appendTo() );
this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
this._on( this.overlay, {
mousedown: "_keepFocus"
} );
this.document.data( "ui-dialog-overlays",
( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
},
_destroyOverlay: function() {
if ( !this.options.modal ) {
return;
}
if ( this.overlay ) {
var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
if ( !overlays ) {
this._off( this.document, "focusin" );
this.document.removeData( "ui-dialog-overlays" );
} else {
this.document.data( "ui-dialog-overlays", overlays );
}
this.overlay.remove();
this.overlay = null;
}
}
} );
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for dialogClass option
$.widget( "ui.dialog", $.ui.dialog, {
options: {
dialogClass: ""
},
_createWrapper: function() {
this._super();
this.uiDialog.addClass( this.options.dialogClass );
},
_setOption: function( key, value ) {
if ( key === "dialogClass" ) {
this.uiDialog
.removeClass( this.options.dialogClass )
.addClass( value );
}
this._superApply( arguments );
}
} );
}
var widgetsDialog = $.ui.dialog;
/*!
* jQuery UI Droppable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Droppable
//>>group: Interactions
//>>description: Enables drop targets for draggable elements.
//>>docs: http://api.jqueryui.com/droppable/
//>>demos: http://jqueryui.com/droppable/
$.widget( "ui.droppable", {
version: "1.12.1",
widgetEventPrefix: "drop",
options: {
accept: "*",
addClasses: true,
greedy: false,
scope: "default",
tolerance: "intersect",
// Callbacks
activate: null,
deactivate: null,
drop: null,
out: null,
over: null
},
_create: function() {
var proportions,
o = this.options,
accept = o.accept;
this.isover = false;
this.isout = true;
this.accept = $.isFunction( accept ) ? accept : function( d ) {
return d.is( accept );
};
this.proportions = function( /* valueToWrite */ ) {
if ( arguments.length ) {
// Store the droppable's proportions
proportions = arguments[ 0 ];
} else {
// Retrieve or derive the droppable's proportions
return proportions ?
proportions :
proportions = {
width: this.element[ 0 ].offsetWidth,
height: this.element[ 0 ].offsetHeight
};
}
};
this._addToManager( o.scope );
o.addClasses && this._addClass( "ui-droppable" );
},
_addToManager: function( scope ) {
// Add the reference and positions to the manager
$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
$.ui.ddmanager.droppables[ scope ].push( this );
},
_splice: function( drop ) {
var i = 0;
for ( ; i < drop.length; i++ ) {
if ( drop[ i ] === this ) {
drop.splice( i, 1 );
}
}
},
_destroy: function() {
var drop = $.ui.ddmanager.droppables[ this.options.scope ];
this._splice( drop );
},
_setOption: function( key, value ) {
if ( key === "accept" ) {
this.accept = $.isFunction( value ) ? value : function( d ) {
return d.is( value );
};
} else if ( key === "scope" ) {
var drop = $.ui.ddmanager.droppables[ this.options.scope ];
this._splice( drop );
this._addToManager( value );
}
this._super( key, value );
},
_activate: function( event ) {
var draggable = $.ui.ddmanager.current;
this._addActiveClass();
if ( draggable ) {
this._trigger( "activate", event, this.ui( draggable ) );
}
},
_deactivate: function( event ) {
var draggable = $.ui.ddmanager.current;
this._removeActiveClass();
if ( draggable ) {
this._trigger( "deactivate", event, this.ui( draggable ) );
}
},
_over: function( event ) {
var draggable = $.ui.ddmanager.current;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return;
}
if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
draggable.element ) ) ) {
this._addHoverClass();
this._trigger( "over", event, this.ui( draggable ) );
}
},
_out: function( event ) {
var draggable = $.ui.ddmanager.current;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return;
}
if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
draggable.element ) ) ) {
this._removeHoverClass();
this._trigger( "out", event, this.ui( draggable ) );
}
},
_drop: function( event, custom ) {
var draggable = custom || $.ui.ddmanager.current,
childrenIntersection = false;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return false;
}
this.element
.find( ":data(ui-droppable)" )
.not( ".ui-draggable-dragging" )
.each( function() {
var inst = $( this ).droppable( "instance" );
if (
inst.options.greedy &&
!inst.options.disabled &&
inst.options.scope === draggable.options.scope &&
inst.accept.call(
inst.element[ 0 ], ( draggable.currentItem || draggable.element )
) &&
intersect(
draggable,
$.extend( inst, { offset: inst.element.offset() } ),
inst.options.tolerance, event
)
) {
childrenIntersection = true;
return false; }
} );
if ( childrenIntersection ) {
return false;
}
if ( this.accept.call( this.element[ 0 ],
( draggable.currentItem || draggable.element ) ) ) {
this._removeActiveClass();
this._removeHoverClass();
this._trigger( "drop", event, this.ui( draggable ) );
return this.element;
}
return false;
},
ui: function( c ) {
return {
draggable: ( c.currentItem || c.element ),
helper: c.helper,
position: c.position,
offset: c.positionAbs
};
},
// Extension points just to make backcompat sane and avoid duplicating logic
// TODO: Remove in 1.13 along with call to it below
_addHoverClass: function() {
this._addClass( "ui-droppable-hover" );
},
_removeHoverClass: function() {
this._removeClass( "ui-droppable-hover" );
},
_addActiveClass: function() {
this._addClass( "ui-droppable-active" );
},
_removeActiveClass: function() {
this._removeClass( "ui-droppable-active" );
}
} );
var intersect = $.ui.intersect = ( function() {
function isOverAxis( x, reference, size ) {
return ( x >= reference ) && ( x < ( reference + size ) );
}
return function( draggable, droppable, toleranceMode, event ) {
if ( !droppable.offset ) {
return false;
}
var x1 = ( draggable.positionAbs ||
draggable.position.absolute ).left + draggable.margins.left,
y1 = ( draggable.positionAbs ||
draggable.position.absolute ).top + draggable.margins.top,
x2 = x1 + draggable.helperProportions.width,
y2 = y1 + draggable.helperProportions.height,
l = droppable.offset.left,
t = droppable.offset.top,
r = l + droppable.proportions().width,
b = t + droppable.proportions().height;
switch ( toleranceMode ) {
case "fit":
return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
case "intersect":
return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
case "pointer":
return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
isOverAxis( event.pageX, l, droppable.proportions().width );
case "touch":
return (
( y1 >= t && y1 <= b ) || // Top edge touching
( y2 >= t && y2 <= b ) || // Bottom edge touching
( y1 < t && y2 > b ) // Surrounded vertically
) && (
( x1 >= l && x1 <= r ) || // Left edge touching
( x2 >= l && x2 <= r ) || // Right edge touching
( x1 < l && x2 > r ) // Surrounded horizontally
);
default:
return false;
}
};
} )();
/*
This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
current: null,
droppables: { "default": [] },
prepareOffsets: function( t, event ) {
var i, j,
m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
type = event ? event.type : null, // workaround for #2317
list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
droppablesLoop: for ( i = 0; i < m.length; i++ ) {
// No disabled and non-accepted
if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
( t.currentItem || t.element ) ) ) ) {
continue;
}
// Filter out elements in the current dragged item
for ( j = 0; j < list.length; j++ ) {
if ( list[ j ] === m[ i ].element[ 0 ] ) {
m[ i ].proportions().height = 0;
continue droppablesLoop;
}
}
m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
if ( !m[ i ].visible ) {
continue;
}
// Activate the droppable if used directly from draggables
if ( type === "mousedown" ) {
m[ i ]._activate.call( m[ i ], event );
}
m[ i ].offset = m[ i ].element.offset();
m[ i ].proportions( {
width: m[ i ].element[ 0 ].offsetWidth,
height: m[ i ].element[ 0 ].offsetHeight
} );
}
},
drop: function( draggable, event ) {
var dropped = false;
// Create a copy of the droppables in case the list changes during the drop (#9116)
$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
if ( !this.options ) {
return;
}
if ( !this.options.disabled && this.visible &&
intersect( draggable, this, this.options.tolerance, event ) ) {
dropped = this._drop.call( this, event ) || dropped;
}
if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
( draggable.currentItem || draggable.element ) ) ) {
this.isout = true;
this.isover = false;
this._deactivate.call( this, event );
}
} );
return dropped;
},
dragStart: function( draggable, event ) {
// Listen for scrolling so that if the dragging causes scrolling the position of the
// droppables can be recalculated (see #5003)
draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
if ( !draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
} );
},
drag: function( draggable, event ) {
// If you have a highly dynamic page, you might try this option. It renders positions
// every time you move the mouse.
if ( draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
// Run through all droppables and check their positions based on specific tolerance options
$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
if ( this.options.disabled || this.greedyChild || !this.visible ) {
return;
}
var parentInstance, scope, parent,
intersects = intersect( draggable, this, this.options.tolerance, event ),
c = !intersects && this.isover ?
"isout" :
( intersects && !this.isover ? "isover" : null );
if ( !c ) {
return;
}
if ( this.options.greedy ) {
// find droppable parents with same scope
scope = this.options.scope;
parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
return $( this ).droppable( "instance" ).options.scope === scope;
} );
if ( parent.length ) {
parentInstance = $( parent[ 0 ] ).droppable( "instance" );
parentInstance.greedyChild = ( c === "isover" );
}
}
// We just moved into a greedy child
if ( parentInstance && c === "isover" ) {
parentInstance.isover = false;
parentInstance.isout = true;
parentInstance._out.call( parentInstance, event );
}
this[ c ] = true;
this[ c === "isout" ? "isover" : "isout" ] = false;
this[ c === "isover" ? "_over" : "_out" ].call( this, event );
// We just moved out of a greedy child
if ( parentInstance && c === "isout" ) {
parentInstance.isout = false;
parentInstance.isover = true;
parentInstance._over.call( parentInstance, event );
}
} );
},
dragStop: function( draggable, event ) {
draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
// Call prepareOffsets one final time since IE does not fire return scroll events when
// overflow was caused by drag (see #5003)
if ( !draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
}
};
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for activeClass and hoverClass options
$.widget( "ui.droppable", $.ui.droppable, {
options: {
hoverClass: false,
activeClass: false
},
_addActiveClass: function() {
this._super();
if ( this.options.activeClass ) {
this.element.addClass( this.options.activeClass );
}
},
_removeActiveClass: function() {
this._super();
if ( this.options.activeClass ) {
this.element.removeClass( this.options.activeClass );
}
},
_addHoverClass: function() {
this._super();
if ( this.options.hoverClass ) {
this.element.addClass( this.options.hoverClass );
}
},
_removeHoverClass: function() {
this._super();
if ( this.options.hoverClass ) {
this.element.removeClass( this.options.hoverClass );
}
}
} );
}
var widgetsDroppable = $.ui.droppable;
/*!
* jQuery UI Progressbar 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Progressbar
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/progressbar/
//>>demos: http://jqueryui.com/progressbar/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/progressbar.css
//>>css.theme: ../../themes/base/theme.css
var widgetsProgressbar = $.widget( "ui.progressbar", {
version: "1.12.1",
options: {
classes: {
"ui-progressbar": "ui-corner-all",
"ui-progressbar-value": "ui-corner-left",
"ui-progressbar-complete": "ui-corner-right"
},
max: 100,
value: 0,
change: null,
complete: null
},
min: 0,
_create: function() {
// Constrain initial value
this.oldValue = this.options.value = this._constrainedValue();
this.element.attr( {
// Only set static values; aria-valuenow and aria-valuemax are
// set inside _refreshValue()
role: "progressbar",
"aria-valuemin": this.min
} );
this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
this.valueDiv = $( "<div>" ).appendTo( this.element );
this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
this._refreshValue();
},
_destroy: function() {
this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
this.valueDiv.remove();
},
value: function( newValue ) {
if ( newValue === undefined ) {
return this.options.value;
}
this.options.value = this._constrainedValue( newValue );
this._refreshValue();
},
_constrainedValue: function( newValue ) {
if ( newValue === undefined ) {
newValue = this.options.value;
}
this.indeterminate = newValue === false;
// Sanitize value
if ( typeof newValue !== "number" ) {
newValue = 0;
}
return this.indeterminate ? false :
Math.min( this.options.max, Math.max( this.min, newValue ) );
},
_setOptions: function( options ) {
// Ensure "value" option is set after other values (like max)
var value = options.value;
delete options.value;
this._super( options );
this.options.value = this._constrainedValue( value );
this._refreshValue();
},
_setOption: function( key, value ) {
if ( key === "max" ) {
// Don't allow a max less than min
value = Math.max( this.min, value );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", value );
this._toggleClass( null, "ui-state-disabled", !!value );
},
_percentage: function() {
return this.indeterminate ?
100 :
100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
},
_refreshValue: function() {
var value = this.options.value,
percentage = this._percentage();
this.valueDiv
.toggle( this.indeterminate || value > this.min )
.width( percentage.toFixed( 0 ) + "%" );
this
._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
value === this.options.max )
._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
if ( this.indeterminate ) {
this.element.removeAttr( "aria-valuenow" );
if ( !this.overlayDiv ) {
this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
}
} else {
this.element.attr( {
"aria-valuemax": this.options.max,
"aria-valuenow": value
} );
if ( this.overlayDiv ) {
this.overlayDiv.remove();
this.overlayDiv = null;
}
}
if ( this.oldValue !== value ) {
this.oldValue = value;
this._trigger( "change" );
}
if ( value === this.options.max ) {
this._trigger( "complete" );
}
}
} );
/*!
* jQuery UI Selectable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Selectable
//>>group: Interactions
//>>description: Allows groups of elements to be selected with the mouse.
//>>docs: http://api.jqueryui.com/selectable/
//>>demos: http://jqueryui.com/selectable/
//>>css.structure: ../../themes/base/selectable.css
var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
version: "1.12.1",
options: {
appendTo: "body",
autoRefresh: true,
distance: 0,
filter: "*",
tolerance: "touch",
// Callbacks
selected: null,
selecting: null,
start: null,
stop: null,
unselected: null,
unselecting: null
},
_create: function() {
var that = this;
this._addClass( "ui-selectable" );
this.dragged = false;
// Cache selectee children based on filter
this.refresh = function() {
that.elementPos = $( that.element[ 0 ] ).offset();
that.selectees = $( that.options.filter, that.element[ 0 ] );
that._addClass( that.selectees, "ui-selectee" );
that.selectees.each( function() {
var $this = $( this ),
selecteeOffset = $this.offset(),
pos = {
left: selecteeOffset.left - that.elementPos.left,
top: selecteeOffset.top - that.elementPos.top
};
$.data( this, "selectable-item", {
element: this,
$element: $this,
left: pos.left,
top: pos.top,
right: pos.left + $this.outerWidth(),
bottom: pos.top + $this.outerHeight(),
startselected: false,
selected: $this.hasClass( "ui-selected" ),
selecting: $this.hasClass( "ui-selecting" ),
unselecting: $this.hasClass( "ui-unselecting" )
} );
} );
};
this.refresh();
this._mouseInit();
this.helper = $( "<div>" );
this._addClass( this.helper, "ui-selectable-helper" );
},
_destroy: function() {
this.selectees.removeData( "selectable-item" );
this._mouseDestroy();
},
_mouseStart: function( event ) {
var that = this,
options = this.options;
this.opos = [ event.pageX, event.pageY ];
this.elementPos = $( this.element[ 0 ] ).offset();
if ( this.options.disabled ) {
return;
}
this.selectees = $( options.filter, this.element[ 0 ] );
this._trigger( "start", event );
$( options.appendTo ).append( this.helper );
// position helper (lasso)
this.helper.css( {
"left": event.pageX,
"top": event.pageY,
"width": 0,
"height": 0
} );
if ( options.autoRefresh ) {
this.refresh();
}
this.selectees.filter( ".ui-selected" ).each( function() {
var selectee = $.data( this, "selectable-item" );
selectee.startselected = true;
if ( !event.metaKey && !event.ctrlKey ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
} );
$( event.target ).parents().addBack().each( function() {
var doSelect,
selectee = $.data( this, "selectable-item" );
if ( selectee ) {
doSelect = ( !event.metaKey && !event.ctrlKey ) ||
!selectee.$element.hasClass( "ui-selected" );
that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
selectee.unselecting = !doSelect;
selectee.selecting = doSelect;
selectee.selected = doSelect;
// selectable (UN)SELECTING callback
if ( doSelect ) {
that._trigger( "selecting", event, {
selecting: selectee.element
} );
} else {
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
return false;
}
} );
},
_mouseDrag: function( event ) {
this.dragged = true;
if ( this.options.disabled ) {
return;
}
var tmp,
that = this,
options = this.options,
x1 = this.opos[ 0 ],
y1 = this.opos[ 1 ],
x2 = event.pageX,
y2 = event.pageY;
if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
this.selectees.each( function() {
var selectee = $.data( this, "selectable-item" ),
hit = false,
offset = {};
//prevent helper from being selected if appendTo: selectable
if ( !selectee || selectee.element === that.element[ 0 ] ) {
return;
}
offset.left = selectee.left + that.elementPos.left;
offset.right = selectee.right + that.elementPos.left;
offset.top = selectee.top + that.elementPos.top;
offset.bottom = selectee.bottom + that.elementPos.top;
if ( options.tolerance === "touch" ) {
hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
offset.bottom < y1 ) );
} else if ( options.tolerance === "fit" ) {
hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
offset.bottom < y2 );
}
if ( hit ) {
// SELECT
if ( selectee.selected ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
}
if ( selectee.unselecting ) {
that._removeClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = false;
}
if ( !selectee.selecting ) {
that._addClass( selectee.$element, "ui-selecting" );
selectee.selecting = true;
// selectable SELECTING callback
that._trigger( "selecting", event, {
selecting: selectee.element
} );
}
} else {
// UNSELECT
if ( selectee.selecting ) {
if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
that._removeClass( selectee.$element, "ui-selecting" );
selectee.selecting = false;
that._addClass( selectee.$element, "ui-selected" );
selectee.selected = true;
} else {
that._removeClass( selectee.$element, "ui-selecting" );
selectee.selecting = false;
if ( selectee.startselected ) {
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
}
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
}
if ( selectee.selected ) {
if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
}
}
} );
return false;
},
_mouseStop: function( event ) {
var that = this;
this.dragged = false;
$( ".ui-unselecting", this.element[ 0 ] ).each( function() {
var selectee = $.data( this, "selectable-item" );
that._removeClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = false;
selectee.startselected = false;
that._trigger( "unselected", event, {
unselected: selectee.element
} );
} );
$( ".ui-selecting", this.element[ 0 ] ).each( function() {
var selectee = $.data( this, "selectable-item" );
that._removeClass( selectee.$element, "ui-selecting" )
._addClass( selectee.$element, "ui-selected" );
selectee.selecting = false;
selectee.selected = true;
selectee.startselected = true;
that._trigger( "selected", event, {
selected: selectee.element
} );
} );
this._trigger( "stop", event );
this.helper.remove();
return false;
}
} );
/*!
* jQuery UI Selectmenu 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Selectmenu
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/selectmenu/
//>>demos: http://jqueryui.com/selectmenu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css
var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
version: "1.12.1",
defaultElement: "<select>",
options: {
appendTo: null,
classes: {
"ui-selectmenu-button-open": "ui-corner-top",
"ui-selectmenu-button-closed": "ui-corner-all"
},
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
},
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
width: false,
// Callbacks
change: null,
close: null,
focus: null,
open: null,
select: null
},
_create: function() {
var selectmenuId = this.element.uniqueId().attr( "id" );
this.ids = {
element: selectmenuId,
button: selectmenuId + "-button",
menu: selectmenuId + "-menu"
};
this._drawButton();
this._drawMenu();
this._bindFormResetHandler();
this._rendered = false;
this.menuItems = $();
},
_drawButton: function() {
var icon,
that = this,
item = this._parseOption(
this.element.find( "option:selected" ),
this.element[ 0 ].selectedIndex
);
// Associate existing label with the new button
this.labels = this.element.labels().attr( "for", this.ids.button );
this._on( this.labels, {
click: function( event ) {
this.button.focus();
event.preventDefault();
}
} );
// Hide original select element
this.element.hide();
// Create button
this.button = $( "<span>", {
tabindex: this.options.disabled ? -1 : 0,
id: this.ids.button,
role: "combobox",
"aria-expanded": "false",
"aria-autocomplete": "list",
"aria-owns": this.ids.menu,
"aria-haspopup": "true",
title: this.element.attr( "title" )
} )
.insertAfter( this.element );
this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
"ui-button ui-widget" );
icon = $( "<span>" ).appendTo( this.button );
this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
this.buttonItem = this._renderButtonItem( item )
.appendTo( this.button );
if ( this.options.width !== false ) {
this._resizeButton();
}
this._on( this.button, this._buttonEvents );
this.button.one( "focusin", function() {
// Delay rendering the menu items until the button receives focus.
// The menu may have already been rendered via a programmatic open.
if ( !that._rendered ) {
that._refreshMenu();
}
} );
},
_drawMenu: function() {
var that = this;
// Create menu
this.menu = $( "<ul>", {
"aria-hidden": "true",
"aria-labelledby": this.ids.button,
id: this.ids.menu
} );
// Wrap menu
this.menuWrap = $( "<div>" ).append( this.menu );
this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
this.menuWrap.appendTo( this._appendTo() );
// Initialize menu widget
this.menuInstance = this.menu
.menu( {
classes: {
"ui-menu": "ui-corner-bottom"
},
role: "listbox",
select: function( event, ui ) {
event.preventDefault();
// Support: IE8
// If the item was selected via a click, the text selection
// will be destroyed in IE
that._setSelection();
that._select( ui.item.data( "ui-selectmenu-item" ), event );
},
focus: function( event, ui ) {
var item = ui.item.data( "ui-selectmenu-item" );
// Prevent inital focus from firing and check if its a newly focused item
if ( that.focusIndex != null && item.index !== that.focusIndex ) {
that._trigger( "focus", event, { item: item } );
if ( !that.isOpen ) {
that._select( item, event );
}
}
that.focusIndex = item.index;
that.button.attr( "aria-activedescendant",
that.menuItems.eq( item.index ).attr( "id" ) );
}
} )
.menu( "instance" );
// Don't close the menu on mouseleave
this.menuInstance._off( this.menu, "mouseleave" );
// Cancel the menu's collapseAll on document click
this.menuInstance._closeOnDocumentClick = function() {
return false;
};
// Selects often contain empty items, but never contain dividers
this.menuInstance._isDivider = function() {
return false;
};
},
refresh: function() {
this._refreshMenu();
this.buttonItem.replaceWith(
this.buttonItem = this._renderButtonItem(
// Fall back to an empty object in case there are no options
this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
)
);
if ( this.options.width === null ) {
this._resizeButton();
}
},
_refreshMenu: function() {
var item,
options = this.element.find( "option" );
this.menu.empty();
this._parseOptions( options );
this._renderMenu( this.menu, this.items );
this.menuInstance.refresh();
this.menuItems = this.menu.find( "li" )
.not( ".ui-selectmenu-optgroup" )
.find( ".ui-menu-item-wrapper" );
this._rendered = true;
if ( !options.length ) {
return;
}
item = this._getSelectedItem();
// Update the menu to have the correct item focused
this.menuInstance.focus( null, item );
this._setAria( item.data( "ui-selectmenu-item" ) );
// Set disabled state
this._setOption( "disabled", this.element.prop( "disabled" ) );
},
open: function( event ) {
if ( this.options.disabled ) {
return;
}
// If this is the first time the menu is being opened, render the items
if ( !this._rendered ) {
this._refreshMenu();
} else {
// Menu clears focus on close, reset focus to selected item
this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
this.menuInstance.focus( null, this._getSelectedItem() );
}
// If there are no options, don't open the menu
if ( !this.menuItems.length ) {
return;
}
this.isOpen = true;
this._toggleAttr();
this._resizeMenu();
this._position();
this._on( this.document, this._documentClick );
this._trigger( "open", event );
},
_position: function() {
this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
},
close: function( event ) {
if ( !this.isOpen ) {
return;
}
this.isOpen = false;
this._toggleAttr();
this.range = null;
this._off( this.document );
this._trigger( "close", event );
},
widget: function() {
return this.button;
},
menuWidget: function() {
return this.menu;
},
_renderButtonItem: function( item ) {
var buttonItem = $( "<span>" );
this._setText( buttonItem, item.label );
this._addClass( buttonItem, "ui-selectmenu-text" );
return buttonItem;
},
_renderMenu: function( ul, items ) {
var that = this,
currentOptgroup = "";
$.each( items, function( index, item ) {
var li;
if ( item.optgroup !== currentOptgroup ) {
li = $( "<li>", {
text: item.optgroup
} );
that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
( item.element.parent( "optgroup" ).prop( "disabled" ) ?
" ui-state-disabled" :
"" ) );
li.appendTo( ul );
currentOptgroup = item.optgroup;
}
that._renderItemData( ul, item );
} );
},
_renderItemData: function( ul, item ) {
return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
},
_renderItem: function( ul, item ) {
var li = $( "<li>" ),
wrapper = $( "<div>", {
title: item.element.attr( "title" )
} );
if ( item.disabled ) {
this._addClass( li, null, "ui-state-disabled" );
}
this._setText( wrapper, item.label );
return li.append( wrapper ).appendTo( ul );
},
_setText: function( element, value ) {
if ( value ) {
element.text( value );
} else {
element.html( " " );
}
},
_move: function( direction, event ) {
var item, next,
filter = ".ui-menu-item";
if ( this.isOpen ) {
item = this.menuItems.eq( this.focusIndex ).parent( "li" );
} else {
item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
filter += ":not(.ui-state-disabled)";
}
if ( direction === "first" || direction === "last" ) {
next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
} else {
next = item[ direction + "All" ]( filter ).eq( 0 );
}
if ( next.length ) {
this.menuInstance.focus( event, next );
}
},
_getSelectedItem: function() {
return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
},
_toggle: function( event ) {
this[ this.isOpen ? "close" : "open" ]( event );
},
_setSelection: function() {
var selection;
if ( !this.range ) {
return;
}
if ( window.getSelection ) {
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange( this.range );
// Support: IE8
} else {
this.range.select();
}
// Support: IE
// Setting the text selection kills the button focus in IE, but
// restoring the focus doesn't kill the selection.
this.button.focus();
},
_documentClick: {
mousedown: function( event ) {
if ( !this.isOpen ) {
return;
}
if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
$.ui.escapeSelector( this.ids.button ) ).length ) {
this.close( event );
}
}
},
_buttonEvents: {
// Prevent text selection from being reset when interacting with the selectmenu (#10144)
mousedown: function() {
var selection;
if ( window.getSelection ) {
selection = window.getSelection();
if ( selection.rangeCount ) {
this.range = selection.getRangeAt( 0 );
}
// Support: IE8
} else {
this.range = document.selection.createRange();
}
},
click: function( event ) {
this._setSelection();
this._toggle( event );
},
keydown: function( event ) {
var preventDefault = true;
switch ( event.keyCode ) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ESCAPE:
this.close( event );
preventDefault = false;
break;
case $.ui.keyCode.ENTER:
if ( this.isOpen ) {
this._selectFocusedItem( event );
}
break;
case $.ui.keyCode.UP:
if ( event.altKey ) {
this._toggle( event );
} else {
this._move( "prev", event );
}
break;
case $.ui.keyCode.DOWN:
if ( event.altKey ) {
this._toggle( event );
} else {
this._move( "next", event );
}
break;
case $.ui.keyCode.SPACE:
if ( this.isOpen ) {
this._selectFocusedItem( event );
} else {
this._toggle( event );
}
break;
case $.ui.keyCode.LEFT:
this._move( "prev", event );
break;
case $.ui.keyCode.RIGHT:
this._move( "next", event );
break;
case $.ui.keyCode.HOME:
case $.ui.keyCode.PAGE_UP:
this._move( "first", event );
break;
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_DOWN:
this._move( "last", event );
break;
default:
this.menu.trigger( event );
preventDefault = false;
}
if ( preventDefault ) {
event.preventDefault();
}
}
},
_selectFocusedItem: function( event ) {
var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
if ( !item.hasClass( "ui-state-disabled" ) ) {
this._select( item.data( "ui-selectmenu-item" ), event );
}
},
_select: function( item, event ) {
var oldIndex = this.element[ 0 ].selectedIndex;
// Change native select element
this.element[ 0 ].selectedIndex = item.index;
this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
this._setAria( item );
this._trigger( "select", event, { item: item } );
if ( item.index !== oldIndex ) {
this._trigger( "change", event, { item: item } );
}
this.close( event );
},
_setAria: function( item ) {
var id = this.menuItems.eq( item.index ).attr( "id" );
this.button.attr( {
"aria-labelledby": id,
"aria-activedescendant": id
} );
this.menu.attr( "aria-activedescendant", id );
},
_setOption: function( key, value ) {
if ( key === "icons" ) {
var icon = this.button.find( "span.ui-icon" );
this._removeClass( icon, null, this.options.icons.button )
._addClass( icon, null, value.button );
}
this._super( key, value );
if ( key === "appendTo" ) {
this.menuWrap.appendTo( this._appendTo() );
}
if ( key === "width" ) {
this._resizeButton();
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this.menuInstance.option( "disabled", value );
this.button.attr( "aria-disabled", value );
this._toggleClass( this.button, null, "ui-state-disabled", value );
this.element.prop( "disabled", value );
if ( value ) {
this.button.attr( "tabindex", -1 );
this.close();
} else {
this.button.attr( "tabindex", 0 );
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element ) {
element = element.jquery || element.nodeType ?
$( element ) :
this.document.find( element ).eq( 0 );
}
if ( !element || !element[ 0 ] ) {
element = this.element.closest( ".ui-front, dialog" );
}
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_toggleAttr: function() {
this.button.attr( "aria-expanded", this.isOpen );
// We can't use two _toggleClass() calls here, because we need to make sure
// we always remove classes first and add them second, otherwise if both classes have the
// same theme class, it will be removed after we add it.
this._removeClass( this.button, "ui-selectmenu-button-" +
( this.isOpen ? "closed" : "open" ) )
._addClass( this.button, "ui-selectmenu-button-" +
( this.isOpen ? "open" : "closed" ) )
._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
this.menu.attr( "aria-hidden", !this.isOpen );
},
_resizeButton: function() {
var width = this.options.width;
// For `width: false`, just remove inline style and stop
if ( width === false ) {
this.button.css( "width", "" );
return;
}
// For `width: null`, match the width of the original element
if ( width === null ) {
width = this.element.show().outerWidth();
this.element.hide();
}
this.button.outerWidth( width );
},
_resizeMenu: function() {
this.menu.outerWidth( Math.max(
this.button.outerWidth(),
// Support: IE10
// IE10 wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping
this.menu.width( "" ).outerWidth() + 1
) );
},
_getCreateOptions: function() {
var options = this._super();
options.disabled = this.element.prop( "disabled" );
return options;
},
_parseOptions: function( options ) {
var that = this,
data = [];
options.each( function( index, item ) {
data.push( that._parseOption( $( item ), index ) );
} );
this.items = data;
},
_parseOption: function( option, index ) {
var optgroup = option.parent( "optgroup" );
return {
element: option,
index: index,
value: option.val(),
label: option.text(),
optgroup: optgroup.attr( "label" ) || "",
disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
};
},
_destroy: function() {
this._unbindFormResetHandler();
this.menuWrap.remove();
this.button.remove();
this.element.show();
this.element.removeUniqueId();
this.labels.attr( "for", this.ids.element );
}
} ] );
/*!
* jQuery UI Slider 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Slider
//>>group: Widgets
//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
//>>docs: http://api.jqueryui.com/slider/
//>>demos: http://jqueryui.com/slider/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/slider.css
//>>css.theme: ../../themes/base/theme.css
var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "slide",
options: {
animate: false,
classes: {
"ui-slider": "ui-corner-all",
"ui-slider-handle": "ui-corner-all",
// Note: ui-widget-header isn't the most fittingly semantic framework class for this
// element, but worked best visually with a variety of themes
"ui-slider-range": "ui-corner-all ui-widget-header"
},
distance: 0,
max: 100,
min: 0,
orientation: "horizontal",
range: false,
step: 1,
value: 0,
values: null,
// Callbacks
change: null,
slide: null,
start: null,
stop: null
},
// Number of pages in a slider
// (how many times can you page up/down to go through the whole range)
numPages: 5,
_create: function() {
this._keySliding = false;
this._mouseSliding = false;
this._animateOff = true;
this._handleIndex = null;
this._detectOrientation();
this._mouseInit();
this._calculateNewMax();
this._addClass( "ui-slider ui-slider-" + this.orientation,
"ui-widget ui-widget-content" );
this._refresh();
this._animateOff = false;
},
_refresh: function() {
this._createRange();
this._createHandles();
this._setupEvents();
this._refreshValue();
},
_createHandles: function() {
var i, handleCount,
options = this.options,
existingHandles = this.element.find( ".ui-slider-handle" ),
handle = "<span tabindex='0'></span>",
handles = [];
handleCount = ( options.values && options.values.length ) || 1;
if ( existingHandles.length > handleCount ) {
existingHandles.slice( handleCount ).remove();
existingHandles = existingHandles.slice( 0, handleCount );
}
for ( i = existingHandles.length; i < handleCount; i++ ) {
handles.push( handle );
}
this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
this.handle = this.handles.eq( 0 );
this.handles.each( function( i ) {
$( this )
.data( "ui-slider-handle-index", i )
.attr( "tabIndex", 0 );
} );
},
_createRange: function() {
var options = this.options;
if ( options.range ) {
if ( options.range === true ) {
if ( !options.values ) {
options.values = [ this._valueMin(), this._valueMin() ];
} else if ( options.values.length && options.values.length !== 2 ) {
options.values = [ options.values[ 0 ], options.values[ 0 ] ];
} else if ( $.isArray( options.values ) ) {
options.values = options.values.slice( 0 );
}
}
if ( !this.range || !this.range.length ) {
this.range = $( "<div>" )
.appendTo( this.element );
this._addClass( this.range, "ui-slider-range" );
} else {
this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
// Handle range switching from true to min/max
this.range.css( {
"left": "",
"bottom": ""
} );
}
if ( options.range === "min" || options.range === "max" ) {
this._addClass( this.range, "ui-slider-range-" + options.range );
}
} else {
if ( this.range ) {
this.range.remove();
}
this.range = null;
}
},
_setupEvents: function() {
this._off( this.handles );
this._on( this.handles, this._handleEvents );
this._hoverable( this.handles );
this._focusable( this.handles );
},
_destroy: function() {
this.handles.remove();
if ( this.range ) {
this.range.remove();
}
this._mouseDestroy();
},
_mouseCapture: function( event ) {
var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
that = this,
o = this.options;
if ( o.disabled ) {
return false;
}
this.elementSize = {
width: this.element.outerWidth(),
height: this.element.outerHeight()
};
this.elementOffset = this.element.offset();
position = { x: event.pageX, y: event.pageY };
normValue = this._normValueFromMouse( position );
distance = this._valueMax() - this._valueMin() + 1;
this.handles.each( function( i ) {
var thisDistance = Math.abs( normValue - that.values( i ) );
if ( ( distance > thisDistance ) ||
( distance === thisDistance &&
( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
distance = thisDistance;
closestHandle = $( this );
index = i;
}
} );
allowed = this._start( event, index );
if ( allowed === false ) {
return false;
}
this._mouseSliding = true;
this._handleIndex = index;
this._addClass( closestHandle, null, "ui-state-active" );
closestHandle.trigger( "focus" );
offset = closestHandle.offset();
mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
top: event.pageY - offset.top -
( closestHandle.height() / 2 ) -
( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
};
if ( !this.handles.hasClass( "ui-state-hover" ) ) {
this._slide( event, index, normValue );
}
this._animateOff = true;
return true;
},
_mouseStart: function() {
return true;
},
_mouseDrag: function( event ) {
var position = { x: event.pageX, y: event.pageY },
normValue = this._normValueFromMouse( position );
this._slide( event, this._handleIndex, normValue );
return false;
},
_mouseStop: function( event ) {
this._removeClass( this.handles, null, "ui-state-active" );
this._mouseSliding = false;
this._stop( event, this._handleIndex );
this._change( event, this._handleIndex );
this._handleIndex = null;
this._clickOffset = null;
this._animateOff = false;
return false;
},
_detectOrientation: function() {
this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
},
_normValueFromMouse: function( position ) {
var pixelTotal,
pixelMouse,
percentMouse,
valueTotal,
valueMouse;
if ( this.orientation === "horizontal" ) {
pixelTotal = this.elementSize.width;
pixelMouse = position.x - this.elementOffset.left -
( this._clickOffset ? this._clickOffset.left : 0 );
} else {
pixelTotal = this.elementSize.height;
pixelMouse = position.y - this.elementOffset.top -
( this._clickOffset ? this._clickOffset.top : 0 );
}
percentMouse = ( pixelMouse / pixelTotal );
if ( percentMouse > 1 ) {
percentMouse = 1;
}
if ( percentMouse < 0 ) {
percentMouse = 0;
}
if ( this.orientation === "vertical" ) {
percentMouse = 1 - percentMouse;
}
valueTotal = this._valueMax() - this._valueMin();
valueMouse = this._valueMin() + percentMouse * valueTotal;
return this._trimAlignValue( valueMouse );
},
_uiHash: function( index, value, values ) {
var uiHash = {
handle: this.handles[ index ],
handleIndex: index,
value: value !== undefined ? value : this.value()
};
if ( this._hasMultipleValues() ) {
uiHash.value = value !== undefined ? value : this.values( index );
uiHash.values = values || this.values();
}
return uiHash;
},
_hasMultipleValues: function() {
return this.options.values && this.options.values.length;
},
_start: function( event, index ) {
return this._trigger( "start", event, this._uiHash( index ) );
},
_slide: function( event, index, newVal ) {
var allowed, otherVal,
currentValue = this.value(),
newValues = this.values();
if ( this._hasMultipleValues() ) {
otherVal = this.values( index ? 0 : 1 );
currentValue = this.values( index );
if ( this.options.values.length === 2 && this.options.range === true ) {
newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
}
newValues[ index ] = newVal;
}
if ( newVal === currentValue ) {
return;
}
allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
// A slide can be canceled by returning false from the slide callback
if ( allowed === false ) {
return;
}
if ( this._hasMultipleValues() ) {
this.values( index, newVal );
} else {
this.value( newVal );
}
},
_stop: function( event, index ) {
this._trigger( "stop", event, this._uiHash( index ) );
},
_change: function( event, index ) {
if ( !this._keySliding && !this._mouseSliding ) {
//store the last changed value index for reference when handles overlap
this._lastChangedValue = index;
this._trigger( "change", event, this._uiHash( index ) );
}
},
value: function( newValue ) {
if ( arguments.length ) {
this.options.value = this._trimAlignValue( newValue );
this._refreshValue();
this._change( null, 0 );
return;
}
return this._value();
},
values: function( index, newValue ) {
var vals,
newValues,
i;
if ( arguments.length > 1 ) {
this.options.values[ index ] = this._trimAlignValue( newValue );
this._refreshValue();
this._change( null, index );
return;
}
if ( arguments.length ) {
if ( $.isArray( arguments[ 0 ] ) ) {
vals = this.options.values;
newValues = arguments[ 0 ];
for ( i = 0; i < vals.length; i += 1 ) {
vals[ i ] = this._trimAlignValue( newValues[ i ] );
this._change( null, i );
}
this._refreshValue();
} else {
if ( this._hasMultipleValues() ) {
return this._values( index );
} else {
return this.value();
}
}
} else {
return this._values();
}
},
_setOption: function( key, value ) {
var i,
valsLength = 0;
if ( key === "range" && this.options.range === true ) {
if ( value === "min" ) {
this.options.value = this._values( 0 );
this.options.values = null;
} else if ( value === "max" ) {
this.options.value = this._values( this.options.values.length - 1 );
this.options.values = null;
}
}
if ( $.isArray( this.options.values ) ) {
valsLength = this.options.values.length;
}
this._super( key, value );
switch ( key ) {
case "orientation":
this._detectOrientation();
this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
._addClass( "ui-slider-" + this.orientation );
this._refreshValue();
if ( this.options.range ) {
this._refreshRange( value );
}
// Reset positioning from previous orientation
this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
break;
case "value":
this._animateOff = true;
this._refreshValue();
this._change( null, 0 );
this._animateOff = false;
break;
case "values":
this._animateOff = true;
this._refreshValue();
// Start from the last handle to prevent unreachable handles (#9046)
for ( i = valsLength - 1; i >= 0; i-- ) {
this._change( null, i );
}
this._animateOff = false;
break;
case "step":
case "min":
case "max":
this._animateOff = true;
this._calculateNewMax();
this._refreshValue();
this._animateOff = false;
break;
case "range":
this._animateOff = true;
this._refresh();
this._animateOff = false;
break;
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this._toggleClass( null, "ui-state-disabled", !!value );
},
//internal value getter
// _value() returns value trimmed by min and max, aligned by step
_value: function() {
var val = this.options.value;
val = this._trimAlignValue( val );
return val;
},
//internal values getter
// _values() returns array of values trimmed by min and max, aligned by step
// _values( index ) returns single value trimmed by min and max, aligned by step
_values: function( index ) {
var val,
vals,
i;
if ( arguments.length ) {
val = this.options.values[ index ];
val = this._trimAlignValue( val );
return val;
} else if ( this._hasMultipleValues() ) {
// .slice() creates a copy of the array
// this copy gets trimmed by min and max and then returned
vals = this.options.values.slice();
for ( i = 0; i < vals.length; i += 1 ) {
vals[ i ] = this._trimAlignValue( vals[ i ] );
}
return vals;
} else {
return [];
}
},
// Returns the step-aligned value that val is closest to, between (inclusive) min and max
_trimAlignValue: function( val ) {
if ( val <= this._valueMin() ) {
return this._valueMin();
}
if ( val >= this._valueMax() ) {
return this._valueMax();
}
var step = ( this.options.step > 0 ) ? this.options.step : 1,
valModStep = ( val - this._valueMin() ) % step,
alignValue = val - valModStep;
if ( Math.abs( valModStep ) * 2 >= step ) {
alignValue += ( valModStep > 0 ) ? step : ( -step );
}
// Since JavaScript has problems with large floats, round
// the final value to 5 digits after the decimal point (see #4124)
return parseFloat( alignValue.toFixed( 5 ) );
},
_calculateNewMax: function() {
var max = this.options.max,
min = this._valueMin(),
step = this.options.step,
aboveMin = Math.round( ( max - min ) / step ) * step;
max = aboveMin + min;
if ( max > this.options.max ) {
//If max is not divisible by step, rounding off may increase its value
max -= step;
}
this.max = parseFloat( max.toFixed( this._precision() ) );
},
_precision: function() {
var precision = this._precisionOf( this.options.step );
if ( this.options.min !== null ) {
precision = Math.max( precision, this._precisionOf( this.options.min ) );
}
return precision;
},
_precisionOf: function( num ) {
var str = num.toString(),
decimal = str.indexOf( "." );
return decimal === -1 ? 0 : str.length - decimal - 1;
},
_valueMin: function() {
return this.options.min;
},
_valueMax: function() {
return this.max;
},
_refreshRange: function( orientation ) {
if ( orientation === "vertical" ) {
this.range.css( { "width": "", "left": "" } );
}
if ( orientation === "horizontal" ) {
this.range.css( { "height": "", "bottom": "" } );
}
},
_refreshValue: function() {
var lastValPercent, valPercent, value, valueMin, valueMax,
oRange = this.options.range,
o = this.options,
that = this,
animate = ( !this._animateOff ) ? o.animate : false,
_set = {};
if ( this._hasMultipleValues() ) {
this.handles.each( function( i ) {
valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
that._valueMin() ) * 100;
_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
if ( that.options.range === true ) {
if ( that.orientation === "horizontal" ) {
if ( i === 0 ) {
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
left: valPercent + "%"
}, o.animate );
}
if ( i === 1 ) {
that.range[ animate ? "animate" : "css" ]( {
width: ( valPercent - lastValPercent ) + "%"
}, {
queue: false,
duration: o.animate
} );
}
} else {
if ( i === 0 ) {
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
bottom: ( valPercent ) + "%"
}, o.animate );
}
if ( i === 1 ) {
that.range[ animate ? "animate" : "css" ]( {
height: ( valPercent - lastValPercent ) + "%"
}, {
queue: false,
duration: o.animate
} );
}
}
}
lastValPercent = valPercent;
} );
} else {
value = this.value();
valueMin = this._valueMin();
valueMax = this._valueMax();
valPercent = ( valueMax !== valueMin ) ?
( value - valueMin ) / ( valueMax - valueMin ) * 100 :
0;
_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
if ( oRange === "min" && this.orientation === "horizontal" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
width: valPercent + "%"
}, o.animate );
}
if ( oRange === "max" && this.orientation === "horizontal" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
width: ( 100 - valPercent ) + "%"
}, o.animate );
}
if ( oRange === "min" && this.orientation === "vertical" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
height: valPercent + "%"
}, o.animate );
}
if ( oRange === "max" && this.orientation === "vertical" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
height: ( 100 - valPercent ) + "%"
}, o.animate );
}
}
},
_handleEvents: {
keydown: function( event ) {
var allowed, curVal, newVal, step,
index = $( event.target ).data( "ui-slider-handle-index" );
switch ( event.keyCode ) {
case $.ui.keyCode.HOME:
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_UP:
case $.ui.keyCode.PAGE_DOWN:
case $.ui.keyCode.UP:
case $.ui.keyCode.RIGHT:
case $.ui.keyCode.DOWN:
case $.ui.keyCode.LEFT:
event.preventDefault();
if ( !this._keySliding ) {
this._keySliding = true;
this._addClass( $( event.target ), null, "ui-state-active" );
allowed = this._start( event, index );
if ( allowed === false ) {
return;
}
}
break;
}
step = this.options.step;
if ( this._hasMultipleValues() ) {
curVal = newVal = this.values( index );
} else {
curVal = newVal = this.value();
}
switch ( event.keyCode ) {
case $.ui.keyCode.HOME:
newVal = this._valueMin();
break;
case $.ui.keyCode.END:
newVal = this._valueMax();
break;
case $.ui.keyCode.PAGE_UP:
newVal = this._trimAlignValue(
curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
);
break;
case $.ui.keyCode.PAGE_DOWN:
newVal = this._trimAlignValue(
curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
break;
case $.ui.keyCode.UP:
case $.ui.keyCode.RIGHT:
if ( curVal === this._valueMax() ) {
return;
}
newVal = this._trimAlignValue( curVal + step );
break;
case $.ui.keyCode.DOWN:
case $.ui.keyCode.LEFT:
if ( curVal === this._valueMin() ) {
return;
}
newVal = this._trimAlignValue( curVal - step );
break;
}
this._slide( event, index, newVal );
},
keyup: function( event ) {
var index = $( event.target ).data( "ui-slider-handle-index" );
if ( this._keySliding ) {
this._keySliding = false;
this._stop( event, index );
this._change( event, index );
this._removeClass( $( event.target ), null, "ui-state-active" );
}
}
}
} );
/*!
* jQuery UI Sortable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Sortable
//>>group: Interactions
//>>description: Enables items in a list to be sorted using the mouse.
//>>docs: http://api.jqueryui.com/sortable/
//>>demos: http://jqueryui.com/sortable/
//>>css.structure: ../../themes/base/sortable.css
var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "sort",
ready: false,
options: {
appendTo: "parent",
axis: false,
connectWith: false,
containment: false,
cursor: "auto",
cursorAt: false,
dropOnEmpty: true,
forcePlaceholderSize: false,
forceHelperSize: false,
grid: false,
handle: false,
helper: "original",
items: "> *",
opacity: false,
placeholder: false,
revert: false,
scroll: true,
scrollSensitivity: 20,
scrollSpeed: 20,
scope: "default",
tolerance: "intersect",
zIndex: 1000,
// Callbacks
activate: null,
beforeStop: null,
change: null,
deactivate: null,
out: null,
over: null,
receive: null,
remove: null,
sort: null,
start: null,
stop: null,
update: null
},
_isOverAxis: function( x, reference, size ) {
return ( x >= reference ) && ( x < ( reference + size ) );
},
_isFloating: function( item ) {
return ( /left|right/ ).test( item.css( "float" ) ) ||
( /inline|table-cell/ ).test( item.css( "display" ) );
},
_create: function() {
this.containerCache = {};
this._addClass( "ui-sortable" );
//Get the items
this.refresh();
//Let's determine the parent's offset
this.offset = this.element.offset();
//Initialize mouse events for interaction
this._mouseInit();
this._setHandleClassName();
//We're ready to go
this.ready = true;
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "handle" ) {
this._setHandleClassName();
}
},
_setHandleClassName: function() {
var that = this;
this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
$.each( this.items, function() {
that._addClass(
this.instance.options.handle ?
this.item.find( this.instance.options.handle ) :
this.item,
"ui-sortable-handle"
);
} );
},
_destroy: function() {
this._mouseDestroy();
for ( var i = this.items.length - 1; i >= 0; i-- ) {
this.items[ i ].item.removeData( this.widgetName + "-item" );
}
return this;
},
_mouseCapture: function( event, overrideHandle ) {
var currentItem = null,
validHandle = false,
that = this;
if ( this.reverting ) {
return false;
}
if ( this.options.disabled || this.options.type === "static" ) {
return false;
}
//We have to refresh the items data once first
this._refreshItems( event );
//Find out if the clicked node (or one of its parents) is a actual item in this.items
$( event.target ).parents().each( function() {
if ( $.data( this, that.widgetName + "-item" ) === that ) {
currentItem = $( this );
return false;
}
} );
if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
currentItem = $( event.target );
}
if ( !currentItem ) {
return false;
}
if ( this.options.handle && !overrideHandle ) {
$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
if ( this === event.target ) {
validHandle = true;
}
} );
if ( !validHandle ) {
return false;
}
}
this.currentItem = currentItem;
this._removeCurrentsFromItems();
return true;
},
_mouseStart: function( event, overrideHandle, noActivation ) {
var i, body,
o = this.options;
this.currentContainer = this;
//We only need to call refreshPositions, because the refreshItems call has been moved to
// mouseCapture
this.refreshPositions();
//Create and append the visible helper
this.helper = this._createHelper( event );
//Cache the helper size
this._cacheHelperProportions();
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Get the next scrolling parent
this.scrollParent = this.helper.scrollParent();
//The element's absolute position on the page minus margins
this.offset = this.currentItem.offset();
this.offset = {
top: this.offset.top - this.margins.top,
left: this.offset.left - this.margins.left
};
$.extend( this.offset, {
click: { //Where the click happened, relative to the element
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
},
parent: this._getParentOffset(),
// This is a relative to absolute position minus the actual position calculation -
// only used for relative positioned helper
relative: this._getRelativeOffset()
} );
// Only after we got the offset, we can change the helper's position to absolute
// TODO: Still need to figure out a way to make relative sorting possible
this.helper.css( "position", "absolute" );
this.cssPosition = this.helper.css( "position" );
//Generate the original position
this.originalPosition = this._generatePosition( event );
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
//Cache the former DOM position
this.domPosition = {
prev: this.currentItem.prev()[ 0 ],
parent: this.currentItem.parent()[ 0 ]
};
// If the helper is not the original, hide the original so it's not playing any role during
// the drag, won't cause anything bad this way
if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
this.currentItem.hide();
}
//Create the placeholder
this._createPlaceholder();
//Set a containment if given in the options
if ( o.containment ) {
this._setContainment();
}
if ( o.cursor && o.cursor !== "auto" ) { // cursor option
body = this.document.find( "body" );
// Support: IE
this.storedCursor = body.css( "cursor" );
body.css( "cursor", o.cursor );
this.storedStylesheet =
$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
}
if ( o.opacity ) { // opacity option
if ( this.helper.css( "opacity" ) ) {
this._storedOpacity = this.helper.css( "opacity" );
}
this.helper.css( "opacity", o.opacity );
}
if ( o.zIndex ) { // zIndex option
if ( this.helper.css( "zIndex" ) ) {
this._storedZIndex = this.helper.css( "zIndex" );
}
this.helper.css( "zIndex", o.zIndex );
}
//Prepare scrolling
if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ].tagName !== "HTML" ) {
this.overflowOffset = this.scrollParent.offset();
}
//Call callbacks
this._trigger( "start", event, this._uiHash() );
//Recache the helper size
if ( !this._preserveHelperProportions ) {
this._cacheHelperProportions();
}
//Post "activate" events to possible containers
if ( !noActivation ) {
for ( i = this.containers.length - 1; i >= 0; i-- ) {
this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
}
}
//Prepare possible droppables
if ( $.ui.ddmanager ) {
$.ui.ddmanager.current = this;
}
if ( $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
this.dragging = true;
this._addClass( this.helper, "ui-sortable-helper" );
// Execute the drag once - this causes the helper not to be visiblebefore getting its
// correct position
this._mouseDrag( event );
return true;
},
_mouseDrag: function( event ) {
var i, item, itemElement, intersection,
o = this.options,
scrolled = false;
//Compute the helpers position
this.position = this._generatePosition( event );
this.positionAbs = this._convertPositionTo( "absolute" );
if ( !this.lastPositionAbs ) {
this.lastPositionAbs = this.positionAbs;
}
//Do scrolling
if ( this.options.scroll ) {
if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ].tagName !== "HTML" ) {
if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
event.pageY < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
}
if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
event.pageX < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
}
} else {
if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
}
if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() - o.scrollSpeed
);
} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() + o.scrollSpeed
);
}
}
if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
}
//Regenerate the absolute position used for position checks
this.positionAbs = this._convertPositionTo( "absolute" );
//Set the helper position
if ( !this.options.axis || this.options.axis !== "y" ) {
this.helper[ 0 ].style.left = this.position.left + "px";
}
if ( !this.options.axis || this.options.axis !== "x" ) {
this.helper[ 0 ].style.top = this.position.top + "px";
}
//Rearrange
for ( i = this.items.length - 1; i >= 0; i-- ) {
//Cache variables and intersection, continue if no intersection
item = this.items[ i ];
itemElement = item.item[ 0 ];
intersection = this._intersectsWithPointer( item );
if ( !intersection ) {
continue;
}
// Only put the placeholder inside the current Container, skip all
// items from other containers. This works because when moving
// an item from one container to another the
// currentContainer is switched before the placeholder is moved.
//
// Without this, moving items in "sub-sortables" can cause
// the placeholder to jitter between the outer and inner container.
if ( item.instance !== this.currentContainer ) {
continue;
}
// Cannot intersect with itself
// no useless actions that have been done before
// no action if the item moved is the parent of the item checked
if ( itemElement !== this.currentItem[ 0 ] &&
this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
!$.contains( this.placeholder[ 0 ], itemElement ) &&
( this.options.type === "semi-dynamic" ?
!$.contains( this.element[ 0 ], itemElement ) :
true
)
) {
this.direction = intersection === 1 ? "down" : "up";
if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
this._rearrange( event, item );
} else {
break;
}
this._trigger( "change", event, this._uiHash() );
break;
}
}
//Post events to containers
this._contactContainers( event );
//Interconnect with droppables
if ( $.ui.ddmanager ) {
$.ui.ddmanager.drag( this, event );
}
//Call callbacks
this._trigger( "sort", event, this._uiHash() );
this.lastPositionAbs = this.positionAbs;
return false;
},
_mouseStop: function( event, noPropagation ) {
if ( !event ) {
return;
}
//If we are using droppables, inform the manager about the drop
if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
$.ui.ddmanager.drop( this, event );
}
if ( this.options.revert ) {
var that = this,
cur = this.placeholder.offset(),
axis = this.options.axis,
animation = {};
if ( !axis || axis === "x" ) {
animation.left = cur.left - this.offset.parent.left - this.margins.left +
( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
0 :
this.offsetParent[ 0 ].scrollLeft
);
}
if ( !axis || axis === "y" ) {
animation.top = cur.top - this.offset.parent.top - this.margins.top +
( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
0 :
this.offsetParent[ 0 ].scrollTop
);
}
this.reverting = true;
$( this.helper ).animate(
animation,
parseInt( this.options.revert, 10 ) || 500,
function() {
that._clear( event );
}
);
} else {
this._clear( event, noPropagation );
}
return false;
},
cancel: function() {
if ( this.dragging ) {
this._mouseUp( new $.Event( "mouseup", { target: null } ) );
if ( this.options.helper === "original" ) {
this.currentItem.css( this._storedCSS );
this._removeClass( this.currentItem, "ui-sortable-helper" );
} else {
this.currentItem.show();
}
//Post deactivating events to containers
for ( var i = this.containers.length - 1; i >= 0; i-- ) {
this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
if ( this.containers[ i ].containerCache.over ) {
this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
this.containers[ i ].containerCache.over = 0;
}
}
}
if ( this.placeholder ) {
//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
// it unbinds ALL events from the original node!
if ( this.placeholder[ 0 ].parentNode ) {
this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
}
if ( this.options.helper !== "original" && this.helper &&
this.helper[ 0 ].parentNode ) {
this.helper.remove();
}
$.extend( this, {
helper: null,
dragging: false,
reverting: false,
_noFinalSort: null
} );
if ( this.domPosition.prev ) {
$( this.domPosition.prev ).after( this.currentItem );
} else {
$( this.domPosition.parent ).prepend( this.currentItem );
}
}
return this;
},
serialize: function( o ) {
var items = this._getItemsAsjQuery( o && o.connected ),
str = [];
o = o || {};
$( items ).each( function() {
var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
if ( res ) {
str.push(
( o.key || res[ 1 ] + "[]" ) +
"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
}
} );
if ( !str.length && o.key ) {
str.push( o.key + "=" );
}
return str.join( "&" );
},
toArray: function( o ) {
var items = this._getItemsAsjQuery( o && o.connected ),
ret = [];
o = o || {};
items.each( function() {
ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
} );
return ret;
},
/* Be careful with the following core functions */
_intersectsWith: function( item ) {
var x1 = this.positionAbs.left,
x2 = x1 + this.helperProportions.width,
y1 = this.positionAbs.top,
y2 = y1 + this.helperProportions.height,
l = item.left,
r = l + item.width,
t = item.top,
b = t + item.height,
dyClick = this.offset.click.top,
dxClick = this.offset.click.left,
isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
( y1 + dyClick ) < b ),
isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
( x1 + dxClick ) < r ),
isOverElement = isOverElementHeight && isOverElementWidth;
if ( this.options.tolerance === "pointer" ||
this.options.forcePointerForContainers ||
( this.options.tolerance !== "pointer" &&
this.helperProportions[ this.floating ? "width" : "height" ] >
item[ this.floating ? "width" : "height" ] )
) {
return isOverElement;
} else {
return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
}
},
_intersectsWithPointer: function( item ) {
var verticalDirection, horizontalDirection,
isOverElementHeight = ( this.options.axis === "x" ) ||
this._isOverAxis(
this.positionAbs.top + this.offset.click.top, item.top, item.height ),
isOverElementWidth = ( this.options.axis === "y" ) ||
this._isOverAxis(
this.positionAbs.left + this.offset.click.left, item.left, item.width ),
isOverElement = isOverElementHeight && isOverElementWidth;
if ( !isOverElement ) {
return false;
}
verticalDirection = this._getDragVerticalDirection();
horizontalDirection = this._getDragHorizontalDirection();
return this.floating ?
( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
: ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
},
_intersectsWithSides: function( item ) {
var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
isOverRightHalf = this._isOverAxis( this.positionAbs.left +
this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
verticalDirection = this._getDragVerticalDirection(),
horizontalDirection = this._getDragHorizontalDirection();
if ( this.floating && horizontalDirection ) {
return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
( horizontalDirection === "left" && !isOverRightHalf ) );
} else {
return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
( verticalDirection === "up" && !isOverBottomHalf ) );
}
},
_getDragVerticalDirection: function() {
var delta = this.positionAbs.top - this.lastPositionAbs.top;
return delta !== 0 && ( delta > 0 ? "down" : "up" );
},
_getDragHorizontalDirection: function() {
var delta = this.positionAbs.left - this.lastPositionAbs.left;
return delta !== 0 && ( delta > 0 ? "right" : "left" );
},
refresh: function( event ) {
this._refreshItems( event );
this._setHandleClassName();
this.refreshPositions();
return this;
},
_connectWith: function() {
var options = this.options;
return options.connectWith.constructor === String ?
[ options.connectWith ] :
options.connectWith;
},
_getItemsAsjQuery: function( connected ) {
var i, j, cur, inst,
items = [],
queries = [],
connectWith = this._connectWith();
if ( connectWith && connected ) {
for ( i = connectWith.length - 1; i >= 0; i-- ) {
cur = $( connectWith[ i ], this.document[ 0 ] );
for ( j = cur.length - 1; j >= 0; j-- ) {
inst = $.data( cur[ j ], this.widgetFullName );
if ( inst && inst !== this && !inst.options.disabled ) {
queries.push( [ $.isFunction( inst.options.items ) ?
inst.options.items.call( inst.element ) :
$( inst.options.items, inst.element )
.not( ".ui-sortable-helper" )
.not( ".ui-sortable-placeholder" ), inst ] );
}
}
}
}
queries.push( [ $.isFunction( this.options.items ) ?
this.options.items
.call( this.element, null, { options: this.options, item: this.currentItem } ) :
$( this.options.items, this.element )
.not( ".ui-sortable-helper" )
.not( ".ui-sortable-placeholder" ), this ] );
function addItems() {
items.push( this );
}
for ( i = queries.length - 1; i >= 0; i-- ) {
queries[ i ][ 0 ].each( addItems );
}
return $( items );
},
_removeCurrentsFromItems: function() {
var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
this.items = $.grep( this.items, function( item ) {
for ( var j = 0; j < list.length; j++ ) {
if ( list[ j ] === item.item[ 0 ] ) {
return false;
}
}
return true;
} );
},
_refreshItems: function( event ) {
this.items = [];
this.containers = [ this ];
var i, j, cur, inst, targetData, _queries, item, queriesLength,
items = this.items,
queries = [ [ $.isFunction( this.options.items ) ?
this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
$( this.options.items, this.element ), this ] ],
connectWith = this._connectWith();
//Shouldn't be run the first time through due to massive slow-down
if ( connectWith && this.ready ) {
for ( i = connectWith.length - 1; i >= 0; i-- ) {
cur = $( connectWith[ i ], this.document[ 0 ] );
for ( j = cur.length - 1; j >= 0; j-- ) {
inst = $.data( cur[ j ], this.widgetFullName );
if ( inst && inst !== this && !inst.options.disabled ) {
queries.push( [ $.isFunction( inst.options.items ) ?
inst.options.items
.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
$( inst.options.items, inst.element ), inst ] );
this.containers.push( inst );
}
}
}
}
for ( i = queries.length - 1; i >= 0; i-- ) {
targetData = queries[ i ][ 1 ];
_queries = queries[ i ][ 0 ];
for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
item = $( _queries[ j ] );
// Data for target checking (mouse manager)
item.data( this.widgetName + "-item", targetData );
items.push( {
item: item,
instance: targetData,
width: 0, height: 0,
left: 0, top: 0
} );
}
}
},
refreshPositions: function( fast ) {
// Determine whether items are being displayed horizontally
this.floating = this.items.length ?
this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
false;
//This has to be redone because due to the item being moved out/into the offsetParent,
// the offsetParent's position will change
if ( this.offsetParent && this.helper ) {
this.offset.parent = this._getParentOffset();
}
var i, item, t, p;
for ( i = this.items.length - 1; i >= 0; i-- ) {
item = this.items[ i ];
//We ignore calculating positions of all connected containers when we're not over them
if ( item.instance !== this.currentContainer && this.currentContainer &&
item.item[ 0 ] !== this.currentItem[ 0 ] ) {
continue;
}
t = this.options.toleranceElement ?
$( this.options.toleranceElement, item.item ) :
item.item;
if ( !fast ) {
item.width = t.outerWidth();
item.height = t.outerHeight();
}
p = t.offset();
item.left = p.left;
item.top = p.top;
}
if ( this.options.custom && this.options.custom.refreshContainers ) {
this.options.custom.refreshContainers.call( this );
} else {
for ( i = this.containers.length - 1; i >= 0; i-- ) {
p = this.containers[ i ].element.offset();
this.containers[ i ].containerCache.left = p.left;
this.containers[ i ].containerCache.top = p.top;
this.containers[ i ].containerCache.width =
this.containers[ i ].element.outerWidth();
this.containers[ i ].containerCache.height =
this.containers[ i ].element.outerHeight();
}
}
return this;
},
_createPlaceholder: function( that ) {
that = that || this;
var className,
o = that.options;
if ( !o.placeholder || o.placeholder.constructor === String ) {
className = o.placeholder;
o.placeholder = {
element: function() {
var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
element = $( "<" + nodeName + ">", that.document[ 0 ] );
that._addClass( element, "ui-sortable-placeholder",
className || that.currentItem[ 0 ].className )
._removeClass( element, "ui-sortable-helper" );
if ( nodeName === "tbody" ) {
that._createTrPlaceholder(
that.currentItem.find( "tr" ).eq( 0 ),
$( "<tr>", that.document[ 0 ] ).appendTo( element )
);
} else if ( nodeName === "tr" ) {
that._createTrPlaceholder( that.currentItem, element );
} else if ( nodeName === "img" ) {
element.attr( "src", that.currentItem.attr( "src" ) );
}
if ( !className ) {
element.css( "visibility", "hidden" );
}
return element;
},
update: function( container, p ) {
// 1. If a className is set as 'placeholder option, we don't force sizes -
// the class is responsible for that
// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
// class name is specified
if ( className && !o.forcePlaceholderSize ) {
return;
}
//If the element doesn't have a actual height by itself (without styles coming
// from a stylesheet), it receives the inline height from the dragged item
if ( !p.height() ) {
p.height(
that.currentItem.innerHeight() -
parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
}
if ( !p.width() ) {
p.width(
that.currentItem.innerWidth() -
parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
}
}
};
}
//Create the placeholder
that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
//Append it after the actual current item
that.currentItem.after( that.placeholder );
//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
o.placeholder.update( that, that.placeholder );
},
_createTrPlaceholder: function( sourceTr, targetTr ) {
var that = this;
sourceTr.children().each( function() {
$( "<td> </td>", that.document[ 0 ] )
.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
.appendTo( targetTr );
} );
},
_contactContainers: function( event ) {
var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
floating, axis,
innermostContainer = null,
innermostIndex = null;
// Get innermost container that intersects with item
for ( i = this.containers.length - 1; i >= 0; i-- ) {
// Never consider a container that's located within the item itself
if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
continue;
}
if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
// If we've already found a container and it's more "inner" than this, then continue
if ( innermostContainer &&
$.contains(
this.containers[ i ].element[ 0 ],
innermostContainer.element[ 0 ] ) ) {
continue;
}
innermostContainer = this.containers[ i ];
innermostIndex = i;
} else {
// container doesn't intersect. trigger "out" event if necessary
if ( this.containers[ i ].containerCache.over ) {
this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
this.containers[ i ].containerCache.over = 0;
}
}
}
// If no intersecting containers found, return
if ( !innermostContainer ) {
return;
}
// Move the item into the container if it's not there already
if ( this.containers.length === 1 ) {
if ( !this.containers[ innermostIndex ].containerCache.over ) {
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
this.containers[ innermostIndex ].containerCache.over = 1;
}
} else {
// When entering a new container, we will find the item with the least distance and
// append our item near it
dist = 10000;
itemWithLeastDistance = null;
floating = innermostContainer.floating || this._isFloating( this.currentItem );
posProperty = floating ? "left" : "top";
sizeProperty = floating ? "width" : "height";
axis = floating ? "pageX" : "pageY";
for ( j = this.items.length - 1; j >= 0; j-- ) {
if ( !$.contains(
this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
) {
continue;
}
if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
continue;
}
cur = this.items[ j ].item.offset()[ posProperty ];
nearBottom = false;
if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
nearBottom = true;
}
if ( Math.abs( event[ axis ] - cur ) < dist ) {
dist = Math.abs( event[ axis ] - cur );
itemWithLeastDistance = this.items[ j ];
this.direction = nearBottom ? "up" : "down";
}
}
//Check if dropOnEmpty is enabled
if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
return;
}
if ( this.currentContainer === this.containers[ innermostIndex ] ) {
if ( !this.currentContainer.containerCache.over ) {
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
this.currentContainer.containerCache.over = 1;
}
return;
}
itemWithLeastDistance ?
this._rearrange( event, itemWithLeastDistance, null, true ) :
this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
this._trigger( "change", event, this._uiHash() );
this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
this.currentContainer = this.containers[ innermostIndex ];
//Update the placeholder
this.options.placeholder.update( this.currentContainer, this.placeholder );
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
this.containers[ innermostIndex ].containerCache.over = 1;
}
},
_createHelper: function( event ) {
var o = this.options,
helper = $.isFunction( o.helper ) ?
$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
//Add the helper to the DOM if that didn't happen already
if ( !helper.parents( "body" ).length ) {
$( o.appendTo !== "parent" ?
o.appendTo :
this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
}
if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
this._storedCSS = {
width: this.currentItem[ 0 ].style.width,
height: this.currentItem[ 0 ].style.height,
position: this.currentItem.css( "position" ),
top: this.currentItem.css( "top" ),
left: this.currentItem.css( "left" )
};
}
if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
helper.width( this.currentItem.width() );
}
if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
helper.height( this.currentItem.height() );
}
return helper;
},
_adjustOffsetFromHelper: function( obj ) {
if ( typeof obj === "string" ) {
obj = obj.split( " " );
}
if ( $.isArray( obj ) ) {
obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
}
if ( "left" in obj ) {
this.offset.click.left = obj.left + this.margins.left;
}
if ( "right" in obj ) {
this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
}
if ( "top" in obj ) {
this.offset.click.top = obj.top + this.margins.top;
}
if ( "bottom" in obj ) {
this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
}
},
_getParentOffset: function() {
//Get the offsetParent and cache its position
this.offsetParent = this.helper.offsetParent();
var po = this.offsetParent.offset();
// This is a special case where we need to modify a offset calculated on start, since the
// following happened:
// 1. The position of the helper is absolute, so it's position is calculated based on the
// next positioned parent
// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
// the document, which means that the scroll is included in the initial calculation of the
// offset of the parent, and never recalculated upon drag
if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
po.left += this.scrollParent.scrollLeft();
po.top += this.scrollParent.scrollTop();
}
// This needs to be actually done for all browsers, since pageX/pageY includes this
// information with an ugly IE fix
if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
( this.offsetParent[ 0 ].tagName &&
this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
po = { top: 0, left: 0 };
}
return {
top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
};
},
_getRelativeOffset: function() {
if ( this.cssPosition === "relative" ) {
var p = this.currentItem.position();
return {
top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
this.scrollParent.scrollTop(),
left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
this.scrollParent.scrollLeft()
};
} else {
return { top: 0, left: 0 };
}
},
_cacheMargins: function() {
this.margins = {
left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
};
},
_cacheHelperProportions: function() {
this.helperProportions = {
width: this.helper.outerWidth(),
height: this.helper.outerHeight()
};
},
_setContainment: function() {
var ce, co, over,
o = this.options;
if ( o.containment === "parent" ) {
o.containment = this.helper[ 0 ].parentNode;
}
if ( o.containment === "document" || o.containment === "window" ) {
this.containment = [
0 - this.offset.relative.left - this.offset.parent.left,
0 - this.offset.relative.top - this.offset.parent.top,
o.containment === "document" ?
this.document.width() :
this.window.width() - this.helperProportions.width - this.margins.left,
( o.containment === "document" ?
( this.document.height() || document.body.parentNode.scrollHeight ) :
this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
) - this.helperProportions.height - this.margins.top
];
}
if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
ce = $( o.containment )[ 0 ];
co = $( o.containment ).offset();
over = ( $( ce ).css( "overflow" ) !== "hidden" );
this.containment = [
co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
this.helperProportions.width - this.margins.left,
co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
this.helperProportions.height - this.margins.top
];
}
},
_convertPositionTo: function( d, pos ) {
if ( !pos ) {
pos = this.position;
}
var mod = d === "absolute" ? 1 : -1,
scroll = this.cssPosition === "absolute" &&
!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
this.offsetParent :
this.scrollParent,
scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
return {
top: (
// The absolute mouse position
pos.top +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top * mod -
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollTop() :
( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
),
left: (
// The absolute mouse position
pos.left +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left * mod -
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
scroll.scrollLeft() ) * mod )
)
};
},
_generatePosition: function( event ) {
var top, left,
o = this.options,
pageX = event.pageX,
pageY = event.pageY,
scroll = this.cssPosition === "absolute" &&
!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
this.offsetParent :
this.scrollParent,
scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
// This is another very weird special case that only happens for relative elements:
// 1. If the css position is relative
// 2. and the scroll parent is the document or similar to the offset parent
// we have to refresh the relative offset during the scroll so there are no jumps
if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
this.offset.relative = this._getRelativeOffset();
}
/*
* - Position constraining -
* Constrain the position to a mix of grid, containment.
*/
if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
if ( this.containment ) {
if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
pageX = this.containment[ 0 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
pageY = this.containment[ 1 ] + this.offset.click.top;
}
if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
pageX = this.containment[ 2 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
pageY = this.containment[ 3 ] + this.offset.click.top;
}
}
if ( o.grid ) {
top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
o.grid[ 1 ] ) * o.grid[ 1 ];
pageY = this.containment ?
( ( top - this.offset.click.top >= this.containment[ 1 ] &&
top - this.offset.click.top <= this.containment[ 3 ] ) ?
top :
( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
top;
left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
o.grid[ 0 ] ) * o.grid[ 0 ];
pageX = this.containment ?
( ( left - this.offset.click.left >= this.containment[ 0 ] &&
left - this.offset.click.left <= this.containment[ 2 ] ) ?
left :
( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
left;
}
}
return {
top: (
// The absolute mouse position
pageY -
// Click offset (relative to the element)
this.offset.click.top -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top +
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollTop() :
( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
),
left: (
// The absolute mouse position
pageX -
// Click offset (relative to the element)
this.offset.click.left -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left +
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollLeft() :
scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
)
};
},
_rearrange: function( event, i, a, hardRefresh ) {
a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
//Various things done here to improve the performance:
// 1. we create a setTimeout, that calls refreshPositions
// 2. on the instance, we have a counter variable, that get's higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout,
// if it's still the same
// 4. this lets only the last addition to the timeout stack through
this.counter = this.counter ? ++this.counter : 1;
var counter = this.counter;
this._delay( function() {
if ( counter === this.counter ) {
//Precompute after each DOM insertion, NOT on mousemove
this.refreshPositions( !hardRefresh );
}
} );
},
_clear: function( event, noPropagation ) {
this.reverting = false;
// We delay all events that have to be triggered to after the point where the placeholder
// has been removed and everything else normalized again
var i,
delayedTriggers = [];
// We first have to update the dom position of the actual currentItem
// Note: don't do it if the current item is already removed (by a user), or it gets
// reappended (see #4088)
if ( !this._noFinalSort && this.currentItem.parent().length ) {
this.placeholder.before( this.currentItem );
}
this._noFinalSort = null;
if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
for ( i in this._storedCSS ) {
if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
this._storedCSS[ i ] = "";
}
}
this.currentItem.css( this._storedCSS );
this._removeClass( this.currentItem, "ui-sortable-helper" );
} else {
this.currentItem.show();
}
if ( this.fromOutside && !noPropagation ) {
delayedTriggers.push( function( event ) {
this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
} );
}
if ( ( this.fromOutside ||
this.domPosition.prev !==
this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
// Trigger update callback if the DOM position has changed
delayedTriggers.push( function( event ) {
this._trigger( "update", event, this._uiHash() );
} );
}
// Check if the items Container has Changed and trigger appropriate
// events.
if ( this !== this.currentContainer ) {
if ( !noPropagation ) {
delayedTriggers.push( function( event ) {
this._trigger( "remove", event, this._uiHash() );
} );
delayedTriggers.push( ( function( c ) {
return function( event ) {
c._trigger( "receive", event, this._uiHash( this ) );
};
} ).call( this, this.currentContainer ) );
delayedTriggers.push( ( function( c ) {
return function( event ) {
c._trigger( "update", event, this._uiHash( this ) );
};
} ).call( this, this.currentContainer ) );
}
}
//Post events to containers
function delayEvent( type, instance, container ) {
return function( event ) {
container._trigger( type, event, instance._uiHash( instance ) );
};
}
for ( i = this.containers.length - 1; i >= 0; i-- ) {
if ( !noPropagation ) {
delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
}
if ( this.containers[ i ].containerCache.over ) {
delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
this.containers[ i ].containerCache.over = 0;
}
}
//Do what was originally in plugins
if ( this.storedCursor ) {
this.document.find( "body" ).css( "cursor", this.storedCursor );
this.storedStylesheet.remove();
}
if ( this._storedOpacity ) {
this.helper.css( "opacity", this._storedOpacity );
}
if ( this._storedZIndex ) {
this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
}
this.dragging = false;
if ( !noPropagation ) {
this._trigger( "beforeStop", event, this._uiHash() );
}
//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
// it unbinds ALL events from the original node!
this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
if ( !this.cancelHelperRemoval ) {
if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
this.helper.remove();
}
this.helper = null;
}
if ( !noPropagation ) {
for ( i = 0; i < delayedTriggers.length; i++ ) {
// Trigger all delayed events
delayedTriggers[ i ].call( this, event );
}
this._trigger( "stop", event, this._uiHash() );
}
this.fromOutside = false;
return !this.cancelHelperRemoval;
},
_trigger: function() {
if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
this.cancel();
}
},
_uiHash: function( _inst ) {
var inst = _inst || this;
return {
helper: inst.helper,
placeholder: inst.placeholder || $( [] ),
position: inst.position,
originalPosition: inst.originalPosition,
offset: inst.positionAbs,
item: inst.currentItem,
sender: _inst ? _inst.element : null
};
}
} );
/*!
* jQuery UI Spinner 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Spinner
//>>group: Widgets
//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
//>>docs: http://api.jqueryui.com/spinner/
//>>demos: http://jqueryui.com/spinner/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/spinner.css
//>>css.theme: ../../themes/base/theme.css
function spinnerModifer( fn ) {
return function() {
var previous = this.element.val();
fn.apply( this, arguments );
this._refresh();
if ( previous !== this.element.val() ) {
this._trigger( "change" );
}
};
}
$.widget( "ui.spinner", {
version: "1.12.1",
defaultElement: "<input>",
widgetEventPrefix: "spin",
options: {
classes: {
"ui-spinner": "ui-corner-all",
"ui-spinner-down": "ui-corner-br",
"ui-spinner-up": "ui-corner-tr"
},
culture: null,
icons: {
down: "ui-icon-triangle-1-s",
up: "ui-icon-triangle-1-n"
},
incremental: true,
max: null,
min: null,
numberFormat: null,
page: 10,
step: 1,
change: null,
spin: null,
start: null,
stop: null
},
_create: function() {
// handle string values that need to be parsed
this._setOption( "max", this.options.max );
this._setOption( "min", this.options.min );
this._setOption( "step", this.options.step );
// Only format if there is a value, prevents the field from being marked
// as invalid in Firefox, see #9573.
if ( this.value() !== "" ) {
// Format the value, but don't constrain.
this._value( this.element.val(), true );
}
this._draw();
this._on( this._events );
this._refresh();
// Turning off autocomplete prevents the browser from remembering the
// value when navigating through history, so we re-enable autocomplete
// if the page is unloaded before the widget is destroyed. #7790
this._on( this.window, {
beforeunload: function() {
this.element.removeAttr( "autocomplete" );
}
} );
},
_getCreateOptions: function() {
var options = this._super();
var element = this.element;
$.each( [ "min", "max", "step" ], function( i, option ) {
var value = element.attr( option );
if ( value != null && value.length ) {
options[ option ] = value;
}
} );
return options;
},
_events: {
keydown: function( event ) {
if ( this._start( event ) && this._keydown( event ) ) {
event.preventDefault();
}
},
keyup: "_stop",
focus: function() {
this.previous = this.element.val();
},
blur: function( event ) {
if ( this.cancelBlur ) {
delete this.cancelBlur;
return;
}
this._stop();
this._refresh();
if ( this.previous !== this.element.val() ) {
this._trigger( "change", event );
}
},
mousewheel: function( event, delta ) {
if ( !delta ) {
return;
}
if ( !this.spinning && !this._start( event ) ) {
return false;
}
this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
clearTimeout( this.mousewheelTimer );
this.mousewheelTimer = this._delay( function() {
if ( this.spinning ) {
this._stop( event );
}
}, 100 );
event.preventDefault();
},
"mousedown .ui-spinner-button": function( event ) {
var previous;
// We never want the buttons to have focus; whenever the user is
// interacting with the spinner, the focus should be on the input.
// If the input is focused then this.previous is properly set from
// when the input first received focus. If the input is not focused
// then we need to set this.previous based on the value before spinning.
previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
this.previous : this.element.val();
function checkFocus() {
var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
if ( !isActive ) {
this.element.trigger( "focus" );
this.previous = previous;
// support: IE
// IE sets focus asynchronously, so we need to check if focus
// moved off of the input because the user clicked on the button.
this._delay( function() {
this.previous = previous;
} );
}
}
// Ensure focus is on (or stays on) the text field
event.preventDefault();
checkFocus.call( this );
// Support: IE
// IE doesn't prevent moving focus even with event.preventDefault()
// so we set a flag to know when we should ignore the blur event
// and check (again) if focus moved off of the input.
this.cancelBlur = true;
this._delay( function() {
delete this.cancelBlur;
checkFocus.call( this );
} );
if ( this._start( event ) === false ) {
return;
}
this._repeat( null, $( event.currentTarget )
.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
},
"mouseup .ui-spinner-button": "_stop",
"mouseenter .ui-spinner-button": function( event ) {
// button will add ui-state-active if mouse was down while mouseleave and kept down
if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
return;
}
if ( this._start( event ) === false ) {
return false;
}
this._repeat( null, $( event.currentTarget )
.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
},
// TODO: do we really want to consider this a stop?
// shouldn't we just stop the repeater and wait until mouseup before
// we trigger the stop event?
"mouseleave .ui-spinner-button": "_stop"
},
// Support mobile enhanced option and make backcompat more sane
_enhance: function() {
this.uiSpinner = this.element
.attr( "autocomplete", "off" )
.wrap( "<span>" )
.parent()
// Add buttons
.append(
"<a></a><a></a>"
);
},
_draw: function() {
this._enhance();
this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
this._addClass( "ui-spinner-input" );
this.element.attr( "role", "spinbutton" );
// Button bindings
this.buttons = this.uiSpinner.children( "a" )
.attr( "tabIndex", -1 )
.attr( "aria-hidden", true )
.button( {
classes: {
"ui-button": ""
}
} );
// TODO: Right now button does not support classes this is already updated in button PR
this._removeClass( this.buttons, "ui-corner-all" );
this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
this.buttons.first().button( {
"icon": this.options.icons.up,
"showLabel": false
} );
this.buttons.last().button( {
"icon": this.options.icons.down,
"showLabel": false
} );
// IE 6 doesn't understand height: 50% for the buttons
// unless the wrapper has an explicit height
if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
this.uiSpinner.height() > 0 ) {
this.uiSpinner.height( this.uiSpinner.height() );
}
},
_keydown: function( event ) {
var options = this.options,
keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.UP:
this._repeat( null, 1, event );
return true;
case keyCode.DOWN:
this._repeat( null, -1, event );
return true;
case keyCode.PAGE_UP:
this._repeat( null, options.page, event );
return true;
case keyCode.PAGE_DOWN:
this._repeat( null, -options.page, event );
return true;
}
return false;
},
_start: function( event ) {
if ( !this.spinning && this._trigger( "start", event ) === false ) {
return false;
}
if ( !this.counter ) {
this.counter = 1;
}
this.spinning = true;
return true;
},
_repeat: function( i, steps, event ) {
i = i || 500;
clearTimeout( this.timer );
this.timer = this._delay( function() {
this._repeat( 40, steps, event );
}, i );
this._spin( steps * this.options.step, event );
},
_spin: function( step, event ) {
var value = this.value() || 0;
if ( !this.counter ) {
this.counter = 1;
}
value = this._adjustValue( value + step * this._increment( this.counter ) );
if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
this._value( value );
this.counter++;
}
},
_increment: function( i ) {
var incremental = this.options.incremental;
if ( incremental ) {
return $.isFunction( incremental ) ?
incremental( i ) :
Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
}
return 1;
},
_precision: function() {
var precision = this._precisionOf( this.options.step );
if ( this.options.min !== null ) {
precision = Math.max( precision, this._precisionOf( this.options.min ) );
}
return precision;
},
_precisionOf: function( num ) {
var str = num.toString(),
decimal = str.indexOf( "." );
return decimal === -1 ? 0 : str.length - decimal - 1;
},
_adjustValue: function( value ) {
var base, aboveMin,
options = this.options;
// Make sure we're at a valid step
// - find out where we are relative to the base (min or 0)
base = options.min !== null ? options.min : 0;
aboveMin = value - base;
// - round to the nearest step
aboveMin = Math.round( aboveMin / options.step ) * options.step;
// - rounding is based on 0, so adjust back to our base
value = base + aboveMin;
// Fix precision from bad JS floating point math
value = parseFloat( value.toFixed( this._precision() ) );
// Clamp the value
if ( options.max !== null && value > options.max ) {
return options.max;
}
if ( options.min !== null && value < options.min ) {
return options.min;
}
return value;
},
_stop: function( event ) {
if ( !this.spinning ) {
return;
}
clearTimeout( this.timer );
clearTimeout( this.mousewheelTimer );
this.counter = 0;
this.spinning = false;
this._trigger( "stop", event );
},
_setOption: function( key, value ) {
var prevValue, first, last;
if ( key === "culture" || key === "numberFormat" ) {
prevValue = this._parse( this.element.val() );
this.options[ key ] = value;
this.element.val( this._format( prevValue ) );
return;
}
if ( key === "max" || key === "min" || key === "step" ) {
if ( typeof value === "string" ) {
value = this._parse( value );
}
}
if ( key === "icons" ) {
first = this.buttons.first().find( ".ui-icon" );
this._removeClass( first, null, this.options.icons.up );
this._addClass( first, null, value.up );
last = this.buttons.last().find( ".ui-icon" );
this._removeClass( last, null, this.options.icons.down );
this._addClass( last, null, value.down );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
this.element.prop( "disabled", !!value );
this.buttons.button( value ? "disable" : "enable" );
},
_setOptions: spinnerModifer( function( options ) {
this._super( options );
} ),
_parse: function( val ) {
if ( typeof val === "string" && val !== "" ) {
val = window.Globalize && this.options.numberFormat ?
Globalize.parseFloat( val, 10, this.options.culture ) : +val;
}
return val === "" || isNaN( val ) ? null : val;
},
_format: function( value ) {
if ( value === "" ) {
return "";
}
return window.Globalize && this.options.numberFormat ?
Globalize.format( value, this.options.numberFormat, this.options.culture ) :
value;
},
_refresh: function() {
this.element.attr( {
"aria-valuemin": this.options.min,
"aria-valuemax": this.options.max,
// TODO: what should we do with values that can't be parsed?
"aria-valuenow": this._parse( this.element.val() )
} );
},
isValid: function() {
var value = this.value();
// Null is invalid
if ( value === null ) {
return false;
}
// If value gets adjusted, it's invalid
return value === this._adjustValue( value );
},
// Update the value without triggering change
_value: function( value, allowAny ) {
var parsed;
if ( value !== "" ) {
parsed = this._parse( value );
if ( parsed !== null ) {
if ( !allowAny ) {
parsed = this._adjustValue( parsed );
}
value = this._format( parsed );
}
}
this.element.val( value );
this._refresh();
},
_destroy: function() {
this.element
.prop( "disabled", false )
.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
this.uiSpinner.replaceWith( this.element );
},
stepUp: spinnerModifer( function( steps ) {
this._stepUp( steps );
} ),
_stepUp: function( steps ) {
if ( this._start() ) {
this._spin( ( steps || 1 ) * this.options.step );
this._stop();
}
},
stepDown: spinnerModifer( function( steps ) {
this._stepDown( steps );
} ),
_stepDown: function( steps ) {
if ( this._start() ) {
this._spin( ( steps || 1 ) * -this.options.step );
this._stop();
}
},
pageUp: spinnerModifer( function( pages ) {
this._stepUp( ( pages || 1 ) * this.options.page );
} ),
pageDown: spinnerModifer( function( pages ) {
this._stepDown( ( pages || 1 ) * this.options.page );
} ),
value: function( newVal ) {
if ( !arguments.length ) {
return this._parse( this.element.val() );
}
spinnerModifer( this._value ).call( this, newVal );
},
widget: function() {
return this.uiSpinner;
}
} );
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for spinner html extension points
$.widget( "ui.spinner", $.ui.spinner, {
_enhance: function() {
this.uiSpinner = this.element
.attr( "autocomplete", "off" )
.wrap( this._uiSpinnerHtml() )
.parent()
// Add buttons
.append( this._buttonHtml() );
},
_uiSpinnerHtml: function() {
return "<span>";
},
_buttonHtml: function() {
return "<a></a><a></a>";
}
} );
}
var widgetsSpinner = $.ui.spinner;
/*!
* jQuery UI Tabs 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Tabs
//>>group: Widgets
//>>description: Transforms a set of container elements into a tab structure.
//>>docs: http://api.jqueryui.com/tabs/
//>>demos: http://jqueryui.com/tabs/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tabs.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.tabs", {
version: "1.12.1",
delay: 300,
options: {
active: null,
classes: {
"ui-tabs": "ui-corner-all",
"ui-tabs-nav": "ui-corner-all",
"ui-tabs-panel": "ui-corner-bottom",
"ui-tabs-tab": "ui-corner-top"
},
collapsible: false,
event: "click",
heightStyle: "content",
hide: null,
show: null,
// Callbacks
activate: null,
beforeActivate: null,
beforeLoad: null,
load: null
},
_isLocal: ( function() {
var rhash = /#.*$/;
return function( anchor ) {
var anchorUrl, locationUrl;
anchorUrl = anchor.href.replace( rhash, "" );
locationUrl = location.href.replace( rhash, "" );
// Decoding may throw an error if the URL isn't UTF-8 (#9518)
try {
anchorUrl = decodeURIComponent( anchorUrl );
} catch ( error ) {}
try {
locationUrl = decodeURIComponent( locationUrl );
} catch ( error ) {}
return anchor.hash.length > 1 && anchorUrl === locationUrl;
};
} )(),
_create: function() {
var that = this,
options = this.options;
this.running = false;
this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
this._processTabs();
options.active = this._initialActive();
// Take disabling tabs via class attribute from HTML
// into account and update option properly.
if ( $.isArray( options.disabled ) ) {
options.disabled = $.unique( options.disabled.concat(
$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
return that.tabs.index( li );
} )
) ).sort();
}
// Check for length avoids error when initializing empty list
if ( this.options.active !== false && this.anchors.length ) {
this.active = this._findActive( options.active );
} else {
this.active = $();
}
this._refresh();
if ( this.active.length ) {
this.load( options.active );
}
},
_initialActive: function() {
var active = this.options.active,
collapsible = this.options.collapsible,
locationHash = location.hash.substring( 1 );
if ( active === null ) {
// check the fragment identifier in the URL
if ( locationHash ) {
this.tabs.each( function( i, tab ) {
if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
active = i;
return false;
}
} );
}
// Check for a tab marked active via a class
if ( active === null ) {
active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
}
// No active tab, set to false
if ( active === null || active === -1 ) {
active = this.tabs.length ? 0 : false;
}
}
// Handle numbers: negative, out of range
if ( active !== false ) {
active = this.tabs.index( this.tabs.eq( active ) );
if ( active === -1 ) {
active = collapsible ? false : 0;
}
}
// Don't allow collapsible: false and active: false
if ( !collapsible && active === false && this.anchors.length ) {
active = 0;
}
return active;
},
_getCreateEventData: function() {
return {
tab: this.active,
panel: !this.active.length ? $() : this._getPanelForTab( this.active )
};
},
_tabKeydown: function( event ) {
var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
selectedIndex = this.tabs.index( focusedTab ),
goingForward = true;
if ( this._handlePageNav( event ) ) {
return;
}
switch ( event.keyCode ) {
case $.ui.keyCode.RIGHT:
case $.ui.keyCode.DOWN:
selectedIndex++;
break;
case $.ui.keyCode.UP:
case $.ui.keyCode.LEFT:
goingForward = false;
selectedIndex--;
break;
case $.ui.keyCode.END:
selectedIndex = this.anchors.length - 1;
break;
case $.ui.keyCode.HOME:
selectedIndex = 0;
break;
case $.ui.keyCode.SPACE:
// Activate only, no collapsing
event.preventDefault();
clearTimeout( this.activating );
this._activate( selectedIndex );
return;
case $.ui.keyCode.ENTER:
// Toggle (cancel delayed activation, allow collapsing)
event.preventDefault();
clearTimeout( this.activating );
// Determine if we should collapse or activate
this._activate( selectedIndex === this.options.active ? false : selectedIndex );
return;
default:
return;
}
// Focus the appropriate tab, based on which key was pressed
event.preventDefault();
clearTimeout( this.activating );
selectedIndex = this._focusNextTab( selectedIndex, goingForward );
// Navigating with control/command key will prevent automatic activation
if ( !event.ctrlKey && !event.metaKey ) {
// Update aria-selected immediately so that AT think the tab is already selected.
// Otherwise AT may confuse the user by stating that they need to activate the tab,
// but the tab will already be activated by the time the announcement finishes.
focusedTab.attr( "aria-selected", "false" );
this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
this.activating = this._delay( function() {
this.option( "active", selectedIndex );
}, this.delay );
}
},
_panelKeydown: function( event ) {
if ( this._handlePageNav( event ) ) {
return;
}
// Ctrl+up moves focus to the current tab
if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
event.preventDefault();
this.active.trigger( "focus" );
}
},
// Alt+page up/down moves focus to the previous/next tab (and activates)
_handlePageNav: function( event ) {
if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
this._activate( this._focusNextTab( this.options.active - 1, false ) );
return true;
}
if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
this._activate( this._focusNextTab( this.options.active + 1, true ) );
return true;
}
},
_findNextTab: function( index, goingForward ) {
var lastTabIndex = this.tabs.length - 1;
function constrain() {
if ( index > lastTabIndex ) {
index = 0;
}
if ( index < 0 ) {
index = lastTabIndex;
}
return index;
}
while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
index = goingForward ? index + 1 : index - 1;
}
return index;
},
_focusNextTab: function( index, goingForward ) {
index = this._findNextTab( index, goingForward );
this.tabs.eq( index ).trigger( "focus" );
return index;
},
_setOption: function( key, value ) {
if ( key === "active" ) {
// _activate() will handle invalid values and update this.options
this._activate( value );
return;
}
this._super( key, value );
if ( key === "collapsible" ) {
this._toggleClass( "ui-tabs-collapsible", null, value );
// Setting collapsible: false while collapsed; open first panel
if ( !value && this.options.active === false ) {
this._activate( 0 );
}
}
if ( key === "event" ) {
this._setupEvents( value );
}
if ( key === "heightStyle" ) {
this._setupHeightStyle( value );
}
},
_sanitizeSelector: function( hash ) {
return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
},
refresh: function() {
var options = this.options,
lis = this.tablist.children( ":has(a[href])" );
// Get disabled tabs from class attribute from HTML
// this will get converted to a boolean if needed in _refresh()
options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
return lis.index( tab );
} );
this._processTabs();
// Was collapsed or no tabs
if ( options.active === false || !this.anchors.length ) {
options.active = false;
this.active = $();
// was active, but active tab is gone
} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
// all remaining tabs are disabled
if ( this.tabs.length === options.disabled.length ) {
options.active = false;
this.active = $();
// activate previous tab
} else {
this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
}
// was active, active tab still exists
} else {
// make sure active index is correct
options.active = this.tabs.index( this.active );
}
this._refresh();
},
_refresh: function() {
this._setOptionDisabled( this.options.disabled );
this._setupEvents( this.options.event );
this._setupHeightStyle( this.options.heightStyle );
this.tabs.not( this.active ).attr( {
"aria-selected": "false",
"aria-expanded": "false",
tabIndex: -1
} );
this.panels.not( this._getPanelForTab( this.active ) )
.hide()
.attr( {
"aria-hidden": "true"
} );
// Make sure one tab is in the tab order
if ( !this.active.length ) {
this.tabs.eq( 0 ).attr( "tabIndex", 0 );
} else {
this.active
.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
this._getPanelForTab( this.active )
.show()
.attr( {
"aria-hidden": "false"
} );
}
},
_processTabs: function() {
var that = this,
prevTabs = this.tabs,
prevAnchors = this.anchors,
prevPanels = this.panels;
this.tablist = this._getList().attr( "role", "tablist" );
this._addClass( this.tablist, "ui-tabs-nav",
"ui-helper-reset ui-helper-clearfix ui-widget-header" );
// Prevent users from focusing disabled tabs via click
this.tablist
.on( "mousedown" + this.eventNamespace, "> li", function( event ) {
if ( $( this ).is( ".ui-state-disabled" ) ) {
event.preventDefault();
}
} )
// Support: IE <9
// Preventing the default action in mousedown doesn't prevent IE
// from focusing the element, so if the anchor gets focused, blur.
// We don't have to worry about focusing the previously focused
// element since clicking on a non-focusable element should focus
// the body anyway.
.on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
this.blur();
}
} );
this.tabs = this.tablist.find( "> li:has(a[href])" )
.attr( {
role: "tab",
tabIndex: -1
} );
this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
this.anchors = this.tabs.map( function() {
return $( "a", this )[ 0 ];
} )
.attr( {
role: "presentation",
tabIndex: -1
} );
this._addClass( this.anchors, "ui-tabs-anchor" );
this.panels = $();
this.anchors.each( function( i, anchor ) {
var selector, panel, panelId,
anchorId = $( anchor ).uniqueId().attr( "id" ),
tab = $( anchor ).closest( "li" ),
originalAriaControls = tab.attr( "aria-controls" );
// Inline tab
if ( that._isLocal( anchor ) ) {
selector = anchor.hash;
panelId = selector.substring( 1 );
panel = that.element.find( that._sanitizeSelector( selector ) );
// remote tab
} else {
// If the tab doesn't already have aria-controls,
// generate an id by using a throw-away element
panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
selector = "#" + panelId;
panel = that.element.find( selector );
if ( !panel.length ) {
panel = that._createPanel( panelId );
panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
}
panel.attr( "aria-live", "polite" );
}
if ( panel.length ) {
that.panels = that.panels.add( panel );
}
if ( originalAriaControls ) {
tab.data( "ui-tabs-aria-controls", originalAriaControls );
}
tab.attr( {
"aria-controls": panelId,
"aria-labelledby": anchorId
} );
panel.attr( "aria-labelledby", anchorId );
} );
this.panels.attr( "role", "tabpanel" );
this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
// Avoid memory leaks (#10056)
if ( prevTabs ) {
this._off( prevTabs.not( this.tabs ) );
this._off( prevAnchors.not( this.anchors ) );
this._off( prevPanels.not( this.panels ) );
}
},
// Allow overriding how to find the list for rare usage scenarios (#7715)
_getList: function() {
return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
},
_createPanel: function( id ) {
return $( "<div>" )
.attr( "id", id )
.data( "ui-tabs-destroy", true );
},
_setOptionDisabled: function( disabled ) {
var currentItem, li, i;
if ( $.isArray( disabled ) ) {
if ( !disabled.length ) {
disabled = false;
} else if ( disabled.length === this.anchors.length ) {
disabled = true;
}
}
// Disable tabs
for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
currentItem = $( li );
if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
currentItem.attr( "aria-disabled", "true" );
this._addClass( currentItem, null, "ui-state-disabled" );
} else {
currentItem.removeAttr( "aria-disabled" );
this._removeClass( currentItem, null, "ui-state-disabled" );
}
}
this.options.disabled = disabled;
this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
disabled === true );
},
_setupEvents: function( event ) {
var events = {};
if ( event ) {
$.each( event.split( " " ), function( index, eventName ) {
events[ eventName ] = "_eventHandler";
} );
}
this._off( this.anchors.add( this.tabs ).add( this.panels ) );
// Always prevent the default action, even when disabled
this._on( true, this.anchors, {
click: function( event ) {
event.preventDefault();
}
} );
this._on( this.anchors, events );
this._on( this.tabs, { keydown: "_tabKeydown" } );
this._on( this.panels, { keydown: "_panelKeydown" } );
this._focusable( this.tabs );
this._hoverable( this.tabs );
},
_setupHeightStyle: function( heightStyle ) {
var maxHeight,
parent = this.element.parent();
if ( heightStyle === "fill" ) {
maxHeight = parent.height();
maxHeight -= this.element.outerHeight() - this.element.height();
this.element.siblings( ":visible" ).each( function() {
var elem = $( this ),
position = elem.css( "position" );
if ( position === "absolute" || position === "fixed" ) {
return;
}
maxHeight -= elem.outerHeight( true );
} );
this.element.children().not( this.panels ).each( function() {
maxHeight -= $( this ).outerHeight( true );
} );
this.panels.each( function() {
$( this ).height( Math.max( 0, maxHeight -
$( this ).innerHeight() + $( this ).height() ) );
} )
.css( "overflow", "auto" );
} else if ( heightStyle === "auto" ) {
maxHeight = 0;
this.panels.each( function() {
maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
} ).height( maxHeight );
}
},
_eventHandler: function( event ) {
var options = this.options,
active = this.active,
anchor = $( event.currentTarget ),
tab = anchor.closest( "li" ),
clickedIsActive = tab[ 0 ] === active[ 0 ],
collapsing = clickedIsActive && options.collapsible,
toShow = collapsing ? $() : this._getPanelForTab( tab ),
toHide = !active.length ? $() : this._getPanelForTab( active ),
eventData = {
oldTab: active,
oldPanel: toHide,
newTab: collapsing ? $() : tab,
newPanel: toShow
};
event.preventDefault();
if ( tab.hasClass( "ui-state-disabled" ) ||
// tab is already loading
tab.hasClass( "ui-tabs-loading" ) ||
// can't switch durning an animation
this.running ||
// click on active header, but not collapsible
( clickedIsActive && !options.collapsible ) ||
// allow canceling activation
( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
return;
}
options.active = collapsing ? false : this.tabs.index( tab );
this.active = clickedIsActive ? $() : tab;
if ( this.xhr ) {
this.xhr.abort();
}
if ( !toHide.length && !toShow.length ) {
$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
}
if ( toShow.length ) {
this.load( this.tabs.index( tab ), event );
}
this._toggle( event, eventData );
},
// Handles show/hide for selecting tabs
_toggle: function( event, eventData ) {
var that = this,
toShow = eventData.newPanel,
toHide = eventData.oldPanel;
this.running = true;
function complete() {
that.running = false;
that._trigger( "activate", event, eventData );
}
function show() {
that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
if ( toShow.length && that.options.show ) {
that._show( toShow, that.options.show, complete );
} else {
toShow.show();
complete();
}
}
// Start out by hiding, then showing, then completing
if ( toHide.length && this.options.hide ) {
this._hide( toHide, this.options.hide, function() {
that._removeClass( eventData.oldTab.closest( "li" ),
"ui-tabs-active", "ui-state-active" );
show();
} );
} else {
this._removeClass( eventData.oldTab.closest( "li" ),
"ui-tabs-active", "ui-state-active" );
toHide.hide();
show();
}
toHide.attr( "aria-hidden", "true" );
eventData.oldTab.attr( {
"aria-selected": "false",
"aria-expanded": "false"
} );
// If we're switching tabs, remove the old tab from the tab order.
// If we're opening from collapsed state, remove the previous tab from the tab order.
// If we're collapsing, then keep the collapsing tab in the tab order.
if ( toShow.length && toHide.length ) {
eventData.oldTab.attr( "tabIndex", -1 );
} else if ( toShow.length ) {
this.tabs.filter( function() {
return $( this ).attr( "tabIndex" ) === 0;
} )
.attr( "tabIndex", -1 );
}
toShow.attr( "aria-hidden", "false" );
eventData.newTab.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
},
_activate: function( index ) {
var anchor,
active = this._findActive( index );
// Trying to activate the already active panel
if ( active[ 0 ] === this.active[ 0 ] ) {
return;
}
// Trying to collapse, simulate a click on the current active header
if ( !active.length ) {
active = this.active;
}
anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
this._eventHandler( {
target: anchor,
currentTarget: anchor,
preventDefault: $.noop
} );
},
_findActive: function( index ) {
return index === false ? $() : this.tabs.eq( index );
},
_getIndex: function( index ) {
// meta-function to give users option to provide a href string instead of a numerical index.
if ( typeof index === "string" ) {
index = this.anchors.index( this.anchors.filter( "[href$='" +
$.ui.escapeSelector( index ) + "']" ) );
}
return index;
},
_destroy: function() {
if ( this.xhr ) {
this.xhr.abort();
}
this.tablist
.removeAttr( "role" )
.off( this.eventNamespace );
this.anchors
.removeAttr( "role tabIndex" )
.removeUniqueId();
this.tabs.add( this.panels ).each( function() {
if ( $.data( this, "ui-tabs-destroy" ) ) {
$( this ).remove();
} else {
$( this ).removeAttr( "role tabIndex " +
"aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
}
} );
this.tabs.each( function() {
var li = $( this ),
prev = li.data( "ui-tabs-aria-controls" );
if ( prev ) {
li
.attr( "aria-controls", prev )
.removeData( "ui-tabs-aria-controls" );
} else {
li.removeAttr( "aria-controls" );
}
} );
this.panels.show();
if ( this.options.heightStyle !== "content" ) {
this.panels.css( "height", "" );
}
},
enable: function( index ) {
var disabled = this.options.disabled;
if ( disabled === false ) {
return;
}
if ( index === undefined ) {
disabled = false;
} else {
index = this._getIndex( index );
if ( $.isArray( disabled ) ) {
disabled = $.map( disabled, function( num ) {
return num !== index ? num : null;
} );
} else {
disabled = $.map( this.tabs, function( li, num ) {
return num !== index ? num : null;
} );
}
}
this._setOptionDisabled( disabled );
},
disable: function( index ) {
var disabled = this.options.disabled;
if ( disabled === true ) {
return;
}
if ( index === undefined ) {
disabled = true;
} else {
index = this._getIndex( index );
if ( $.inArray( index, disabled ) !== -1 ) {
return;
}
if ( $.isArray( disabled ) ) {
disabled = $.merge( [ index ], disabled ).sort();
} else {
disabled = [ index ];
}
}
this._setOptionDisabled( disabled );
},
load: function( index, event ) {
index = this._getIndex( index );
var that = this,
tab = this.tabs.eq( index ),
anchor = tab.find( ".ui-tabs-anchor" ),
panel = this._getPanelForTab( tab ),
eventData = {
tab: tab,
panel: panel
},
complete = function( jqXHR, status ) {
if ( status === "abort" ) {
that.panels.stop( false, true );
}
that._removeClass( tab, "ui-tabs-loading" );
panel.removeAttr( "aria-busy" );
if ( jqXHR === that.xhr ) {
delete that.xhr;
}
};
// Not remote
if ( this._isLocal( anchor[ 0 ] ) ) {
return;
}
this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
// Support: jQuery <1.8
// jQuery <1.8 returns false if the request is canceled in beforeSend,
// but as of 1.8, $.ajax() always returns a jqXHR object.
if ( this.xhr && this.xhr.statusText !== "canceled" ) {
this._addClass( tab, "ui-tabs-loading" );
panel.attr( "aria-busy", "true" );
this.xhr
.done( function( response, status, jqXHR ) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout( function() {
panel.html( response );
that._trigger( "load", event, eventData );
complete( jqXHR, status );
}, 1 );
} )
.fail( function( jqXHR, status ) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout( function() {
complete( jqXHR, status );
}, 1 );
} );
}
},
_ajaxSettings: function( anchor, event, eventData ) {
var that = this;
return {
// Support: IE <11 only
// Strip any hash that exists to prevent errors with the Ajax request
url: anchor.attr( "href" ).replace( /#.*$/, "" ),
beforeSend: function( jqXHR, settings ) {
return that._trigger( "beforeLoad", event,
$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
}
};
},
_getPanelForTab: function( tab ) {
var id = $( tab ).attr( "aria-controls" );
return this.element.find( this._sanitizeSelector( "#" + id ) );
}
} );
// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for ui-tab class (now ui-tabs-tab)
$.widget( "ui.tabs", $.ui.tabs, {
_processTabs: function() {
this._superApply( arguments );
this._addClass( this.tabs, "ui-tab" );
}
} );
}
var widgetsTabs = $.ui.tabs;
/*!
* jQuery UI Tooltip 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Tooltip
//>>group: Widgets
//>>description: Shows additional information for any element on hover or focus.
//>>docs: http://api.jqueryui.com/tooltip/
//>>demos: http://jqueryui.com/tooltip/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tooltip.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.tooltip", {
version: "1.12.1",
options: {
classes: {
"ui-tooltip": "ui-corner-all ui-widget-shadow"
},
content: function() {
// support: IE<9, Opera in jQuery <1.7
// .text() can't accept undefined, so coerce to a string
var title = $( this ).attr( "title" ) || "";
// Escape title, since we're going from an attribute to raw HTML
return $( "<a>" ).text( title ).html();
},
hide: true,
// Disabled elements have inconsistent behavior across browsers (#8661)
items: "[title]:not([disabled])",
position: {
my: "left top+15",
at: "left bottom",
collision: "flipfit flip"
},
show: true,
track: false,
// Callbacks
close: null,
open: null
},
_addDescribedBy: function( elem, id ) {
var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
describedby.push( id );
elem
.data( "ui-tooltip-id", id )
.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
},
_removeDescribedBy: function( elem ) {
var id = elem.data( "ui-tooltip-id" ),
describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
index = $.inArray( id, describedby );
if ( index !== -1 ) {
describedby.splice( index, 1 );
}
elem.removeData( "ui-tooltip-id" );
describedby = $.trim( describedby.join( " " ) );
if ( describedby ) {
elem.attr( "aria-describedby", describedby );
} else {
elem.removeAttr( "aria-describedby" );
}
},
_create: function() {
this._on( {
mouseover: "open",
focusin: "open"
} );
// IDs of generated tooltips, needed for destroy
this.tooltips = {};
// IDs of parent tooltips where we removed the title attribute
this.parents = {};
// Append the aria-live region so tooltips announce correctly
this.liveRegion = $( "<div>" )
.attr( {
role: "log",
"aria-live": "assertive",
"aria-relevant": "additions"
} )
.appendTo( this.document[ 0 ].body );
this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
this.disabledTitles = $( [] );
},
_setOption: function( key, value ) {
var that = this;
this._super( key, value );
if ( key === "content" ) {
$.each( this.tooltips, function( id, tooltipData ) {
that._updateContent( tooltipData.element );
} );
}
},
_setOptionDisabled: function( value ) {
this[ value ? "_disable" : "_enable" ]();
},
_disable: function() {
var that = this;
// Close open tooltips
$.each( this.tooltips, function( id, tooltipData ) {
var event = $.Event( "blur" );
event.target = event.currentTarget = tooltipData.element[ 0 ];
that.close( event, true );
} );
// Remove title attributes to prevent native tooltips
this.disabledTitles = this.disabledTitles.add(
this.element.find( this.options.items ).addBack()
.filter( function() {
var element = $( this );
if ( element.is( "[title]" ) ) {
return element
.data( "ui-tooltip-title", element.attr( "title" ) )
.removeAttr( "title" );
}
} )
);
},
_enable: function() {
// restore title attributes
this.disabledTitles.each( function() {
var element = $( this );
if ( element.data( "ui-tooltip-title" ) ) {
element.attr( "title", element.data( "ui-tooltip-title" ) );
}
} );
this.disabledTitles = $( [] );
},
open: function( event ) {
var that = this,
target = $( event ? event.target : this.element )
// we need closest here due to mouseover bubbling,
// but always pointing at the same event target
.closest( this.options.items );
// No element to show a tooltip for or the tooltip is already open
if ( !target.length || target.data( "ui-tooltip-id" ) ) {
return;
}
if ( target.attr( "title" ) ) {
target.data( "ui-tooltip-title", target.attr( "title" ) );
}
target.data( "ui-tooltip-open", true );
// Kill parent tooltips, custom or native, for hover
if ( event && event.type === "mouseover" ) {
target.parents().each( function() {
var parent = $( this ),
blurEvent;
if ( parent.data( "ui-tooltip-open" ) ) {
blurEvent = $.Event( "blur" );
blurEvent.target = blurEvent.currentTarget = this;
that.close( blurEvent, true );
}
if ( parent.attr( "title" ) ) {
parent.uniqueId();
that.parents[ this.id ] = {
element: this,
title: parent.attr( "title" )
};
parent.attr( "title", "" );
}
} );
}
this._registerCloseHandlers( event, target );
this._updateContent( target, event );
},
_updateContent: function( target, event ) {
var content,
contentOption = this.options.content,
that = this,
eventType = event ? event.type : null;
if ( typeof contentOption === "string" || contentOption.nodeType ||
contentOption.jquery ) {
return this._open( event, target, contentOption );
}
content = contentOption.call( target[ 0 ], function( response ) {
// IE may instantly serve a cached response for ajax requests
// delay this call to _open so the other call to _open runs first
that._delay( function() {
// Ignore async response if tooltip was closed already
if ( !target.data( "ui-tooltip-open" ) ) {
return;
}
// JQuery creates a special event for focusin when it doesn't
// exist natively. To improve performance, the native event
// object is reused and the type is changed. Therefore, we can't
// rely on the type being correct after the event finished
// bubbling, so we set it back to the previous value. (#8740)
if ( event ) {
event.type = eventType;
}
this._open( event, target, response );
} );
} );
if ( content ) {
this._open( event, target, content );
}
},
_open: function( event, target, content ) {
var tooltipData, tooltip, delayedShow, a11yContent,
positionOption = $.extend( {}, this.options.position );
if ( !content ) {
return;
}
// Content can be updated multiple times. If the tooltip already
// exists, then just update the content and bail.
tooltipData = this._find( target );
if ( tooltipData ) {
tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
return;
}
// If we have a title, clear it to prevent the native tooltip
// we have to check first to avoid defining a title if none exists
// (we don't want to cause an element to start matching [title])
//
// We use removeAttr only for key events, to allow IE to export the correct
// accessible attributes. For mouse events, set to empty string to avoid
// native tooltip showing up (happens only when removing inside mouseover).
if ( target.is( "[title]" ) ) {
if ( event && event.type === "mouseover" ) {
target.attr( "title", "" );
} else {
target.removeAttr( "title" );
}
}
tooltipData = this._tooltip( target );
tooltip = tooltipData.tooltip;
this._addDescribedBy( target, tooltip.attr( "id" ) );
tooltip.find( ".ui-tooltip-content" ).html( content );
// Support: Voiceover on OS X, JAWS on IE <= 9
// JAWS announces deletions even when aria-relevant="additions"
// Voiceover will sometimes re-read the entire log region's contents from the beginning
this.liveRegion.children().hide();
a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
a11yContent.appendTo( this.liveRegion );
function position( event ) {
positionOption.of = event;
if ( tooltip.is( ":hidden" ) ) {
return;
}
tooltip.position( positionOption );
}
if ( this.options.track && event && /^mouse/.test( event.type ) ) {
this._on( this.document, {
mousemove: position
} );
// trigger once to override element-relative positioning
position( event );
} else {
tooltip.position( $.extend( {
of: target
}, this.options.position ) );
}
tooltip.hide();
this._show( tooltip, this.options.show );
// Handle tracking tooltips that are shown with a delay (#8644). As soon
// as the tooltip is visible, position the tooltip using the most recent
// event.
// Adds the check to add the timers only when both delay and track options are set (#14682)
if ( this.options.track && this.options.show && this.options.show.delay ) {
delayedShow = this.delayedShow = setInterval( function() {
if ( tooltip.is( ":visible" ) ) {
position( positionOption.of );
clearInterval( delayedShow );
}
}, $.fx.interval );
}
this._trigger( "open", event, { tooltip: tooltip } );
},
_registerCloseHandlers: function( event, target ) {
var events = {
keyup: function( event ) {
if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
var fakeEvent = $.Event( event );
fakeEvent.currentTarget = target[ 0 ];
this.close( fakeEvent, true );
}
}
};
// Only bind remove handler for delegated targets. Non-delegated
// tooltips will handle this in destroy.
if ( target[ 0 ] !== this.element[ 0 ] ) {
events.remove = function() {
this._removeTooltip( this._find( target ).tooltip );
};
}
if ( !event || event.type === "mouseover" ) {
events.mouseleave = "close";
}
if ( !event || event.type === "focusin" ) {
events.focusout = "close";
}
this._on( true, target, events );
},
close: function( event ) {
var tooltip,
that = this,
target = $( event ? event.currentTarget : this.element ),
tooltipData = this._find( target );
// The tooltip may already be closed
if ( !tooltipData ) {
// We set ui-tooltip-open immediately upon open (in open()), but only set the
// additional data once there's actually content to show (in _open()). So even if the
// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
// the period between open() and _open().
target.removeData( "ui-tooltip-open" );
return;
}
tooltip = tooltipData.tooltip;
// Disabling closes the tooltip, so we need to track when we're closing
// to avoid an infinite loop in case the tooltip becomes disabled on close
if ( tooltipData.closing ) {
return;
}
// Clear the interval for delayed tracking tooltips
clearInterval( this.delayedShow );
// Only set title if we had one before (see comment in _open())
// If the title attribute has changed since open(), don't restore
if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
target.attr( "title", target.data( "ui-tooltip-title" ) );
}
this._removeDescribedBy( target );
tooltipData.hiding = true;
tooltip.stop( true );
this._hide( tooltip, this.options.hide, function() {
that._removeTooltip( $( this ) );
} );
target.removeData( "ui-tooltip-open" );
this._off( target, "mouseleave focusout keyup" );
// Remove 'remove' binding only on delegated targets
if ( target[ 0 ] !== this.element[ 0 ] ) {
this._off( target, "remove" );
}
this._off( this.document, "mousemove" );
if ( event && event.type === "mouseleave" ) {
$.each( this.parents, function( id, parent ) {
$( parent.element ).attr( "title", parent.title );
delete that.parents[ id ];
} );
}
tooltipData.closing = true;
this._trigger( "close", event, { tooltip: tooltip } );
if ( !tooltipData.hiding ) {
tooltipData.closing = false;
}
},
_tooltip: function( element ) {
var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
content = $( "<div>" ).appendTo( tooltip ),
id = tooltip.uniqueId().attr( "id" );
this._addClass( content, "ui-tooltip-content" );
this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
tooltip.appendTo( this._appendTo( element ) );
return this.tooltips[ id ] = {
element: element,
tooltip: tooltip
};
},
_find: function( target ) {
var id = target.data( "ui-tooltip-id" );
return id ? this.tooltips[ id ] : null;
},
_removeTooltip: function( tooltip ) {
tooltip.remove();
delete this.tooltips[ tooltip.attr( "id" ) ];
},
_appendTo: function( target ) {
var element = target.closest( ".ui-front, dialog" );
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_destroy: function() {
var that = this;
// Close open tooltips
$.each( this.tooltips, function( id, tooltipData ) {
// Delegate to close method to handle common cleanup
var event = $.Event( "blur" ),
element = tooltipData.element;
event.target = event.currentTarget = element[ 0 ];
that.close( event, true );
// Remove immediately; destroying an open tooltip doesn't use the
// hide animation
$( "#" + id ).remove();
// Restore the title
if ( element.data( "ui-tooltip-title" ) ) {
// If the title attribute has changed since open(), don't restore
if ( !element.attr( "title" ) ) {
element.attr( "title", element.data( "ui-tooltip-title" ) );
}
element.removeData( "ui-tooltip-title" );
}
} );
this.liveRegion.remove();
}
} );
// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for tooltipClass option
$.widget( "ui.tooltip", $.ui.tooltip, {
options: {
tooltipClass: null
},
_tooltip: function() {
var tooltipData = this._superApply( arguments );
if ( this.options.tooltipClass ) {
tooltipData.tooltip.addClass( this.options.tooltipClass );
}
return tooltipData;
}
} );
}
var widgetsTooltip = $.ui.tooltip;
}));
(function defineMustache(global,factory){if(typeof exports==="object"&&exports&&typeof exports.nodeName!=="string"){factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],factory)}else{global.Mustache={};factory(global.Mustache)}})(this,function mustacheFactory(mustache){var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i<valueLength;++i){chr=value.charAt(i);if(isWhitespace(chr)){spaces.push(tokens.length)}else{nonSpace=true}tokens.push(["text",chr,start,start+1]);start+=1;if(chr==="\n")stripSpace()}}if(!scanner.scan(openingTagRe))break;hasTag=true;type=scanner.scan(tagRe)||"name";scanner.scan(whiteRe);if(type==="="){value=scanner.scanUntil(equalsRe);scanner.scan(equalsRe);scanner.scanUntil(closingTagRe)}else if(type==="{"){value=scanner.scanUntil(closingCurlyRe);scanner.scan(curlyRe);scanner.scanUntil(closingTagRe);type="&"}else{value=scanner.scanUntil(closingTagRe)}if(!scanner.scan(closingTagRe))throw new Error("Unclosed tag at "+scanner.pos);token=[type,value,start,scanner.pos];tokens.push(token);if(type==="#"||type==="^"){sections.push(token)}else if(type==="/"){openSection=sections.pop();if(!openSection)throw new Error('Unopened section "'+value+'" at '+start);if(openSection[1]!==value)throw new Error('Unclosed section "'+openSection[1]+'" at '+start)}else if(type==="name"||type==="{"||type==="&"){nonSpace=true}else if(type==="="){compileTags(value)}}openSection=sections.pop();if(openSection)throw new Error('Unclosed section "'+openSection[1]+'" at '+scanner.pos);return nestTokens(squashTokens(tokens))}function squashTokens(tokens){var squashedTokens=[];var token,lastToken;for(var i=0,numTokens=tokens.length;i<numTokens;++i){token=tokens[i];if(token){if(token[0]==="text"&&lastToken&&lastToken[0]==="text"){lastToken[1]+=token[1];lastToken[3]=token[3]}else{squashedTokens.push(token);lastToken=token}}}return squashedTokens}function nestTokens(tokens){var nestedTokens=[];var collector=nestedTokens;var sections=[];var token,section;for(var i=0,numTokens=tokens.length;i<numTokens;++i){token=tokens[i];switch(token[0]){case"#":case"^":collector.push(token);sections.push(token);collector=token[4]=[];break;case"/":section=sections.pop();section[5]=token[2];collector=sections.length>0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function eos(){return this.tail===""};Scanner.prototype.scan=function scan(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function scanUntil(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function push(view){return new Context(view,this)};Context.prototype.lookup=function lookup(name){var cache=this.cache;var value;if(cache.hasOwnProperty(name)){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index<names.length){if(index===names.length-1)lookupHit=hasProperty(value,names[index]);value=value[names[index++]]}}else{value=context.view[name];lookupHit=hasProperty(context.view,name)}if(lookupHit)break;context=context.parent}cache[name]=value}if(isFunction(value))value=value.call(this.view);return value};function Writer(){this.cache={}}Writer.prototype.clearCache=function clearCache(){this.cache={}};Writer.prototype.parse=function parse(template,tags){var cache=this.cache;var tokens=cache[template];if(tokens==null)tokens=cache[template]=parseTemplate(template,tags);return tokens};Writer.prototype.render=function render(template,view,partials){var tokens=this.parse(template);var context=view instanceof Context?view:new Context(view);return this.renderTokens(tokens,context,partials,template)};Writer.prototype.renderTokens=function renderTokens(tokens,context,partials,originalTemplate){var buffer="";var token,symbol,value;for(var i=0,numTokens=tokens.length;i<numTokens;++i){value=undefined;token=tokens[i];symbol=token[0];if(symbol==="#")value=this.renderSection(token,context,partials,originalTemplate);else if(symbol==="^")value=this.renderInverted(token,context,partials,originalTemplate);else if(symbol===">")value=this.renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this.unescapedValue(token,context);else if(symbol==="name")value=this.escapedValue(token,context);else if(symbol==="text")value=this.rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype.renderSection=function renderSection(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;j<valueLength;++j){buffer+=this.renderTokens(token[4],context.push(value[j]),partials,originalTemplate)}}else if(typeof value==="object"||typeof value==="string"||typeof value==="number"){buffer+=this.renderTokens(token[4],context.push(value),partials,originalTemplate)}else if(isFunction(value)){if(typeof originalTemplate!=="string")throw new Error("Cannot use higher-order sections without the original template");value=value.call(context.view,originalTemplate.slice(token[3],token[5]),subRender);if(value!=null)buffer+=value}else{buffer+=this.renderTokens(token[4],context,partials,originalTemplate)}return buffer};Writer.prototype.renderInverted=function renderInverted(token,context,partials,originalTemplate){var value=context.lookup(token[1]);if(!value||isArray(value)&&value.length===0)return this.renderTokens(token[4],context,partials,originalTemplate)};Writer.prototype.renderPartial=function renderPartial(token,context,partials){if(!partials)return;var value=isFunction(partials)?partials(token[1]):partials[token[1]];if(value!=null)return this.renderTokens(this.parse(value),context,partials,value)};Writer.prototype.unescapedValue=function unescapedValue(token,context){var value=context.lookup(token[1]);if(value!=null)return value};Writer.prototype.escapedValue=function escapedValue(token,context){var value=context.lookup(token[1]);if(value!=null)return mustache.escape(value)};Writer.prototype.rawValue=function rawValue(token){return token[1]};mustache.name="mustache.js";mustache.version="2.3.2";mustache.tags=["{{","}}"];var defaultWriter=new Writer;mustache.clearCache=function clearCache(){return defaultWriter.clearCache()};mustache.parse=function parse(template,tags){return defaultWriter.parse(template,tags)};mustache.render=function render(template,view,partials){if(typeof template!=="string"){throw new TypeError('Invalid template! Template should be a "string" '+'but "'+typeStr(template)+'" was given as the first '+"argument for mustache#render(template, view, partials)")}return defaultWriter.render(template,view,partials)};mustache.to_html=function to_html(template,view,partials,send){var result=mustache.render(template,view,partials);if(isFunction(send)){send(result)}else{return result}};mustache.escape=escapeHtml;mustache.Scanner=Scanner;mustache.Context=Context;mustache.Writer=Writer;return mustache});
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImpxdWVyeS1taWdyYXRlLmpzIiwicGFjZS5qcyIsInNyY2RvYy1wb2x5ZmlsbC5qcyIsImpxdWVyeS11aS5qcyIsIm11c3RhY2hlLm1pbi5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNodkJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3Y2QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2xGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2p4a0JBO0FBQ0EiLCJmaWxlIjoiY29tcGF0aWJpbGl0eS12ZW5kb3IuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiFcclxuICogalF1ZXJ5IE1pZ3JhdGUgLSB2MS40LjEgLSAyMDE2LTA1LTE5XHJcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXHJcbiAqL1xyXG4oZnVuY3Rpb24oIGpRdWVyeSwgd2luZG93LCB1bmRlZmluZWQgKSB7XG4vLyBTZWUgaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTMzMzVcbi8vIFwidXNlIHN0cmljdFwiO1xuXHJcblxualF1ZXJ5Lm1pZ3JhdGVWZXJzaW9uID0gXCIxLjQuMVwiO1xuXHJcblxudmFyIHdhcm5lZEFib3V0ID0ge307XG5cbi8vIExpc3Qgb2Ygd2FybmluZ3MgYWxyZWFkeSBnaXZlbjsgcHVibGljIHJlYWQgb25seVxualF1ZXJ5Lm1pZ3JhdGVXYXJuaW5ncyA9IFtdO1xuXG4vLyBTZXQgdG8gdHJ1ZSB0byBwcmV2ZW50IGNvbnNvbGUgb3V0cHV0OyBtaWdyYXRlV2FybmluZ3Mgc3RpbGwgbWFpbnRhaW5lZFxuLy8galF1ZXJ5Lm1pZ3JhdGVNdXRlID0gZmFsc2U7XG5cbi8vIFNob3cgYSBtZXNzYWdlIG9uIHRoZSBjb25zb2xlIHNvIGRldnMga25vdyB3ZSdyZSBhY3RpdmVcbmlmICggd2luZG93LmNvbnNvbGUgJiYgd2luZG93LmNvbnNvbGUubG9nICkge1xuXHR3aW5kb3cuY29uc29sZS5sb2coIFwiSlFNSUdSQVRFOiBNaWdyYXRlIGlzIGluc3RhbGxlZFwiICtcblx0XHQoIGpRdWVyeS5taWdyYXRlTXV0ZSA/IFwiXCIgOiBcIiB3aXRoIGxvZ2dpbmcgYWN0aXZlXCIgKSArXG5cdFx0XCIsIHZlcnNpb24gXCIgKyBqUXVlcnkubWlncmF0ZVZlcnNpb24gKTtcbn1cblxuLy8gU2V0IHRvIGZhbHNlIHRvIGRpc2FibGUgdHJhY2VzIHRoYXQgYXBwZWFyIHdpdGggd2FybmluZ3NcbmlmICggalF1ZXJ5Lm1pZ3JhdGVUcmFjZSA9PT0gdW5kZWZpbmVkICkge1xuXHRqUXVlcnkubWlncmF0ZVRyYWNlID0gdHJ1ZTtcbn1cblxuLy8gRm9yZ2V0IGFueSB3YXJuaW5ncyB3ZSd2ZSBhbHJlYWR5IGdpdmVuOyBwdWJsaWNcbmpRdWVyeS5taWdyYXRlUmVzZXQgPSBmdW5jdGlvbigpIHtcblx0d2FybmVkQWJvdXQgPSB7fTtcblx0alF1ZXJ5Lm1pZ3JhdGVXYXJuaW5ncy5sZW5ndGggPSAwO1xufTtcblxuZnVuY3Rpb24gbWlncmF0ZVdhcm4oIG1zZykge1xuXHR2YXIgY29uc29sZSA9IHdpbmRvdy5jb25zb2xlO1xuXHRpZiAoICF3YXJuZWRBYm91dFsgbXNnIF0gKSB7XG5cdFx0d2FybmVkQWJvdXRbIG1zZyBdID0gdHJ1ZTtcblx0XHRqUXVlcnkubWlncmF0ZVdhcm5pbmdzLnB1c2goIG1zZyApO1xuXHRcdGlmICggY29uc29sZSAmJiBjb25zb2xlLndhcm4gJiYgIWpRdWVyeS5taWdyYXRlTXV0ZSApIHtcblx0XHRcdGNvbnNvbGUud2FybiggXCJKUU1JR1JBVEU6IFwiICsgbXNnICk7XG5cdFx0XHRpZiAoIGpRdWVyeS5taWdyYXRlVHJhY2UgJiYgY29uc29sZS50cmFjZSApIHtcblx0XHRcdFx0Y29uc29sZS50cmFjZSgpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBtaWdyYXRlV2FyblByb3AoIG9iaiwgcHJvcCwgdmFsdWUsIG1zZyApIHtcblx0aWYgKCBPYmplY3QuZGVmaW5lUHJvcGVydHkgKSB7XG5cdFx0Ly8gT24gRVM1IGJyb3dzZXJzIChub24tb2xkSUUpLCB3YXJuIGlmIHRoZSBjb2RlIHRyaWVzIHRvIGdldCBwcm9wO1xuXHRcdC8vIGFsbG93IHByb3BlcnR5IHRvIGJlIG92ZXJ3cml0dGVuIGluIGNhc2Ugc29tZSBvdGhlciBwbHVnaW4gd2FudHMgaXRcblx0XHR0cnkge1xuXHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCBvYmosIHByb3AsIHtcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdG1pZ3JhdGVXYXJuKCBtc2cgKTtcblx0XHRcdFx0XHRyZXR1cm4gdmFsdWU7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHNldDogZnVuY3Rpb24oIG5ld1ZhbHVlICkge1xuXHRcdFx0XHRcdG1pZ3JhdGVXYXJuKCBtc2cgKTtcblx0XHRcdFx0XHR2YWx1ZSA9IG5ld1ZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9KTtcblx0XHRcdHJldHVybjtcblx0XHR9IGNhdGNoKCBlcnIgKSB7XG5cdFx0XHQvLyBJRTggaXMgYSBkb3BlIGFib3V0IE9iamVjdC5kZWZpbmVQcm9wZXJ0eSwgY2FuJ3Qgd2FybiB0aGVyZVxuXHRcdH1cblx0fVxuXG5cdC8vIE5vbi1FUzUgKG9yIGJyb2tlbikgYnJvd3NlcjsganVzdCBzZXQgdGhlIHByb3BlcnR5XG5cdGpRdWVyeS5fZGVmaW5lUHJvcGVydHlCcm9rZW4gPSB0cnVlO1xuXHRvYmpbIHByb3AgXSA9IHZhbHVlO1xufVxuXG5pZiAoIGRvY3VtZW50LmNvbXBhdE1vZGUgPT09IFwiQmFja0NvbXBhdFwiICkge1xuXHQvLyBqUXVlcnkgaGFzIG5ldmVyIHN1cHBvcnRlZCBvciB0ZXN0ZWQgUXVpcmtzIE1vZGVcblx0bWlncmF0ZVdhcm4oIFwialF1ZXJ5IGlzIG5vdCBjb21wYXRpYmxlIHdpdGggUXVpcmtzIE1vZGVcIiApO1xufVxuXHJcblxudmFyIGF0dHJGbiA9IGpRdWVyeSggXCI8aW5wdXQvPlwiLCB7IHNpemU6IDEgfSApLmF0dHIoXCJzaXplXCIpICYmIGpRdWVyeS5hdHRyRm4sXG5cdG9sZEF0dHIgPSBqUXVlcnkuYXR0cixcblx0dmFsdWVBdHRyR2V0ID0galF1ZXJ5LmF0dHJIb29rcy52YWx1ZSAmJiBqUXVlcnkuYXR0ckhvb2tzLnZhbHVlLmdldCB8fFxuXHRcdGZ1bmN0aW9uKCkgeyByZXR1cm4gbnVsbDsgfSxcblx0dmFsdWVBdHRyU2V0ID0galF1ZXJ5LmF0dHJIb29rcy52YWx1ZSAmJiBqUXVlcnkuYXR0ckhvb2tzLnZhbHVlLnNldCB8fFxuXHRcdGZ1bmN0aW9uKCkgeyByZXR1cm4gdW5kZWZpbmVkOyB9LFxuXHRybm9UeXBlID0gL14oPzppbnB1dHxidXR0b24pJC9pLFxuXHRybm9BdHRyTm9kZVR5cGUgPSAvXlsyMzhdJC8sXG5cdHJib29sZWFuID0gL14oPzphdXRvZm9jdXN8YXV0b3BsYXl8YXN5bmN8Y2hlY2tlZHxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZHxzZWxlY3RlZCkkL2ksXG5cdHJ1c2VEZWZhdWx0ID0gL14oPzpjaGVja2VkfHNlbGVjdGVkKSQvaTtcblxuLy8galF1ZXJ5LmF0dHJGblxubWlncmF0ZVdhcm5Qcm9wKCBqUXVlcnksIFwiYXR0ckZuXCIsIGF0dHJGbiB8fCB7fSwgXCJqUXVlcnkuYXR0ckZuIGlzIGRlcHJlY2F0ZWRcIiApO1xuXG5qUXVlcnkuYXR0ciA9IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCB2YWx1ZSwgcGFzcyApIHtcblx0dmFyIGxvd2VyTmFtZSA9IG5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRuVHlwZSA9IGVsZW0gJiYgZWxlbS5ub2RlVHlwZTtcblxuXHRpZiAoIHBhc3MgKSB7XG5cdFx0Ly8gU2luY2UgcGFzcyBpcyB1c2VkIGludGVybmFsbHksIHdlIG9ubHkgd2FybiBmb3IgbmV3IGpRdWVyeVxuXHRcdC8vIHZlcnNpb25zIHdoZXJlIHRoZXJlIGlzbid0IGEgcGFzcyBhcmcgaW4gdGhlIGZvcm1hbCBwYXJhbXNcblx0XHRpZiAoIG9sZEF0dHIubGVuZ3RoIDwgNCApIHtcblx0XHRcdG1pZ3JhdGVXYXJuKFwialF1ZXJ5LmZuLmF0dHIoIHByb3BzLCBwYXNzICkgaXMgZGVwcmVjYXRlZFwiKTtcblx0XHR9XG5cdFx0aWYgKCBlbGVtICYmICFybm9BdHRyTm9kZVR5cGUudGVzdCggblR5cGUgKSAmJlxuXHRcdFx0KGF0dHJGbiA/IG5hbWUgaW4gYXR0ckZuIDogalF1ZXJ5LmlzRnVuY3Rpb24oalF1ZXJ5LmZuW25hbWVdKSkgKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5KCBlbGVtIClbIG5hbWUgXSggdmFsdWUgKTtcblx0XHR9XG5cdH1cblxuXHQvLyBXYXJuIGlmIHVzZXIgdHJpZXMgdG8gc2V0IGB0eXBlYCwgc2luY2UgaXQgYnJlYWtzIG9uIElFIDYvNy84OyBieSBjaGVja2luZ1xuXHQvLyBmb3IgZGlzY29ubmVjdGVkIGVsZW1lbnRzIHdlIGRvbid0IHdhcm4gb24gJCggXCI8YnV0dG9uPlwiLCB7IHR5cGU6IFwiYnV0dG9uXCIgfSApLlxuXHRpZiAoIG5hbWUgPT09IFwidHlwZVwiICYmIHZhbHVlICE9PSB1bmRlZmluZWQgJiYgcm5vVHlwZS50ZXN0KCBlbGVtLm5vZGVOYW1lICkgJiYgZWxlbS5wYXJlbnROb2RlICkge1xuXHRcdG1pZ3JhdGVXYXJuKFwiQ2FuJ3QgY2hhbmdlIHRoZSAndHlwZScgb2YgYW4gaW5wdXQgb3IgYnV0dG9uIGluIElFIDYvNy84XCIpO1xuXHR9XG5cblx0Ly8gUmVzdG9yZSBib29sSG9vayBmb3IgYm9vbGVhbiBwcm9wZXJ0eS9hdHRyaWJ1dGUgc3luY2hyb25pemF0aW9uXG5cdGlmICggIWpRdWVyeS5hdHRySG9va3NbIGxvd2VyTmFtZSBdICYmIHJib29sZWFuLnRlc3QoIGxvd2VyTmFtZSApICkge1xuXHRcdGpRdWVyeS5hdHRySG9va3NbIGxvd2VyTmFtZSBdID0ge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0XHRcdFx0Ly8gQWxpZ24gYm9vbGVhbiBhdHRyaWJ1dGVzIHdpdGggY29ycmVzcG9uZGluZyBwcm9wZXJ0aWVzXG5cdFx0XHRcdC8vIEZhbGwgYmFjayB0byBhdHRyaWJ1dGUgcHJlc2VuY2Ugd2hlcmUgc29tZSBib29sZWFucyBhcmUgbm90IHN1cHBvcnRlZFxuXHRcdFx0XHR2YXIgYXR0ck5vZGUsXG5cdFx0XHRcdFx0cHJvcGVydHkgPSBqUXVlcnkucHJvcCggZWxlbSwgbmFtZSApO1xuXHRcdFx0XHRyZXR1cm4gcHJvcGVydHkgPT09IHRydWUgfHwgdHlwZW9mIHByb3BlcnR5ICE9PSBcImJvb2xlYW5cIiAmJlxuXHRcdFx0XHRcdCggYXR0ck5vZGUgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUobmFtZSkgKSAmJiBhdHRyTm9kZS5ub2RlVmFsdWUgIT09IGZhbHNlID9cblxuXHRcdFx0XHRcdG5hbWUudG9Mb3dlckNhc2UoKSA6XG5cdFx0XHRcdFx0dW5kZWZpbmVkO1xuXHRcdFx0fSxcblx0XHRcdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlLCBuYW1lICkge1xuXHRcdFx0XHR2YXIgcHJvcE5hbWU7XG5cdFx0XHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdC8vIFJlbW92ZSBib29sZWFuIGF0dHJpYnV0ZXMgd2hlbiBzZXQgdG8gZmFsc2Vcblx0XHRcdFx0XHRqUXVlcnkucmVtb3ZlQXR0ciggZWxlbSwgbmFtZSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdC8vIHZhbHVlIGlzIHRydWUgc2luY2Ugd2Uga25vdyBhdCB0aGlzIHBvaW50IGl0J3MgdHlwZSBib29sZWFuIGFuZCBub3QgZmFsc2Vcblx0XHRcdFx0XHQvLyBTZXQgYm9vbGVhbiBhdHRyaWJ1dGVzIHRvIHRoZSBzYW1lIG5hbWUgYW5kIHNldCB0aGUgRE9NIHByb3BlcnR5XG5cdFx0XHRcdFx0cHJvcE5hbWUgPSBqUXVlcnkucHJvcEZpeFsgbmFtZSBdIHx8IG5hbWU7XG5cdFx0XHRcdFx0aWYgKCBwcm9wTmFtZSBpbiBlbGVtICkge1xuXHRcdFx0XHRcdFx0Ly8gT25seSBzZXQgdGhlIElETCBzcGVjaWZpY2FsbHkgaWYgaXQgYWxyZWFkeSBleGlzdHMgb24gdGhlIGVsZW1lbnRcblx0XHRcdFx0XHRcdGVsZW1bIHByb3BOYW1lIF0gPSB0cnVlO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGVsZW0uc2V0QXR0cmlidXRlKCBuYW1lLCBuYW1lLnRvTG93ZXJDYXNlKCkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbmFtZTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly8gV2FybiBvbmx5IGZvciBhdHRyaWJ1dGVzIHRoYXQgY2FuIHJlbWFpbiBkaXN0aW5jdCBmcm9tIHRoZWlyIHByb3BlcnRpZXMgcG9zdC0xLjlcblx0XHRpZiAoIHJ1c2VEZWZhdWx0LnRlc3QoIGxvd2VyTmFtZSApICkge1xuXHRcdFx0bWlncmF0ZVdhcm4oIFwialF1ZXJ5LmZuLmF0dHIoJ1wiICsgbG93ZXJOYW1lICsgXCInKSBtaWdodCB1c2UgcHJvcGVydHkgaW5zdGVhZCBvZiBhdHRyaWJ1dGVcIiApO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBvbGRBdHRyLmNhbGwoIGpRdWVyeSwgZWxlbSwgbmFtZSwgdmFsdWUgKTtcbn07XG5cbi8vIGF0dHJIb29rczogdmFsdWVcbmpRdWVyeS5hdHRySG9va3MudmFsdWUgPSB7XG5cdGdldDogZnVuY3Rpb24oIGVsZW0sIG5hbWUgKSB7XG5cdFx0dmFyIG5vZGVOYW1lID0gKCBlbGVtLm5vZGVOYW1lIHx8IFwiXCIgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiYnV0dG9uXCIgKSB7XG5cdFx0XHRyZXR1cm4gdmFsdWVBdHRyR2V0LmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdFx0aWYgKCBub2RlTmFtZSAhPT0gXCJpbnB1dFwiICYmIG5vZGVOYW1lICE9PSBcIm9wdGlvblwiICkge1xuXHRcdFx0bWlncmF0ZVdhcm4oXCJqUXVlcnkuZm4uYXR0cigndmFsdWUnKSBubyBsb25nZXIgZ2V0cyBwcm9wZXJ0aWVzXCIpO1xuXHRcdH1cblx0XHRyZXR1cm4gbmFtZSBpbiBlbGVtID9cblx0XHRcdGVsZW0udmFsdWUgOlxuXHRcdFx0bnVsbDtcblx0fSxcblx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7XG5cdFx0dmFyIG5vZGVOYW1lID0gKCBlbGVtLm5vZGVOYW1lIHx8IFwiXCIgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiYnV0dG9uXCIgKSB7XG5cdFx0XHRyZXR1cm4gdmFsdWVBdHRyU2V0LmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdFx0aWYgKCBub2RlTmFtZSAhPT0gXCJpbnB1dFwiICYmIG5vZGVOYW1lICE9PSBcIm9wdGlvblwiICkge1xuXHRcdFx0bWlncmF0ZVdhcm4oXCJqUXVlcnkuZm4uYXR0cigndmFsdWUnLCB2YWwpIG5vIGxvbmdlciBzZXRzIHByb3BlcnRpZXNcIik7XG5cdFx0fVxuXHRcdC8vIERvZXMgbm90IHJldHVybiBzbyB0aGF0IHNldEF0dHJpYnV0ZSBpcyBhbHNvIHVzZWRcblx0XHRlbGVtLnZhbHVlID0gdmFsdWU7XG5cdH1cbn07XG5cclxuXG52YXIgbWF0Y2hlZCwgYnJvd3Nlcixcblx0b2xkSW5pdCA9IGpRdWVyeS5mbi5pbml0LFxuXHRvbGRGaW5kID0galF1ZXJ5LmZpbmQsXG5cdG9sZFBhcnNlSlNPTiA9IGpRdWVyeS5wYXJzZUpTT04sXG5cdHJzcGFjZUFuZ2xlID0gL15cXHMqPC8sXG5cdHJhdHRySGFzaFRlc3QgPSAvXFxbKFxccypbLVxcd10rXFxzKikoW358XiQqXT89KVxccyooWy1cXHcjXSo/I1stXFx3I10qKVxccypcXF0vLFxuXHRyYXR0ckhhc2hHbG9iID0gL1xcWyhcXHMqWy1cXHddK1xccyopKFt+fF4kKl0/PSlcXHMqKFstXFx3I10qPyNbLVxcdyNdKilcXHMqXFxdL2csXG5cdC8vIE5vdGU6IFhTUyBjaGVjayBpcyBkb25lIGJlbG93IGFmdGVyIHN0cmluZyBpcyB0cmltbWVkXG5cdHJxdWlja0V4cHIgPSAvXihbXjxdKikoPFtcXHdcXFddKz4pKFtePl0qKSQvO1xuXG4vLyAkKGh0bWwpIFwibG9va3MgbGlrZSBodG1sXCIgcnVsZSBjaGFuZ2VcbmpRdWVyeS5mbi5pbml0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByb290alF1ZXJ5ICkge1xuXHR2YXIgbWF0Y2gsIHJldDtcblxuXHRpZiAoIHNlbGVjdG9yICYmIHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRpZiAoICFqUXVlcnkuaXNQbGFpbk9iamVjdCggY29udGV4dCApICYmXG5cdFx0XHRcdChtYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggalF1ZXJ5LnRyaW0oIHNlbGVjdG9yICkgKSkgJiYgbWF0Y2hbIDAgXSApIHtcblxuXHRcdFx0Ly8gVGhpcyBpcyBhbiBIVE1MIHN0cmluZyBhY2NvcmRpbmcgdG8gdGhlIFwib2xkXCIgcnVsZXM7IGlzIGl0IHN0aWxsP1xuXHRcdFx0aWYgKCAhcnNwYWNlQW5nbGUudGVzdCggc2VsZWN0b3IgKSApIHtcblx0XHRcdFx0bWlncmF0ZVdhcm4oXCIkKGh0bWwpIEhUTUwgc3RyaW5ncyBtdXN0IHN0YXJ0IHdpdGggJzwnIGNoYXJhY3RlclwiKTtcblx0XHRcdH1cblx0XHRcdGlmICggbWF0Y2hbIDMgXSApIHtcblx0XHRcdFx0bWlncmF0ZVdhcm4oXCIkKGh0bWwpIEhUTUwgdGV4dCBhZnRlciBsYXN0IHRhZyBpcyBpZ25vcmVkXCIpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDb25zaXN0ZW50bHkgcmVqZWN0IGFueSBIVE1MLWxpa2Ugc3RyaW5nIHN0YXJ0aW5nIHdpdGggYSBoYXNoIChnaC05NTIxKVxuXHRcdFx0Ly8gTm90ZSB0aGF0IHRoaXMgbWF5IGJyZWFrIGpRdWVyeSAxLjYueCBjb2RlIHRoYXQgb3RoZXJ3aXNlIHdvdWxkIHdvcmsuXG5cdFx0XHRpZiAoIG1hdGNoWyAwIF0uY2hhckF0KCAwICkgPT09IFwiI1wiICkge1xuXHRcdFx0XHRtaWdyYXRlV2FybihcIkhUTUwgc3RyaW5nIGNhbm5vdCBzdGFydCB3aXRoIGEgJyMnIGNoYXJhY3RlclwiKTtcblx0XHRcdFx0alF1ZXJ5LmVycm9yKFwiSlFNSUdSQVRFOiBJbnZhbGlkIHNlbGVjdG9yIHN0cmluZyAoWFNTKVwiKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTm93IHByb2Nlc3MgdXNpbmcgbG9vc2UgcnVsZXM7IGxldCBwcmUtMS44IHBsYXkgdG9vXG5cdFx0XHQvLyBJcyB0aGlzIGEgalF1ZXJ5IGNvbnRleHQ/IHBhcnNlSFRNTCBleHBlY3RzIGEgRE9NIGVsZW1lbnQgKCMxNzgpXG5cdFx0XHRpZiAoIGNvbnRleHQgJiYgY29udGV4dC5jb250ZXh0ICYmIGNvbnRleHQuY29udGV4dC5ub2RlVHlwZSApIHtcblx0XHRcdFx0Y29udGV4dCA9IGNvbnRleHQuY29udGV4dDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBqUXVlcnkucGFyc2VIVE1MICkge1xuXHRcdFx0XHRyZXR1cm4gb2xkSW5pdC5jYWxsKCB0aGlzLFxuXHRcdFx0XHRcdFx0alF1ZXJ5LnBhcnNlSFRNTCggbWF0Y2hbIDIgXSwgY29udGV4dCAmJiBjb250ZXh0Lm93bmVyRG9jdW1lbnQgfHxcblx0XHRcdFx0XHRcdFx0Y29udGV4dCB8fCBkb2N1bWVudCwgdHJ1ZSApLCBjb250ZXh0LCByb290alF1ZXJ5ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0ID0gb2xkSW5pdC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cblx0Ly8gRmlsbCBpbiBzZWxlY3RvciBhbmQgY29udGV4dCBwcm9wZXJ0aWVzIHNvIC5saXZlKCkgd29ya3Ncblx0aWYgKCBzZWxlY3RvciAmJiBzZWxlY3Rvci5zZWxlY3RvciAhPT0gdW5kZWZpbmVkICkge1xuXHRcdC8vIEEgalF1ZXJ5IG9iamVjdCwgY29weSBpdHMgcHJvcGVydGllc1xuXHRcdHJldC5zZWxlY3RvciA9IHNlbGVjdG9yLnNlbGVjdG9yO1xuXHRcdHJldC5jb250ZXh0ID0gc2VsZWN0b3IuY29udGV4dDtcblxuXHR9IGVsc2Uge1xuXHRcdHJldC5zZWxlY3RvciA9IHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiA/IHNlbGVjdG9yIDogXCJcIjtcblx0XHRpZiAoIHNlbGVjdG9yICkge1xuXHRcdFx0cmV0LmNvbnRleHQgPSBzZWxlY3Rvci5ub2RlVHlwZT8gc2VsZWN0b3IgOiBjb250ZXh0IHx8IGRvY3VtZW50O1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiByZXQ7XG59O1xualF1ZXJ5LmZuLmluaXQucHJvdG90eXBlID0galF1ZXJ5LmZuO1xuXG5qUXVlcnkuZmluZCA9IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0dmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggYXJndW1lbnRzICk7XG5cblx0Ly8gU3VwcG9ydDogUGhhbnRvbUpTIDEueFxuXHQvLyBTdHJpbmcjbWF0Y2ggZmFpbHMgdG8gbWF0Y2ggd2hlbiB1c2VkIHdpdGggYSAvL2cgUmVnRXhwLCBvbmx5IG9uIHNvbWUgc3RyaW5nc1xuXHRpZiAoIHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiAmJiByYXR0ckhhc2hUZXN0LnRlc3QoIHNlbGVjdG9yICkgKSB7XG5cblx0XHQvLyBUaGUgbm9uc3RhbmRhcmQgYW5kIHVuZG9jdW1lbnRlZCB1bnF1b3RlZC1oYXNoIHdhcyByZW1vdmVkIGluIGpRdWVyeSAxLjEyLjBcblx0XHQvLyBGaXJzdCBzZWUgaWYgcVMgdGhpbmtzIGl0J3MgYSB2YWxpZCBzZWxlY3RvciwgaWYgc28gYXZvaWQgYSBmYWxzZSBwb3NpdGl2ZVxuXHRcdHRyeSB7XG5cdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCBzZWxlY3RvciApO1xuXHRcdH0gY2F0Y2ggKCBlcnIxICkge1xuXG5cdFx0XHQvLyBEaWRuJ3QgKmxvb2sqIHZhbGlkIHRvIHFTQSwgd2FybiBhbmQgdHJ5IHF1b3Rpbmcgd2hhdCB3ZSB0aGluayBpcyB0aGUgdmFsdWVcblx0XHRcdHNlbGVjdG9yID0gc2VsZWN0b3IucmVwbGFjZSggcmF0dHJIYXNoR2xvYiwgZnVuY3Rpb24oIF8sIGF0dHIsIG9wLCB2YWx1ZSApIHtcblx0XHRcdFx0cmV0dXJuIFwiW1wiICsgYXR0ciArIG9wICsgXCJcXFwiXCIgKyB2YWx1ZSArIFwiXFxcIl1cIjtcblx0XHRcdH0gKTtcblxuXHRcdFx0Ly8gSWYgdGhlIHJlZ2V4cCAqbWF5KiBoYXZlIGNyZWF0ZWQgYW4gaW52YWxpZCBzZWxlY3RvciwgZG9uJ3QgdXBkYXRlIGl0XG5cdFx0XHQvLyBOb3RlIHRoYXQgdGhlcmUgbWF5IGJlIGZhbHNlIGFsYXJtcyBpZiBzZWxlY3RvciB1c2VzIGpRdWVyeSBleHRlbnNpb25zXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRkb2N1bWVudC5xdWVyeVNlbGVjdG9yKCBzZWxlY3RvciApO1xuXHRcdFx0XHRtaWdyYXRlV2FybiggXCJBdHRyaWJ1dGUgc2VsZWN0b3Igd2l0aCAnIycgbXVzdCBiZSBxdW90ZWQ6IFwiICsgYXJnc1sgMCBdICk7XG5cdFx0XHRcdGFyZ3NbIDAgXSA9IHNlbGVjdG9yO1xuXHRcdFx0fSBjYXRjaCAoIGVycjIgKSB7XG5cdFx0XHRcdG1pZ3JhdGVXYXJuKCBcIkF0dHJpYnV0ZSBzZWxlY3RvciB3aXRoICcjJyB3YXMgbm90IGZpeGVkOiBcIiArIGFyZ3NbIDAgXSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBvbGRGaW5kLmFwcGx5KCB0aGlzLCBhcmdzICk7XG59O1xuXG4vLyBDb3B5IHByb3BlcnRpZXMgYXR0YWNoZWQgdG8gb3JpZ2luYWwgalF1ZXJ5LmZpbmQgbWV0aG9kIChlLmcuIC5hdHRyLCAuaXNYTUwpXG52YXIgZmluZFByb3A7XG5mb3IgKCBmaW5kUHJvcCBpbiBvbGRGaW5kICkge1xuXHRpZiAoIE9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCggb2xkRmluZCwgZmluZFByb3AgKSApIHtcblx0XHRqUXVlcnkuZmluZFsgZmluZFByb3AgXSA9IG9sZEZpbmRbIGZpbmRQcm9wIF07XG5cdH1cbn1cblxuLy8gTGV0ICQucGFyc2VKU09OKGZhbHN5X3ZhbHVlKSByZXR1cm4gbnVsbFxualF1ZXJ5LnBhcnNlSlNPTiA9IGZ1bmN0aW9uKCBqc29uICkge1xuXHRpZiAoICFqc29uICkge1xuXHRcdG1pZ3JhdGVXYXJuKFwialF1ZXJ5LnBhcnNlSlNPTiByZXF1aXJlcyBhIHZhbGlkIEpTT04gc3RyaW5nXCIpO1xuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cdHJldHVybiBvbGRQYXJzZUpTT04uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xufTtcblxualF1ZXJ5LnVhTWF0Y2ggPSBmdW5jdGlvbiggdWEgKSB7XG5cdHVhID0gdWEudG9Mb3dlckNhc2UoKTtcblxuXHR2YXIgbWF0Y2ggPSAvKGNocm9tZSlbIFxcL10oW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcblx0XHQvKHdlYmtpdClbIFxcL10oW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcblx0XHQvKG9wZXJhKSg/Oi4qdmVyc2lvbnwpWyBcXC9dKFtcXHcuXSspLy5leGVjKCB1YSApIHx8XG5cdFx0Lyhtc2llKSAoW1xcdy5dKykvLmV4ZWMoIHVhICkgfHxcblx0XHR1YS5pbmRleE9mKFwiY29tcGF0aWJsZVwiKSA8IDAgJiYgLyhtb3ppbGxhKSg/Oi4qPyBydjooW1xcdy5dKyl8KS8uZXhlYyggdWEgKSB8fFxuXHRcdFtdO1xuXG5cdHJldHVybiB7XG5cdFx0YnJvd3NlcjogbWF0Y2hbIDEgXSB8fCBcIlwiLFxuXHRcdHZlcnNpb246IG1hdGNoWyAyIF0gfHwgXCIwXCJcblx0fTtcbn07XG5cbi8vIERvbid0IGNsb2JiZXIgYW55IGV4aXN0aW5nIGpRdWVyeS5icm93c2VyIGluIGNhc2UgaXQncyBkaWZmZXJlbnRcbmlmICggIWpRdWVyeS5icm93c2VyICkge1xuXHRtYXRjaGVkID0galF1ZXJ5LnVhTWF0Y2goIG5hdmlnYXRvci51c2VyQWdlbnQgKTtcblx0YnJvd3NlciA9IHt9O1xuXG5cdGlmICggbWF0Y2hlZC5icm93c2VyICkge1xuXHRcdGJyb3dzZXJbIG1hdGNoZWQuYnJvd3NlciBdID0gdHJ1ZTtcblx0XHRicm93c2VyLnZlcnNpb24gPSBtYXRjaGVkLnZlcnNpb247XG5cdH1cblxuXHQvLyBDaHJvbWUgaXMgV2Via2l0LCBidXQgV2Via2l0IGlzIGFsc28gU2FmYXJpLlxuXHRpZiAoIGJyb3dzZXIuY2hyb21lICkge1xuXHRcdGJyb3dzZXIud2Via2l0ID0gdHJ1ZTtcblx0fSBlbHNlIGlmICggYnJvd3Nlci53ZWJraXQgKSB7XG5cdFx0YnJvd3Nlci5zYWZhcmkgPSB0cnVlO1xuXHR9XG5cblx0alF1ZXJ5LmJyb3dzZXIgPSBicm93c2VyO1xufVxuXG4vLyBXYXJuIGlmIHRoZSBjb2RlIHRyaWVzIHRvIGdldCBqUXVlcnkuYnJvd3NlclxubWlncmF0ZVdhcm5Qcm9wKCBqUXVlcnksIFwiYnJvd3NlclwiLCBqUXVlcnkuYnJvd3NlciwgXCJqUXVlcnkuYnJvd3NlciBpcyBkZXByZWNhdGVkXCIgKTtcblxuLy8galF1ZXJ5LmJveE1vZGVsIGRlcHJlY2F0ZWQgaW4gMS4zLCBqUXVlcnkuc3VwcG9ydC5ib3hNb2RlbCBkZXByZWNhdGVkIGluIDEuN1xualF1ZXJ5LmJveE1vZGVsID0galF1ZXJ5LnN1cHBvcnQuYm94TW9kZWwgPSAoZG9jdW1lbnQuY29tcGF0TW9kZSA9PT0gXCJDU1MxQ29tcGF0XCIpO1xubWlncmF0ZVdhcm5Qcm9wKCBqUXVlcnksIFwiYm94TW9kZWxcIiwgalF1ZXJ5LmJveE1vZGVsLCBcImpRdWVyeS5ib3hNb2RlbCBpcyBkZXByZWNhdGVkXCIgKTtcbm1pZ3JhdGVXYXJuUHJvcCggalF1ZXJ5LnN1cHBvcnQsIFwiYm94TW9kZWxcIiwgalF1ZXJ5LnN1cHBvcnQuYm94TW9kZWwsIFwialF1ZXJ5LnN1cHBvcnQuYm94TW9kZWwgaXMgZGVwcmVjYXRlZFwiICk7XG5cbmpRdWVyeS5zdWIgPSBmdW5jdGlvbigpIHtcblx0ZnVuY3Rpb24galF1ZXJ5U3ViKCBzZWxlY3RvciwgY29udGV4dCApIHtcblx0XHRyZXR1cm4gbmV3IGpRdWVyeVN1Yi5mbi5pbml0KCBzZWxlY3RvciwgY29udGV4dCApO1xuXHR9XG5cdGpRdWVyeS5leHRlbmQoIHRydWUsIGpRdWVyeVN1YiwgdGhpcyApO1xuXHRqUXVlcnlTdWIuc3VwZXJjbGFzcyA9IHRoaXM7XG5cdGpRdWVyeVN1Yi5mbiA9IGpRdWVyeVN1Yi5wcm90b3R5cGUgPSB0aGlzKCk7XG5cdGpRdWVyeVN1Yi5mbi5jb25zdHJ1Y3RvciA9IGpRdWVyeVN1Yjtcblx0alF1ZXJ5U3ViLnN1YiA9IHRoaXMuc3ViO1xuXHRqUXVlcnlTdWIuZm4uaW5pdCA9IGZ1bmN0aW9uIGluaXQoIHNlbGVjdG9yLCBjb250ZXh0ICkge1xuXHRcdHZhciBpbnN0YW5jZSA9IGpRdWVyeS5mbi5pbml0LmNhbGwoIHRoaXMsIHNlbGVjdG9yLCBjb250ZXh0LCByb290alF1ZXJ5U3ViICk7XG5cdFx0cmV0dXJuIGluc3RhbmNlIGluc3RhbmNlb2YgalF1ZXJ5U3ViID9cblx0XHRcdGluc3RhbmNlIDpcblx0XHRcdGpRdWVyeVN1YiggaW5zdGFuY2UgKTtcblx0fTtcblx0alF1ZXJ5U3ViLmZuLmluaXQucHJvdG90eXBlID0galF1ZXJ5U3ViLmZuO1xuXHR2YXIgcm9vdGpRdWVyeVN1YiA9IGpRdWVyeVN1Yihkb2N1bWVudCk7XG5cdG1pZ3JhdGVXYXJuKCBcImpRdWVyeS5zdWIoKSBpcyBkZXByZWNhdGVkXCIgKTtcblx0cmV0dXJuIGpRdWVyeVN1Yjtcbn07XG5cbi8vIFRoZSBudW1iZXIgb2YgZWxlbWVudHMgY29udGFpbmVkIGluIHRoZSBtYXRjaGVkIGVsZW1lbnQgc2V0XG5qUXVlcnkuZm4uc2l6ZSA9IGZ1bmN0aW9uKCkge1xuXHRtaWdyYXRlV2FybiggXCJqUXVlcnkuZm4uc2l6ZSgpIGlzIGRlcHJlY2F0ZWQ7IHVzZSB0aGUgLmxlbmd0aCBwcm9wZXJ0eVwiICk7XG5cdHJldHVybiB0aGlzLmxlbmd0aDtcbn07XG5cclxuXG52YXIgaW50ZXJuYWxTd2FwQ2FsbCA9IGZhbHNlO1xuXG4vLyBJZiB0aGlzIHZlcnNpb24gb2YgalF1ZXJ5IGhhcyAuc3dhcCgpLCBkb24ndCBmYWxzZS1hbGFybSBvbiBpbnRlcm5hbCB1c2VzXG5pZiAoIGpRdWVyeS5zd2FwICkge1xuXHRqUXVlcnkuZWFjaCggWyBcImhlaWdodFwiLCBcIndpZHRoXCIsIFwicmVsaWFibGVNYXJnaW5SaWdodFwiIF0sIGZ1bmN0aW9uKCBfLCBuYW1lICkge1xuXHRcdHZhciBvbGRIb29rID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gJiYgalF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0uZ2V0O1xuXG5cdFx0aWYgKCBvbGRIb29rICkge1xuXHRcdFx0alF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0uZ2V0ID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciByZXQ7XG5cblx0XHRcdFx0aW50ZXJuYWxTd2FwQ2FsbCA9IHRydWU7XG5cdFx0XHRcdHJldCA9IG9sZEhvb2suYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRpbnRlcm5hbFN3YXBDYWxsID0gZmFsc2U7XG5cdFx0XHRcdHJldHVybiByZXQ7XG5cdFx0XHR9O1xuXHRcdH1cblx0fSk7XG59XG5cbmpRdWVyeS5zd2FwID0gZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIGNhbGxiYWNrLCBhcmdzICkge1xuXHR2YXIgcmV0LCBuYW1lLFxuXHRcdG9sZCA9IHt9O1xuXG5cdGlmICggIWludGVybmFsU3dhcENhbGwgKSB7XG5cdFx0bWlncmF0ZVdhcm4oIFwialF1ZXJ5LnN3YXAoKSBpcyB1bmRvY3VtZW50ZWQgYW5kIGRlcHJlY2F0ZWRcIiApO1xuXHR9XG5cblx0Ly8gUmVtZW1iZXIgdGhlIG9sZCB2YWx1ZXMsIGFuZCBpbnNlcnQgdGhlIG5ldyBvbmVzXG5cdGZvciAoIG5hbWUgaW4gb3B0aW9ucyApIHtcblx0XHRvbGRbIG5hbWUgXSA9IGVsZW0uc3R5bGVbIG5hbWUgXTtcblx0XHRlbGVtLnN0eWxlWyBuYW1lIF0gPSBvcHRpb25zWyBuYW1lIF07XG5cdH1cblxuXHRyZXQgPSBjYWxsYmFjay5hcHBseSggZWxlbSwgYXJncyB8fCBbXSApO1xuXG5cdC8vIFJldmVydCB0aGUgb2xkIHZhbHVlc1xuXHRmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7XG5cdFx0ZWxlbS5zdHlsZVsgbmFtZSBdID0gb2xkWyBuYW1lIF07XG5cdH1cblxuXHRyZXR1cm4gcmV0O1xufTtcblxyXG5cbi8vIEVuc3VyZSB0aGF0ICQuYWpheCBnZXRzIHRoZSBuZXcgcGFyc2VKU09OIGRlZmluZWQgaW4gY29yZS5qc1xualF1ZXJ5LmFqYXhTZXR1cCh7XG5cdGNvbnZlcnRlcnM6IHtcblx0XHRcInRleHQganNvblwiOiBqUXVlcnkucGFyc2VKU09OXG5cdH1cbn0pO1xuXHJcblxudmFyIG9sZEZuRGF0YSA9IGpRdWVyeS5mbi5kYXRhO1xuXG5qUXVlcnkuZm4uZGF0YSA9IGZ1bmN0aW9uKCBuYW1lICkge1xuXHR2YXIgcmV0LCBldnQsXG5cdFx0ZWxlbSA9IHRoaXNbMF07XG5cblx0Ly8gSGFuZGxlcyAxLjcgd2hpY2ggaGFzIHRoaXMgYmVoYXZpb3IgYW5kIDEuOCB3aGljaCBkb2Vzbid0XG5cdGlmICggZWxlbSAmJiBuYW1lID09PSBcImV2ZW50c1wiICYmIGFyZ3VtZW50cy5sZW5ndGggPT09IDEgKSB7XG5cdFx0cmV0ID0galF1ZXJ5LmRhdGEoIGVsZW0sIG5hbWUgKTtcblx0XHRldnQgPSBqUXVlcnkuX2RhdGEoIGVsZW0sIG5hbWUgKTtcblx0XHRpZiAoICggcmV0ID09PSB1bmRlZmluZWQgfHwgcmV0ID09PSBldnQgKSAmJiBldnQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdG1pZ3JhdGVXYXJuKFwiVXNlIG9mIGpRdWVyeS5mbi5kYXRhKCdldmVudHMnKSBpcyBkZXByZWNhdGVkXCIpO1xuXHRcdFx0cmV0dXJuIGV2dDtcblx0XHR9XG5cdH1cblx0cmV0dXJuIG9sZEZuRGF0YS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG59O1xuXHJcblxudmFyIHJzY3JpcHRUeXBlID0gL1xcLyhqYXZhfGVjbWEpc2NyaXB0L2k7XG5cbi8vIFNpbmNlIGpRdWVyeS5jbGVhbiBpcyB1c2VkIGludGVybmFsbHkgb24gb2xkZXIgdmVyc2lvbnMsIHdlIG9ubHkgc2hpbSBpZiBpdCdzIG1pc3NpbmdcbmlmICggIWpRdWVyeS5jbGVhbiApIHtcblx0alF1ZXJ5LmNsZWFuID0gZnVuY3Rpb24oIGVsZW1zLCBjb250ZXh0LCBmcmFnbWVudCwgc2NyaXB0cyApIHtcblx0XHQvLyBTZXQgY29udGV4dCBwZXIgMS44IGxvZ2ljXG5cdFx0Y29udGV4dCA9IGNvbnRleHQgfHwgZG9jdW1lbnQ7XG5cdFx0Y29udGV4dCA9ICFjb250ZXh0Lm5vZGVUeXBlICYmIGNvbnRleHRbMF0gfHwgY29udGV4dDtcblx0XHRjb250ZXh0ID0gY29udGV4dC5vd25lckRvY3VtZW50IHx8IGNvbnRleHQ7XG5cblx0XHRtaWdyYXRlV2FybihcImpRdWVyeS5jbGVhbigpIGlzIGRlcHJlY2F0ZWRcIik7XG5cblx0XHR2YXIgaSwgZWxlbSwgaGFuZGxlU2NyaXB0LCBqc1RhZ3MsXG5cdFx0XHRyZXQgPSBbXTtcblxuXHRcdGpRdWVyeS5tZXJnZSggcmV0LCBqUXVlcnkuYnVpbGRGcmFnbWVudCggZWxlbXMsIGNvbnRleHQgKS5jaGlsZE5vZGVzICk7XG5cblx0XHQvLyBDb21wbGV4IGxvZ2ljIGxpZnRlZCBkaXJlY3RseSBmcm9tIGpRdWVyeSAxLjhcblx0XHRpZiAoIGZyYWdtZW50ICkge1xuXHRcdFx0Ly8gU3BlY2lhbCBoYW5kbGluZyBvZiBlYWNoIHNjcmlwdCBlbGVtZW50XG5cdFx0XHRoYW5kbGVTY3JpcHQgPSBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0Ly8gQ2hlY2sgaWYgd2UgY29uc2lkZXIgaXQgZXhlY3V0YWJsZVxuXHRcdFx0XHRpZiAoICFlbGVtLnR5cGUgfHwgcnNjcmlwdFR5cGUudGVzdCggZWxlbS50eXBlICkgKSB7XG5cdFx0XHRcdFx0Ly8gRGV0YWNoIHRoZSBzY3JpcHQgYW5kIHN0b3JlIGl0IGluIHRoZSBzY3JpcHRzIGFycmF5IChpZiBwcm92aWRlZCkgb3IgdGhlIGZyYWdtZW50XG5cdFx0XHRcdFx0Ly8gUmV0dXJuIHRydXRoeSB0byBpbmRpY2F0ZSB0aGF0IGl0IGhhcyBiZWVuIGhhbmRsZWRcblx0XHRcdFx0XHRyZXR1cm4gc2NyaXB0cyA/XG5cdFx0XHRcdFx0XHRzY3JpcHRzLnB1c2goIGVsZW0ucGFyZW50Tm9kZSA/IGVsZW0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggZWxlbSApIDogZWxlbSApIDpcblx0XHRcdFx0XHRcdGZyYWdtZW50LmFwcGVuZENoaWxkKCBlbGVtICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRcdGZvciAoIGkgPSAwOyAoZWxlbSA9IHJldFtpXSkgIT0gbnVsbDsgaSsrICkge1xuXHRcdFx0XHQvLyBDaGVjayBpZiB3ZSdyZSBkb25lIGFmdGVyIGhhbmRsaW5nIGFuIGV4ZWN1dGFibGUgc2NyaXB0XG5cdFx0XHRcdGlmICggISggalF1ZXJ5Lm5vZGVOYW1lKCBlbGVtLCBcInNjcmlwdFwiICkgJiYgaGFuZGxlU2NyaXB0KCBlbGVtICkgKSApIHtcblx0XHRcdFx0XHQvLyBBcHBlbmQgdG8gZnJhZ21lbnQgYW5kIGhhbmRsZSBlbWJlZGRlZCBzY3JpcHRzXG5cdFx0XHRcdFx0ZnJhZ21lbnQuYXBwZW5kQ2hpbGQoIGVsZW0gKTtcblx0XHRcdFx0XHRpZiAoIHR5cGVvZiBlbGVtLmdldEVsZW1lbnRzQnlUYWdOYW1lICE9PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdFx0XHRcdFx0Ly8gaGFuZGxlU2NyaXB0IGFsdGVycyB0aGUgRE9NLCBzbyB1c2UgalF1ZXJ5Lm1lcmdlIHRvIGVuc3VyZSBzbmFwc2hvdCBpdGVyYXRpb25cblx0XHRcdFx0XHRcdGpzVGFncyA9IGpRdWVyeS5ncmVwKCBqUXVlcnkubWVyZ2UoIFtdLCBlbGVtLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwic2NyaXB0XCIpICksIGhhbmRsZVNjcmlwdCApO1xuXG5cdFx0XHRcdFx0XHQvLyBTcGxpY2UgdGhlIHNjcmlwdHMgaW50byByZXQgYWZ0ZXIgdGhlaXIgZm9ybWVyIGFuY2VzdG9yIGFuZCBhZHZhbmNlIG91ciBpbmRleCBiZXlvbmQgdGhlbVxuXHRcdFx0XHRcdFx0cmV0LnNwbGljZS5hcHBseSggcmV0LCBbaSArIDEsIDBdLmNvbmNhdCgganNUYWdzICkgKTtcblx0XHRcdFx0XHRcdGkgKz0ganNUYWdzLmxlbmd0aDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gcmV0O1xuXHR9O1xufVxuXHJcbnZhciBldmVudEFkZCA9IGpRdWVyeS5ldmVudC5hZGQsXG5cdGV2ZW50UmVtb3ZlID0galF1ZXJ5LmV2ZW50LnJlbW92ZSxcblx0ZXZlbnRUcmlnZ2VyID0galF1ZXJ5LmV2ZW50LnRyaWdnZXIsXG5cdG9sZFRvZ2dsZSA9IGpRdWVyeS5mbi50b2dnbGUsXG5cdG9sZExpdmUgPSBqUXVlcnkuZm4ubGl2ZSxcblx0b2xkRGllID0galF1ZXJ5LmZuLmRpZSxcblx0b2xkTG9hZCA9IGpRdWVyeS5mbi5sb2FkLFxuXHRhamF4RXZlbnRzID0gXCJhamF4U3RhcnR8YWpheFN0b3B8YWpheFNlbmR8YWpheENvbXBsZXRlfGFqYXhFcnJvcnxhamF4U3VjY2Vzc1wiLFxuXHRyYWpheEV2ZW50ID0gbmV3IFJlZ0V4cCggXCJcXFxcYig/OlwiICsgYWpheEV2ZW50cyArIFwiKVxcXFxiXCIgKSxcblx0cmhvdmVySGFjayA9IC8oPzpefFxccylob3ZlcihcXC5cXFMrfClcXGIvLFxuXHRob3ZlckhhY2sgPSBmdW5jdGlvbiggZXZlbnRzICkge1xuXHRcdGlmICggdHlwZW9mKCBldmVudHMgKSAhPT0gXCJzdHJpbmdcIiB8fCBqUXVlcnkuZXZlbnQuc3BlY2lhbC5ob3ZlciApIHtcblx0XHRcdHJldHVybiBldmVudHM7XG5cdFx0fVxuXHRcdGlmICggcmhvdmVySGFjay50ZXN0KCBldmVudHMgKSApIHtcblx0XHRcdG1pZ3JhdGVXYXJuKFwiJ2hvdmVyJyBwc2V1ZG8tZXZlbnQgaXMgZGVwcmVjYXRlZCwgdXNlICdtb3VzZWVudGVyIG1vdXNlbGVhdmUnXCIpO1xuXHRcdH1cblx0XHRyZXR1cm4gZXZlbnRzICYmIGV2ZW50cy5yZXBsYWNlKCByaG92ZXJIYWNrLCBcIm1vdXNlZW50ZXIkMSBtb3VzZWxlYXZlJDFcIiApO1xuXHR9O1xuXG4vLyBFdmVudCBwcm9wcyByZW1vdmVkIGluIDEuOSwgcHV0IHRoZW0gYmFjayBpZiBuZWVkZWQ7IG5vIHByYWN0aWNhbCB3YXkgdG8gd2FybiB0aGVtXG5pZiAoIGpRdWVyeS5ldmVudC5wcm9wcyAmJiBqUXVlcnkuZXZlbnQucHJvcHNbIDAgXSAhPT0gXCJhdHRyQ2hhbmdlXCIgKSB7XG5cdGpRdWVyeS5ldmVudC5wcm9wcy51bnNoaWZ0KCBcImF0dHJDaGFuZ2VcIiwgXCJhdHRyTmFtZVwiLCBcInJlbGF0ZWROb2RlXCIsIFwic3JjRWxlbWVudFwiICk7XG59XG5cbi8vIFVuZG9jdW1lbnRlZCBqUXVlcnkuZXZlbnQuaGFuZGxlIHdhcyBcImRlcHJlY2F0ZWRcIiBpbiBqUXVlcnkgMS43XG5pZiAoIGpRdWVyeS5ldmVudC5kaXNwYXRjaCApIHtcblx0bWlncmF0ZVdhcm5Qcm9wKCBqUXVlcnkuZXZlbnQsIFwiaGFuZGxlXCIsIGpRdWVyeS5ldmVudC5kaXNwYXRjaCwgXCJqUXVlcnkuZXZlbnQuaGFuZGxlIGlzIHVuZG9jdW1lbnRlZCBhbmQgZGVwcmVjYXRlZFwiICk7XG59XG5cbi8vIFN1cHBvcnQgZm9yICdob3ZlcicgcHNldWRvLWV2ZW50IGFuZCBhamF4IGV2ZW50IHdhcm5pbmdzXG5qUXVlcnkuZXZlbnQuYWRkID0gZnVuY3Rpb24oIGVsZW0sIHR5cGVzLCBoYW5kbGVyLCBkYXRhLCBzZWxlY3RvciApe1xuXHRpZiAoIGVsZW0gIT09IGRvY3VtZW50ICYmIHJhamF4RXZlbnQudGVzdCggdHlwZXMgKSApIHtcblx0XHRtaWdyYXRlV2FybiggXCJBSkFYIGV2ZW50cyBzaG91bGQgYmUgYXR0YWNoZWQgdG8gZG9jdW1lbnQ6IFwiICsgdHlwZXMgKTtcblx0fVxuXHRldmVudEFkZC5jYWxsKCB0aGlzLCBlbGVtLCBob3ZlckhhY2soIHR5cGVzIHx8IFwiXCIgKSwgaGFuZGxlciwgZGF0YSwgc2VsZWN0b3IgKTtcbn07XG5qUXVlcnkuZXZlbnQucmVtb3ZlID0gZnVuY3Rpb24oIGVsZW0sIHR5cGVzLCBoYW5kbGVyLCBzZWxlY3RvciwgbWFwcGVkVHlwZXMgKXtcblx0ZXZlbnRSZW1vdmUuY2FsbCggdGhpcywgZWxlbSwgaG92ZXJIYWNrKCB0eXBlcyApIHx8IFwiXCIsIGhhbmRsZXIsIHNlbGVjdG9yLCBtYXBwZWRUeXBlcyApO1xufTtcblxualF1ZXJ5LmVhY2goIFsgXCJsb2FkXCIsIFwidW5sb2FkXCIsIFwiZXJyb3JcIiBdLCBmdW5jdGlvbiggXywgbmFtZSApIHtcblxuXHRqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFyZ3VtZW50cywgMCApO1xuXG5cdFx0Ly8gSWYgdGhpcyBpcyBhbiBhamF4IGxvYWQoKSB0aGUgZmlyc3QgYXJnIHNob3VsZCBiZSB0aGUgc3RyaW5nIFVSTDtcblx0XHQvLyB0ZWNobmljYWxseSB0aGlzIGNvdWxkIGFsc28gYmUgdGhlIFwiQW55dGhpbmdcIiBhcmcgb2YgdGhlIGV2ZW50IC5sb2FkKClcblx0XHQvLyB3aGljaCBqdXN0IGdvZXMgdG8gc2hvdyB3aHkgdGhpcyBkdW1iIHNpZ25hdHVyZSBoYXMgYmVlbiBkZXByZWNhdGVkIVxuXHRcdC8vIGpRdWVyeSBjdXN0b20gYnVpbGRzIHRoYXQgZXhjbHVkZSB0aGUgQWpheCBtb2R1bGUganVzdGlmaWFibHkgZGllIGhlcmUuXG5cdFx0aWYgKCBuYW1lID09PSBcImxvYWRcIiAmJiB0eXBlb2YgYXJnc1sgMCBdID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0cmV0dXJuIG9sZExvYWQuYXBwbHkoIHRoaXMsIGFyZ3MgKTtcblx0XHR9XG5cblx0XHRtaWdyYXRlV2FybiggXCJqUXVlcnkuZm4uXCIgKyBuYW1lICsgXCIoKSBpcyBkZXByZWNhdGVkXCIgKTtcblxuXHRcdGFyZ3Muc3BsaWNlKCAwLCAwLCBuYW1lICk7XG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuYmluZC5hcHBseSggdGhpcywgYXJncyApO1xuXHRcdH1cblxuXHRcdC8vIFVzZSAudHJpZ2dlckhhbmRsZXIgaGVyZSBiZWNhdXNlOlxuXHRcdC8vIC0gbG9hZCBhbmQgdW5sb2FkIGV2ZW50cyBkb24ndCBuZWVkIHRvIGJ1YmJsZSwgb25seSBhcHBsaWVkIHRvIHdpbmRvdyBvciBpbWFnZVxuXHRcdC8vIC0gZXJyb3IgZXZlbnQgc2hvdWxkIG5vdCBidWJibGUgdG8gd2luZG93LCBhbHRob3VnaCBpdCBkb2VzIHByZS0xLjdcblx0XHQvLyBTZWUgaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTE4MjBcblx0XHR0aGlzLnRyaWdnZXJIYW5kbGVyLmFwcGx5KCB0aGlzLCBhcmdzICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH07XG5cbn0pO1xuXG5qUXVlcnkuZm4udG9nZ2xlID0gZnVuY3Rpb24oIGZuLCBmbjIgKSB7XG5cblx0Ly8gRG9uJ3QgbWVzcyB3aXRoIGFuaW1hdGlvbiBvciBjc3MgdG9nZ2xlc1xuXHRpZiAoICFqUXVlcnkuaXNGdW5jdGlvbiggZm4gKSB8fCAhalF1ZXJ5LmlzRnVuY3Rpb24oIGZuMiApICkge1xuXHRcdHJldHVybiBvbGRUb2dnbGUuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHR9XG5cdG1pZ3JhdGVXYXJuKFwialF1ZXJ5LmZuLnRvZ2dsZShoYW5kbGVyLCBoYW5kbGVyLi4uKSBpcyBkZXByZWNhdGVkXCIpO1xuXG5cdC8vIFNhdmUgcmVmZXJlbmNlIHRvIGFyZ3VtZW50cyBmb3IgYWNjZXNzIGluIGNsb3N1cmVcblx0dmFyIGFyZ3MgPSBhcmd1bWVudHMsXG5cdFx0Z3VpZCA9IGZuLmd1aWQgfHwgalF1ZXJ5Lmd1aWQrKyxcblx0XHRpID0gMCxcblx0XHR0b2dnbGVyID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0Ly8gRmlndXJlIG91dCB3aGljaCBmdW5jdGlvbiB0byBleGVjdXRlXG5cdFx0XHR2YXIgbGFzdFRvZ2dsZSA9ICggalF1ZXJ5Ll9kYXRhKCB0aGlzLCBcImxhc3RUb2dnbGVcIiArIGZuLmd1aWQgKSB8fCAwICkgJSBpO1xuXHRcdFx0alF1ZXJ5Ll9kYXRhKCB0aGlzLCBcImxhc3RUb2dnbGVcIiArIGZuLmd1aWQsIGxhc3RUb2dnbGUgKyAxICk7XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB0aGF0IGNsaWNrcyBzdG9wXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHQvLyBhbmQgZXhlY3V0ZSB0aGUgZnVuY3Rpb25cblx0XHRcdHJldHVybiBhcmdzWyBsYXN0VG9nZ2xlIF0uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApIHx8IGZhbHNlO1xuXHRcdH07XG5cblx0Ly8gbGluayBhbGwgdGhlIGZ1bmN0aW9ucywgc28gYW55IG9mIHRoZW0gY2FuIHVuYmluZCB0aGlzIGNsaWNrIGhhbmRsZXJcblx0dG9nZ2xlci5ndWlkID0gZ3VpZDtcblx0d2hpbGUgKCBpIDwgYXJncy5sZW5ndGggKSB7XG5cdFx0YXJnc1sgaSsrIF0uZ3VpZCA9IGd1aWQ7XG5cdH1cblxuXHRyZXR1cm4gdGhpcy5jbGljayggdG9nZ2xlciApO1xufTtcblxualF1ZXJ5LmZuLmxpdmUgPSBmdW5jdGlvbiggdHlwZXMsIGRhdGEsIGZuICkge1xuXHRtaWdyYXRlV2FybihcImpRdWVyeS5mbi5saXZlKCkgaXMgZGVwcmVjYXRlZFwiKTtcblx0aWYgKCBvbGRMaXZlICkge1xuXHRcdHJldHVybiBvbGRMaXZlLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0fVxuXHRqUXVlcnkoIHRoaXMuY29udGV4dCApLm9uKCB0eXBlcywgdGhpcy5zZWxlY3RvciwgZGF0YSwgZm4gKTtcblx0cmV0dXJuIHRoaXM7XG59O1xuXG5qUXVlcnkuZm4uZGllID0gZnVuY3Rpb24oIHR5cGVzLCBmbiApIHtcblx0bWlncmF0ZVdhcm4oXCJqUXVlcnkuZm4uZGllKCkgaXMgZGVwcmVjYXRlZFwiKTtcblx0aWYgKCBvbGREaWUgKSB7XG5cdFx0cmV0dXJuIG9sZERpZS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdH1cblx0alF1ZXJ5KCB0aGlzLmNvbnRleHQgKS5vZmYoIHR5cGVzLCB0aGlzLnNlbGVjdG9yIHx8IFwiKipcIiwgZm4gKTtcblx0cmV0dXJuIHRoaXM7XG59O1xuXG4vLyBUdXJuIGdsb2JhbCBldmVudHMgaW50byBkb2N1bWVudC10cmlnZ2VyZWQgZXZlbnRzXG5qUXVlcnkuZXZlbnQudHJpZ2dlciA9IGZ1bmN0aW9uKCBldmVudCwgZGF0YSwgZWxlbSwgb25seUhhbmRsZXJzICApe1xuXHRpZiAoICFlbGVtICYmICFyYWpheEV2ZW50LnRlc3QoIGV2ZW50ICkgKSB7XG5cdFx0bWlncmF0ZVdhcm4oIFwiR2xvYmFsIGV2ZW50cyBhcmUgdW5kb2N1bWVudGVkIGFuZCBkZXByZWNhdGVkXCIgKTtcblx0fVxuXHRyZXR1cm4gZXZlbnRUcmlnZ2VyLmNhbGwoIHRoaXMsICBldmVudCwgZGF0YSwgZWxlbSB8fCBkb2N1bWVudCwgb25seUhhbmRsZXJzICApO1xufTtcbmpRdWVyeS5lYWNoKCBhamF4RXZlbnRzLnNwbGl0KFwifFwiKSxcblx0ZnVuY3Rpb24oIF8sIG5hbWUgKSB7XG5cdFx0alF1ZXJ5LmV2ZW50LnNwZWNpYWxbIG5hbWUgXSA9IHtcblx0XHRcdHNldHVwOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGVsZW0gPSB0aGlzO1xuXG5cdFx0XHRcdC8vIFRoZSBkb2N1bWVudCBuZWVkcyBubyBzaGltbWluZzsgbXVzdCBiZSAhPT0gZm9yIG9sZElFXG5cdFx0XHRcdGlmICggZWxlbSAhPT0gZG9jdW1lbnQgKSB7XG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LmFkZCggZG9jdW1lbnQsIG5hbWUgKyBcIi5cIiArIGpRdWVyeS5ndWlkLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyKCBuYW1lLCBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggYXJndW1lbnRzLCAxICksIGVsZW0sIHRydWUgKTtcblx0XHRcdFx0XHR9KTtcblx0XHRcdFx0XHRqUXVlcnkuX2RhdGEoIHRoaXMsIG5hbWUsIGpRdWVyeS5ndWlkKysgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9LFxuXHRcdFx0dGVhcmRvd246IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHRoaXMgIT09IGRvY3VtZW50ICkge1xuXHRcdFx0XHRcdGpRdWVyeS5ldmVudC5yZW1vdmUoIGRvY3VtZW50LCBuYW1lICsgXCIuXCIgKyBqUXVlcnkuX2RhdGEoIHRoaXMsIG5hbWUgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG4pO1xuXG5qUXVlcnkuZXZlbnQuc3BlY2lhbC5yZWFkeSA9IHtcblx0c2V0dXA6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcyA9PT0gZG9jdW1lbnQgKSB7XG5cdFx0XHRtaWdyYXRlV2FybiggXCIncmVhZHknIGV2ZW50IGlzIGRlcHJlY2F0ZWRcIiApO1xuXHRcdH1cblx0fVxufTtcblxyXG52YXIgb2xkU2VsZiA9IGpRdWVyeS5mbi5hbmRTZWxmIHx8IGpRdWVyeS5mbi5hZGRCYWNrLFxuXHRvbGRGbkZpbmQgPSBqUXVlcnkuZm4uZmluZDtcblxualF1ZXJ5LmZuLmFuZFNlbGYgPSBmdW5jdGlvbigpIHtcblx0bWlncmF0ZVdhcm4oXCJqUXVlcnkuZm4uYW5kU2VsZigpIHJlcGxhY2VkIGJ5IGpRdWVyeS5mbi5hZGRCYWNrKClcIik7XG5cdHJldHVybiBvbGRTZWxmLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcbn07XG5cbmpRdWVyeS5mbi5maW5kID0gZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHR2YXIgcmV0ID0gb2xkRm5GaW5kLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0cmV0LmNvbnRleHQgPSB0aGlzLmNvbnRleHQ7XG5cdHJldC5zZWxlY3RvciA9IHRoaXMuc2VsZWN0b3IgPyB0aGlzLnNlbGVjdG9yICsgXCIgXCIgKyBzZWxlY3RvciA6IHNlbGVjdG9yO1xuXHRyZXR1cm4gcmV0O1xufTtcblxyXG5cbi8vIGpRdWVyeSAxLjYgZGlkIG5vdCBzdXBwb3J0IENhbGxiYWNrcywgZG8gbm90IHdhcm4gdGhlcmVcbmlmICggalF1ZXJ5LkNhbGxiYWNrcyApIHtcblxuXHR2YXIgb2xkRGVmZXJyZWQgPSBqUXVlcnkuRGVmZXJyZWQsXG5cdFx0dHVwbGVzID0gW1xuXHRcdFx0Ly8gYWN0aW9uLCBhZGQgbGlzdGVuZXIsIGNhbGxiYWNrcywgLnRoZW4gaGFuZGxlcnMsIGZpbmFsIHN0YXRlXG5cdFx0XHRbIFwicmVzb2x2ZVwiLCBcImRvbmVcIiwgalF1ZXJ5LkNhbGxiYWNrcyhcIm9uY2UgbWVtb3J5XCIpLFxuXHRcdFx0XHRqUXVlcnkuQ2FsbGJhY2tzKFwib25jZSBtZW1vcnlcIiksIFwicmVzb2x2ZWRcIiBdLFxuXHRcdFx0WyBcInJlamVjdFwiLCBcImZhaWxcIiwgalF1ZXJ5LkNhbGxiYWNrcyhcIm9uY2UgbWVtb3J5XCIpLFxuXHRcdFx0XHRqUXVlcnkuQ2FsbGJhY2tzKFwib25jZSBtZW1vcnlcIiksIFwicmVqZWN0ZWRcIiBdLFxuXHRcdFx0WyBcIm5vdGlmeVwiLCBcInByb2dyZXNzXCIsIGpRdWVyeS5DYWxsYmFja3MoXCJtZW1vcnlcIiksXG5cdFx0XHRcdGpRdWVyeS5DYWxsYmFja3MoXCJtZW1vcnlcIikgXVxuXHRcdF07XG5cblx0alF1ZXJ5LkRlZmVycmVkID0gZnVuY3Rpb24oIGZ1bmMgKSB7XG5cdFx0dmFyIGRlZmVycmVkID0gb2xkRGVmZXJyZWQoKSxcblx0XHRcdHByb21pc2UgPSBkZWZlcnJlZC5wcm9taXNlKCk7XG5cblx0XHRkZWZlcnJlZC5waXBlID0gcHJvbWlzZS5waXBlID0gZnVuY3Rpb24oIC8qIGZuRG9uZSwgZm5GYWlsLCBmblByb2dyZXNzICovICkge1xuXHRcdFx0dmFyIGZucyA9IGFyZ3VtZW50cztcblxuXHRcdFx0bWlncmF0ZVdhcm4oIFwiZGVmZXJyZWQucGlwZSgpIGlzIGRlcHJlY2F0ZWRcIiApO1xuXG5cdFx0XHRyZXR1cm4galF1ZXJ5LkRlZmVycmVkKGZ1bmN0aW9uKCBuZXdEZWZlciApIHtcblx0XHRcdFx0alF1ZXJ5LmVhY2goIHR1cGxlcywgZnVuY3Rpb24oIGksIHR1cGxlICkge1xuXHRcdFx0XHRcdHZhciBmbiA9IGpRdWVyeS5pc0Z1bmN0aW9uKCBmbnNbIGkgXSApICYmIGZuc1sgaSBdO1xuXHRcdFx0XHRcdC8vIGRlZmVycmVkLmRvbmUoZnVuY3Rpb24oKSB7IGJpbmQgdG8gbmV3RGVmZXIgb3IgbmV3RGVmZXIucmVzb2x2ZSB9KVxuXHRcdFx0XHRcdC8vIGRlZmVycmVkLmZhaWwoZnVuY3Rpb24oKSB7IGJpbmQgdG8gbmV3RGVmZXIgb3IgbmV3RGVmZXIucmVqZWN0IH0pXG5cdFx0XHRcdFx0Ly8gZGVmZXJyZWQucHJvZ3Jlc3MoZnVuY3Rpb24oKSB7IGJpbmQgdG8gbmV3RGVmZXIgb3IgbmV3RGVmZXIubm90aWZ5IH0pXG5cdFx0XHRcdFx0ZGVmZXJyZWRbIHR1cGxlWzFdIF0oZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHR2YXIgcmV0dXJuZWQgPSBmbiAmJiBmbi5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdFx0XHRpZiAoIHJldHVybmVkICYmIGpRdWVyeS5pc0Z1bmN0aW9uKCByZXR1cm5lZC5wcm9taXNlICkgKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybmVkLnByb21pc2UoKVxuXHRcdFx0XHRcdFx0XHRcdC5kb25lKCBuZXdEZWZlci5yZXNvbHZlIClcblx0XHRcdFx0XHRcdFx0XHQuZmFpbCggbmV3RGVmZXIucmVqZWN0IClcblx0XHRcdFx0XHRcdFx0XHQucHJvZ3Jlc3MoIG5ld0RlZmVyLm5vdGlmeSApO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0bmV3RGVmZXJbIHR1cGxlWyAwIF0gKyBcIldpdGhcIiBdKFxuXHRcdFx0XHRcdFx0XHRcdHRoaXMgPT09IHByb21pc2UgPyBuZXdEZWZlci5wcm9taXNlKCkgOiB0aGlzLFxuXHRcdFx0XHRcdFx0XHRcdGZuID8gWyByZXR1cm5lZCBdIDogYXJndW1lbnRzXG5cdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0XHRmbnMgPSBudWxsO1xuXHRcdFx0fSkucHJvbWlzZSgpO1xuXG5cdFx0fTtcblxuXHRcdGRlZmVycmVkLmlzUmVzb2x2ZWQgPSBmdW5jdGlvbigpIHtcblx0XHRcdG1pZ3JhdGVXYXJuKCBcImRlZmVycmVkLmlzUmVzb2x2ZWQgaXMgZGVwcmVjYXRlZFwiICk7XG5cdFx0XHRyZXR1cm4gZGVmZXJyZWQuc3RhdGUoKSA9PT0gXCJyZXNvbHZlZFwiO1xuXHRcdH07XG5cblx0XHRkZWZlcnJlZC5pc1JlamVjdGVkID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRtaWdyYXRlV2FybiggXCJkZWZlcnJlZC5pc1JlamVjdGVkIGlzIGRlcHJlY2F0ZWRcIiApO1xuXHRcdFx0cmV0dXJuIGRlZmVycmVkLnN0YXRlKCkgPT09IFwicmVqZWN0ZWRcIjtcblx0XHR9O1xuXG5cdFx0aWYgKCBmdW5jICkge1xuXHRcdFx0ZnVuYy5jYWxsKCBkZWZlcnJlZCwgZGVmZXJyZWQgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZGVmZXJyZWQ7XG5cdH07XG5cbn1cclxuXHJcbn0pKCBqUXVlcnksIHdpbmRvdyApO1xyXG4iLCIoZnVuY3Rpb24oKSB7XG4gIHZhciBBamF4TW9uaXRvciwgQmFyLCBEb2N1bWVudE1vbml0b3IsIEVsZW1lbnRNb25pdG9yLCBFbGVtZW50VHJhY2tlciwgRXZlbnRMYWdNb25pdG9yLCBFdmVudGVkLCBFdmVudHMsIE5vVGFyZ2V0RXJyb3IsIFBhY2UsIFJlcXVlc3RJbnRlcmNlcHQsIFNPVVJDRV9LRVlTLCBTY2FsZXIsIFNvY2tldFJlcXVlc3RUcmFja2VyLCBYSFJSZXF1ZXN0VHJhY2tlciwgYW5pbWF0aW9uLCBhdmdBbXBsaXR1ZGUsIGJhciwgY2FuY2VsQW5pbWF0aW9uLCBjYW5jZWxBbmltYXRpb25GcmFtZSwgZGVmYXVsdE9wdGlvbnMsIGV4dGVuZCwgZXh0ZW5kTmF0aXZlLCBnZXRGcm9tRE9NLCBnZXRJbnRlcmNlcHQsIGhhbmRsZVB1c2hTdGF0ZSwgaWdub3JlU3RhY2ssIGluaXQsIG5vdywgb3B0aW9ucywgcmVxdWVzdEFuaW1hdGlvbkZyYW1lLCByZXN1bHQsIHJ1bkFuaW1hdGlvbiwgc2NhbGVycywgc2hvdWxkSWdub3JlVVJMLCBzaG91bGRUcmFjaywgc291cmNlLCBzb3VyY2VzLCB1bmlTY2FsZXIsIF9XZWJTb2NrZXQsIF9YRG9tYWluUmVxdWVzdCwgX1hNTEh0dHBSZXF1ZXN0LCBfaSwgX2ludGVyY2VwdCwgX2xlbiwgX3B1c2hTdGF0ZSwgX3JlZiwgX3JlZjEsIF9yZXBsYWNlU3RhdGUsXG4gICAgX19zbGljZSA9IFtdLnNsaWNlLFxuICAgIF9faGFzUHJvcCA9IHt9Lmhhc093blByb3BlcnR5LFxuICAgIF9fZXh0ZW5kcyA9IGZ1bmN0aW9uKGNoaWxkLCBwYXJlbnQpIHsgZm9yICh2YXIga2V5IGluIHBhcmVudCkgeyBpZiAoX19oYXNQcm9wLmNhbGwocGFyZW50LCBrZXkpKSBjaGlsZFtrZXldID0gcGFyZW50W2tleV07IH0gZnVuY3Rpb24gY3RvcigpIHsgdGhpcy5jb25zdHJ1Y3RvciA9IGNoaWxkOyB9IGN0b3IucHJvdG90eXBlID0gcGFyZW50LnByb3RvdHlwZTsgY2hpbGQucHJvdG90eXBlID0gbmV3IGN0b3IoKTsgY2hpbGQuX19zdXBlcl9fID0gcGFyZW50LnByb3RvdHlwZTsgcmV0dXJuIGNoaWxkOyB9LFxuICAgIF9faW5kZXhPZiA9IFtdLmluZGV4T2YgfHwgZnVuY3Rpb24oaXRlbSkgeyBmb3IgKHZhciBpID0gMCwgbCA9IHRoaXMubGVuZ3RoOyBpIDwgbDsgaSsrKSB7IGlmIChpIGluIHRoaXMgJiYgdGhpc1tpXSA9PT0gaXRlbSkgcmV0dXJuIGk7IH0gcmV0dXJuIC0xOyB9O1xuXG4gIGRlZmF1bHRPcHRpb25zID0ge1xuICAgIGNhdGNodXBUaW1lOiAxMDAsXG4gICAgaW5pdGlhbFJhdGU6IC4wMyxcbiAgICBtaW5UaW1lOiAyNTAsXG4gICAgZ2hvc3RUaW1lOiAxMDAsXG4gICAgbWF4UHJvZ3Jlc3NQZXJGcmFtZTogMjAsXG4gICAgZWFzZUZhY3RvcjogMS4yNSxcbiAgICBzdGFydE9uUGFnZUxvYWQ6IHRydWUsXG4gICAgcmVzdGFydE9uUHVzaFN0YXRlOiB0cnVlLFxuICAgIHJlc3RhcnRPblJlcXVlc3RBZnRlcjogNTAwLFxuICAgIHRhcmdldDogJ2JvZHknLFxuICAgIGVsZW1lbnRzOiB7XG4gICAgICBjaGVja0ludGVydmFsOiAxMDAsXG4gICAgICBzZWxlY3RvcnM6IFsnYm9keSddXG4gICAgfSxcbiAgICBldmVudExhZzoge1xuICAgICAgbWluU2FtcGxlczogMTAsXG4gICAgICBzYW1wbGVDb3VudDogMyxcbiAgICAgIGxhZ1RocmVzaG9sZDogM1xuICAgIH0sXG4gICAgYWpheDoge1xuICAgICAgdHJhY2tNZXRob2RzOiBbJ0dFVCddLFxuICAgICAgdHJhY2tXZWJTb2NrZXRzOiB0cnVlLFxuICAgICAgaWdub3JlVVJMczogW11cbiAgICB9XG4gIH07XG5cbiAgbm93ID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIF9yZWY7XG4gICAgcmV0dXJuIChfcmVmID0gdHlwZW9mIHBlcmZvcm1hbmNlICE9PSBcInVuZGVmaW5lZFwiICYmIHBlcmZvcm1hbmNlICE9PSBudWxsID8gdHlwZW9mIHBlcmZvcm1hbmNlLm5vdyA9PT0gXCJmdW5jdGlvblwiID8gcGVyZm9ybWFuY2Uubm93KCkgOiB2b2lkIDAgOiB2b2lkIDApICE9IG51bGwgPyBfcmVmIDogKyhuZXcgRGF0ZSk7XG4gIH07XG5cbiAgcmVxdWVzdEFuaW1hdGlvbkZyYW1lID0gd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSB8fCB3aW5kb3cubW96UmVxdWVzdEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy53ZWJraXRSZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgd2luZG93Lm1zUmVxdWVzdEFuaW1hdGlvbkZyYW1lO1xuXG4gIGNhbmNlbEFuaW1hdGlvbkZyYW1lID0gd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lIHx8IHdpbmRvdy5tb3pDYW5jZWxBbmltYXRpb25GcmFtZTtcblxuICBpZiAocmVxdWVzdEFuaW1hdGlvbkZyYW1lID09IG51bGwpIHtcbiAgICByZXF1ZXN0QW5pbWF0aW9uRnJhbWUgPSBmdW5jdGlvbihmbikge1xuICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZm4sIDUwKTtcbiAgICB9O1xuICAgIGNhbmNlbEFuaW1hdGlvbkZyYW1lID0gZnVuY3Rpb24oaWQpIHtcbiAgICAgIHJldHVybiBjbGVhclRpbWVvdXQoaWQpO1xuICAgIH07XG4gIH1cblxuICBydW5BbmltYXRpb24gPSBmdW5jdGlvbihmbikge1xuICAgIHZhciBsYXN0LCB0aWNrO1xuICAgIGxhc3QgPSBub3coKTtcbiAgICB0aWNrID0gZnVuY3Rpb24oKSB7XG4gICAgICB2YXIgZGlmZjtcbiAgICAgIGRpZmYgPSBub3coKSAtIGxhc3Q7XG4gICAgICBpZiAoZGlmZiA+PSAzMykge1xuICAgICAgICBsYXN0ID0gbm93KCk7XG4gICAgICAgIHJldHVybiBmbihkaWZmLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKHRpY2spO1xuICAgICAgICB9KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KHRpY2ssIDMzIC0gZGlmZik7XG4gICAgICB9XG4gICAgfTtcbiAgICByZXR1cm4gdGljaygpO1xuICB9O1xuXG4gIHJlc3VsdCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBhcmdzLCBrZXksIG9iajtcbiAgICBvYmogPSBhcmd1bWVudHNbMF0sIGtleSA9IGFyZ3VtZW50c1sxXSwgYXJncyA9IDMgPD0gYXJndW1lbnRzLmxlbmd0aCA/IF9fc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpIDogW107XG4gICAgaWYgKHR5cGVvZiBvYmpba2V5XSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgcmV0dXJuIG9ialtrZXldLmFwcGx5KG9iaiwgYXJncyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBvYmpba2V5XTtcbiAgICB9XG4gIH07XG5cbiAgZXh0ZW5kID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGtleSwgb3V0LCBzb3VyY2UsIHNvdXJjZXMsIHZhbCwgX2ksIF9sZW47XG4gICAgb3V0ID0gYXJndW1lbnRzWzBdLCBzb3VyY2VzID0gMiA8PSBhcmd1bWVudHMubGVuZ3RoID8gX19zbGljZS5jYWxsKGFyZ3VtZW50cywgMSkgOiBbXTtcbiAgICBmb3IgKF9pID0gMCwgX2xlbiA9IHNvdXJjZXMubGVuZ3RoOyBfaSA8IF9sZW47IF9pKyspIHtcbiAgICAgIHNvdXJjZSA9IHNvdXJjZXNbX2ldO1xuICAgICAgaWYgKHNvdXJjZSkge1xuICAgICAgICBmb3IgKGtleSBpbiBzb3VyY2UpIHtcbiAgICAgICAgICBpZiAoIV9faGFzUHJvcC5jYWxsKHNvdXJjZSwga2V5KSkgY29udGludWU7XG4gICAgICAgICAgdmFsID0gc291cmNlW2tleV07XG4gICAgICAgICAgaWYgKChvdXRba2V5XSAhPSBudWxsKSAmJiB0eXBlb2Ygb3V0W2tleV0gPT09ICdvYmplY3QnICYmICh2YWwgIT0gbnVsbCkgJiYgdHlwZW9mIHZhbCA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGV4dGVuZChvdXRba2V5XSwgdmFsKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgb3V0W2tleV0gPSB2YWw7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBvdXQ7XG4gIH07XG5cbiAgYXZnQW1wbGl0dWRlID0gZnVuY3Rpb24oYXJyKSB7XG4gICAgdmFyIGNvdW50LCBzdW0sIHYsIF9pLCBfbGVuO1xuICAgIHN1bSA9IGNvdW50ID0gMDtcbiAgICBmb3IgKF9pID0gMCwgX2xlbiA9IGFyci5sZW5ndGg7IF9pIDwgX2xlbjsgX2krKykge1xuICAgICAgdiA9IGFycltfaV07XG4gICAgICBzdW0gKz0gTWF0aC5hYnModik7XG4gICAgICBjb3VudCsrO1xuICAgIH1cbiAgICByZXR1cm4gc3VtIC8gY291bnQ7XG4gIH07XG5cbiAgZ2V0RnJvbURPTSA9IGZ1bmN0aW9uKGtleSwganNvbikge1xuICAgIHZhciBkYXRhLCBlLCBlbDtcbiAgICBpZiAoa2V5ID09IG51bGwpIHtcbiAgICAgIGtleSA9ICdvcHRpb25zJztcbiAgICB9XG4gICAgaWYgKGpzb24gPT0gbnVsbCkge1xuICAgICAganNvbiA9IHRydWU7XG4gICAgfVxuICAgIGVsID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihcIltkYXRhLXBhY2UtXCIgKyBrZXkgKyBcIl1cIik7XG4gICAgaWYgKCFlbCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBkYXRhID0gZWwuZ2V0QXR0cmlidXRlKFwiZGF0YS1wYWNlLVwiICsga2V5KTtcbiAgICBpZiAoIWpzb24pIHtcbiAgICAgIHJldHVybiBkYXRhO1xuICAgIH1cbiAgICB0cnkge1xuICAgICAgcmV0dXJuIEpTT04ucGFyc2UoZGF0YSk7XG4gICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICBlID0gX2Vycm9yO1xuICAgICAgcmV0dXJuIHR5cGVvZiBjb25zb2xlICE9PSBcInVuZGVmaW5lZFwiICYmIGNvbnNvbGUgIT09IG51bGwgPyBjb25zb2xlLmVycm9yKFwiRXJyb3IgcGFyc2luZyBpbmxpbmUgcGFjZSBvcHRpb25zXCIsIGUpIDogdm9pZCAwO1xuICAgIH1cbiAgfTtcblxuICBFdmVudGVkID0gKGZ1bmN0aW9uKCkge1xuICAgIGZ1bmN0aW9uIEV2ZW50ZWQoKSB7fVxuXG4gICAgRXZlbnRlZC5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldmVudCwgaGFuZGxlciwgY3R4LCBvbmNlKSB7XG4gICAgICB2YXIgX2Jhc2U7XG4gICAgICBpZiAob25jZSA9PSBudWxsKSB7XG4gICAgICAgIG9uY2UgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLmJpbmRpbmdzID09IG51bGwpIHtcbiAgICAgICAgdGhpcy5iaW5kaW5ncyA9IHt9O1xuICAgICAgfVxuICAgICAgaWYgKChfYmFzZSA9IHRoaXMuYmluZGluZ3MpW2V2ZW50XSA9PSBudWxsKSB7XG4gICAgICAgIF9iYXNlW2V2ZW50XSA9IFtdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuYmluZGluZ3NbZXZlbnRdLnB1c2goe1xuICAgICAgICBoYW5kbGVyOiBoYW5kbGVyLFxuICAgICAgICBjdHg6IGN0eCxcbiAgICAgICAgb25jZTogb25jZVxuICAgICAgfSk7XG4gICAgfTtcblxuICAgIEV2ZW50ZWQucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbihldmVudCwgaGFuZGxlciwgY3R4KSB7XG4gICAgICByZXR1cm4gdGhpcy5vbihldmVudCwgaGFuZGxlciwgY3R4LCB0cnVlKTtcbiAgICB9O1xuXG4gICAgRXZlbnRlZC5wcm90b3R5cGUub2ZmID0gZnVuY3Rpb24oZXZlbnQsIGhhbmRsZXIpIHtcbiAgICAgIHZhciBpLCBfcmVmLCBfcmVzdWx0cztcbiAgICAgIGlmICgoKF9yZWYgPSB0aGlzLmJpbmRpbmdzKSAhPSBudWxsID8gX3JlZltldmVudF0gOiB2b2lkIDApID09IG51bGwpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgICAgaWYgKGhhbmRsZXIgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZGVsZXRlIHRoaXMuYmluZGluZ3NbZXZlbnRdO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaSA9IDA7XG4gICAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICAgIHdoaWxlIChpIDwgdGhpcy5iaW5kaW5nc1tldmVudF0ubGVuZ3RoKSB7XG4gICAgICAgICAgaWYgKHRoaXMuYmluZGluZ3NbZXZlbnRdW2ldLmhhbmRsZXIgPT09IGhhbmRsZXIpIHtcbiAgICAgICAgICAgIF9yZXN1bHRzLnB1c2godGhpcy5iaW5kaW5nc1tldmVudF0uc3BsaWNlKGksIDEpKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgX3Jlc3VsdHMucHVzaChpKyspO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gX3Jlc3VsdHM7XG4gICAgICB9XG4gICAgfTtcblxuICAgIEV2ZW50ZWQucHJvdG90eXBlLnRyaWdnZXIgPSBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBhcmdzLCBjdHgsIGV2ZW50LCBoYW5kbGVyLCBpLCBvbmNlLCBfcmVmLCBfcmVmMSwgX3Jlc3VsdHM7XG4gICAgICBldmVudCA9IGFyZ3VtZW50c1swXSwgYXJncyA9IDIgPD0gYXJndW1lbnRzLmxlbmd0aCA/IF9fc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpIDogW107XG4gICAgICBpZiAoKF9yZWYgPSB0aGlzLmJpbmRpbmdzKSAhPSBudWxsID8gX3JlZltldmVudF0gOiB2b2lkIDApIHtcbiAgICAgICAgaSA9IDA7XG4gICAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICAgIHdoaWxlIChpIDwgdGhpcy5iaW5kaW5nc1tldmVudF0ubGVuZ3RoKSB7XG4gICAgICAgICAgX3JlZjEgPSB0aGlzLmJpbmRpbmdzW2V2ZW50XVtpXSwgaGFuZGxlciA9IF9yZWYxLmhhbmRsZXIsIGN0eCA9IF9yZWYxLmN0eCwgb25jZSA9IF9yZWYxLm9uY2U7XG4gICAgICAgICAgaGFuZGxlci5hcHBseShjdHggIT0gbnVsbCA/IGN0eCA6IHRoaXMsIGFyZ3MpO1xuICAgICAgICAgIGlmIChvbmNlKSB7XG4gICAgICAgICAgICBfcmVzdWx0cy5wdXNoKHRoaXMuYmluZGluZ3NbZXZlbnRdLnNwbGljZShpLCAxKSk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIF9yZXN1bHRzLnB1c2goaSsrKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9yZXN1bHRzO1xuICAgICAgfVxuICAgIH07XG5cbiAgICByZXR1cm4gRXZlbnRlZDtcblxuICB9KSgpO1xuXG4gIFBhY2UgPSB3aW5kb3cuUGFjZSB8fCB7fTtcblxuICB3aW5kb3cuUGFjZSA9IFBhY2U7XG5cbiAgZXh0ZW5kKFBhY2UsIEV2ZW50ZWQucHJvdG90eXBlKTtcblxuICBvcHRpb25zID0gUGFjZS5vcHRpb25zID0gZXh0ZW5kKHt9LCBkZWZhdWx0T3B0aW9ucywgd2luZG93LnBhY2VPcHRpb25zLCBnZXRGcm9tRE9NKCkpO1xuXG4gIF9yZWYgPSBbJ2FqYXgnLCAnZG9jdW1lbnQnLCAnZXZlbnRMYWcnLCAnZWxlbWVudHMnXTtcbiAgZm9yIChfaSA9IDAsIF9sZW4gPSBfcmVmLmxlbmd0aDsgX2kgPCBfbGVuOyBfaSsrKSB7XG4gICAgc291cmNlID0gX3JlZltfaV07XG4gICAgaWYgKG9wdGlvbnNbc291cmNlXSA9PT0gdHJ1ZSkge1xuICAgICAgb3B0aW9uc1tzb3VyY2VdID0gZGVmYXVsdE9wdGlvbnNbc291cmNlXTtcbiAgICB9XG4gIH1cblxuICBOb1RhcmdldEVycm9yID0gKGZ1bmN0aW9uKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhOb1RhcmdldEVycm9yLCBfc3VwZXIpO1xuXG4gICAgZnVuY3Rpb24gTm9UYXJnZXRFcnJvcigpIHtcbiAgICAgIF9yZWYxID0gTm9UYXJnZXRFcnJvci5fX3N1cGVyX18uY29uc3RydWN0b3IuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICAgIHJldHVybiBfcmVmMTtcbiAgICB9XG5cbiAgICByZXR1cm4gTm9UYXJnZXRFcnJvcjtcblxuICB9KShFcnJvcik7XG5cbiAgQmFyID0gKGZ1bmN0aW9uKCkge1xuICAgIGZ1bmN0aW9uIEJhcigpIHtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgIH1cblxuICAgIEJhci5wcm90b3R5cGUuZ2V0RWxlbWVudCA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIHRhcmdldEVsZW1lbnQ7XG4gICAgICBpZiAodGhpcy5lbCA9PSBudWxsKSB7XG4gICAgICAgIHRhcmdldEVsZW1lbnQgPSBkb2N1bWVudC5xdWVyeVNlbGVjdG9yKG9wdGlvbnMudGFyZ2V0KTtcbiAgICAgICAgaWYgKCF0YXJnZXRFbGVtZW50KSB7XG4gICAgICAgICAgdGhyb3cgbmV3IE5vVGFyZ2V0RXJyb3I7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5lbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuICAgICAgICB0aGlzLmVsLmNsYXNzTmFtZSA9IFwicGFjZSBwYWNlLWFjdGl2ZVwiO1xuICAgICAgICBkb2N1bWVudC5ib2R5LmNsYXNzTmFtZSA9IGRvY3VtZW50LmJvZHkuY2xhc3NOYW1lLnJlcGxhY2UoL3BhY2UtZG9uZS9nLCAnJyk7XG4gICAgICAgIGRvY3VtZW50LmJvZHkuY2xhc3NOYW1lICs9ICcgcGFjZS1ydW5uaW5nJztcbiAgICAgICAgdGhpcy5lbC5pbm5lckhUTUwgPSAnPGRpdiBjbGFzcz1cInBhY2UtcHJvZ3Jlc3NcIj5cXG4gIDxkaXYgY2xhc3M9XCJwYWNlLXByb2dyZXNzLWlubmVyXCI+PC9kaXY+XFxuPC9kaXY+XFxuPGRpdiBjbGFzcz1cInBhY2UtYWN0aXZpdHlcIj48L2Rpdj4nO1xuICAgICAgICBpZiAodGFyZ2V0RWxlbWVudC5maXJzdENoaWxkICE9IG51bGwpIHtcbiAgICAgICAgICB0YXJnZXRFbGVtZW50Lmluc2VydEJlZm9yZSh0aGlzLmVsLCB0YXJnZXRFbGVtZW50LmZpcnN0Q2hpbGQpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRhcmdldEVsZW1lbnQuYXBwZW5kQ2hpbGQodGhpcy5lbCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmVsO1xuICAgIH07XG5cbiAgICBCYXIucHJvdG90eXBlLmZpbmlzaCA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGVsO1xuICAgICAgZWwgPSB0aGlzLmdldEVsZW1lbnQoKTtcbiAgICAgIGVsLmNsYXNzTmFtZSA9IGVsLmNsYXNzTmFtZS5yZXBsYWNlKCdwYWNlLWFjdGl2ZScsICcnKTtcbiAgICAgIGVsLmNsYXNzTmFtZSArPSAnIHBhY2UtaW5hY3RpdmUnO1xuICAgICAgZG9jdW1lbnQuYm9keS5jbGFzc05hbWUgPSBkb2N1bWVudC5ib2R5LmNsYXNzTmFtZS5yZXBsYWNlKCdwYWNlLXJ1bm5pbmcnLCAnJyk7XG4gICAgICByZXR1cm4gZG9jdW1lbnQuYm9keS5jbGFzc05hbWUgKz0gJyBwYWNlLWRvbmUnO1xuICAgIH07XG5cbiAgICBCYXIucHJvdG90eXBlLnVwZGF0ZSA9IGZ1bmN0aW9uKHByb2cpIHtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSBwcm9nO1xuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyKCk7XG4gICAgfTtcblxuICAgIEJhci5wcm90b3R5cGUuZGVzdHJveSA9IGZ1bmN0aW9uKCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5nZXRFbGVtZW50KCkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCh0aGlzLmdldEVsZW1lbnQoKSk7XG4gICAgICB9IGNhdGNoIChfZXJyb3IpIHtcbiAgICAgICAgTm9UYXJnZXRFcnJvciA9IF9lcnJvcjtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0aGlzLmVsID0gdm9pZCAwO1xuICAgIH07XG5cbiAgICBCYXIucHJvdG90eXBlLnJlbmRlciA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGVsLCBrZXksIHByb2dyZXNzU3RyLCB0cmFuc2Zvcm0sIF9qLCBfbGVuMSwgX3JlZjI7XG4gICAgICBpZiAoZG9jdW1lbnQucXVlcnlTZWxlY3RvcihvcHRpb25zLnRhcmdldCkgPT0gbnVsbCkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBlbCA9IHRoaXMuZ2V0RWxlbWVudCgpO1xuICAgICAgdHJhbnNmb3JtID0gXCJ0cmFuc2xhdGUzZChcIiArIHRoaXMucHJvZ3Jlc3MgKyBcIiUsIDAsIDApXCI7XG4gICAgICBfcmVmMiA9IFsnd2Via2l0VHJhbnNmb3JtJywgJ21zVHJhbnNmb3JtJywgJ3RyYW5zZm9ybSddO1xuICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjIubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgIGtleSA9IF9yZWYyW19qXTtcbiAgICAgICAgZWwuY2hpbGRyZW5bMF0uc3R5bGVba2V5XSA9IHRyYW5zZm9ybTtcbiAgICAgIH1cbiAgICAgIGlmICghdGhpcy5sYXN0UmVuZGVyZWRQcm9ncmVzcyB8fCB0aGlzLmxhc3RSZW5kZXJlZFByb2dyZXNzIHwgMCAhPT0gdGhpcy5wcm9ncmVzcyB8IDApIHtcbiAgICAgICAgZWwuY2hpbGRyZW5bMF0uc2V0QXR0cmlidXRlKCdkYXRhLXByb2dyZXNzLXRleHQnLCBcIlwiICsgKHRoaXMucHJvZ3Jlc3MgfCAwKSArIFwiJVwiKTtcbiAgICAgICAgaWYgKHRoaXMucHJvZ3Jlc3MgPj0gMTAwKSB7XG4gICAgICAgICAgcHJvZ3Jlc3NTdHIgPSAnOTknO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHByb2dyZXNzU3RyID0gdGhpcy5wcm9ncmVzcyA8IDEwID8gXCIwXCIgOiBcIlwiO1xuICAgICAgICAgIHByb2dyZXNzU3RyICs9IHRoaXMucHJvZ3Jlc3MgfCAwO1xuICAgICAgICB9XG4gICAgICAgIGVsLmNoaWxkcmVuWzBdLnNldEF0dHJpYnV0ZSgnZGF0YS1wcm9ncmVzcycsIFwiXCIgKyBwcm9ncmVzc1N0cik7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5sYXN0UmVuZGVyZWRQcm9ncmVzcyA9IHRoaXMucHJvZ3Jlc3M7XG4gICAgfTtcblxuICAgIEJhci5wcm90b3R5cGUuZG9uZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHRoaXMucHJvZ3Jlc3MgPj0gMTAwO1xuICAgIH07XG5cbiAgICByZXR1cm4gQmFyO1xuXG4gIH0pKCk7XG5cbiAgRXZlbnRzID0gKGZ1bmN0aW9uKCkge1xuICAgIGZ1bmN0aW9uIEV2ZW50cygpIHtcbiAgICAgIHRoaXMuYmluZGluZ3MgPSB7fTtcbiAgICB9XG5cbiAgICBFdmVudHMucHJvdG90eXBlLnRyaWdnZXIgPSBmdW5jdGlvbihuYW1lLCB2YWwpIHtcbiAgICAgIHZhciBiaW5kaW5nLCBfaiwgX2xlbjEsIF9yZWYyLCBfcmVzdWx0cztcbiAgICAgIGlmICh0aGlzLmJpbmRpbmdzW25hbWVdICE9IG51bGwpIHtcbiAgICAgICAgX3JlZjIgPSB0aGlzLmJpbmRpbmdzW25hbWVdO1xuICAgICAgICBfcmVzdWx0cyA9IFtdO1xuICAgICAgICBmb3IgKF9qID0gMCwgX2xlbjEgPSBfcmVmMi5sZW5ndGg7IF9qIDwgX2xlbjE7IF9qKyspIHtcbiAgICAgICAgICBiaW5kaW5nID0gX3JlZjJbX2pdO1xuICAgICAgICAgIF9yZXN1bHRzLnB1c2goYmluZGluZy5jYWxsKHRoaXMsIHZhbCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBfcmVzdWx0cztcbiAgICAgIH1cbiAgICB9O1xuXG4gICAgRXZlbnRzLnByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uKG5hbWUsIGZuKSB7XG4gICAgICB2YXIgX2Jhc2U7XG4gICAgICBpZiAoKF9iYXNlID0gdGhpcy5iaW5kaW5ncylbbmFtZV0gPT0gbnVsbCkge1xuICAgICAgICBfYmFzZVtuYW1lXSA9IFtdO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHRoaXMuYmluZGluZ3NbbmFtZV0ucHVzaChmbik7XG4gICAgfTtcblxuICAgIHJldHVybiBFdmVudHM7XG5cbiAgfSkoKTtcblxuICBfWE1MSHR0cFJlcXVlc3QgPSB3aW5kb3cuWE1MSHR0cFJlcXVlc3Q7XG5cbiAgX1hEb21haW5SZXF1ZXN0ID0gd2luZG93LlhEb21haW5SZXF1ZXN0O1xuXG4gIF9XZWJTb2NrZXQgPSB3aW5kb3cuV2ViU29ja2V0O1xuXG4gIGV4dGVuZE5hdGl2ZSA9IGZ1bmN0aW9uKHRvLCBmcm9tKSB7XG4gICAgdmFyIGUsIGtleSwgX3Jlc3VsdHM7XG4gICAgX3Jlc3VsdHMgPSBbXTtcbiAgICBmb3IgKGtleSBpbiBmcm9tLnByb3RvdHlwZSkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCh0b1trZXldID09IG51bGwpICYmIHR5cGVvZiBmcm9tW2tleV0gIT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICBpZiAodHlwZW9mIE9iamVjdC5kZWZpbmVQcm9wZXJ0eSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAgICAgX3Jlc3VsdHMucHVzaChPYmplY3QuZGVmaW5lUHJvcGVydHkodG8sIGtleSwge1xuICAgICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmcm9tLnByb3RvdHlwZVtrZXldO1xuICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICBjb25maWd1cmFibGU6IHRydWUsXG4gICAgICAgICAgICAgIGVudW1lcmFibGU6IHRydWVcbiAgICAgICAgICAgIH0pKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgX3Jlc3VsdHMucHVzaCh0b1trZXldID0gZnJvbS5wcm90b3R5cGVba2V5XSk7XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIF9yZXN1bHRzLnB1c2godm9pZCAwKTtcbiAgICAgICAgfVxuICAgICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICAgIGUgPSBfZXJyb3I7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBfcmVzdWx0cztcbiAgfTtcblxuICBpZ25vcmVTdGFjayA9IFtdO1xuXG4gIFBhY2UuaWdub3JlID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MsIGZuLCByZXQ7XG4gICAgZm4gPSBhcmd1bWVudHNbMF0sIGFyZ3MgPSAyIDw9IGFyZ3VtZW50cy5sZW5ndGggPyBfX3NsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSA6IFtdO1xuICAgIGlnbm9yZVN0YWNrLnVuc2hpZnQoJ2lnbm9yZScpO1xuICAgIHJldCA9IGZuLmFwcGx5KG51bGwsIGFyZ3MpO1xuICAgIGlnbm9yZVN0YWNrLnNoaWZ0KCk7XG4gICAgcmV0dXJuIHJldDtcbiAgfTtcblxuICBQYWNlLnRyYWNrID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIGFyZ3MsIGZuLCByZXQ7XG4gICAgZm4gPSBhcmd1bWVudHNbMF0sIGFyZ3MgPSAyIDw9IGFyZ3VtZW50cy5sZW5ndGggPyBfX3NsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSA6IFtdO1xuICAgIGlnbm9yZVN0YWNrLnVuc2hpZnQoJ3RyYWNrJyk7XG4gICAgcmV0ID0gZm4uYXBwbHkobnVsbCwgYXJncyk7XG4gICAgaWdub3JlU3RhY2suc2hpZnQoKTtcbiAgICByZXR1cm4gcmV0O1xuICB9O1xuXG4gIHNob3VsZFRyYWNrID0gZnVuY3Rpb24obWV0aG9kKSB7XG4gICAgdmFyIF9yZWYyO1xuICAgIGlmIChtZXRob2QgPT0gbnVsbCkge1xuICAgICAgbWV0aG9kID0gJ0dFVCc7XG4gICAgfVxuICAgIGlmIChpZ25vcmVTdGFja1swXSA9PT0gJ3RyYWNrJykge1xuICAgICAgcmV0dXJuICdmb3JjZSc7XG4gICAgfVxuICAgIGlmICghaWdub3JlU3RhY2subGVuZ3RoICYmIG9wdGlvbnMuYWpheCkge1xuICAgICAgaWYgKG1ldGhvZCA9PT0gJ3NvY2tldCcgJiYgb3B0aW9ucy5hamF4LnRyYWNrV2ViU29ja2V0cykge1xuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgIH0gZWxzZSBpZiAoX3JlZjIgPSBtZXRob2QudG9VcHBlckNhc2UoKSwgX19pbmRleE9mLmNhbGwob3B0aW9ucy5hamF4LnRyYWNrTWV0aG9kcywgX3JlZjIpID49IDApIHtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfTtcblxuICBSZXF1ZXN0SW50ZXJjZXB0ID0gKGZ1bmN0aW9uKF9zdXBlcikge1xuICAgIF9fZXh0ZW5kcyhSZXF1ZXN0SW50ZXJjZXB0LCBfc3VwZXIpO1xuXG4gICAgZnVuY3Rpb24gUmVxdWVzdEludGVyY2VwdCgpIHtcbiAgICAgIHZhciBtb25pdG9yWEhSLFxuICAgICAgICBfdGhpcyA9IHRoaXM7XG4gICAgICBSZXF1ZXN0SW50ZXJjZXB0Ll9fc3VwZXJfXy5jb25zdHJ1Y3Rvci5hcHBseSh0aGlzLCBhcmd1bWVudHMpO1xuICAgICAgbW9uaXRvclhIUiA9IGZ1bmN0aW9uKHJlcSkge1xuICAgICAgICB2YXIgX29wZW47XG4gICAgICAgIF9vcGVuID0gcmVxLm9wZW47XG4gICAgICAgIHJldHVybiByZXEub3BlbiA9IGZ1bmN0aW9uKHR5cGUsIHVybCwgYXN5bmMpIHtcbiAgICAgICAgICBpZiAoc2hvdWxkVHJhY2sodHlwZSkpIHtcbiAgICAgICAgICAgIF90aGlzLnRyaWdnZXIoJ3JlcXVlc3QnLCB7XG4gICAgICAgICAgICAgIHR5cGU6IHR5cGUsXG4gICAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgICByZXF1ZXN0OiByZXFcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gX29wZW4uYXBwbHkocmVxLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgICAgfTtcbiAgICAgIHdpbmRvdy5YTUxIdHRwUmVxdWVzdCA9IGZ1bmN0aW9uKGZsYWdzKSB7XG4gICAgICAgIHZhciByZXE7XG4gICAgICAgIHJlcSA9IG5ldyBfWE1MSHR0cFJlcXVlc3QoZmxhZ3MpO1xuICAgICAgICBtb25pdG9yWEhSKHJlcSk7XG4gICAgICAgIHJldHVybiByZXE7XG4gICAgICB9O1xuICAgICAgdHJ5IHtcbiAgICAgICAgZXh0ZW5kTmF0aXZlKHdpbmRvdy5YTUxIdHRwUmVxdWVzdCwgX1hNTEh0dHBSZXF1ZXN0KTtcbiAgICAgIH0gY2F0Y2ggKF9lcnJvcikge31cbiAgICAgIGlmIChfWERvbWFpblJlcXVlc3QgIT0gbnVsbCkge1xuICAgICAgICB3aW5kb3cuWERvbWFpblJlcXVlc3QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICB2YXIgcmVxO1xuICAgICAgICAgIHJlcSA9IG5ldyBfWERvbWFpblJlcXVlc3Q7XG4gICAgICAgICAgbW9uaXRvclhIUihyZXEpO1xuICAgICAgICAgIHJldHVybiByZXE7XG4gICAgICAgIH07XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgZXh0ZW5kTmF0aXZlKHdpbmRvdy5YRG9tYWluUmVxdWVzdCwgX1hEb21haW5SZXF1ZXN0KTtcbiAgICAgICAgfSBjYXRjaCAoX2Vycm9yKSB7fVxuICAgICAgfVxuICAgICAgaWYgKChfV2ViU29ja2V0ICE9IG51bGwpICYmIG9wdGlvbnMuYWpheC50cmFja1dlYlNvY2tldHMpIHtcbiAgICAgICAgd2luZG93LldlYlNvY2tldCA9IGZ1bmN0aW9uKHVybCwgcHJvdG9jb2xzKSB7XG4gICAgICAgICAgdmFyIHJlcTtcbiAgICAgICAgICBpZiAocHJvdG9jb2xzICE9IG51bGwpIHtcbiAgICAgICAgICAgIHJlcSA9IG5ldyBfV2ViU29ja2V0KHVybCwgcHJvdG9jb2xzKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVxID0gbmV3IF9XZWJTb2NrZXQodXJsKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKHNob3VsZFRyYWNrKCdzb2NrZXQnKSkge1xuICAgICAgICAgICAgX3RoaXMudHJpZ2dlcigncmVxdWVzdCcsIHtcbiAgICAgICAgICAgICAgdHlwZTogJ3NvY2tldCcsXG4gICAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgICBwcm90b2NvbHM6IHByb3RvY29scyxcbiAgICAgICAgICAgICAgcmVxdWVzdDogcmVxXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIHJlcTtcbiAgICAgICAgfTtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBleHRlbmROYXRpdmUod2luZG93LldlYlNvY2tldCwgX1dlYlNvY2tldCk7XG4gICAgICAgIH0gY2F0Y2ggKF9lcnJvcikge31cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gUmVxdWVzdEludGVyY2VwdDtcblxuICB9KShFdmVudHMpO1xuXG4gIF9pbnRlcmNlcHQgPSBudWxsO1xuXG4gIGdldEludGVyY2VwdCA9IGZ1bmN0aW9uKCkge1xuICAgIGlmIChfaW50ZXJjZXB0ID09IG51bGwpIHtcbiAgICAgIF9pbnRlcmNlcHQgPSBuZXcgUmVxdWVzdEludGVyY2VwdDtcbiAgICB9XG4gICAgcmV0dXJuIF9pbnRlcmNlcHQ7XG4gIH07XG5cbiAgc2hvdWxkSWdub3JlVVJMID0gZnVuY3Rpb24odXJsKSB7XG4gICAgdmFyIHBhdHRlcm4sIF9qLCBfbGVuMSwgX3JlZjI7XG4gICAgX3JlZjIgPSBvcHRpb25zLmFqYXguaWdub3JlVVJMcztcbiAgICBmb3IgKF9qID0gMCwgX2xlbjEgPSBfcmVmMi5sZW5ndGg7IF9qIDwgX2xlbjE7IF9qKyspIHtcbiAgICAgIHBhdHRlcm4gPSBfcmVmMltfal07XG4gICAgICBpZiAodHlwZW9mIHBhdHRlcm4gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIGlmICh1cmwuaW5kZXhPZihwYXR0ZXJuKSAhPT0gLTEpIHtcbiAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKHBhdHRlcm4udGVzdCh1cmwpKSB7XG4gICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9O1xuXG4gIGdldEludGVyY2VwdCgpLm9uKCdyZXF1ZXN0JywgZnVuY3Rpb24oX2FyZykge1xuICAgIHZhciBhZnRlciwgYXJncywgcmVxdWVzdCwgdHlwZSwgdXJsO1xuICAgIHR5cGUgPSBfYXJnLnR5cGUsIHJlcXVlc3QgPSBfYXJnLnJlcXVlc3QsIHVybCA9IF9hcmcudXJsO1xuICAgIGlmIChzaG91bGRJZ25vcmVVUkwodXJsKSkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBpZiAoIVBhY2UucnVubmluZyAmJiAob3B0aW9ucy5yZXN0YXJ0T25SZXF1ZXN0QWZ0ZXIgIT09IGZhbHNlIHx8IHNob3VsZFRyYWNrKHR5cGUpID09PSAnZm9yY2UnKSkge1xuICAgICAgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgIGFmdGVyID0gb3B0aW9ucy5yZXN0YXJ0T25SZXF1ZXN0QWZ0ZXIgfHwgMDtcbiAgICAgIGlmICh0eXBlb2YgYWZ0ZXIgPT09ICdib29sZWFuJykge1xuICAgICAgICBhZnRlciA9IDA7XG4gICAgICB9XG4gICAgICByZXR1cm4gc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHN0aWxsQWN0aXZlLCBfaiwgX2xlbjEsIF9yZWYyLCBfcmVmMywgX3Jlc3VsdHM7XG4gICAgICAgIGlmICh0eXBlID09PSAnc29ja2V0Jykge1xuICAgICAgICAgIHN0aWxsQWN0aXZlID0gcmVxdWVzdC5yZWFkeVN0YXRlIDwgMjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzdGlsbEFjdGl2ZSA9ICgwIDwgKF9yZWYyID0gcmVxdWVzdC5yZWFkeVN0YXRlKSAmJiBfcmVmMiA8IDQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdGlsbEFjdGl2ZSkge1xuICAgICAgICAgIFBhY2UucmVzdGFydCgpO1xuICAgICAgICAgIF9yZWYzID0gUGFjZS5zb3VyY2VzO1xuICAgICAgICAgIF9yZXN1bHRzID0gW107XG4gICAgICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjMubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgICAgICBzb3VyY2UgPSBfcmVmM1tfal07XG4gICAgICAgICAgICBpZiAoc291cmNlIGluc3RhbmNlb2YgQWpheE1vbml0b3IpIHtcbiAgICAgICAgICAgICAgc291cmNlLndhdGNoLmFwcGx5KHNvdXJjZSwgYXJncyk7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgX3Jlc3VsdHMucHVzaCh2b2lkIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gX3Jlc3VsdHM7XG4gICAgICAgIH1cbiAgICAgIH0sIGFmdGVyKTtcbiAgICB9XG4gIH0pO1xuXG4gIEFqYXhNb25pdG9yID0gKGZ1bmN0aW9uKCkge1xuICAgIGZ1bmN0aW9uIEFqYXhNb25pdG9yKCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgIHRoaXMuZWxlbWVudHMgPSBbXTtcbiAgICAgIGdldEludGVyY2VwdCgpLm9uKCdyZXF1ZXN0JywgZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiBfdGhpcy53YXRjaC5hcHBseShfdGhpcywgYXJndW1lbnRzKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIEFqYXhNb25pdG9yLnByb3RvdHlwZS53YXRjaCA9IGZ1bmN0aW9uKF9hcmcpIHtcbiAgICAgIHZhciByZXF1ZXN0LCB0cmFja2VyLCB0eXBlLCB1cmw7XG4gICAgICB0eXBlID0gX2FyZy50eXBlLCByZXF1ZXN0ID0gX2FyZy5yZXF1ZXN0LCB1cmwgPSBfYXJnLnVybDtcbiAgICAgIGlmIChzaG91bGRJZ25vcmVVUkwodXJsKSkge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgICBpZiAodHlwZSA9PT0gJ3NvY2tldCcpIHtcbiAgICAgICAgdHJhY2tlciA9IG5ldyBTb2NrZXRSZXF1ZXN0VHJhY2tlcihyZXF1ZXN0KTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRyYWNrZXIgPSBuZXcgWEhSUmVxdWVzdFRyYWNrZXIocmVxdWVzdCk7XG4gICAgICB9XG4gICAgICByZXR1cm4gdGhpcy5lbGVtZW50cy5wdXNoKHRyYWNrZXIpO1xuICAgIH07XG5cbiAgICByZXR1cm4gQWpheE1vbml0b3I7XG5cbiAgfSkoKTtcblxuICBYSFJSZXF1ZXN0VHJhY2tlciA9IChmdW5jdGlvbigpIHtcbiAgICBmdW5jdGlvbiBYSFJSZXF1ZXN0VHJhY2tlcihyZXF1ZXN0KSB7XG4gICAgICB2YXIgZXZlbnQsIHNpemUsIF9qLCBfbGVuMSwgX29ucmVhZHlzdGF0ZWNoYW5nZSwgX3JlZjIsXG4gICAgICAgIF90aGlzID0gdGhpcztcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgICAgaWYgKHdpbmRvdy5Qcm9ncmVzc0V2ZW50ICE9IG51bGwpIHtcbiAgICAgICAgc2l6ZSA9IG51bGw7XG4gICAgICAgIHJlcXVlc3QuYWRkRXZlbnRMaXN0ZW5lcigncHJvZ3Jlc3MnLCBmdW5jdGlvbihldnQpIHtcbiAgICAgICAgICBpZiAoZXZ0Lmxlbmd0aENvbXB1dGFibGUpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5wcm9ncmVzcyA9IDEwMCAqIGV2dC5sb2FkZWQgLyBldnQudG90YWw7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5wcm9ncmVzcyA9IF90aGlzLnByb2dyZXNzICsgKDEwMCAtIF90aGlzLnByb2dyZXNzKSAvIDI7XG4gICAgICAgICAgfVxuICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgIF9yZWYyID0gWydsb2FkJywgJ2Fib3J0JywgJ3RpbWVvdXQnLCAnZXJyb3InXTtcbiAgICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjIubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgICAgZXZlbnQgPSBfcmVmMltfal07XG4gICAgICAgICAgcmVxdWVzdC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiBfdGhpcy5wcm9ncmVzcyA9IDEwMDtcbiAgICAgICAgICB9LCBmYWxzZSk7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIF9vbnJlYWR5c3RhdGVjaGFuZ2UgPSByZXF1ZXN0Lm9ucmVhZHlzdGF0ZWNoYW5nZTtcbiAgICAgICAgcmVxdWVzdC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICB2YXIgX3JlZjM7XG4gICAgICAgICAgaWYgKChfcmVmMyA9IHJlcXVlc3QucmVhZHlTdGF0ZSkgPT09IDAgfHwgX3JlZjMgPT09IDQpIHtcbiAgICAgICAgICAgIF90aGlzLnByb2dyZXNzID0gMTAwO1xuICAgICAgICAgIH0gZWxzZSBpZiAocmVxdWVzdC5yZWFkeVN0YXRlID09PSAzKSB7XG4gICAgICAgICAgICBfdGhpcy5wcm9ncmVzcyA9IDUwO1xuICAgICAgICAgIH1cbiAgICAgICAgICByZXR1cm4gdHlwZW9mIF9vbnJlYWR5c3RhdGVjaGFuZ2UgPT09IFwiZnVuY3Rpb25cIiA/IF9vbnJlYWR5c3RhdGVjaGFuZ2UuYXBwbHkobnVsbCwgYXJndW1lbnRzKSA6IHZvaWQgMDtcbiAgICAgICAgfTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gWEhSUmVxdWVzdFRyYWNrZXI7XG5cbiAgfSkoKTtcblxuICBTb2NrZXRSZXF1ZXN0VHJhY2tlciA9IChmdW5jdGlvbigpIHtcbiAgICBmdW5jdGlvbiBTb2NrZXRSZXF1ZXN0VHJhY2tlcihyZXF1ZXN0KSB7XG4gICAgICB2YXIgZXZlbnQsIF9qLCBfbGVuMSwgX3JlZjIsXG4gICAgICAgIF90aGlzID0gdGhpcztcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgICAgX3JlZjIgPSBbJ2Vycm9yJywgJ29wZW4nXTtcbiAgICAgIGZvciAoX2ogPSAwLCBfbGVuMSA9IF9yZWYyLmxlbmd0aDsgX2ogPCBfbGVuMTsgX2orKykge1xuICAgICAgICBldmVudCA9IF9yZWYyW19qXTtcbiAgICAgICAgcmVxdWVzdC5hZGRFdmVudExpc3RlbmVyKGV2ZW50LCBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMucHJvZ3Jlc3MgPSAxMDA7XG4gICAgICAgIH0sIGZhbHNlKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gU29ja2V0UmVxdWVzdFRyYWNrZXI7XG5cbiAgfSkoKTtcblxuICBFbGVtZW50TW9uaXRvciA9IChmdW5jdGlvbigpIHtcbiAgICBmdW5jdGlvbiBFbGVtZW50TW9uaXRvcihvcHRpb25zKSB7XG4gICAgICB2YXIgc2VsZWN0b3IsIF9qLCBfbGVuMSwgX3JlZjI7XG4gICAgICBpZiAob3B0aW9ucyA9PSBudWxsKSB7XG4gICAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICAgIH1cbiAgICAgIHRoaXMuZWxlbWVudHMgPSBbXTtcbiAgICAgIGlmIChvcHRpb25zLnNlbGVjdG9ycyA9PSBudWxsKSB7XG4gICAgICAgIG9wdGlvbnMuc2VsZWN0b3JzID0gW107XG4gICAgICB9XG4gICAgICBfcmVmMiA9IG9wdGlvbnMuc2VsZWN0b3JzO1xuICAgICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjIubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICAgIHNlbGVjdG9yID0gX3JlZjJbX2pdO1xuICAgICAgICB0aGlzLmVsZW1lbnRzLnB1c2gobmV3IEVsZW1lbnRUcmFja2VyKHNlbGVjdG9yKSk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIEVsZW1lbnRNb25pdG9yO1xuXG4gIH0pKCk7XG5cbiAgRWxlbWVudFRyYWNrZXIgPSAoZnVuY3Rpb24oKSB7XG4gICAgZnVuY3Rpb24gRWxlbWVudFRyYWNrZXIoc2VsZWN0b3IpIHtcbiAgICAgIHRoaXMuc2VsZWN0b3IgPSBzZWxlY3RvcjtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSAwO1xuICAgICAgdGhpcy5jaGVjaygpO1xuICAgIH1cblxuICAgIEVsZW1lbnRUcmFja2VyLnByb3RvdHlwZS5jaGVjayA9IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIF90aGlzID0gdGhpcztcbiAgICAgIGlmIChkb2N1bWVudC5xdWVyeVNlbGVjdG9yKHRoaXMuc2VsZWN0b3IpKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmRvbmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBzZXRUaW1lb3V0KChmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMuY2hlY2soKTtcbiAgICAgICAgfSksIG9wdGlvbnMuZWxlbWVudHMuY2hlY2tJbnRlcnZhbCk7XG4gICAgICB9XG4gICAgfTtcblxuICAgIEVsZW1lbnRUcmFja2VyLnByb3RvdHlwZS5kb25lID0gZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gdGhpcy5wcm9ncmVzcyA9IDEwMDtcbiAgICB9O1xuXG4gICAgcmV0dXJuIEVsZW1lbnRUcmFja2VyO1xuXG4gIH0pKCk7XG5cbiAgRG9jdW1lbnRNb25pdG9yID0gKGZ1bmN0aW9uKCkge1xuICAgIERvY3VtZW50TW9uaXRvci5wcm90b3R5cGUuc3RhdGVzID0ge1xuICAgICAgbG9hZGluZzogMCxcbiAgICAgIGludGVyYWN0aXZlOiA1MCxcbiAgICAgIGNvbXBsZXRlOiAxMDBcbiAgICB9O1xuXG4gICAgZnVuY3Rpb24gRG9jdW1lbnRNb25pdG9yKCkge1xuICAgICAgdmFyIF9vbnJlYWR5c3RhdGVjaGFuZ2UsIF9yZWYyLFxuICAgICAgICBfdGhpcyA9IHRoaXM7XG4gICAgICB0aGlzLnByb2dyZXNzID0gKF9yZWYyID0gdGhpcy5zdGF0ZXNbZG9jdW1lbnQucmVhZHlTdGF0ZV0pICE9IG51bGwgPyBfcmVmMiA6IDEwMDtcbiAgICAgIF9vbnJlYWR5c3RhdGVjaGFuZ2UgPSBkb2N1bWVudC5vbnJlYWR5c3RhdGVjaGFuZ2U7XG4gICAgICBkb2N1bWVudC5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKF90aGlzLnN0YXRlc1tkb2N1bWVudC5yZWFkeVN0YXRlXSAhPSBudWxsKSB7XG4gICAgICAgICAgX3RoaXMucHJvZ3Jlc3MgPSBfdGhpcy5zdGF0ZXNbZG9jdW1lbnQucmVhZHlTdGF0ZV07XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHR5cGVvZiBfb25yZWFkeXN0YXRlY2hhbmdlID09PSBcImZ1bmN0aW9uXCIgPyBfb25yZWFkeXN0YXRlY2hhbmdlLmFwcGx5KG51bGwsIGFyZ3VtZW50cykgOiB2b2lkIDA7XG4gICAgICB9O1xuICAgIH1cblxuICAgIHJldHVybiBEb2N1bWVudE1vbml0b3I7XG5cbiAgfSkoKTtcblxuICBFdmVudExhZ01vbml0b3IgPSAoZnVuY3Rpb24oKSB7XG4gICAgZnVuY3Rpb24gRXZlbnRMYWdNb25pdG9yKCkge1xuICAgICAgdmFyIGF2ZywgaW50ZXJ2YWwsIGxhc3QsIHBvaW50cywgc2FtcGxlcyxcbiAgICAgICAgX3RoaXMgPSB0aGlzO1xuICAgICAgdGhpcy5wcm9ncmVzcyA9IDA7XG4gICAgICBhdmcgPSAwO1xuICAgICAgc2FtcGxlcyA9IFtdO1xuICAgICAgcG9pbnRzID0gMDtcbiAgICAgIGxhc3QgPSBub3coKTtcbiAgICAgIGludGVydmFsID0gc2V0SW50ZXJ2YWwoZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBkaWZmO1xuICAgICAgICBkaWZmID0gbm93KCkgLSBsYXN0IC0gNTA7XG4gICAgICAgIGxhc3QgPSBub3coKTtcbiAgICAgICAgc2FtcGxlcy5wdXNoKGRpZmYpO1xuICAgICAgICBpZiAoc2FtcGxlcy5sZW5ndGggPiBvcHRpb25zLmV2ZW50TGFnLnNhbXBsZUNvdW50KSB7XG4gICAgICAgICAgc2FtcGxlcy5zaGlmdCgpO1xuICAgICAgICB9XG4gICAgICAgIGF2ZyA9IGF2Z0FtcGxpdHVkZShzYW1wbGVzKTtcbiAgICAgICAgaWYgKCsrcG9pbnRzID49IG9wdGlvbnMuZXZlbnRMYWcubWluU2FtcGxlcyAmJiBhdmcgPCBvcHRpb25zLmV2ZW50TGFnLmxhZ1RocmVzaG9sZCkge1xuICAgICAgICAgIF90aGlzLnByb2dyZXNzID0gMTAwO1xuICAgICAgICAgIHJldHVybiBjbGVhckludGVydmFsKGludGVydmFsKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gX3RoaXMucHJvZ3Jlc3MgPSAxMDAgKiAoMyAvIChhdmcgKyAzKSk7XG4gICAgICAgIH1cbiAgICAgIH0sIDUwKTtcbiAgICB9XG5cbiAgICByZXR1cm4gRXZlbnRMYWdNb25pdG9yO1xuXG4gIH0pKCk7XG5cbiAgU2NhbGVyID0gKGZ1bmN0aW9uKCkge1xuICAgIGZ1bmN0aW9uIFNjYWxlcihzb3VyY2UpIHtcbiAgICAgIHRoaXMuc291cmNlID0gc291cmNlO1xuICAgICAgdGhpcy5sYXN0ID0gdGhpcy5zaW5jZUxhc3RVcGRhdGUgPSAwO1xuICAgICAgdGhpcy5yYXRlID0gb3B0aW9ucy5pbml0aWFsUmF0ZTtcbiAgICAgIHRoaXMuY2F0Y2h1cCA9IDA7XG4gICAgICB0aGlzLnByb2dyZXNzID0gdGhpcy5sYXN0UHJvZ3Jlc3MgPSAwO1xuICAgICAgaWYgKHRoaXMuc291cmNlICE9IG51bGwpIHtcbiAgICAgICAgdGhpcy5wcm9ncmVzcyA9IHJlc3VsdCh0aGlzLnNvdXJjZSwgJ3Byb2dyZXNzJyk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgU2NhbGVyLnByb3RvdHlwZS50aWNrID0gZnVuY3Rpb24oZnJhbWVUaW1lLCB2YWwpIHtcbiAgICAgIHZhciBzY2FsaW5nO1xuICAgICAgaWYgKHZhbCA9PSBudWxsKSB7XG4gICAgICAgIHZhbCA9IHJlc3VsdCh0aGlzLnNvdXJjZSwgJ3Byb2dyZXNzJyk7XG4gICAgICB9XG4gICAgICBpZiAodmFsID49IDEwMCkge1xuICAgICAgICB0aGlzLmRvbmUgPSB0cnVlO1xuICAgICAgfVxuICAgICAgaWYgKHZhbCA9PT0gdGhpcy5sYXN0KSB7XG4gICAgICAgIHRoaXMuc2luY2VMYXN0VXBkYXRlICs9IGZyYW1lVGltZTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICh0aGlzLnNpbmNlTGFzdFVwZGF0ZSkge1xuICAgICAgICAgIHRoaXMucmF0ZSA9ICh2YWwgLSB0aGlzLmxhc3QpIC8gdGhpcy5zaW5jZUxhc3RVcGRhdGU7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5jYXRjaHVwID0gKHZhbCAtIHRoaXMucHJvZ3Jlc3MpIC8gb3B0aW9ucy5jYXRjaHVwVGltZTtcbiAgICAgICAgdGhpcy5zaW5jZUxhc3RVcGRhdGUgPSAwO1xuICAgICAgICB0aGlzLmxhc3QgPSB2YWw7XG4gICAgICB9XG4gICAgICBpZiAodmFsID4gdGhpcy5wcm9ncmVzcykge1xuICAgICAgICB0aGlzLnByb2dyZXNzICs9IHRoaXMuY2F0Y2h1cCAqIGZyYW1lVGltZTtcbiAgICAgIH1cbiAgICAgIHNjYWxpbmcgPSAxIC0gTWF0aC5wb3codGhpcy5wcm9ncmVzcyAvIDEwMCwgb3B0aW9ucy5lYXNlRmFjdG9yKTtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgKz0gc2NhbGluZyAqIHRoaXMucmF0ZSAqIGZyYW1lVGltZTtcbiAgICAgIHRoaXMucHJvZ3Jlc3MgPSBNYXRoLm1pbih0aGlzLmxhc3RQcm9ncmVzcyArIG9wdGlvbnMubWF4UHJvZ3Jlc3NQZXJGcmFtZSwgdGhpcy5wcm9ncmVzcyk7XG4gICAgICB0aGlzLnByb2dyZXNzID0gTWF0aC5tYXgoMCwgdGhpcy5wcm9ncmVzcyk7XG4gICAgICB0aGlzLnByb2dyZXNzID0gTWF0aC5taW4oMTAwLCB0aGlzLnByb2dyZXNzKTtcbiAgICAgIHRoaXMubGFzdFByb2dyZXNzID0gdGhpcy5wcm9ncmVzcztcbiAgICAgIHJldHVybiB0aGlzLnByb2dyZXNzO1xuICAgIH07XG5cbiAgICByZXR1cm4gU2NhbGVyO1xuXG4gIH0pKCk7XG5cbiAgc291cmNlcyA9IG51bGw7XG5cbiAgc2NhbGVycyA9IG51bGw7XG5cbiAgYmFyID0gbnVsbDtcblxuICB1bmlTY2FsZXIgPSBudWxsO1xuXG4gIGFuaW1hdGlvbiA9IG51bGw7XG5cbiAgY2FuY2VsQW5pbWF0aW9uID0gbnVsbDtcblxuICBQYWNlLnJ1bm5pbmcgPSBmYWxzZTtcblxuICBoYW5kbGVQdXNoU3RhdGUgPSBmdW5jdGlvbigpIHtcbiAgICBpZiAob3B0aW9ucy5yZXN0YXJ0T25QdXNoU3RhdGUpIHtcbiAgICAgIHJldHVybiBQYWNlLnJlc3RhcnQoKTtcbiAgICB9XG4gIH07XG5cbiAgaWYgKHdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZSAhPSBudWxsKSB7XG4gICAgX3B1c2hTdGF0ZSA9IHdpbmRvdy5oaXN0b3J5LnB1c2hTdGF0ZTtcbiAgICB3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUgPSBmdW5jdGlvbigpIHtcbiAgICAgIGhhbmRsZVB1c2hTdGF0ZSgpO1xuICAgICAgcmV0dXJuIF9wdXNoU3RhdGUuYXBwbHkod2luZG93Lmhpc3RvcnksIGFyZ3VtZW50cyk7XG4gICAgfTtcbiAgfVxuXG4gIGlmICh3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGUgIT0gbnVsbCkge1xuICAgIF9yZXBsYWNlU3RhdGUgPSB3aW5kb3cuaGlzdG9yeS5yZXBsYWNlU3RhdGU7XG4gICAgd2luZG93Lmhpc3RvcnkucmVwbGFjZVN0YXRlID0gZnVuY3Rpb24oKSB7XG4gICAgICBoYW5kbGVQdXNoU3RhdGUoKTtcbiAgICAgIHJldHVybiBfcmVwbGFjZVN0YXRlLmFwcGx5KHdpbmRvdy5oaXN0b3J5LCBhcmd1bWVudHMpO1xuICAgIH07XG4gIH1cblxuICBTT1VSQ0VfS0VZUyA9IHtcbiAgICBhamF4OiBBamF4TW9uaXRvcixcbiAgICBlbGVtZW50czogRWxlbWVudE1vbml0b3IsXG4gICAgZG9jdW1lbnQ6IERvY3VtZW50TW9uaXRvcixcbiAgICBldmVudExhZzogRXZlbnRMYWdNb25pdG9yXG4gIH07XG5cbiAgKGluaXQgPSBmdW5jdGlvbigpIHtcbiAgICB2YXIgdHlwZSwgX2osIF9rLCBfbGVuMSwgX2xlbjIsIF9yZWYyLCBfcmVmMywgX3JlZjQ7XG4gICAgUGFjZS5zb3VyY2VzID0gc291cmNlcyA9IFtdO1xuICAgIF9yZWYyID0gWydhamF4JywgJ2VsZW1lbnRzJywgJ2RvY3VtZW50JywgJ2V2ZW50TGFnJ107XG4gICAgZm9yIChfaiA9IDAsIF9sZW4xID0gX3JlZjIubGVuZ3RoOyBfaiA8IF9sZW4xOyBfaisrKSB7XG4gICAgICB0eXBlID0gX3JlZjJbX2pdO1xuICAgICAgaWYgKG9wdGlvbnNbdHlwZV0gIT09IGZhbHNlKSB7XG4gICAgICAgIHNvdXJjZXMucHVzaChuZXcgU09VUkNFX0tFWVNbdHlwZV0ob3B0aW9uc1t0eXBlXSkpO1xuICAgICAgfVxuICAgIH1cbiAgICBfcmVmNCA9IChfcmVmMyA9IG9wdGlvbnMuZXh0cmFTb3VyY2VzKSAhPSBudWxsID8gX3JlZjMgOiBbXTtcbiAgICBmb3IgKF9rID0gMCwgX2xlbjIgPSBfcmVmNC5sZW5ndGg7IF9rIDwgX2xlbjI7IF9rKyspIHtcbiAgICAgIHNvdXJjZSA9IF9yZWY0W19rXTtcbiAgICAgIHNvdXJjZXMucHVzaChuZXcgc291cmNlKG9wdGlvbnMpKTtcbiAgICB9XG4gICAgUGFjZS5iYXIgPSBiYXIgPSBuZXcgQmFyO1xuICAgIHNjYWxlcnMgPSBbXTtcbiAgICByZXR1cm4gdW5pU2NhbGVyID0gbmV3IFNjYWxlcjtcbiAgfSkoKTtcblxuICBQYWNlLnN0b3AgPSBmdW5jdGlvbigpIHtcbiAgICBQYWNlLnRyaWdnZXIoJ3N0b3AnKTtcbiAgICBQYWNlLnJ1bm5pbmcgPSBmYWxzZTtcbiAgICBiYXIuZGVzdHJveSgpO1xuICAgIGNhbmNlbEFuaW1hdGlvbiA9IHRydWU7XG4gICAgaWYgKGFuaW1hdGlvbiAhPSBudWxsKSB7XG4gICAgICBpZiAodHlwZW9mIGNhbmNlbEFuaW1hdGlvbkZyYW1lID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgY2FuY2VsQW5pbWF0aW9uRnJhbWUoYW5pbWF0aW9uKTtcbiAgICAgIH1cbiAgICAgIGFuaW1hdGlvbiA9IG51bGw7XG4gICAgfVxuICAgIHJldHVybiBpbml0KCk7XG4gIH07XG5cbiAgUGFjZS5yZXN0YXJ0ID0gZnVuY3Rpb24oKSB7XG4gICAgUGFjZS50cmlnZ2VyKCdyZXN0YXJ0Jyk7XG4gICAgUGFjZS5zdG9wKCk7XG4gICAgcmV0dXJuIFBhY2Uuc3RhcnQoKTtcbiAgfTtcblxuICBQYWNlLmdvID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHN0YXJ0O1xuICAgIFBhY2UucnVubmluZyA9IHRydWU7XG4gICAgYmFyLnJlbmRlcigpO1xuICAgIHN0YXJ0ID0gbm93KCk7XG4gICAgY2FuY2VsQW5pbWF0aW9uID0gZmFsc2U7XG4gICAgcmV0dXJuIGFuaW1hdGlvbiA9IHJ1bkFuaW1hdGlvbihmdW5jdGlvbihmcmFtZVRpbWUsIGVucXVldWVOZXh0RnJhbWUpIHtcbiAgICAgIHZhciBhdmcsIGNvdW50LCBkb25lLCBlbGVtZW50LCBlbGVtZW50cywgaSwgaiwgcmVtYWluaW5nLCBzY2FsZXIsIHNjYWxlckxpc3QsIHN1bSwgX2osIF9rLCBfbGVuMSwgX2xlbjIsIF9yZWYyO1xuICAgICAgcmVtYWluaW5nID0gMTAwIC0gYmFyLnByb2dyZXNzO1xuICAgICAgY291bnQgPSBzdW0gPSAwO1xuICAgICAgZG9uZSA9IHRydWU7XG4gICAgICBmb3IgKGkgPSBfaiA9IDAsIF9sZW4xID0gc291cmNlcy5sZW5ndGg7IF9qIDwgX2xlbjE7IGkgPSArK19qKSB7XG4gICAgICAgIHNvdXJjZSA9IHNvdXJjZXNbaV07XG4gICAgICAgIHNjYWxlckxpc3QgPSBzY2FsZXJzW2ldICE9IG51bGwgPyBzY2FsZXJzW2ldIDogc2NhbGVyc1tpXSA9IFtdO1xuICAgICAgICBlbGVtZW50cyA9IChfcmVmMiA9IHNvdXJjZS5lbGVtZW50cykgIT0gbnVsbCA/IF9yZWYyIDogW3NvdXJjZV07XG4gICAgICAgIGZvciAoaiA9IF9rID0gMCwgX2xlbjIgPSBlbGVtZW50cy5sZW5ndGg7IF9rIDwgX2xlbjI7IGogPSArK19rKSB7XG4gICAgICAgICAgZWxlbWVudCA9IGVsZW1lbnRzW2pdO1xuICAgICAgICAgIHNjYWxlciA9IHNjYWxlckxpc3Rbal0gIT0gbnVsbCA/IHNjYWxlckxpc3Rbal0gOiBzY2FsZXJMaXN0W2pdID0gbmV3IFNjYWxlcihlbGVtZW50KTtcbiAgICAgICAgICBkb25lICY9IHNjYWxlci5kb25lO1xuICAgICAgICAgIGlmIChzY2FsZXIuZG9uZSkge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvdW50Kys7XG4gICAgICAgICAgc3VtICs9IHNjYWxlci50aWNrKGZyYW1lVGltZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGF2ZyA9IHN1bSAvIGNvdW50O1xuICAgICAgYmFyLnVwZGF0ZSh1bmlTY2FsZXIudGljayhmcmFtZVRpbWUsIGF2ZykpO1xuICAgICAgaWYgKGJhci5kb25lKCkgfHwgZG9uZSB8fCBjYW5jZWxBbmltYXRpb24pIHtcbiAgICAgICAgYmFyLnVwZGF0ZSgxMDApO1xuICAgICAgICBQYWNlLnRyaWdnZXIoJ2RvbmUnKTtcbiAgICAgICAgcmV0dXJuIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgYmFyLmZpbmlzaCgpO1xuICAgICAgICAgIFBhY2UucnVubmluZyA9IGZhbHNlO1xuICAgICAgICAgIHJldHVybiBQYWNlLnRyaWdnZXIoJ2hpZGUnKTtcbiAgICAgICAgfSwgTWF0aC5tYXgob3B0aW9ucy5naG9zdFRpbWUsIE1hdGgubWF4KG9wdGlvbnMubWluVGltZSAtIChub3coKSAtIHN0YXJ0KSwgMCkpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBlbnF1ZXVlTmV4dEZyYW1lKCk7XG4gICAgICB9XG4gICAgfSk7XG4gIH07XG5cbiAgUGFjZS5zdGFydCA9IGZ1bmN0aW9uKF9vcHRpb25zKSB7XG4gICAgZXh0ZW5kKG9wdGlvbnMsIF9vcHRpb25zKTtcbiAgICBQYWNlLnJ1bm5pbmcgPSB0cnVlO1xuICAgIHRyeSB7XG4gICAgICBiYXIucmVuZGVyKCk7XG4gICAgfSBjYXRjaCAoX2Vycm9yKSB7XG4gICAgICBOb1RhcmdldEVycm9yID0gX2Vycm9yO1xuICAgIH1cbiAgICBpZiAoIWRvY3VtZW50LnF1ZXJ5U2VsZWN0b3IoJy5wYWNlJykpIHtcbiAgICAgIHJldHVybiBzZXRUaW1lb3V0KFBhY2Uuc3RhcnQsIDUwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgUGFjZS50cmlnZ2VyKCdzdGFydCcpO1xuICAgICAgcmV0dXJuIFBhY2UuZ28oKTtcbiAgICB9XG4gIH07XG5cbiAgaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAgIGRlZmluZShbJ3BhY2UnXSwgZnVuY3Rpb24oKSB7XG4gICAgICByZXR1cm4gUGFjZTtcbiAgICB9KTtcbiAgfSBlbHNlIGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcpIHtcbiAgICBtb2R1bGUuZXhwb3J0cyA9IFBhY2U7XG4gIH0gZWxzZSB7XG4gICAgaWYgKG9wdGlvbnMuc3RhcnRPblBhZ2VMb2FkKSB7XG4gICAgICBQYWNlLnN0YXJ0KCk7XG4gICAgfVxuICB9XG5cbn0pLmNhbGwodGhpcyk7XG4iLCIoZnVuY3Rpb24ocm9vdCwgZmFjdG9yeSkge1xuXHQvLyBgcm9vdGAgZG9lcyBub3QgcmVzb2x2ZSB0byB0aGUgZ2xvYmFsIHdpbmRvdyBvYmplY3QgaW4gYSBCcm93c2VyaWZpZWRcblx0Ly8gYnVuZGxlLCBzbyBhIGRpcmVjdCByZWZlcmVuY2UgdG8gdGhhdCBvYmplY3QgaXMgdXNlZCBpbnN0ZWFkLlxuXHR2YXIgX3NyY0RvYyA9IHdpbmRvdy5zcmNEb2M7XG5cblx0aWYgKHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSB7XG5cdFx0ZGVmaW5lKFsnZXhwb3J0cyddLCBmdW5jdGlvbihleHBvcnRzKSB7XG5cdFx0XHRmYWN0b3J5KGV4cG9ydHMsIF9zcmNEb2MpO1xuXHRcdFx0cm9vdC5zcmNEb2MgPSBleHBvcnRzO1xuXHRcdH0pO1xuXHR9IGVsc2UgaWYgKHR5cGVvZiBleHBvcnRzID09PSBcIm9iamVjdFwiKSB7XG5cdFx0ZmFjdG9yeShleHBvcnRzLCBfc3JjRG9jKTtcblx0fSBlbHNlIHtcblx0XHRyb290LnNyY0RvYyA9IHt9O1xuXHRcdGZhY3Rvcnkocm9vdC5zcmNEb2MsIF9zcmNEb2MpO1xuXHR9XG59KSh0aGlzLCBmdW5jdGlvbihleHBvcnRzLCBfc3JjRG9jKSB7XG5cdHZhciBpZHgsIGlmcmFtZXM7XG5cdHZhciBpc0NvbXBsaWFudCA9ICEhKFwic3JjZG9jXCIgaW4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImlmcmFtZVwiKSk7XG5cdHZhciBpbXBsZW1lbnRhdGlvbnMgPSB7XG5cdFx0Y29tcGxpYW50OiBmdW5jdGlvbiggaWZyYW1lLCBjb250ZW50ICkge1xuXG5cdFx0XHRpZiAoY29udGVudCkge1xuXHRcdFx0XHRpZnJhbWUuc2V0QXR0cmlidXRlKFwic3JjZG9jXCIsIGNvbnRlbnQpO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0bGVnYWN5OiBmdW5jdGlvbiggaWZyYW1lLCBjb250ZW50ICkge1xuXG5cdFx0XHR2YXIganNVcmw7XG5cblx0XHRcdGlmICghaWZyYW1lIHx8ICFpZnJhbWUuZ2V0QXR0cmlidXRlKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCFjb250ZW50KSB7XG5cdFx0XHRcdGNvbnRlbnQgPSBpZnJhbWUuZ2V0QXR0cmlidXRlKFwic3JjZG9jXCIpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWZyYW1lLnNldEF0dHJpYnV0ZShcInNyY2RvY1wiLCBjb250ZW50KTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKGNvbnRlbnQpIHtcblx0XHRcdFx0Ly8gVGhlIHZhbHVlIHJldHVybmVkIGJ5IGEgc2NyaXB0LXRhcmdldGVkIFVSTCB3aWxsIGJlIHVzZWQgYXNcblx0XHRcdFx0Ly8gdGhlIGlGcmFtZSdzIGNvbnRlbnQuIENyZWF0ZSBzdWNoIGEgVVJMIHdoaWNoIHJldHVybnMgdGhlXG5cdFx0XHRcdC8vIGlGcmFtZSBlbGVtZW50J3MgYHNyY2RvY2AgYXR0cmlidXRlLlxuXHRcdFx0XHRqc1VybCA9IFwiamF2YXNjcmlwdDogd2luZG93LmZyYW1lRWxlbWVudC5nZXRBdHRyaWJ1dGUoJ3NyY2RvYycpO1wiO1xuXG5cdFx0XHRcdGlmcmFtZS5zZXRBdHRyaWJ1dGUoXCJzcmNcIiwganNVcmwpO1xuXG5cdFx0XHRcdC8vIEV4cGxpY2l0bHkgc2V0IHRoZSBpRnJhbWUncyB3aW5kb3cubG9jYXRpb24gZm9yXG5cdFx0XHRcdC8vIGNvbXBhdGFiaWxpdHkgd2l0aCBJRTksIHdoaWNoIGRvZXMgbm90IHJlYWN0IHRvIGNoYW5nZXMgaW5cblx0XHRcdFx0Ly8gdGhlIGBzcmNgIGF0dHJpYnV0ZSB3aGVuIGl0IGlzIGEgYGphdmFzY3JpcHQ6YCBVUkwsIGZvclxuXHRcdFx0XHQvLyBzb21lIHJlYXNvblxuXHRcdFx0XHRpZiAoaWZyYW1lLmNvbnRlbnRXaW5kb3cpIHtcblx0XHRcdFx0XHRpZnJhbWUuY29udGVudFdpbmRvdy5sb2NhdGlvbiA9IGpzVXJsO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHR2YXIgc3JjRG9jID0gZXhwb3J0cztcblx0Ly8gQXNzdW1lIHRoZSBiZXN0XG5cdHNyY0RvYy5zZXQgPSBpbXBsZW1lbnRhdGlvbnMuY29tcGxpYW50O1xuXHRzcmNEb2Mubm9Db25mbGljdCA9IGZ1bmN0aW9uKCkge1xuXHRcdHdpbmRvdy5zcmNEb2MgPSBfc3JjRG9jO1xuXHRcdHJldHVybiBzcmNEb2M7XG5cdH07XG5cblx0Ly8gSWYgdGhlIGJyb3dzZXIgc3VwcG9ydHMgc3JjZG9jLCBubyBzaGltbWluZyBpcyBuZWNlc3Nhcnlcblx0aWYgKGlzQ29tcGxpYW50KSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0c3JjRG9jLnNldCA9IGltcGxlbWVudGF0aW9ucy5sZWdhY3k7XG5cblx0Ly8gQXV0b21hdGljYWxseSBzaGltIGFueSBpZnJhbWVzIGFscmVhZHkgcHJlc2VudCBpbiB0aGUgZG9jdW1lbnRcblx0aWZyYW1lcyA9IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKFwiaWZyYW1lXCIpO1xuXHRpZHggPSBpZnJhbWVzLmxlbmd0aDtcblxuXHR3aGlsZSAoaWR4LS0pIHtcblx0XHRzcmNEb2Muc2V0KCBpZnJhbWVzW2lkeF0gKTtcblx0fVxuXG59KTtcbiIsIi8qISBqUXVlcnkgVUkgLSB2MS4xMi4xIC0gMjAxNi0wOS0xNFxuKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4qIEluY2x1ZGVzOiB3aWRnZXQuanMsIHBvc2l0aW9uLmpzLCBkYXRhLmpzLCBkaXNhYmxlLXNlbGVjdGlvbi5qcywgZWZmZWN0LmpzLCBlZmZlY3RzL2VmZmVjdC1ibGluZC5qcywgZWZmZWN0cy9lZmZlY3QtYm91bmNlLmpzLCBlZmZlY3RzL2VmZmVjdC1jbGlwLmpzLCBlZmZlY3RzL2VmZmVjdC1kcm9wLmpzLCBlZmZlY3RzL2VmZmVjdC1leHBsb2RlLmpzLCBlZmZlY3RzL2VmZmVjdC1mYWRlLmpzLCBlZmZlY3RzL2VmZmVjdC1mb2xkLmpzLCBlZmZlY3RzL2VmZmVjdC1oaWdobGlnaHQuanMsIGVmZmVjdHMvZWZmZWN0LXB1ZmYuanMsIGVmZmVjdHMvZWZmZWN0LXB1bHNhdGUuanMsIGVmZmVjdHMvZWZmZWN0LXNjYWxlLmpzLCBlZmZlY3RzL2VmZmVjdC1zaGFrZS5qcywgZWZmZWN0cy9lZmZlY3Qtc2l6ZS5qcywgZWZmZWN0cy9lZmZlY3Qtc2xpZGUuanMsIGVmZmVjdHMvZWZmZWN0LXRyYW5zZmVyLmpzLCBmb2N1c2FibGUuanMsIGZvcm0tcmVzZXQtbWl4aW4uanMsIGpxdWVyeS0xLTcuanMsIGtleWNvZGUuanMsIGxhYmVscy5qcywgc2Nyb2xsLXBhcmVudC5qcywgdGFiYmFibGUuanMsIHVuaXF1ZS1pZC5qcywgd2lkZ2V0cy9hY2NvcmRpb24uanMsIHdpZGdldHMvYXV0b2NvbXBsZXRlLmpzLCB3aWRnZXRzL2J1dHRvbi5qcywgd2lkZ2V0cy9jaGVja2JveHJhZGlvLmpzLCB3aWRnZXRzL2NvbnRyb2xncm91cC5qcywgd2lkZ2V0cy9kYXRlcGlja2VyLmpzLCB3aWRnZXRzL2RpYWxvZy5qcywgd2lkZ2V0cy9kcmFnZ2FibGUuanMsIHdpZGdldHMvZHJvcHBhYmxlLmpzLCB3aWRnZXRzL21lbnUuanMsIHdpZGdldHMvbW91c2UuanMsIHdpZGdldHMvcHJvZ3Jlc3NiYXIuanMsIHdpZGdldHMvcmVzaXphYmxlLmpzLCB3aWRnZXRzL3NlbGVjdGFibGUuanMsIHdpZGdldHMvc2VsZWN0bWVudS5qcywgd2lkZ2V0cy9zbGlkZXIuanMsIHdpZGdldHMvc29ydGFibGUuanMsIHdpZGdldHMvc3Bpbm5lci5qcywgd2lkZ2V0cy90YWJzLmpzLCB3aWRnZXRzL3Rvb2x0aXAuanNcbiogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnM7IExpY2Vuc2VkIE1JVCAqL1xuXG4oZnVuY3Rpb24oIGZhY3RvcnkgKSB7XG5cdGlmICggdHlwZW9mIGRlZmluZSA9PT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQgKSB7XG5cblx0XHQvLyBBTUQuIFJlZ2lzdGVyIGFzIGFuIGFub255bW91cyBtb2R1bGUuXG5cdFx0ZGVmaW5lKFsgXCJqcXVlcnlcIiBdLCBmYWN0b3J5ICk7XG5cdH0gZWxzZSB7XG5cblx0XHQvLyBCcm93c2VyIGdsb2JhbHNcblx0XHRmYWN0b3J5KCBqUXVlcnkgKTtcblx0fVxufShmdW5jdGlvbiggJCApIHtcblxuJC51aSA9ICQudWkgfHwge307XG5cbnZhciB2ZXJzaW9uID0gJC51aS52ZXJzaW9uID0gXCIxLjEyLjFcIjtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBXaWRnZXQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFdpZGdldFxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFByb3ZpZGVzIGEgZmFjdG9yeSBmb3IgY3JlYXRpbmcgc3RhdGVmdWwgd2lkZ2V0cyB3aXRoIGEgY29tbW9uIEFQSS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9qUXVlcnkud2lkZ2V0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3dpZGdldC9cblxuXG5cbnZhciB3aWRnZXRVdWlkID0gMDtcbnZhciB3aWRnZXRTbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcblxuJC5jbGVhbkRhdGEgPSAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRyZXR1cm4gZnVuY3Rpb24oIGVsZW1zICkge1xuXHRcdHZhciBldmVudHMsIGVsZW0sIGk7XG5cdFx0Zm9yICggaSA9IDA7ICggZWxlbSA9IGVsZW1zWyBpIF0gKSAhPSBudWxsOyBpKysgKSB7XG5cdFx0XHR0cnkge1xuXG5cdFx0XHRcdC8vIE9ubHkgdHJpZ2dlciByZW1vdmUgd2hlbiBuZWNlc3NhcnkgdG8gc2F2ZSB0aW1lXG5cdFx0XHRcdGV2ZW50cyA9ICQuX2RhdGEoIGVsZW0sIFwiZXZlbnRzXCIgKTtcblx0XHRcdFx0aWYgKCBldmVudHMgJiYgZXZlbnRzLnJlbW92ZSApIHtcblx0XHRcdFx0XHQkKCBlbGVtICkudHJpZ2dlckhhbmRsZXIoIFwicmVtb3ZlXCIgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBIdHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC84MjM1XG5cdFx0XHR9IGNhdGNoICggZSApIHt9XG5cdFx0fVxuXHRcdG9yaWcoIGVsZW1zICk7XG5cdH07XG59ICkoICQuY2xlYW5EYXRhICk7XG5cbiQud2lkZ2V0ID0gZnVuY3Rpb24oIG5hbWUsIGJhc2UsIHByb3RvdHlwZSApIHtcblx0dmFyIGV4aXN0aW5nQ29uc3RydWN0b3IsIGNvbnN0cnVjdG9yLCBiYXNlUHJvdG90eXBlO1xuXG5cdC8vIFByb3hpZWRQcm90b3R5cGUgYWxsb3dzIHRoZSBwcm92aWRlZCBwcm90b3R5cGUgdG8gcmVtYWluIHVubW9kaWZpZWRcblx0Ly8gc28gdGhhdCBpdCBjYW4gYmUgdXNlZCBhcyBhIG1peGluIGZvciBtdWx0aXBsZSB3aWRnZXRzICgjODg3Nilcblx0dmFyIHByb3hpZWRQcm90b3R5cGUgPSB7fTtcblxuXHR2YXIgbmFtZXNwYWNlID0gbmFtZS5zcGxpdCggXCIuXCIgKVsgMCBdO1xuXHRuYW1lID0gbmFtZS5zcGxpdCggXCIuXCIgKVsgMSBdO1xuXHR2YXIgZnVsbE5hbWUgPSBuYW1lc3BhY2UgKyBcIi1cIiArIG5hbWU7XG5cblx0aWYgKCAhcHJvdG90eXBlICkge1xuXHRcdHByb3RvdHlwZSA9IGJhc2U7XG5cdFx0YmFzZSA9ICQuV2lkZ2V0O1xuXHR9XG5cblx0aWYgKCAkLmlzQXJyYXkoIHByb3RvdHlwZSApICkge1xuXHRcdHByb3RvdHlwZSA9ICQuZXh0ZW5kLmFwcGx5KCBudWxsLCBbIHt9IF0uY29uY2F0KCBwcm90b3R5cGUgKSApO1xuXHR9XG5cblx0Ly8gQ3JlYXRlIHNlbGVjdG9yIGZvciBwbHVnaW5cblx0JC5leHByWyBcIjpcIiBdWyBmdWxsTmFtZS50b0xvd2VyQ2FzZSgpIF0gPSBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gISEkLmRhdGEoIGVsZW0sIGZ1bGxOYW1lICk7XG5cdH07XG5cblx0JFsgbmFtZXNwYWNlIF0gPSAkWyBuYW1lc3BhY2UgXSB8fCB7fTtcblx0ZXhpc3RpbmdDb25zdHJ1Y3RvciA9ICRbIG5hbWVzcGFjZSBdWyBuYW1lIF07XG5cdGNvbnN0cnVjdG9yID0gJFsgbmFtZXNwYWNlIF1bIG5hbWUgXSA9IGZ1bmN0aW9uKCBvcHRpb25zLCBlbGVtZW50ICkge1xuXG5cdFx0Ly8gQWxsb3cgaW5zdGFudGlhdGlvbiB3aXRob3V0IFwibmV3XCIga2V5d29yZFxuXHRcdGlmICggIXRoaXMuX2NyZWF0ZVdpZGdldCApIHtcblx0XHRcdHJldHVybiBuZXcgY29uc3RydWN0b3IoIG9wdGlvbnMsIGVsZW1lbnQgKTtcblx0XHR9XG5cblx0XHQvLyBBbGxvdyBpbnN0YW50aWF0aW9uIHdpdGhvdXQgaW5pdGlhbGl6aW5nIGZvciBzaW1wbGUgaW5oZXJpdGFuY2Vcblx0XHQvLyBtdXN0IHVzZSBcIm5ld1wiIGtleXdvcmQgKHRoZSBjb2RlIGFib3ZlIGFsd2F5cyBwYXNzZXMgYXJncylcblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLl9jcmVhdGVXaWRnZXQoIG9wdGlvbnMsIGVsZW1lbnQgKTtcblx0XHR9XG5cdH07XG5cblx0Ly8gRXh0ZW5kIHdpdGggdGhlIGV4aXN0aW5nIGNvbnN0cnVjdG9yIHRvIGNhcnJ5IG92ZXIgYW55IHN0YXRpYyBwcm9wZXJ0aWVzXG5cdCQuZXh0ZW5kKCBjb25zdHJ1Y3RvciwgZXhpc3RpbmdDb25zdHJ1Y3Rvciwge1xuXHRcdHZlcnNpb246IHByb3RvdHlwZS52ZXJzaW9uLFxuXG5cdFx0Ly8gQ29weSB0aGUgb2JqZWN0IHVzZWQgdG8gY3JlYXRlIHRoZSBwcm90b3R5cGUgaW4gY2FzZSB3ZSBuZWVkIHRvXG5cdFx0Ly8gcmVkZWZpbmUgdGhlIHdpZGdldCBsYXRlclxuXHRcdF9wcm90bzogJC5leHRlbmQoIHt9LCBwcm90b3R5cGUgKSxcblxuXHRcdC8vIFRyYWNrIHdpZGdldHMgdGhhdCBpbmhlcml0IGZyb20gdGhpcyB3aWRnZXQgaW4gY2FzZSB0aGlzIHdpZGdldCBpc1xuXHRcdC8vIHJlZGVmaW5lZCBhZnRlciBhIHdpZGdldCBpbmhlcml0cyBmcm9tIGl0XG5cdFx0X2NoaWxkQ29uc3RydWN0b3JzOiBbXVxuXHR9ICk7XG5cblx0YmFzZVByb3RvdHlwZSA9IG5ldyBiYXNlKCk7XG5cblx0Ly8gV2UgbmVlZCB0byBtYWtlIHRoZSBvcHRpb25zIGhhc2ggYSBwcm9wZXJ0eSBkaXJlY3RseSBvbiB0aGUgbmV3IGluc3RhbmNlXG5cdC8vIG90aGVyd2lzZSB3ZSdsbCBtb2RpZnkgdGhlIG9wdGlvbnMgaGFzaCBvbiB0aGUgcHJvdG90eXBlIHRoYXQgd2UncmVcblx0Ly8gaW5oZXJpdGluZyBmcm9tXG5cdGJhc2VQcm90b3R5cGUub3B0aW9ucyA9ICQud2lkZ2V0LmV4dGVuZCgge30sIGJhc2VQcm90b3R5cGUub3B0aW9ucyApO1xuXHQkLmVhY2goIHByb3RvdHlwZSwgZnVuY3Rpb24oIHByb3AsIHZhbHVlICkge1xuXHRcdGlmICggISQuaXNGdW5jdGlvbiggdmFsdWUgKSApIHtcblx0XHRcdHByb3hpZWRQcm90b3R5cGVbIHByb3AgXSA9IHZhbHVlO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRwcm94aWVkUHJvdG90eXBlWyBwcm9wIF0gPSAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0ZnVuY3Rpb24gX3N1cGVyKCkge1xuXHRcdFx0XHRyZXR1cm4gYmFzZS5wcm90b3R5cGVbIHByb3AgXS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHR9XG5cblx0XHRcdGZ1bmN0aW9uIF9zdXBlckFwcGx5KCBhcmdzICkge1xuXHRcdFx0XHRyZXR1cm4gYmFzZS5wcm90b3R5cGVbIHByb3AgXS5hcHBseSggdGhpcywgYXJncyApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBfX3N1cGVyID0gdGhpcy5fc3VwZXI7XG5cdFx0XHRcdHZhciBfX3N1cGVyQXBwbHkgPSB0aGlzLl9zdXBlckFwcGx5O1xuXHRcdFx0XHR2YXIgcmV0dXJuVmFsdWU7XG5cblx0XHRcdFx0dGhpcy5fc3VwZXIgPSBfc3VwZXI7XG5cdFx0XHRcdHRoaXMuX3N1cGVyQXBwbHkgPSBfc3VwZXJBcHBseTtcblxuXHRcdFx0XHRyZXR1cm5WYWx1ZSA9IHZhbHVlLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblxuXHRcdFx0XHR0aGlzLl9zdXBlciA9IF9fc3VwZXI7XG5cdFx0XHRcdHRoaXMuX3N1cGVyQXBwbHkgPSBfX3N1cGVyQXBwbHk7XG5cblx0XHRcdFx0cmV0dXJuIHJldHVyblZhbHVlO1xuXHRcdFx0fTtcblx0XHR9ICkoKTtcblx0fSApO1xuXHRjb25zdHJ1Y3Rvci5wcm90b3R5cGUgPSAkLndpZGdldC5leHRlbmQoIGJhc2VQcm90b3R5cGUsIHtcblxuXHRcdC8vIFRPRE86IHJlbW92ZSBzdXBwb3J0IGZvciB3aWRnZXRFdmVudFByZWZpeFxuXHRcdC8vIGFsd2F5cyB1c2UgdGhlIG5hbWUgKyBhIGNvbG9uIGFzIHRoZSBwcmVmaXgsIGUuZy4sIGRyYWdnYWJsZTpzdGFydFxuXHRcdC8vIGRvbid0IHByZWZpeCBmb3Igd2lkZ2V0cyB0aGF0IGFyZW4ndCBET00tYmFzZWRcblx0XHR3aWRnZXRFdmVudFByZWZpeDogZXhpc3RpbmdDb25zdHJ1Y3RvciA/ICggYmFzZVByb3RvdHlwZS53aWRnZXRFdmVudFByZWZpeCB8fCBuYW1lICkgOiBuYW1lXG5cdH0sIHByb3hpZWRQcm90b3R5cGUsIHtcblx0XHRjb25zdHJ1Y3RvcjogY29uc3RydWN0b3IsXG5cdFx0bmFtZXNwYWNlOiBuYW1lc3BhY2UsXG5cdFx0d2lkZ2V0TmFtZTogbmFtZSxcblx0XHR3aWRnZXRGdWxsTmFtZTogZnVsbE5hbWVcblx0fSApO1xuXG5cdC8vIElmIHRoaXMgd2lkZ2V0IGlzIGJlaW5nIHJlZGVmaW5lZCB0aGVuIHdlIG5lZWQgdG8gZmluZCBhbGwgd2lkZ2V0cyB0aGF0XG5cdC8vIGFyZSBpbmhlcml0aW5nIGZyb20gaXQgYW5kIHJlZGVmaW5lIGFsbCBvZiB0aGVtIHNvIHRoYXQgdGhleSBpbmhlcml0IGZyb21cblx0Ly8gdGhlIG5ldyB2ZXJzaW9uIG9mIHRoaXMgd2lkZ2V0LiBXZSdyZSBlc3NlbnRpYWxseSB0cnlpbmcgdG8gcmVwbGFjZSBvbmVcblx0Ly8gbGV2ZWwgaW4gdGhlIHByb3RvdHlwZSBjaGFpbi5cblx0aWYgKCBleGlzdGluZ0NvbnN0cnVjdG9yICkge1xuXHRcdCQuZWFjaCggZXhpc3RpbmdDb25zdHJ1Y3Rvci5fY2hpbGRDb25zdHJ1Y3RvcnMsIGZ1bmN0aW9uKCBpLCBjaGlsZCApIHtcblx0XHRcdHZhciBjaGlsZFByb3RvdHlwZSA9IGNoaWxkLnByb3RvdHlwZTtcblxuXHRcdFx0Ly8gUmVkZWZpbmUgdGhlIGNoaWxkIHdpZGdldCB1c2luZyB0aGUgc2FtZSBwcm90b3R5cGUgdGhhdCB3YXNcblx0XHRcdC8vIG9yaWdpbmFsbHkgdXNlZCwgYnV0IGluaGVyaXQgZnJvbSB0aGUgbmV3IHZlcnNpb24gb2YgdGhlIGJhc2Vcblx0XHRcdCQud2lkZ2V0KCBjaGlsZFByb3RvdHlwZS5uYW1lc3BhY2UgKyBcIi5cIiArIGNoaWxkUHJvdG90eXBlLndpZGdldE5hbWUsIGNvbnN0cnVjdG9yLFxuXHRcdFx0XHRjaGlsZC5fcHJvdG8gKTtcblx0XHR9ICk7XG5cblx0XHQvLyBSZW1vdmUgdGhlIGxpc3Qgb2YgZXhpc3RpbmcgY2hpbGQgY29uc3RydWN0b3JzIGZyb20gdGhlIG9sZCBjb25zdHJ1Y3RvclxuXHRcdC8vIHNvIHRoZSBvbGQgY2hpbGQgY29uc3RydWN0b3JzIGNhbiBiZSBnYXJiYWdlIGNvbGxlY3RlZFxuXHRcdGRlbGV0ZSBleGlzdGluZ0NvbnN0cnVjdG9yLl9jaGlsZENvbnN0cnVjdG9ycztcblx0fSBlbHNlIHtcblx0XHRiYXNlLl9jaGlsZENvbnN0cnVjdG9ycy5wdXNoKCBjb25zdHJ1Y3RvciApO1xuXHR9XG5cblx0JC53aWRnZXQuYnJpZGdlKCBuYW1lLCBjb25zdHJ1Y3RvciApO1xuXG5cdHJldHVybiBjb25zdHJ1Y3Rvcjtcbn07XG5cbiQud2lkZ2V0LmV4dGVuZCA9IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdHZhciBpbnB1dCA9IHdpZGdldFNsaWNlLmNhbGwoIGFyZ3VtZW50cywgMSApO1xuXHR2YXIgaW5wdXRJbmRleCA9IDA7XG5cdHZhciBpbnB1dExlbmd0aCA9IGlucHV0Lmxlbmd0aDtcblx0dmFyIGtleTtcblx0dmFyIHZhbHVlO1xuXG5cdGZvciAoIDsgaW5wdXRJbmRleCA8IGlucHV0TGVuZ3RoOyBpbnB1dEluZGV4KysgKSB7XG5cdFx0Zm9yICgga2V5IGluIGlucHV0WyBpbnB1dEluZGV4IF0gKSB7XG5cdFx0XHR2YWx1ZSA9IGlucHV0WyBpbnB1dEluZGV4IF1bIGtleSBdO1xuXHRcdFx0aWYgKCBpbnB1dFsgaW5wdXRJbmRleCBdLmhhc093blByb3BlcnR5KCBrZXkgKSAmJiB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdC8vIENsb25lIG9iamVjdHNcblx0XHRcdFx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIHZhbHVlICkgKSB7XG5cdFx0XHRcdFx0dGFyZ2V0WyBrZXkgXSA9ICQuaXNQbGFpbk9iamVjdCggdGFyZ2V0WyBrZXkgXSApID9cblx0XHRcdFx0XHRcdCQud2lkZ2V0LmV4dGVuZCgge30sIHRhcmdldFsga2V5IF0sIHZhbHVlICkgOlxuXG5cdFx0XHRcdFx0XHQvLyBEb24ndCBleHRlbmQgc3RyaW5ncywgYXJyYXlzLCBldGMuIHdpdGggb2JqZWN0c1xuXHRcdFx0XHRcdFx0JC53aWRnZXQuZXh0ZW5kKCB7fSwgdmFsdWUgKTtcblxuXHRcdFx0XHQvLyBDb3B5IGV2ZXJ5dGhpbmcgZWxzZSBieSByZWZlcmVuY2Vcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0YXJnZXRbIGtleSBdID0gdmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblx0cmV0dXJuIHRhcmdldDtcbn07XG5cbiQud2lkZ2V0LmJyaWRnZSA9IGZ1bmN0aW9uKCBuYW1lLCBvYmplY3QgKSB7XG5cdHZhciBmdWxsTmFtZSA9IG9iamVjdC5wcm90b3R5cGUud2lkZ2V0RnVsbE5hbWUgfHwgbmFtZTtcblx0JC5mblsgbmFtZSBdID0gZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIGlzTWV0aG9kQ2FsbCA9IHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiO1xuXHRcdHZhciBhcmdzID0gd2lkZ2V0U2xpY2UuY2FsbCggYXJndW1lbnRzLCAxICk7XG5cdFx0dmFyIHJldHVyblZhbHVlID0gdGhpcztcblxuXHRcdGlmICggaXNNZXRob2RDYWxsICkge1xuXG5cdFx0XHQvLyBJZiB0aGlzIGlzIGFuIGVtcHR5IGNvbGxlY3Rpb24sIHdlIG5lZWQgdG8gaGF2ZSB0aGUgaW5zdGFuY2UgbWV0aG9kXG5cdFx0XHQvLyByZXR1cm4gdW5kZWZpbmVkIGluc3RlYWQgb2YgdGhlIGpRdWVyeSBpbnN0YW5jZVxuXHRcdFx0aWYgKCAhdGhpcy5sZW5ndGggJiYgb3B0aW9ucyA9PT0gXCJpbnN0YW5jZVwiICkge1xuXHRcdFx0XHRyZXR1cm5WYWx1ZSA9IHVuZGVmaW5lZDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIG1ldGhvZFZhbHVlO1xuXHRcdFx0XHRcdHZhciBpbnN0YW5jZSA9ICQuZGF0YSggdGhpcywgZnVsbE5hbWUgKTtcblxuXHRcdFx0XHRcdGlmICggb3B0aW9ucyA9PT0gXCJpbnN0YW5jZVwiICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuVmFsdWUgPSBpbnN0YW5jZTtcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICFpbnN0YW5jZSApIHtcblx0XHRcdFx0XHRcdHJldHVybiAkLmVycm9yKCBcImNhbm5vdCBjYWxsIG1ldGhvZHMgb24gXCIgKyBuYW1lICtcblx0XHRcdFx0XHRcdFx0XCIgcHJpb3IgdG8gaW5pdGlhbGl6YXRpb247IFwiICtcblx0XHRcdFx0XHRcdFx0XCJhdHRlbXB0ZWQgdG8gY2FsbCBtZXRob2QgJ1wiICsgb3B0aW9ucyArIFwiJ1wiICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhJC5pc0Z1bmN0aW9uKCBpbnN0YW5jZVsgb3B0aW9ucyBdICkgfHwgb3B0aW9ucy5jaGFyQXQoIDAgKSA9PT0gXCJfXCIgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gJC5lcnJvciggXCJubyBzdWNoIG1ldGhvZCAnXCIgKyBvcHRpb25zICsgXCInIGZvciBcIiArIG5hbWUgK1xuXHRcdFx0XHRcdFx0XHRcIiB3aWRnZXQgaW5zdGFuY2VcIiApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdG1ldGhvZFZhbHVlID0gaW5zdGFuY2VbIG9wdGlvbnMgXS5hcHBseSggaW5zdGFuY2UsIGFyZ3MgKTtcblxuXHRcdFx0XHRcdGlmICggbWV0aG9kVmFsdWUgIT09IGluc3RhbmNlICYmIG1ldGhvZFZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm5WYWx1ZSA9IG1ldGhvZFZhbHVlICYmIG1ldGhvZFZhbHVlLmpxdWVyeSA/XG5cdFx0XHRcdFx0XHRcdHJldHVyblZhbHVlLnB1c2hTdGFjayggbWV0aG9kVmFsdWUuZ2V0KCkgKSA6XG5cdFx0XHRcdFx0XHRcdG1ldGhvZFZhbHVlO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIEFsbG93IG11bHRpcGxlIGhhc2hlcyB0byBiZSBwYXNzZWQgb24gaW5pdFxuXHRcdFx0aWYgKCBhcmdzLmxlbmd0aCApIHtcblx0XHRcdFx0b3B0aW9ucyA9ICQud2lkZ2V0LmV4dGVuZC5hcHBseSggbnVsbCwgWyBvcHRpb25zIF0uY29uY2F0KCBhcmdzICkgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGluc3RhbmNlID0gJC5kYXRhKCB0aGlzLCBmdWxsTmFtZSApO1xuXHRcdFx0XHRpZiAoIGluc3RhbmNlICkge1xuXHRcdFx0XHRcdGluc3RhbmNlLm9wdGlvbiggb3B0aW9ucyB8fCB7fSApO1xuXHRcdFx0XHRcdGlmICggaW5zdGFuY2UuX2luaXQgKSB7XG5cdFx0XHRcdFx0XHRpbnN0YW5jZS5faW5pdCgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQkLmRhdGEoIHRoaXMsIGZ1bGxOYW1lLCBuZXcgb2JqZWN0KCBvcHRpb25zLCB0aGlzICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHJldHVybiByZXR1cm5WYWx1ZTtcblx0fTtcbn07XG5cbiQuV2lkZ2V0ID0gZnVuY3Rpb24oIC8qIG9wdGlvbnMsIGVsZW1lbnQgKi8gKSB7fTtcbiQuV2lkZ2V0Ll9jaGlsZENvbnN0cnVjdG9ycyA9IFtdO1xuXG4kLldpZGdldC5wcm90b3R5cGUgPSB7XG5cdHdpZGdldE5hbWU6IFwid2lkZ2V0XCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcIlwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8ZGl2PlwiLFxuXG5cdG9wdGlvbnM6IHtcblx0XHRjbGFzc2VzOiB7fSxcblx0XHRkaXNhYmxlZDogZmFsc2UsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRjcmVhdGU6IG51bGxcblx0fSxcblxuXHRfY3JlYXRlV2lkZ2V0OiBmdW5jdGlvbiggb3B0aW9ucywgZWxlbWVudCApIHtcblx0XHRlbGVtZW50ID0gJCggZWxlbWVudCB8fCB0aGlzLmRlZmF1bHRFbGVtZW50IHx8IHRoaXMgKVsgMCBdO1xuXHRcdHRoaXMuZWxlbWVudCA9ICQoIGVsZW1lbnQgKTtcblx0XHR0aGlzLnV1aWQgPSB3aWRnZXRVdWlkKys7XG5cdFx0dGhpcy5ldmVudE5hbWVzcGFjZSA9IFwiLlwiICsgdGhpcy53aWRnZXROYW1lICsgdGhpcy51dWlkO1xuXG5cdFx0dGhpcy5iaW5kaW5ncyA9ICQoKTtcblx0XHR0aGlzLmhvdmVyYWJsZSA9ICQoKTtcblx0XHR0aGlzLmZvY3VzYWJsZSA9ICQoKTtcblx0XHR0aGlzLmNsYXNzZXNFbGVtZW50TG9va3VwID0ge307XG5cblx0XHRpZiAoIGVsZW1lbnQgIT09IHRoaXMgKSB7XG5cdFx0XHQkLmRhdGEoIGVsZW1lbnQsIHRoaXMud2lkZ2V0RnVsbE5hbWUsIHRoaXMgKTtcblx0XHRcdHRoaXMuX29uKCB0cnVlLCB0aGlzLmVsZW1lbnQsIHtcblx0XHRcdFx0cmVtb3ZlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0aWYgKCBldmVudC50YXJnZXQgPT09IGVsZW1lbnQgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmRlc3Ryb3koKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHRcdHRoaXMuZG9jdW1lbnQgPSAkKCBlbGVtZW50LnN0eWxlID9cblxuXHRcdFx0XHQvLyBFbGVtZW50IHdpdGhpbiB0aGUgZG9jdW1lbnRcblx0XHRcdFx0ZWxlbWVudC5vd25lckRvY3VtZW50IDpcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIHdpbmRvdyBvciBkb2N1bWVudFxuXHRcdFx0XHRlbGVtZW50LmRvY3VtZW50IHx8IGVsZW1lbnQgKTtcblx0XHRcdHRoaXMud2luZG93ID0gJCggdGhpcy5kb2N1bWVudFsgMCBdLmRlZmF1bHRWaWV3IHx8IHRoaXMuZG9jdW1lbnRbIDAgXS5wYXJlbnRXaW5kb3cgKTtcblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnMgPSAkLndpZGdldC5leHRlbmQoIHt9LFxuXHRcdFx0dGhpcy5vcHRpb25zLFxuXHRcdFx0dGhpcy5fZ2V0Q3JlYXRlT3B0aW9ucygpLFxuXHRcdFx0b3B0aW9ucyApO1xuXG5cdFx0dGhpcy5fY3JlYXRlKCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbkRpc2FibGVkKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKTtcblx0XHR9XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcImNyZWF0ZVwiLCBudWxsLCB0aGlzLl9nZXRDcmVhdGVFdmVudERhdGEoKSApO1xuXHRcdHRoaXMuX2luaXQoKTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHt9O1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVFdmVudERhdGE6ICQubm9vcCxcblxuXHRfY3JlYXRlOiAkLm5vb3AsXG5cblx0X2luaXQ6ICQubm9vcCxcblxuXHRkZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLl9kZXN0cm95KCk7XG5cdFx0JC5lYWNoKCB0aGlzLmNsYXNzZXNFbGVtZW50TG9va3VwLCBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCB2YWx1ZSwga2V5ICk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gV2UgY2FuIHByb2JhYmx5IHJlbW92ZSB0aGUgdW5iaW5kIGNhbGxzIGluIDIuMFxuXHRcdC8vIGFsbCBldmVudCBiaW5kaW5ncyBzaG91bGQgZ28gdGhyb3VnaCB0aGlzLl9vbigpXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQub2ZmKCB0aGlzLmV2ZW50TmFtZXNwYWNlIClcblx0XHRcdC5yZW1vdmVEYXRhKCB0aGlzLndpZGdldEZ1bGxOYW1lICk7XG5cdFx0dGhpcy53aWRnZXQoKVxuXHRcdFx0Lm9mZiggdGhpcy5ldmVudE5hbWVzcGFjZSApXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJhcmlhLWRpc2FibGVkXCIgKTtcblxuXHRcdC8vIENsZWFuIHVwIGV2ZW50cyBhbmQgc3RhdGVzXG5cdFx0dGhpcy5iaW5kaW5ncy5vZmYoIHRoaXMuZXZlbnROYW1lc3BhY2UgKTtcblx0fSxcblxuXHRfZGVzdHJveTogJC5ub29wLFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWxlbWVudDtcblx0fSxcblxuXHRvcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBvcHRpb25zID0ga2V5O1xuXHRcdHZhciBwYXJ0cztcblx0XHR2YXIgY3VyT3B0aW9uO1xuXHRcdHZhciBpO1xuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHQvLyBEb24ndCByZXR1cm4gYSByZWZlcmVuY2UgdG8gdGhlIGludGVybmFsIGhhc2hcblx0XHRcdHJldHVybiAkLndpZGdldC5leHRlbmQoIHt9LCB0aGlzLm9wdGlvbnMgKTtcblx0XHR9XG5cblx0XHRpZiAoIHR5cGVvZiBrZXkgPT09IFwic3RyaW5nXCIgKSB7XG5cblx0XHRcdC8vIEhhbmRsZSBuZXN0ZWQga2V5cywgZS5nLiwgXCJmb28uYmFyXCIgPT4geyBmb286IHsgYmFyOiBfX18gfSB9XG5cdFx0XHRvcHRpb25zID0ge307XG5cdFx0XHRwYXJ0cyA9IGtleS5zcGxpdCggXCIuXCIgKTtcblx0XHRcdGtleSA9IHBhcnRzLnNoaWZ0KCk7XG5cdFx0XHRpZiAoIHBhcnRzLmxlbmd0aCApIHtcblx0XHRcdFx0Y3VyT3B0aW9uID0gb3B0aW9uc1sga2V5IF0gPSAkLndpZGdldC5leHRlbmQoIHt9LCB0aGlzLm9wdGlvbnNbIGtleSBdICk7XG5cdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgcGFydHMubGVuZ3RoIC0gMTsgaSsrICkge1xuXHRcdFx0XHRcdGN1ck9wdGlvblsgcGFydHNbIGkgXSBdID0gY3VyT3B0aW9uWyBwYXJ0c1sgaSBdIF0gfHwge307XG5cdFx0XHRcdFx0Y3VyT3B0aW9uID0gY3VyT3B0aW9uWyBwYXJ0c1sgaSBdIF07XG5cdFx0XHRcdH1cblx0XHRcdFx0a2V5ID0gcGFydHMucG9wKCk7XG5cdFx0XHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdFx0XHRyZXR1cm4gY3VyT3B0aW9uWyBrZXkgXSA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IGN1ck9wdGlvblsga2V5IF07XG5cdFx0XHRcdH1cblx0XHRcdFx0Y3VyT3B0aW9uWyBrZXkgXSA9IHZhbHVlO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID09PSAxICkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLm9wdGlvbnNbIGtleSBdID09PSB1bmRlZmluZWQgPyBudWxsIDogdGhpcy5vcHRpb25zWyBrZXkgXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRvcHRpb25zWyBrZXkgXSA9IHZhbHVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX3NldE9wdGlvbnMoIG9wdGlvbnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25zOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIga2V5O1xuXG5cdFx0Zm9yICgga2V5IGluIG9wdGlvbnMgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb24oIGtleSwgb3B0aW9uc1sga2V5IF0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJjbGFzc2VzXCIgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb25DbGFzc2VzKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMub3B0aW9uc1sga2V5IF0gPSB2YWx1ZTtcblxuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb25EaXNhYmxlZCggdmFsdWUgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfc2V0T3B0aW9uQ2xhc3NlczogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBjbGFzc0tleSwgZWxlbWVudHMsIGN1cnJlbnRFbGVtZW50cztcblxuXHRcdGZvciAoIGNsYXNzS2V5IGluIHZhbHVlICkge1xuXHRcdFx0Y3VycmVudEVsZW1lbnRzID0gdGhpcy5jbGFzc2VzRWxlbWVudExvb2t1cFsgY2xhc3NLZXkgXTtcblx0XHRcdGlmICggdmFsdWVbIGNsYXNzS2V5IF0gPT09IHRoaXMub3B0aW9ucy5jbGFzc2VzWyBjbGFzc0tleSBdIHx8XG5cdFx0XHRcdFx0IWN1cnJlbnRFbGVtZW50cyB8fFxuXHRcdFx0XHRcdCFjdXJyZW50RWxlbWVudHMubGVuZ3RoICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2UgYXJlIGRvaW5nIHRoaXMgdG8gY3JlYXRlIGEgbmV3IGpRdWVyeSBvYmplY3QgYmVjYXVzZSB0aGUgX3JlbW92ZUNsYXNzKCkgY2FsbFxuXHRcdFx0Ly8gb24gdGhlIG5leHQgbGluZSBpcyBnb2luZyB0byBkZXN0cm95IHRoZSByZWZlcmVuY2UgdG8gdGhlIGN1cnJlbnQgZWxlbWVudHMgYmVpbmdcblx0XHRcdC8vIHRyYWNrZWQuIFdlIG5lZWQgdG8gc2F2ZSBhIGNvcHkgb2YgdGhpcyBjb2xsZWN0aW9uIHNvIHRoYXQgd2UgY2FuIGFkZCB0aGUgbmV3IGNsYXNzZXNcblx0XHRcdC8vIGJlbG93LlxuXHRcdFx0ZWxlbWVudHMgPSAkKCBjdXJyZW50RWxlbWVudHMuZ2V0KCkgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjdXJyZW50RWxlbWVudHMsIGNsYXNzS2V5ICk7XG5cblx0XHRcdC8vIFdlIGRvbid0IHVzZSBfYWRkQ2xhc3MoKSBoZXJlLCBiZWNhdXNlIHRoYXQgdXNlcyB0aGlzLm9wdGlvbnMuY2xhc3Nlc1xuXHRcdFx0Ly8gZm9yIGdlbmVyYXRpbmcgdGhlIHN0cmluZyBvZiBjbGFzc2VzLiBXZSB3YW50IHRvIHVzZSB0aGUgdmFsdWUgcGFzc2VkIGluIGZyb21cblx0XHRcdC8vIF9zZXRPcHRpb24oKSwgdGhpcyBpcyB0aGUgbmV3IHZhbHVlIG9mIHRoZSBjbGFzc2VzIG9wdGlvbiB3aGljaCB3YXMgcGFzc2VkIHRvXG5cdFx0XHQvLyBfc2V0T3B0aW9uKCkuIFdlIHBhc3MgdGhpcyB2YWx1ZSBkaXJlY3RseSB0byBfY2xhc3NlcygpLlxuXHRcdFx0ZWxlbWVudHMuYWRkQ2xhc3MoIHRoaXMuX2NsYXNzZXMoIHtcblx0XHRcdFx0ZWxlbWVudDogZWxlbWVudHMsXG5cdFx0XHRcdGtleXM6IGNsYXNzS2V5LFxuXHRcdFx0XHRjbGFzc2VzOiB2YWx1ZSxcblx0XHRcdFx0YWRkOiB0cnVlXG5cdFx0XHR9ICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMud2lkZ2V0KCksIHRoaXMud2lkZ2V0RnVsbE5hbWUgKyBcIi1kaXNhYmxlZFwiLCBudWxsLCAhIXZhbHVlICk7XG5cblx0XHQvLyBJZiB0aGUgd2lkZ2V0IGlzIGJlY29taW5nIGRpc2FibGVkLCB0aGVuIG5vdGhpbmcgaXMgaW50ZXJhY3RpdmVcblx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaG92ZXJhYmxlLCBudWxsLCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmZvY3VzYWJsZSwgbnVsbCwgXCJ1aS1zdGF0ZS1mb2N1c1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdGVuYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3NldE9wdGlvbnMoIHsgZGlzYWJsZWQ6IGZhbHNlIH0gKTtcblx0fSxcblxuXHRkaXNhYmxlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5fc2V0T3B0aW9ucyggeyBkaXNhYmxlZDogdHJ1ZSB9ICk7XG5cdH0sXG5cblx0X2NsYXNzZXM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciBmdWxsID0gW107XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0b3B0aW9ucyA9ICQuZXh0ZW5kKCB7XG5cdFx0XHRlbGVtZW50OiB0aGlzLmVsZW1lbnQsXG5cdFx0XHRjbGFzc2VzOiB0aGlzLm9wdGlvbnMuY2xhc3NlcyB8fCB7fVxuXHRcdH0sIG9wdGlvbnMgKTtcblxuXHRcdGZ1bmN0aW9uIHByb2Nlc3NDbGFzc1N0cmluZyggY2xhc3NlcywgY2hlY2tPcHRpb24gKSB7XG5cdFx0XHR2YXIgY3VycmVudCwgaTtcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgY2xhc3Nlcy5sZW5ndGg7IGkrKyApIHtcblx0XHRcdFx0Y3VycmVudCA9IHRoYXQuY2xhc3Nlc0VsZW1lbnRMb29rdXBbIGNsYXNzZXNbIGkgXSBdIHx8ICQoKTtcblx0XHRcdFx0aWYgKCBvcHRpb25zLmFkZCApIHtcblx0XHRcdFx0XHRjdXJyZW50ID0gJCggJC51bmlxdWUoIGN1cnJlbnQuZ2V0KCkuY29uY2F0KCBvcHRpb25zLmVsZW1lbnQuZ2V0KCkgKSApICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y3VycmVudCA9ICQoIGN1cnJlbnQubm90KCBvcHRpb25zLmVsZW1lbnQgKS5nZXQoKSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoYXQuY2xhc3Nlc0VsZW1lbnRMb29rdXBbIGNsYXNzZXNbIGkgXSBdID0gY3VycmVudDtcblx0XHRcdFx0ZnVsbC5wdXNoKCBjbGFzc2VzWyBpIF0gKTtcblx0XHRcdFx0aWYgKCBjaGVja09wdGlvbiAmJiBvcHRpb25zLmNsYXNzZXNbIGNsYXNzZXNbIGkgXSBdICkge1xuXHRcdFx0XHRcdGZ1bGwucHVzaCggb3B0aW9ucy5jbGFzc2VzWyBjbGFzc2VzWyBpIF0gXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fb24oIG9wdGlvbnMuZWxlbWVudCwge1xuXHRcdFx0XCJyZW1vdmVcIjogXCJfdW50cmFja0NsYXNzZXNFbGVtZW50XCJcblx0XHR9ICk7XG5cblx0XHRpZiAoIG9wdGlvbnMua2V5cyApIHtcblx0XHRcdHByb2Nlc3NDbGFzc1N0cmluZyggb3B0aW9ucy5rZXlzLm1hdGNoKCAvXFxTKy9nICkgfHwgW10sIHRydWUgKTtcblx0XHR9XG5cdFx0aWYgKCBvcHRpb25zLmV4dHJhICkge1xuXHRcdFx0cHJvY2Vzc0NsYXNzU3RyaW5nKCBvcHRpb25zLmV4dHJhLm1hdGNoKCAvXFxTKy9nICkgfHwgW10gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZnVsbC5qb2luKCBcIiBcIiApO1xuXHR9LFxuXG5cdF91bnRyYWNrQ2xhc3Nlc0VsZW1lbnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0JC5lYWNoKCB0aGF0LmNsYXNzZXNFbGVtZW50TG9va3VwLCBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdGlmICggJC5pbkFycmF5KCBldmVudC50YXJnZXQsIHZhbHVlICkgIT09IC0xICkge1xuXHRcdFx0XHR0aGF0LmNsYXNzZXNFbGVtZW50TG9va3VwWyBrZXkgXSA9ICQoIHZhbHVlLm5vdCggZXZlbnQudGFyZ2V0ICkuZ2V0KCkgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X3JlbW92ZUNsYXNzOiBmdW5jdGlvbiggZWxlbWVudCwga2V5cywgZXh0cmEgKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3RvZ2dsZUNsYXNzKCBlbGVtZW50LCBrZXlzLCBleHRyYSwgZmFsc2UgKTtcblx0fSxcblxuXHRfYWRkQ2xhc3M6IGZ1bmN0aW9uKCBlbGVtZW50LCBrZXlzLCBleHRyYSApIHtcblx0XHRyZXR1cm4gdGhpcy5fdG9nZ2xlQ2xhc3MoIGVsZW1lbnQsIGtleXMsIGV4dHJhLCB0cnVlICk7XG5cdH0sXG5cblx0X3RvZ2dsZUNsYXNzOiBmdW5jdGlvbiggZWxlbWVudCwga2V5cywgZXh0cmEsIGFkZCApIHtcblx0XHRhZGQgPSAoIHR5cGVvZiBhZGQgPT09IFwiYm9vbGVhblwiICkgPyBhZGQgOiBleHRyYTtcblx0XHR2YXIgc2hpZnQgPSAoIHR5cGVvZiBlbGVtZW50ID09PSBcInN0cmluZ1wiIHx8IGVsZW1lbnQgPT09IG51bGwgKSxcblx0XHRcdG9wdGlvbnMgPSB7XG5cdFx0XHRcdGV4dHJhOiBzaGlmdCA/IGtleXMgOiBleHRyYSxcblx0XHRcdFx0a2V5czogc2hpZnQgPyBlbGVtZW50IDoga2V5cyxcblx0XHRcdFx0ZWxlbWVudDogc2hpZnQgPyB0aGlzLmVsZW1lbnQgOiBlbGVtZW50LFxuXHRcdFx0XHRhZGQ6IGFkZFxuXHRcdFx0fTtcblx0XHRvcHRpb25zLmVsZW1lbnQudG9nZ2xlQ2xhc3MoIHRoaXMuX2NsYXNzZXMoIG9wdGlvbnMgKSwgYWRkICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X29uOiBmdW5jdGlvbiggc3VwcHJlc3NEaXNhYmxlZENoZWNrLCBlbGVtZW50LCBoYW5kbGVycyApIHtcblx0XHR2YXIgZGVsZWdhdGVFbGVtZW50O1xuXHRcdHZhciBpbnN0YW5jZSA9IHRoaXM7XG5cblx0XHQvLyBObyBzdXBwcmVzc0Rpc2FibGVkQ2hlY2sgZmxhZywgc2h1ZmZsZSBhcmd1bWVudHNcblx0XHRpZiAoIHR5cGVvZiBzdXBwcmVzc0Rpc2FibGVkQ2hlY2sgIT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0aGFuZGxlcnMgPSBlbGVtZW50O1xuXHRcdFx0ZWxlbWVudCA9IHN1cHByZXNzRGlzYWJsZWRDaGVjaztcblx0XHRcdHN1cHByZXNzRGlzYWJsZWRDaGVjayA9IGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIE5vIGVsZW1lbnQgYXJndW1lbnQsIHNodWZmbGUgYW5kIHVzZSB0aGlzLmVsZW1lbnRcblx0XHRpZiAoICFoYW5kbGVycyApIHtcblx0XHRcdGhhbmRsZXJzID0gZWxlbWVudDtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmVsZW1lbnQ7XG5cdFx0XHRkZWxlZ2F0ZUVsZW1lbnQgPSB0aGlzLndpZGdldCgpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtZW50ID0gZGVsZWdhdGVFbGVtZW50ID0gJCggZWxlbWVudCApO1xuXHRcdFx0dGhpcy5iaW5kaW5ncyA9IHRoaXMuYmluZGluZ3MuYWRkKCBlbGVtZW50ICk7XG5cdFx0fVxuXG5cdFx0JC5lYWNoKCBoYW5kbGVycywgZnVuY3Rpb24oIGV2ZW50LCBoYW5kbGVyICkge1xuXHRcdFx0ZnVuY3Rpb24gaGFuZGxlclByb3h5KCkge1xuXG5cdFx0XHRcdC8vIEFsbG93IHdpZGdldHMgdG8gY3VzdG9taXplIHRoZSBkaXNhYmxlZCBoYW5kbGluZ1xuXHRcdFx0XHQvLyAtIGRpc2FibGVkIGFzIGFuIGFycmF5IGluc3RlYWQgb2YgYm9vbGVhblxuXHRcdFx0XHQvLyAtIGRpc2FibGVkIGNsYXNzIGFzIG1ldGhvZCBmb3IgZGlzYWJsaW5nIGluZGl2aWR1YWwgcGFydHNcblx0XHRcdFx0aWYgKCAhc3VwcHJlc3NEaXNhYmxlZENoZWNrICYmXG5cdFx0XHRcdFx0XHQoIGluc3RhbmNlLm9wdGlvbnMuZGlzYWJsZWQgPT09IHRydWUgfHxcblx0XHRcdFx0XHRcdCQoIHRoaXMgKS5oYXNDbGFzcyggXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuICggdHlwZW9mIGhhbmRsZXIgPT09IFwic3RyaW5nXCIgPyBpbnN0YW5jZVsgaGFuZGxlciBdIDogaGFuZGxlciApXG5cdFx0XHRcdFx0LmFwcGx5KCBpbnN0YW5jZSwgYXJndW1lbnRzICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvcHkgdGhlIGd1aWQgc28gZGlyZWN0IHVuYmluZGluZyB3b3Jrc1xuXHRcdFx0aWYgKCB0eXBlb2YgaGFuZGxlciAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0aGFuZGxlclByb3h5Lmd1aWQgPSBoYW5kbGVyLmd1aWQgPVxuXHRcdFx0XHRcdGhhbmRsZXIuZ3VpZCB8fCBoYW5kbGVyUHJveHkuZ3VpZCB8fCAkLmd1aWQrKztcblx0XHRcdH1cblxuXHRcdFx0dmFyIG1hdGNoID0gZXZlbnQubWF0Y2goIC9eKFtcXHc6LV0qKVxccyooLiopJC8gKTtcblx0XHRcdHZhciBldmVudE5hbWUgPSBtYXRjaFsgMSBdICsgaW5zdGFuY2UuZXZlbnROYW1lc3BhY2U7XG5cdFx0XHR2YXIgc2VsZWN0b3IgPSBtYXRjaFsgMiBdO1xuXG5cdFx0XHRpZiAoIHNlbGVjdG9yICkge1xuXHRcdFx0XHRkZWxlZ2F0ZUVsZW1lbnQub24oIGV2ZW50TmFtZSwgc2VsZWN0b3IsIGhhbmRsZXJQcm94eSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWxlbWVudC5vbiggZXZlbnROYW1lLCBoYW5kbGVyUHJveHkgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X29mZjogZnVuY3Rpb24oIGVsZW1lbnQsIGV2ZW50TmFtZSApIHtcblx0XHRldmVudE5hbWUgPSAoIGV2ZW50TmFtZSB8fCBcIlwiICkuc3BsaXQoIFwiIFwiICkuam9pbiggdGhpcy5ldmVudE5hbWVzcGFjZSArIFwiIFwiICkgK1xuXHRcdFx0dGhpcy5ldmVudE5hbWVzcGFjZTtcblx0XHRlbGVtZW50Lm9mZiggZXZlbnROYW1lICkub2ZmKCBldmVudE5hbWUgKTtcblxuXHRcdC8vIENsZWFyIHRoZSBzdGFjayB0byBhdm9pZCBtZW1vcnkgbGVha3MgKCMxMDA1Nilcblx0XHR0aGlzLmJpbmRpbmdzID0gJCggdGhpcy5iaW5kaW5ncy5ub3QoIGVsZW1lbnQgKS5nZXQoKSApO1xuXHRcdHRoaXMuZm9jdXNhYmxlID0gJCggdGhpcy5mb2N1c2FibGUubm90KCBlbGVtZW50ICkuZ2V0KCkgKTtcblx0XHR0aGlzLmhvdmVyYWJsZSA9ICQoIHRoaXMuaG92ZXJhYmxlLm5vdCggZWxlbWVudCApLmdldCgpICk7XG5cdH0sXG5cblx0X2RlbGF5OiBmdW5jdGlvbiggaGFuZGxlciwgZGVsYXkgKSB7XG5cdFx0ZnVuY3Rpb24gaGFuZGxlclByb3h5KCkge1xuXHRcdFx0cmV0dXJuICggdHlwZW9mIGhhbmRsZXIgPT09IFwic3RyaW5nXCIgPyBpbnN0YW5jZVsgaGFuZGxlciBdIDogaGFuZGxlciApXG5cdFx0XHRcdC5hcHBseSggaW5zdGFuY2UsIGFyZ3VtZW50cyApO1xuXHRcdH1cblx0XHR2YXIgaW5zdGFuY2UgPSB0aGlzO1xuXHRcdHJldHVybiBzZXRUaW1lb3V0KCBoYW5kbGVyUHJveHksIGRlbGF5IHx8IDAgKTtcblx0fSxcblxuXHRfaG92ZXJhYmxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR0aGlzLmhvdmVyYWJsZSA9IHRoaXMuaG92ZXJhYmxlLmFkZCggZWxlbWVudCApO1xuXHRcdHRoaXMuX29uKCBlbGVtZW50LCB7XG5cdFx0XHRtb3VzZWVudGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdFx0fSxcblx0XHRcdG1vdXNlbGVhdmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9mb2N1c2FibGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHRoaXMuZm9jdXNhYmxlID0gdGhpcy5mb2N1c2FibGUuYWRkKCBlbGVtZW50ICk7XG5cdFx0dGhpcy5fb24oIGVsZW1lbnQsIHtcblx0XHRcdGZvY3VzaW46IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1mb2N1c1wiICk7XG5cdFx0XHR9LFxuXHRcdFx0Zm9jdXNvdXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1mb2N1c1wiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF90cmlnZ2VyOiBmdW5jdGlvbiggdHlwZSwgZXZlbnQsIGRhdGEgKSB7XG5cdFx0dmFyIHByb3AsIG9yaWc7XG5cdFx0dmFyIGNhbGxiYWNrID0gdGhpcy5vcHRpb25zWyB0eXBlIF07XG5cblx0XHRkYXRhID0gZGF0YSB8fCB7fTtcblx0XHRldmVudCA9ICQuRXZlbnQoIGV2ZW50ICk7XG5cdFx0ZXZlbnQudHlwZSA9ICggdHlwZSA9PT0gdGhpcy53aWRnZXRFdmVudFByZWZpeCA/XG5cdFx0XHR0eXBlIDpcblx0XHRcdHRoaXMud2lkZ2V0RXZlbnRQcmVmaXggKyB0eXBlICkudG9Mb3dlckNhc2UoKTtcblxuXHRcdC8vIFRoZSBvcmlnaW5hbCBldmVudCBtYXkgY29tZSBmcm9tIGFueSBlbGVtZW50XG5cdFx0Ly8gc28gd2UgbmVlZCB0byByZXNldCB0aGUgdGFyZ2V0IG9uIHRoZSBuZXcgZXZlbnRcblx0XHRldmVudC50YXJnZXQgPSB0aGlzLmVsZW1lbnRbIDAgXTtcblxuXHRcdC8vIENvcHkgb3JpZ2luYWwgZXZlbnQgcHJvcGVydGllcyBvdmVyIHRvIHRoZSBuZXcgZXZlbnRcblx0XHRvcmlnID0gZXZlbnQub3JpZ2luYWxFdmVudDtcblx0XHRpZiAoIG9yaWcgKSB7XG5cdFx0XHRmb3IgKCBwcm9wIGluIG9yaWcgKSB7XG5cdFx0XHRcdGlmICggISggcHJvcCBpbiBldmVudCApICkge1xuXHRcdFx0XHRcdGV2ZW50WyBwcm9wIF0gPSBvcmlnWyBwcm9wIF07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggZXZlbnQsIGRhdGEgKTtcblx0XHRyZXR1cm4gISggJC5pc0Z1bmN0aW9uKCBjYWxsYmFjayApICYmXG5cdFx0XHRjYWxsYmFjay5hcHBseSggdGhpcy5lbGVtZW50WyAwIF0sIFsgZXZlbnQgXS5jb25jYXQoIGRhdGEgKSApID09PSBmYWxzZSB8fFxuXHRcdFx0ZXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkgKTtcblx0fVxufTtcblxuJC5lYWNoKCB7IHNob3c6IFwiZmFkZUluXCIsIGhpZGU6IFwiZmFkZU91dFwiIH0sIGZ1bmN0aW9uKCBtZXRob2QsIGRlZmF1bHRFZmZlY3QgKSB7XG5cdCQuV2lkZ2V0LnByb3RvdHlwZVsgXCJfXCIgKyBtZXRob2QgXSA9IGZ1bmN0aW9uKCBlbGVtZW50LCBvcHRpb25zLCBjYWxsYmFjayApIHtcblx0XHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0b3B0aW9ucyA9IHsgZWZmZWN0OiBvcHRpb25zIH07XG5cdFx0fVxuXG5cdFx0dmFyIGhhc09wdGlvbnM7XG5cdFx0dmFyIGVmZmVjdE5hbWUgPSAhb3B0aW9ucyA/XG5cdFx0XHRtZXRob2QgOlxuXHRcdFx0b3B0aW9ucyA9PT0gdHJ1ZSB8fCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJudW1iZXJcIiA/XG5cdFx0XHRcdGRlZmF1bHRFZmZlY3QgOlxuXHRcdFx0XHRvcHRpb25zLmVmZmVjdCB8fCBkZWZhdWx0RWZmZWN0O1xuXG5cdFx0b3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG5cdFx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJudW1iZXJcIiApIHtcblx0XHRcdG9wdGlvbnMgPSB7IGR1cmF0aW9uOiBvcHRpb25zIH07XG5cdFx0fVxuXG5cdFx0aGFzT3B0aW9ucyA9ICEkLmlzRW1wdHlPYmplY3QoIG9wdGlvbnMgKTtcblx0XHRvcHRpb25zLmNvbXBsZXRlID0gY2FsbGJhY2s7XG5cblx0XHRpZiAoIG9wdGlvbnMuZGVsYXkgKSB7XG5cdFx0XHRlbGVtZW50LmRlbGF5KCBvcHRpb25zLmRlbGF5ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBoYXNPcHRpb25zICYmICQuZWZmZWN0cyAmJiAkLmVmZmVjdHMuZWZmZWN0WyBlZmZlY3ROYW1lIF0gKSB7XG5cdFx0XHRlbGVtZW50WyBtZXRob2QgXSggb3B0aW9ucyApO1xuXHRcdH0gZWxzZSBpZiAoIGVmZmVjdE5hbWUgIT09IG1ldGhvZCAmJiBlbGVtZW50WyBlZmZlY3ROYW1lIF0gKSB7XG5cdFx0XHRlbGVtZW50WyBlZmZlY3ROYW1lIF0oIG9wdGlvbnMuZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nLCBjYWxsYmFjayApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtZW50LnF1ZXVlKCBmdW5jdGlvbiggbmV4dCApIHtcblx0XHRcdFx0JCggdGhpcyApWyBtZXRob2QgXSgpO1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdGNhbGxiYWNrLmNhbGwoIGVsZW1lbnRbIDAgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG5leHQoKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdH07XG59ICk7XG5cbnZhciB3aWRnZXQgPSAkLndpZGdldDtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBQb3NpdGlvbiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICpcbiAqIGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Bvc2l0aW9uL1xuICovXG5cbi8vPj5sYWJlbDogUG9zaXRpb25cbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBQb3NpdGlvbnMgZWxlbWVudHMgcmVsYXRpdmUgdG8gb3RoZXIgZWxlbWVudHMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcG9zaXRpb24vXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vcG9zaXRpb24vXG5cblxuKCBmdW5jdGlvbigpIHtcbnZhciBjYWNoZWRTY3JvbGxiYXJXaWR0aCxcblx0bWF4ID0gTWF0aC5tYXgsXG5cdGFicyA9IE1hdGguYWJzLFxuXHRyaG9yaXpvbnRhbCA9IC9sZWZ0fGNlbnRlcnxyaWdodC8sXG5cdHJ2ZXJ0aWNhbCA9IC90b3B8Y2VudGVyfGJvdHRvbS8sXG5cdHJvZmZzZXQgPSAvW1xcK1xcLV1cXGQrKFxcLltcXGRdKyk/JT8vLFxuXHRycG9zaXRpb24gPSAvXlxcdysvLFxuXHRycGVyY2VudCA9IC8lJC8sXG5cdF9wb3NpdGlvbiA9ICQuZm4ucG9zaXRpb247XG5cbmZ1bmN0aW9uIGdldE9mZnNldHMoIG9mZnNldHMsIHdpZHRoLCBoZWlnaHQgKSB7XG5cdHJldHVybiBbXG5cdFx0cGFyc2VGbG9hdCggb2Zmc2V0c1sgMCBdICkgKiAoIHJwZXJjZW50LnRlc3QoIG9mZnNldHNbIDAgXSApID8gd2lkdGggLyAxMDAgOiAxICksXG5cdFx0cGFyc2VGbG9hdCggb2Zmc2V0c1sgMSBdICkgKiAoIHJwZXJjZW50LnRlc3QoIG9mZnNldHNbIDEgXSApID8gaGVpZ2h0IC8gMTAwIDogMSApXG5cdF07XG59XG5cbmZ1bmN0aW9uIHBhcnNlQ3NzKCBlbGVtZW50LCBwcm9wZXJ0eSApIHtcblx0cmV0dXJuIHBhcnNlSW50KCAkLmNzcyggZWxlbWVudCwgcHJvcGVydHkgKSwgMTAgKSB8fCAwO1xufVxuXG5mdW5jdGlvbiBnZXREaW1lbnNpb25zKCBlbGVtICkge1xuXHR2YXIgcmF3ID0gZWxlbVsgMCBdO1xuXHRpZiAoIHJhdy5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IGVsZW0ud2lkdGgoKSxcblx0XHRcdGhlaWdodDogZWxlbS5oZWlnaHQoKSxcblx0XHRcdG9mZnNldDogeyB0b3A6IDAsIGxlZnQ6IDAgfVxuXHRcdH07XG5cdH1cblx0aWYgKCAkLmlzV2luZG93KCByYXcgKSApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IGVsZW0ud2lkdGgoKSxcblx0XHRcdGhlaWdodDogZWxlbS5oZWlnaHQoKSxcblx0XHRcdG9mZnNldDogeyB0b3A6IGVsZW0uc2Nyb2xsVG9wKCksIGxlZnQ6IGVsZW0uc2Nyb2xsTGVmdCgpIH1cblx0XHR9O1xuXHR9XG5cdGlmICggcmF3LnByZXZlbnREZWZhdWx0ICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogMCxcblx0XHRcdGhlaWdodDogMCxcblx0XHRcdG9mZnNldDogeyB0b3A6IHJhdy5wYWdlWSwgbGVmdDogcmF3LnBhZ2VYIH1cblx0XHR9O1xuXHR9XG5cdHJldHVybiB7XG5cdFx0d2lkdGg6IGVsZW0ub3V0ZXJXaWR0aCgpLFxuXHRcdGhlaWdodDogZWxlbS5vdXRlckhlaWdodCgpLFxuXHRcdG9mZnNldDogZWxlbS5vZmZzZXQoKVxuXHR9O1xufVxuXG4kLnBvc2l0aW9uID0ge1xuXHRzY3JvbGxiYXJXaWR0aDogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCBjYWNoZWRTY3JvbGxiYXJXaWR0aCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIGNhY2hlZFNjcm9sbGJhcldpZHRoO1xuXHRcdH1cblx0XHR2YXIgdzEsIHcyLFxuXHRcdFx0ZGl2ID0gJCggXCI8ZGl2IFwiICtcblx0XHRcdFx0XCJzdHlsZT0nZGlzcGxheTpibG9jaztwb3NpdGlvbjphYnNvbHV0ZTt3aWR0aDo1MHB4O2hlaWdodDo1MHB4O292ZXJmbG93OmhpZGRlbjsnPlwiICtcblx0XHRcdFx0XCI8ZGl2IHN0eWxlPSdoZWlnaHQ6MTAwcHg7d2lkdGg6YXV0bzsnPjwvZGl2PjwvZGl2PlwiICksXG5cdFx0XHRpbm5lckRpdiA9IGRpdi5jaGlsZHJlbigpWyAwIF07XG5cblx0XHQkKCBcImJvZHlcIiApLmFwcGVuZCggZGl2ICk7XG5cdFx0dzEgPSBpbm5lckRpdi5vZmZzZXRXaWR0aDtcblx0XHRkaXYuY3NzKCBcIm92ZXJmbG93XCIsIFwic2Nyb2xsXCIgKTtcblxuXHRcdHcyID0gaW5uZXJEaXYub2Zmc2V0V2lkdGg7XG5cblx0XHRpZiAoIHcxID09PSB3MiApIHtcblx0XHRcdHcyID0gZGl2WyAwIF0uY2xpZW50V2lkdGg7XG5cdFx0fVxuXG5cdFx0ZGl2LnJlbW92ZSgpO1xuXG5cdFx0cmV0dXJuICggY2FjaGVkU2Nyb2xsYmFyV2lkdGggPSB3MSAtIHcyICk7XG5cdH0sXG5cdGdldFNjcm9sbEluZm86IGZ1bmN0aW9uKCB3aXRoaW4gKSB7XG5cdFx0dmFyIG92ZXJmbG93WCA9IHdpdGhpbi5pc1dpbmRvdyB8fCB3aXRoaW4uaXNEb2N1bWVudCA/IFwiXCIgOlxuXHRcdFx0XHR3aXRoaW4uZWxlbWVudC5jc3MoIFwib3ZlcmZsb3cteFwiICksXG5cdFx0XHRvdmVyZmxvd1kgPSB3aXRoaW4uaXNXaW5kb3cgfHwgd2l0aGluLmlzRG9jdW1lbnQgPyBcIlwiIDpcblx0XHRcdFx0d2l0aGluLmVsZW1lbnQuY3NzKCBcIm92ZXJmbG93LXlcIiApLFxuXHRcdFx0aGFzT3ZlcmZsb3dYID0gb3ZlcmZsb3dYID09PSBcInNjcm9sbFwiIHx8XG5cdFx0XHRcdCggb3ZlcmZsb3dYID09PSBcImF1dG9cIiAmJiB3aXRoaW4ud2lkdGggPCB3aXRoaW4uZWxlbWVudFsgMCBdLnNjcm9sbFdpZHRoICksXG5cdFx0XHRoYXNPdmVyZmxvd1kgPSBvdmVyZmxvd1kgPT09IFwic2Nyb2xsXCIgfHxcblx0XHRcdFx0KCBvdmVyZmxvd1kgPT09IFwiYXV0b1wiICYmIHdpdGhpbi5oZWlnaHQgPCB3aXRoaW4uZWxlbWVudFsgMCBdLnNjcm9sbEhlaWdodCApO1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogaGFzT3ZlcmZsb3dZID8gJC5wb3NpdGlvbi5zY3JvbGxiYXJXaWR0aCgpIDogMCxcblx0XHRcdGhlaWdodDogaGFzT3ZlcmZsb3dYID8gJC5wb3NpdGlvbi5zY3JvbGxiYXJXaWR0aCgpIDogMFxuXHRcdH07XG5cdH0sXG5cdGdldFdpdGhpbkluZm86IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciB3aXRoaW5FbGVtZW50ID0gJCggZWxlbWVudCB8fCB3aW5kb3cgKSxcblx0XHRcdGlzV2luZG93ID0gJC5pc1dpbmRvdyggd2l0aGluRWxlbWVudFsgMCBdICksXG5cdFx0XHRpc0RvY3VtZW50ID0gISF3aXRoaW5FbGVtZW50WyAwIF0gJiYgd2l0aGluRWxlbWVudFsgMCBdLm5vZGVUeXBlID09PSA5LFxuXHRcdFx0aGFzT2Zmc2V0ID0gIWlzV2luZG93ICYmICFpc0RvY3VtZW50O1xuXHRcdHJldHVybiB7XG5cdFx0XHRlbGVtZW50OiB3aXRoaW5FbGVtZW50LFxuXHRcdFx0aXNXaW5kb3c6IGlzV2luZG93LFxuXHRcdFx0aXNEb2N1bWVudDogaXNEb2N1bWVudCxcblx0XHRcdG9mZnNldDogaGFzT2Zmc2V0ID8gJCggZWxlbWVudCApLm9mZnNldCgpIDogeyBsZWZ0OiAwLCB0b3A6IDAgfSxcblx0XHRcdHNjcm9sbExlZnQ6IHdpdGhpbkVsZW1lbnQuc2Nyb2xsTGVmdCgpLFxuXHRcdFx0c2Nyb2xsVG9wOiB3aXRoaW5FbGVtZW50LnNjcm9sbFRvcCgpLFxuXHRcdFx0d2lkdGg6IHdpdGhpbkVsZW1lbnQub3V0ZXJXaWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiB3aXRoaW5FbGVtZW50Lm91dGVySGVpZ2h0KClcblx0XHR9O1xuXHR9XG59O1xuXG4kLmZuLnBvc2l0aW9uID0gZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdGlmICggIW9wdGlvbnMgfHwgIW9wdGlvbnMub2YgKSB7XG5cdFx0cmV0dXJuIF9wb3NpdGlvbi5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdH1cblxuXHQvLyBNYWtlIGEgY29weSwgd2UgZG9uJ3Qgd2FudCB0byBtb2RpZnkgYXJndW1lbnRzXG5cdG9wdGlvbnMgPSAkLmV4dGVuZCgge30sIG9wdGlvbnMgKTtcblxuXHR2YXIgYXRPZmZzZXQsIHRhcmdldFdpZHRoLCB0YXJnZXRIZWlnaHQsIHRhcmdldE9mZnNldCwgYmFzZVBvc2l0aW9uLCBkaW1lbnNpb25zLFxuXHRcdHRhcmdldCA9ICQoIG9wdGlvbnMub2YgKSxcblx0XHR3aXRoaW4gPSAkLnBvc2l0aW9uLmdldFdpdGhpbkluZm8oIG9wdGlvbnMud2l0aGluICksXG5cdFx0c2Nyb2xsSW5mbyA9ICQucG9zaXRpb24uZ2V0U2Nyb2xsSW5mbyggd2l0aGluICksXG5cdFx0Y29sbGlzaW9uID0gKCBvcHRpb25zLmNvbGxpc2lvbiB8fCBcImZsaXBcIiApLnNwbGl0KCBcIiBcIiApLFxuXHRcdG9mZnNldHMgPSB7fTtcblxuXHRkaW1lbnNpb25zID0gZ2V0RGltZW5zaW9ucyggdGFyZ2V0ICk7XG5cdGlmICggdGFyZ2V0WyAwIF0ucHJldmVudERlZmF1bHQgKSB7XG5cblx0XHQvLyBGb3JjZSBsZWZ0IHRvcCB0byBhbGxvdyBmbGlwcGluZ1xuXHRcdG9wdGlvbnMuYXQgPSBcImxlZnQgdG9wXCI7XG5cdH1cblx0dGFyZ2V0V2lkdGggPSBkaW1lbnNpb25zLndpZHRoO1xuXHR0YXJnZXRIZWlnaHQgPSBkaW1lbnNpb25zLmhlaWdodDtcblx0dGFyZ2V0T2Zmc2V0ID0gZGltZW5zaW9ucy5vZmZzZXQ7XG5cblx0Ly8gQ2xvbmUgdG8gcmV1c2Ugb3JpZ2luYWwgdGFyZ2V0T2Zmc2V0IGxhdGVyXG5cdGJhc2VQb3NpdGlvbiA9ICQuZXh0ZW5kKCB7fSwgdGFyZ2V0T2Zmc2V0ICk7XG5cblx0Ly8gRm9yY2UgbXkgYW5kIGF0IHRvIGhhdmUgdmFsaWQgaG9yaXpvbnRhbCBhbmQgdmVydGljYWwgcG9zaXRpb25zXG5cdC8vIGlmIGEgdmFsdWUgaXMgbWlzc2luZyBvciBpbnZhbGlkLCBpdCB3aWxsIGJlIGNvbnZlcnRlZCB0byBjZW50ZXJcblx0JC5lYWNoKCBbIFwibXlcIiwgXCJhdFwiIF0sIGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwb3MgPSAoIG9wdGlvbnNbIHRoaXMgXSB8fCBcIlwiICkuc3BsaXQoIFwiIFwiICksXG5cdFx0XHRob3Jpem9udGFsT2Zmc2V0LFxuXHRcdFx0dmVydGljYWxPZmZzZXQ7XG5cblx0XHRpZiAoIHBvcy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRwb3MgPSByaG9yaXpvbnRhbC50ZXN0KCBwb3NbIDAgXSApID9cblx0XHRcdFx0cG9zLmNvbmNhdCggWyBcImNlbnRlclwiIF0gKSA6XG5cdFx0XHRcdHJ2ZXJ0aWNhbC50ZXN0KCBwb3NbIDAgXSApID9cblx0XHRcdFx0XHRbIFwiY2VudGVyXCIgXS5jb25jYXQoIHBvcyApIDpcblx0XHRcdFx0XHRbIFwiY2VudGVyXCIsIFwiY2VudGVyXCIgXTtcblx0XHR9XG5cdFx0cG9zWyAwIF0gPSByaG9yaXpvbnRhbC50ZXN0KCBwb3NbIDAgXSApID8gcG9zWyAwIF0gOiBcImNlbnRlclwiO1xuXHRcdHBvc1sgMSBdID0gcnZlcnRpY2FsLnRlc3QoIHBvc1sgMSBdICkgPyBwb3NbIDEgXSA6IFwiY2VudGVyXCI7XG5cblx0XHQvLyBDYWxjdWxhdGUgb2Zmc2V0c1xuXHRcdGhvcml6b250YWxPZmZzZXQgPSByb2Zmc2V0LmV4ZWMoIHBvc1sgMCBdICk7XG5cdFx0dmVydGljYWxPZmZzZXQgPSByb2Zmc2V0LmV4ZWMoIHBvc1sgMSBdICk7XG5cdFx0b2Zmc2V0c1sgdGhpcyBdID0gW1xuXHRcdFx0aG9yaXpvbnRhbE9mZnNldCA/IGhvcml6b250YWxPZmZzZXRbIDAgXSA6IDAsXG5cdFx0XHR2ZXJ0aWNhbE9mZnNldCA/IHZlcnRpY2FsT2Zmc2V0WyAwIF0gOiAwXG5cdFx0XTtcblxuXHRcdC8vIFJlZHVjZSB0byBqdXN0IHRoZSBwb3NpdGlvbnMgd2l0aG91dCB0aGUgb2Zmc2V0c1xuXHRcdG9wdGlvbnNbIHRoaXMgXSA9IFtcblx0XHRcdHJwb3NpdGlvbi5leGVjKCBwb3NbIDAgXSApWyAwIF0sXG5cdFx0XHRycG9zaXRpb24uZXhlYyggcG9zWyAxIF0gKVsgMCBdXG5cdFx0XTtcblx0fSApO1xuXG5cdC8vIE5vcm1hbGl6ZSBjb2xsaXNpb24gb3B0aW9uXG5cdGlmICggY29sbGlzaW9uLmxlbmd0aCA9PT0gMSApIHtcblx0XHRjb2xsaXNpb25bIDEgXSA9IGNvbGxpc2lvblsgMCBdO1xuXHR9XG5cblx0aWYgKCBvcHRpb25zLmF0WyAwIF0gPT09IFwicmlnaHRcIiApIHtcblx0XHRiYXNlUG9zaXRpb24ubGVmdCArPSB0YXJnZXRXaWR0aDtcblx0fSBlbHNlIGlmICggb3B0aW9ucy5hdFsgMCBdID09PSBcImNlbnRlclwiICkge1xuXHRcdGJhc2VQb3NpdGlvbi5sZWZ0ICs9IHRhcmdldFdpZHRoIC8gMjtcblx0fVxuXG5cdGlmICggb3B0aW9ucy5hdFsgMSBdID09PSBcImJvdHRvbVwiICkge1xuXHRcdGJhc2VQb3NpdGlvbi50b3AgKz0gdGFyZ2V0SGVpZ2h0O1xuXHR9IGVsc2UgaWYgKCBvcHRpb25zLmF0WyAxIF0gPT09IFwiY2VudGVyXCIgKSB7XG5cdFx0YmFzZVBvc2l0aW9uLnRvcCArPSB0YXJnZXRIZWlnaHQgLyAyO1xuXHR9XG5cblx0YXRPZmZzZXQgPSBnZXRPZmZzZXRzKCBvZmZzZXRzLmF0LCB0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0ICk7XG5cdGJhc2VQb3NpdGlvbi5sZWZ0ICs9IGF0T2Zmc2V0WyAwIF07XG5cdGJhc2VQb3NpdGlvbi50b3AgKz0gYXRPZmZzZXRbIDEgXTtcblxuXHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgY29sbGlzaW9uUG9zaXRpb24sIHVzaW5nLFxuXHRcdFx0ZWxlbSA9ICQoIHRoaXMgKSxcblx0XHRcdGVsZW1XaWR0aCA9IGVsZW0ub3V0ZXJXaWR0aCgpLFxuXHRcdFx0ZWxlbUhlaWdodCA9IGVsZW0ub3V0ZXJIZWlnaHQoKSxcblx0XHRcdG1hcmdpbkxlZnQgPSBwYXJzZUNzcyggdGhpcywgXCJtYXJnaW5MZWZ0XCIgKSxcblx0XHRcdG1hcmdpblRvcCA9IHBhcnNlQ3NzKCB0aGlzLCBcIm1hcmdpblRvcFwiICksXG5cdFx0XHRjb2xsaXNpb25XaWR0aCA9IGVsZW1XaWR0aCArIG1hcmdpbkxlZnQgKyBwYXJzZUNzcyggdGhpcywgXCJtYXJnaW5SaWdodFwiICkgK1xuXHRcdFx0XHRzY3JvbGxJbmZvLndpZHRoLFxuXHRcdFx0Y29sbGlzaW9uSGVpZ2h0ID0gZWxlbUhlaWdodCArIG1hcmdpblRvcCArIHBhcnNlQ3NzKCB0aGlzLCBcIm1hcmdpbkJvdHRvbVwiICkgK1xuXHRcdFx0XHRzY3JvbGxJbmZvLmhlaWdodCxcblx0XHRcdHBvc2l0aW9uID0gJC5leHRlbmQoIHt9LCBiYXNlUG9zaXRpb24gKSxcblx0XHRcdG15T2Zmc2V0ID0gZ2V0T2Zmc2V0cyggb2Zmc2V0cy5teSwgZWxlbS5vdXRlcldpZHRoKCksIGVsZW0ub3V0ZXJIZWlnaHQoKSApO1xuXG5cdFx0aWYgKCBvcHRpb25zLm15WyAwIF0gPT09IFwicmlnaHRcIiApIHtcblx0XHRcdHBvc2l0aW9uLmxlZnQgLT0gZWxlbVdpZHRoO1xuXHRcdH0gZWxzZSBpZiAoIG9wdGlvbnMubXlbIDAgXSA9PT0gXCJjZW50ZXJcIiApIHtcblx0XHRcdHBvc2l0aW9uLmxlZnQgLT0gZWxlbVdpZHRoIC8gMjtcblx0XHR9XG5cblx0XHRpZiAoIG9wdGlvbnMubXlbIDEgXSA9PT0gXCJib3R0b21cIiApIHtcblx0XHRcdHBvc2l0aW9uLnRvcCAtPSBlbGVtSGVpZ2h0O1xuXHRcdH0gZWxzZSBpZiAoIG9wdGlvbnMubXlbIDEgXSA9PT0gXCJjZW50ZXJcIiApIHtcblx0XHRcdHBvc2l0aW9uLnRvcCAtPSBlbGVtSGVpZ2h0IC8gMjtcblx0XHR9XG5cblx0XHRwb3NpdGlvbi5sZWZ0ICs9IG15T2Zmc2V0WyAwIF07XG5cdFx0cG9zaXRpb24udG9wICs9IG15T2Zmc2V0WyAxIF07XG5cblx0XHRjb2xsaXNpb25Qb3NpdGlvbiA9IHtcblx0XHRcdG1hcmdpbkxlZnQ6IG1hcmdpbkxlZnQsXG5cdFx0XHRtYXJnaW5Ub3A6IG1hcmdpblRvcFxuXHRcdH07XG5cblx0XHQkLmVhY2goIFsgXCJsZWZ0XCIsIFwidG9wXCIgXSwgZnVuY3Rpb24oIGksIGRpciApIHtcblx0XHRcdGlmICggJC51aS5wb3NpdGlvblsgY29sbGlzaW9uWyBpIF0gXSApIHtcblx0XHRcdFx0JC51aS5wb3NpdGlvblsgY29sbGlzaW9uWyBpIF0gXVsgZGlyIF0oIHBvc2l0aW9uLCB7XG5cdFx0XHRcdFx0dGFyZ2V0V2lkdGg6IHRhcmdldFdpZHRoLFxuXHRcdFx0XHRcdHRhcmdldEhlaWdodDogdGFyZ2V0SGVpZ2h0LFxuXHRcdFx0XHRcdGVsZW1XaWR0aDogZWxlbVdpZHRoLFxuXHRcdFx0XHRcdGVsZW1IZWlnaHQ6IGVsZW1IZWlnaHQsXG5cdFx0XHRcdFx0Y29sbGlzaW9uUG9zaXRpb246IGNvbGxpc2lvblBvc2l0aW9uLFxuXHRcdFx0XHRcdGNvbGxpc2lvbldpZHRoOiBjb2xsaXNpb25XaWR0aCxcblx0XHRcdFx0XHRjb2xsaXNpb25IZWlnaHQ6IGNvbGxpc2lvbkhlaWdodCxcblx0XHRcdFx0XHRvZmZzZXQ6IFsgYXRPZmZzZXRbIDAgXSArIG15T2Zmc2V0WyAwIF0sIGF0T2Zmc2V0IFsgMSBdICsgbXlPZmZzZXRbIDEgXSBdLFxuXHRcdFx0XHRcdG15OiBvcHRpb25zLm15LFxuXHRcdFx0XHRcdGF0OiBvcHRpb25zLmF0LFxuXHRcdFx0XHRcdHdpdGhpbjogd2l0aGluLFxuXHRcdFx0XHRcdGVsZW06IGVsZW1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdGlmICggb3B0aW9ucy51c2luZyApIHtcblxuXHRcdFx0Ly8gQWRkcyBmZWVkYmFjayBhcyBzZWNvbmQgYXJndW1lbnQgdG8gdXNpbmcgY2FsbGJhY2ssIGlmIHByZXNlbnRcblx0XHRcdHVzaW5nID0gZnVuY3Rpb24oIHByb3BzICkge1xuXHRcdFx0XHR2YXIgbGVmdCA9IHRhcmdldE9mZnNldC5sZWZ0IC0gcG9zaXRpb24ubGVmdCxcblx0XHRcdFx0XHRyaWdodCA9IGxlZnQgKyB0YXJnZXRXaWR0aCAtIGVsZW1XaWR0aCxcblx0XHRcdFx0XHR0b3AgPSB0YXJnZXRPZmZzZXQudG9wIC0gcG9zaXRpb24udG9wLFxuXHRcdFx0XHRcdGJvdHRvbSA9IHRvcCArIHRhcmdldEhlaWdodCAtIGVsZW1IZWlnaHQsXG5cdFx0XHRcdFx0ZmVlZGJhY2sgPSB7XG5cdFx0XHRcdFx0XHR0YXJnZXQ6IHtcblx0XHRcdFx0XHRcdFx0ZWxlbWVudDogdGFyZ2V0LFxuXHRcdFx0XHRcdFx0XHRsZWZ0OiB0YXJnZXRPZmZzZXQubGVmdCxcblx0XHRcdFx0XHRcdFx0dG9wOiB0YXJnZXRPZmZzZXQudG9wLFxuXHRcdFx0XHRcdFx0XHR3aWR0aDogdGFyZ2V0V2lkdGgsXG5cdFx0XHRcdFx0XHRcdGhlaWdodDogdGFyZ2V0SGVpZ2h0XG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0ZWxlbWVudDoge1xuXHRcdFx0XHRcdFx0XHRlbGVtZW50OiBlbGVtLFxuXHRcdFx0XHRcdFx0XHRsZWZ0OiBwb3NpdGlvbi5sZWZ0LFxuXHRcdFx0XHRcdFx0XHR0b3A6IHBvc2l0aW9uLnRvcCxcblx0XHRcdFx0XHRcdFx0d2lkdGg6IGVsZW1XaWR0aCxcblx0XHRcdFx0XHRcdFx0aGVpZ2h0OiBlbGVtSGVpZ2h0XG5cdFx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdFx0aG9yaXpvbnRhbDogcmlnaHQgPCAwID8gXCJsZWZ0XCIgOiBsZWZ0ID4gMCA/IFwicmlnaHRcIiA6IFwiY2VudGVyXCIsXG5cdFx0XHRcdFx0XHR2ZXJ0aWNhbDogYm90dG9tIDwgMCA/IFwidG9wXCIgOiB0b3AgPiAwID8gXCJib3R0b21cIiA6IFwibWlkZGxlXCJcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRpZiAoIHRhcmdldFdpZHRoIDwgZWxlbVdpZHRoICYmIGFicyggbGVmdCArIHJpZ2h0ICkgPCB0YXJnZXRXaWR0aCApIHtcblx0XHRcdFx0XHRmZWVkYmFjay5ob3Jpem9udGFsID0gXCJjZW50ZXJcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHRhcmdldEhlaWdodCA8IGVsZW1IZWlnaHQgJiYgYWJzKCB0b3AgKyBib3R0b20gKSA8IHRhcmdldEhlaWdodCApIHtcblx0XHRcdFx0XHRmZWVkYmFjay52ZXJ0aWNhbCA9IFwibWlkZGxlXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBtYXgoIGFicyggbGVmdCApLCBhYnMoIHJpZ2h0ICkgKSA+IG1heCggYWJzKCB0b3AgKSwgYWJzKCBib3R0b20gKSApICkge1xuXHRcdFx0XHRcdGZlZWRiYWNrLmltcG9ydGFudCA9IFwiaG9yaXpvbnRhbFwiO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGZlZWRiYWNrLmltcG9ydGFudCA9IFwidmVydGljYWxcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRvcHRpb25zLnVzaW5nLmNhbGwoIHRoaXMsIHByb3BzLCBmZWVkYmFjayApO1xuXHRcdFx0fTtcblx0XHR9XG5cblx0XHRlbGVtLm9mZnNldCggJC5leHRlbmQoIHBvc2l0aW9uLCB7IHVzaW5nOiB1c2luZyB9ICkgKTtcblx0fSApO1xufTtcblxuJC51aS5wb3NpdGlvbiA9IHtcblx0Zml0OiB7XG5cdFx0bGVmdDogZnVuY3Rpb24oIHBvc2l0aW9uLCBkYXRhICkge1xuXHRcdFx0dmFyIHdpdGhpbiA9IGRhdGEud2l0aGluLFxuXHRcdFx0XHR3aXRoaW5PZmZzZXQgPSB3aXRoaW4uaXNXaW5kb3cgPyB3aXRoaW4uc2Nyb2xsTGVmdCA6IHdpdGhpbi5vZmZzZXQubGVmdCxcblx0XHRcdFx0b3V0ZXJXaWR0aCA9IHdpdGhpbi53aWR0aCxcblx0XHRcdFx0Y29sbGlzaW9uUG9zTGVmdCA9IHBvc2l0aW9uLmxlZnQgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpbkxlZnQsXG5cdFx0XHRcdG92ZXJMZWZ0ID0gd2l0aGluT2Zmc2V0IC0gY29sbGlzaW9uUG9zTGVmdCxcblx0XHRcdFx0b3ZlclJpZ2h0ID0gY29sbGlzaW9uUG9zTGVmdCArIGRhdGEuY29sbGlzaW9uV2lkdGggLSBvdXRlcldpZHRoIC0gd2l0aGluT2Zmc2V0LFxuXHRcdFx0XHRuZXdPdmVyUmlnaHQ7XG5cblx0XHRcdC8vIEVsZW1lbnQgaXMgd2lkZXIgdGhhbiB3aXRoaW5cblx0XHRcdGlmICggZGF0YS5jb2xsaXNpb25XaWR0aCA+IG91dGVyV2lkdGggKSB7XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciB0aGUgbGVmdCBzaWRlIG9mIHdpdGhpblxuXHRcdFx0XHRpZiAoIG92ZXJMZWZ0ID4gMCAmJiBvdmVyUmlnaHQgPD0gMCApIHtcblx0XHRcdFx0XHRuZXdPdmVyUmlnaHQgPSBwb3NpdGlvbi5sZWZ0ICsgb3ZlckxlZnQgKyBkYXRhLmNvbGxpc2lvbldpZHRoIC0gb3V0ZXJXaWR0aCAtXG5cdFx0XHRcdFx0XHR3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdFx0cG9zaXRpb24ubGVmdCArPSBvdmVyTGVmdCAtIG5ld092ZXJSaWdodDtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIHJpZ2h0IHNpZGUgb2Ygd2l0aGluXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG92ZXJSaWdodCA+IDAgJiYgb3ZlckxlZnQgPD0gMCApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ID0gd2l0aGluT2Zmc2V0O1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgYm90aCBsZWZ0IGFuZCByaWdodCBzaWRlcyBvZiB3aXRoaW5cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRpZiAoIG92ZXJMZWZ0ID4gb3ZlclJpZ2h0ICkge1xuXHRcdFx0XHRcdFx0cG9zaXRpb24ubGVmdCA9IHdpdGhpbk9mZnNldCArIG91dGVyV2lkdGggLSBkYXRhLmNvbGxpc2lvbldpZHRoO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ID0gd2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBUb28gZmFyIGxlZnQgLT4gYWxpZ24gd2l0aCBsZWZ0IGVkZ2Vcblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJMZWZ0ID4gMCApIHtcblx0XHRcdFx0cG9zaXRpb24ubGVmdCArPSBvdmVyTGVmdDtcblxuXHRcdFx0Ly8gVG9vIGZhciByaWdodCAtPiBhbGlnbiB3aXRoIHJpZ2h0IGVkZ2Vcblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJSaWdodCA+IDAgKSB7XG5cdFx0XHRcdHBvc2l0aW9uLmxlZnQgLT0gb3ZlclJpZ2h0O1xuXG5cdFx0XHQvLyBBZGp1c3QgYmFzZWQgb24gcG9zaXRpb24gYW5kIG1hcmdpblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cG9zaXRpb24ubGVmdCA9IG1heCggcG9zaXRpb24ubGVmdCAtIGNvbGxpc2lvblBvc0xlZnQsIHBvc2l0aW9uLmxlZnQgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdHRvcDogZnVuY3Rpb24oIHBvc2l0aW9uLCBkYXRhICkge1xuXHRcdFx0dmFyIHdpdGhpbiA9IGRhdGEud2l0aGluLFxuXHRcdFx0XHR3aXRoaW5PZmZzZXQgPSB3aXRoaW4uaXNXaW5kb3cgPyB3aXRoaW4uc2Nyb2xsVG9wIDogd2l0aGluLm9mZnNldC50b3AsXG5cdFx0XHRcdG91dGVySGVpZ2h0ID0gZGF0YS53aXRoaW4uaGVpZ2h0LFxuXHRcdFx0XHRjb2xsaXNpb25Qb3NUb3AgPSBwb3NpdGlvbi50b3AgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpblRvcCxcblx0XHRcdFx0b3ZlclRvcCA9IHdpdGhpbk9mZnNldCAtIGNvbGxpc2lvblBvc1RvcCxcblx0XHRcdFx0b3ZlckJvdHRvbSA9IGNvbGxpc2lvblBvc1RvcCArIGRhdGEuY29sbGlzaW9uSGVpZ2h0IC0gb3V0ZXJIZWlnaHQgLSB3aXRoaW5PZmZzZXQsXG5cdFx0XHRcdG5ld092ZXJCb3R0b207XG5cblx0XHRcdC8vIEVsZW1lbnQgaXMgdGFsbGVyIHRoYW4gd2l0aGluXG5cdFx0XHRpZiAoIGRhdGEuY29sbGlzaW9uSGVpZ2h0ID4gb3V0ZXJIZWlnaHQgKSB7XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciB0aGUgdG9wIG9mIHdpdGhpblxuXHRcdFx0XHRpZiAoIG92ZXJUb3AgPiAwICYmIG92ZXJCb3R0b20gPD0gMCApIHtcblx0XHRcdFx0XHRuZXdPdmVyQm90dG9tID0gcG9zaXRpb24udG9wICsgb3ZlclRvcCArIGRhdGEuY29sbGlzaW9uSGVpZ2h0IC0gb3V0ZXJIZWlnaHQgLVxuXHRcdFx0XHRcdFx0d2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRcdHBvc2l0aW9uLnRvcCArPSBvdmVyVG9wIC0gbmV3T3ZlckJvdHRvbTtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIGJvdHRvbSBvZiB3aXRoaW5cblx0XHRcdFx0fSBlbHNlIGlmICggb3ZlckJvdHRvbSA+IDAgJiYgb3ZlclRvcCA8PSAwICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLnRvcCA9IHdpdGhpbk9mZnNldDtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIGJvdGggdG9wIGFuZCBib3R0b20gb2Ygd2l0aGluXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0aWYgKCBvdmVyVG9wID4gb3ZlckJvdHRvbSApIHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uLnRvcCA9IHdpdGhpbk9mZnNldCArIG91dGVySGVpZ2h0IC0gZGF0YS5jb2xsaXNpb25IZWlnaHQ7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uLnRvcCA9IHdpdGhpbk9mZnNldDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0Ly8gVG9vIGZhciB1cCAtPiBhbGlnbiB3aXRoIHRvcFxuXHRcdFx0fSBlbHNlIGlmICggb3ZlclRvcCA+IDAgKSB7XG5cdFx0XHRcdHBvc2l0aW9uLnRvcCArPSBvdmVyVG9wO1xuXG5cdFx0XHQvLyBUb28gZmFyIGRvd24gLT4gYWxpZ24gd2l0aCBib3R0b20gZWRnZVxuXHRcdFx0fSBlbHNlIGlmICggb3ZlckJvdHRvbSA+IDAgKSB7XG5cdFx0XHRcdHBvc2l0aW9uLnRvcCAtPSBvdmVyQm90dG9tO1xuXG5cdFx0XHQvLyBBZGp1c3QgYmFzZWQgb24gcG9zaXRpb24gYW5kIG1hcmdpblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cG9zaXRpb24udG9wID0gbWF4KCBwb3NpdGlvbi50b3AgLSBjb2xsaXNpb25Qb3NUb3AsIHBvc2l0aW9uLnRvcCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0ZmxpcDoge1xuXHRcdGxlZnQ6IGZ1bmN0aW9uKCBwb3NpdGlvbiwgZGF0YSApIHtcblx0XHRcdHZhciB3aXRoaW4gPSBkYXRhLndpdGhpbixcblx0XHRcdFx0d2l0aGluT2Zmc2V0ID0gd2l0aGluLm9mZnNldC5sZWZ0ICsgd2l0aGluLnNjcm9sbExlZnQsXG5cdFx0XHRcdG91dGVyV2lkdGggPSB3aXRoaW4ud2lkdGgsXG5cdFx0XHRcdG9mZnNldExlZnQgPSB3aXRoaW4uaXNXaW5kb3cgPyB3aXRoaW4uc2Nyb2xsTGVmdCA6IHdpdGhpbi5vZmZzZXQubGVmdCxcblx0XHRcdFx0Y29sbGlzaW9uUG9zTGVmdCA9IHBvc2l0aW9uLmxlZnQgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpbkxlZnQsXG5cdFx0XHRcdG92ZXJMZWZ0ID0gY29sbGlzaW9uUG9zTGVmdCAtIG9mZnNldExlZnQsXG5cdFx0XHRcdG92ZXJSaWdodCA9IGNvbGxpc2lvblBvc0xlZnQgKyBkYXRhLmNvbGxpc2lvbldpZHRoIC0gb3V0ZXJXaWR0aCAtIG9mZnNldExlZnQsXG5cdFx0XHRcdG15T2Zmc2V0ID0gZGF0YS5teVsgMCBdID09PSBcImxlZnRcIiA/XG5cdFx0XHRcdFx0LWRhdGEuZWxlbVdpZHRoIDpcblx0XHRcdFx0XHRkYXRhLm15WyAwIF0gPT09IFwicmlnaHRcIiA/XG5cdFx0XHRcdFx0XHRkYXRhLmVsZW1XaWR0aCA6XG5cdFx0XHRcdFx0XHQwLFxuXHRcdFx0XHRhdE9mZnNldCA9IGRhdGEuYXRbIDAgXSA9PT0gXCJsZWZ0XCIgP1xuXHRcdFx0XHRcdGRhdGEudGFyZ2V0V2lkdGggOlxuXHRcdFx0XHRcdGRhdGEuYXRbIDAgXSA9PT0gXCJyaWdodFwiID9cblx0XHRcdFx0XHRcdC1kYXRhLnRhcmdldFdpZHRoIDpcblx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdG9mZnNldCA9IC0yICogZGF0YS5vZmZzZXRbIDAgXSxcblx0XHRcdFx0bmV3T3ZlclJpZ2h0LFxuXHRcdFx0XHRuZXdPdmVyTGVmdDtcblxuXHRcdFx0aWYgKCBvdmVyTGVmdCA8IDAgKSB7XG5cdFx0XHRcdG5ld092ZXJSaWdodCA9IHBvc2l0aW9uLmxlZnQgKyBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0ICsgZGF0YS5jb2xsaXNpb25XaWR0aCAtXG5cdFx0XHRcdFx0b3V0ZXJXaWR0aCAtIHdpdGhpbk9mZnNldDtcblx0XHRcdFx0aWYgKCBuZXdPdmVyUmlnaHQgPCAwIHx8IG5ld092ZXJSaWdodCA8IGFicyggb3ZlckxlZnQgKSApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ICs9IG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJSaWdodCA+IDAgKSB7XG5cdFx0XHRcdG5ld092ZXJMZWZ0ID0gcG9zaXRpb24ubGVmdCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luTGVmdCArIG15T2Zmc2V0ICtcblx0XHRcdFx0XHRhdE9mZnNldCArIG9mZnNldCAtIG9mZnNldExlZnQ7XG5cdFx0XHRcdGlmICggbmV3T3ZlckxlZnQgPiAwIHx8IGFicyggbmV3T3ZlckxlZnQgKSA8IG92ZXJSaWdodCApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ICs9IG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXHRcdHRvcDogZnVuY3Rpb24oIHBvc2l0aW9uLCBkYXRhICkge1xuXHRcdFx0dmFyIHdpdGhpbiA9IGRhdGEud2l0aGluLFxuXHRcdFx0XHR3aXRoaW5PZmZzZXQgPSB3aXRoaW4ub2Zmc2V0LnRvcCArIHdpdGhpbi5zY3JvbGxUb3AsXG5cdFx0XHRcdG91dGVySGVpZ2h0ID0gd2l0aGluLmhlaWdodCxcblx0XHRcdFx0b2Zmc2V0VG9wID0gd2l0aGluLmlzV2luZG93ID8gd2l0aGluLnNjcm9sbFRvcCA6IHdpdGhpbi5vZmZzZXQudG9wLFxuXHRcdFx0XHRjb2xsaXNpb25Qb3NUb3AgPSBwb3NpdGlvbi50b3AgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpblRvcCxcblx0XHRcdFx0b3ZlclRvcCA9IGNvbGxpc2lvblBvc1RvcCAtIG9mZnNldFRvcCxcblx0XHRcdFx0b3ZlckJvdHRvbSA9IGNvbGxpc2lvblBvc1RvcCArIGRhdGEuY29sbGlzaW9uSGVpZ2h0IC0gb3V0ZXJIZWlnaHQgLSBvZmZzZXRUb3AsXG5cdFx0XHRcdHRvcCA9IGRhdGEubXlbIDEgXSA9PT0gXCJ0b3BcIixcblx0XHRcdFx0bXlPZmZzZXQgPSB0b3AgP1xuXHRcdFx0XHRcdC1kYXRhLmVsZW1IZWlnaHQgOlxuXHRcdFx0XHRcdGRhdGEubXlbIDEgXSA9PT0gXCJib3R0b21cIiA/XG5cdFx0XHRcdFx0XHRkYXRhLmVsZW1IZWlnaHQgOlxuXHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0YXRPZmZzZXQgPSBkYXRhLmF0WyAxIF0gPT09IFwidG9wXCIgP1xuXHRcdFx0XHRcdGRhdGEudGFyZ2V0SGVpZ2h0IDpcblx0XHRcdFx0XHRkYXRhLmF0WyAxIF0gPT09IFwiYm90dG9tXCIgP1xuXHRcdFx0XHRcdFx0LWRhdGEudGFyZ2V0SGVpZ2h0IDpcblx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdG9mZnNldCA9IC0yICogZGF0YS5vZmZzZXRbIDEgXSxcblx0XHRcdFx0bmV3T3ZlclRvcCxcblx0XHRcdFx0bmV3T3ZlckJvdHRvbTtcblx0XHRcdGlmICggb3ZlclRvcCA8IDAgKSB7XG5cdFx0XHRcdG5ld092ZXJCb3R0b20gPSBwb3NpdGlvbi50b3AgKyBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0ICsgZGF0YS5jb2xsaXNpb25IZWlnaHQgLVxuXHRcdFx0XHRcdG91dGVySGVpZ2h0IC0gd2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRpZiAoIG5ld092ZXJCb3R0b20gPCAwIHx8IG5ld092ZXJCb3R0b20gPCBhYnMoIG92ZXJUb3AgKSApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi50b3AgKz0gbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldDtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmICggb3ZlckJvdHRvbSA+IDAgKSB7XG5cdFx0XHRcdG5ld092ZXJUb3AgPSBwb3NpdGlvbi50b3AgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpblRvcCArIG15T2Zmc2V0ICsgYXRPZmZzZXQgK1xuXHRcdFx0XHRcdG9mZnNldCAtIG9mZnNldFRvcDtcblx0XHRcdFx0aWYgKCBuZXdPdmVyVG9wID4gMCB8fCBhYnMoIG5ld092ZXJUb3AgKSA8IG92ZXJCb3R0b20gKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24udG9wICs9IG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdGZsaXBmaXQ6IHtcblx0XHRsZWZ0OiBmdW5jdGlvbigpIHtcblx0XHRcdCQudWkucG9zaXRpb24uZmxpcC5sZWZ0LmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdCQudWkucG9zaXRpb24uZml0LmxlZnQuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH0sXG5cdFx0dG9wOiBmdW5jdGlvbigpIHtcblx0XHRcdCQudWkucG9zaXRpb24uZmxpcC50b3AuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0JC51aS5wb3NpdGlvbi5maXQudG9wLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdH1cbn07XG5cbn0gKSgpO1xuXG52YXIgcG9zaXRpb24gPSAkLnVpLnBvc2l0aW9uO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIDpkYXRhIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiA6ZGF0YSBTZWxlY3RvclxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFNlbGVjdHMgZWxlbWVudHMgd2hpY2ggaGF2ZSBkYXRhIHN0b3JlZCB1bmRlciB0aGUgc3BlY2lmaWVkIGtleS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kYXRhLXNlbGVjdG9yL1xuXG5cbnZhciBkYXRhID0gJC5leHRlbmQoICQuZXhwclsgXCI6XCIgXSwge1xuXHRkYXRhOiAkLmV4cHIuY3JlYXRlUHNldWRvID9cblx0XHQkLmV4cHIuY3JlYXRlUHNldWRvKCBmdW5jdGlvbiggZGF0YU5hbWUgKSB7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHJldHVybiAhISQuZGF0YSggZWxlbSwgZGF0YU5hbWUgKTtcblx0XHRcdH07XG5cdFx0fSApIDpcblxuXHRcdC8vIFN1cHBvcnQ6IGpRdWVyeSA8MS44XG5cdFx0ZnVuY3Rpb24oIGVsZW0sIGksIG1hdGNoICkge1xuXHRcdFx0cmV0dXJuICEhJC5kYXRhKCBlbGVtLCBtYXRjaFsgMyBdICk7XG5cdFx0fVxufSApO1xuXG4vKiFcbiAqIGpRdWVyeSBVSSBEaXNhYmxlIFNlbGVjdGlvbiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogZGlzYWJsZVNlbGVjdGlvblxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IERpc2FibGUgc2VsZWN0aW9uIG9mIHRleHQgY29udGVudCB3aXRoaW4gdGhlIHNldCBvZiBtYXRjaGVkIGVsZW1lbnRzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2Rpc2FibGVTZWxlY3Rpb24vXG5cbi8vIFRoaXMgZmlsZSBpcyBkZXByZWNhdGVkXG5cblxudmFyIGRpc2FibGVTZWxlY3Rpb24gPSAkLmZuLmV4dGVuZCgge1xuXHRkaXNhYmxlU2VsZWN0aW9uOiAoIGZ1bmN0aW9uKCkge1xuXHRcdHZhciBldmVudFR5cGUgPSBcIm9uc2VsZWN0c3RhcnRcIiBpbiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImRpdlwiICkgP1xuXHRcdFx0XCJzZWxlY3RzdGFydFwiIDpcblx0XHRcdFwibW91c2Vkb3duXCI7XG5cblx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5vbiggZXZlbnRUeXBlICsgXCIudWktZGlzYWJsZVNlbGVjdGlvblwiLCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9ICk7XG5cdFx0fTtcblx0fSApKCksXG5cblx0ZW5hYmxlU2VsZWN0aW9uOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5vZmYoIFwiLnVpLWRpc2FibGVTZWxlY3Rpb25cIiApO1xuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRWZmZWN0cyBDb3JlXG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRlc2NyaXB0aW9uOiBFeHRlbmRzIHRoZSBpbnRlcm5hbCBqUXVlcnkgZWZmZWN0cy4gSW5jbHVkZXMgbW9ycGhpbmcgYW5kIGVhc2luZy4gUmVxdWlyZWQgYnkgYWxsIG90aGVyIGVmZmVjdHMuXG4vLyBqc2NzOmVuYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2NhdGVnb3J5L2VmZmVjdHMtY29yZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZGF0YVNwYWNlID0gXCJ1aS1lZmZlY3RzLVwiLFxuXHRkYXRhU3BhY2VTdHlsZSA9IFwidWktZWZmZWN0cy1zdHlsZVwiLFxuXHRkYXRhU3BhY2VBbmltYXRlZCA9IFwidWktZWZmZWN0cy1hbmltYXRlZFwiLFxuXG5cdC8vIENyZWF0ZSBhIGxvY2FsIGpRdWVyeSBiZWNhdXNlIGpRdWVyeSBDb2xvciByZWxpZXMgb24gaXQgYW5kIHRoZVxuXHQvLyBnbG9iYWwgbWF5IG5vdCBleGlzdCB3aXRoIEFNRCBhbmQgYSBjdXN0b20gYnVpbGQgKCMxMDE5OSlcblx0alF1ZXJ5ID0gJDtcblxuJC5lZmZlY3RzID0ge1xuXHRlZmZlY3Q6IHt9XG59O1xuXG4vKiFcbiAqIGpRdWVyeSBDb2xvciBBbmltYXRpb25zIHYyLjEuMlxuICogaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9qcXVlcnktY29sb3JcbiAqXG4gKiBDb3B5cmlnaHQgMjAxNCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKlxuICogRGF0ZTogV2VkIEphbiAxNiAwODo0NzowOSAyMDEzIC0wNjAwXG4gKi9cbiggZnVuY3Rpb24oIGpRdWVyeSwgdW5kZWZpbmVkICkge1xuXG5cdHZhciBzdGVwSG9va3MgPSBcImJhY2tncm91bmRDb2xvciBib3JkZXJCb3R0b21Db2xvciBib3JkZXJMZWZ0Q29sb3IgYm9yZGVyUmlnaHRDb2xvciBcIiArXG5cdFx0XCJib3JkZXJUb3BDb2xvciBjb2xvciBjb2x1bW5SdWxlQ29sb3Igb3V0bGluZUNvbG9yIHRleHREZWNvcmF0aW9uQ29sb3IgdGV4dEVtcGhhc2lzQ29sb3JcIixcblxuXHQvLyBQbHVzZXF1YWxzIHRlc3QgZm9yICs9IDEwMCAtPSAxMDBcblx0cnBsdXNlcXVhbHMgPSAvXihbXFwtK10pPVxccyooXFxkK1xcLj9cXGQqKS8sXG5cblx0Ly8gQSBzZXQgb2YgUkUncyB0aGF0IGNhbiBtYXRjaCBzdHJpbmdzIGFuZCBnZW5lcmF0ZSBjb2xvciB0dXBsZXMuXG5cdHN0cmluZ1BhcnNlcnMgPSBbIHtcblx0XHRcdHJlOiAvcmdiYT9cXChcXHMqKFxcZHsxLDN9KVxccyosXFxzKihcXGR7MSwzfSlcXHMqLFxccyooXFxkezEsM30pXFxzKig/OixcXHMqKFxcZD8oPzpcXC5cXGQrKT8pXFxzKik/XFwpLyxcblx0XHRcdHBhcnNlOiBmdW5jdGlvbiggZXhlY1Jlc3VsdCApIHtcblx0XHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAxIF0sXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMiBdLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDMgXSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyA0IF1cblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9LCB7XG5cdFx0XHRyZTogL3JnYmE/XFwoXFxzKihcXGQrKD86XFwuXFxkKyk/KVxcJVxccyosXFxzKihcXGQrKD86XFwuXFxkKyk/KVxcJVxccyosXFxzKihcXGQrKD86XFwuXFxkKyk/KVxcJVxccyooPzosXFxzKihcXGQ/KD86XFwuXFxkKyk/KVxccyopP1xcKS8sXG5cdFx0XHRwYXJzZTogZnVuY3Rpb24oIGV4ZWNSZXN1bHQgKSB7XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMSBdICogMi41NSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAyIF0gKiAyLjU1LFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDMgXSAqIDIuNTUsXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgNCBdXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0fSwge1xuXG5cdFx0XHQvLyBUaGlzIHJlZ2V4IGlnbm9yZXMgQS1GIGJlY2F1c2UgaXQncyBjb21wYXJlZCBhZ2FpbnN0IGFuIGFscmVhZHkgbG93ZXJjYXNlZCBzdHJpbmdcblx0XHRcdHJlOiAvIyhbYS1mMC05XXsyfSkoW2EtZjAtOV17Mn0pKFthLWYwLTldezJ9KS8sXG5cdFx0XHRwYXJzZTogZnVuY3Rpb24oIGV4ZWNSZXN1bHQgKSB7XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDEgXSwgMTYgKSxcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMiBdLCAxNiApLFxuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAzIF0sIDE2IClcblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9LCB7XG5cblx0XHRcdC8vIFRoaXMgcmVnZXggaWdub3JlcyBBLUYgYmVjYXVzZSBpdCdzIGNvbXBhcmVkIGFnYWluc3QgYW4gYWxyZWFkeSBsb3dlcmNhc2VkIHN0cmluZ1xuXHRcdFx0cmU6IC8jKFthLWYwLTldKShbYS1mMC05XSkoW2EtZjAtOV0pLyxcblx0XHRcdHBhcnNlOiBmdW5jdGlvbiggZXhlY1Jlc3VsdCApIHtcblx0XHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMSBdICsgZXhlY1Jlc3VsdFsgMSBdLCAxNiApLFxuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAyIF0gKyBleGVjUmVzdWx0WyAyIF0sIDE2ICksXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDMgXSArIGV4ZWNSZXN1bHRbIDMgXSwgMTYgKVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH0sIHtcblx0XHRcdHJlOiAvaHNsYT9cXChcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFxzKixcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFwlXFxzKixcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFwlXFxzKig/OixcXHMqKFxcZD8oPzpcXC5cXGQrKT8pXFxzKik/XFwpLyxcblx0XHRcdHNwYWNlOiBcImhzbGFcIixcblx0XHRcdHBhcnNlOiBmdW5jdGlvbiggZXhlY1Jlc3VsdCApIHtcblx0XHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAxIF0sXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMiBdIC8gMTAwLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDMgXSAvIDEwMCxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyA0IF1cblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9IF0sXG5cblx0Ly8gSlF1ZXJ5LkNvbG9yKCApXG5cdGNvbG9yID0galF1ZXJ5LkNvbG9yID0gZnVuY3Rpb24oIGNvbG9yLCBncmVlbiwgYmx1ZSwgYWxwaGEgKSB7XG5cdFx0cmV0dXJuIG5ldyBqUXVlcnkuQ29sb3IuZm4ucGFyc2UoIGNvbG9yLCBncmVlbiwgYmx1ZSwgYWxwaGEgKTtcblx0fSxcblx0c3BhY2VzID0ge1xuXHRcdHJnYmE6IHtcblx0XHRcdHByb3BzOiB7XG5cdFx0XHRcdHJlZDoge1xuXHRcdFx0XHRcdGlkeDogMCxcblx0XHRcdFx0XHR0eXBlOiBcImJ5dGVcIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRncmVlbjoge1xuXHRcdFx0XHRcdGlkeDogMSxcblx0XHRcdFx0XHR0eXBlOiBcImJ5dGVcIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRibHVlOiB7XG5cdFx0XHRcdFx0aWR4OiAyLFxuXHRcdFx0XHRcdHR5cGU6IFwiYnl0ZVwiXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0aHNsYToge1xuXHRcdFx0cHJvcHM6IHtcblx0XHRcdFx0aHVlOiB7XG5cdFx0XHRcdFx0aWR4OiAwLFxuXHRcdFx0XHRcdHR5cGU6IFwiZGVncmVlc1wiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHNhdHVyYXRpb246IHtcblx0XHRcdFx0XHRpZHg6IDEsXG5cdFx0XHRcdFx0dHlwZTogXCJwZXJjZW50XCJcblx0XHRcdFx0fSxcblx0XHRcdFx0bGlnaHRuZXNzOiB7XG5cdFx0XHRcdFx0aWR4OiAyLFxuXHRcdFx0XHRcdHR5cGU6IFwicGVyY2VudFwiXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdHByb3BUeXBlcyA9IHtcblx0XHRcImJ5dGVcIjoge1xuXHRcdFx0Zmxvb3I6IHRydWUsXG5cdFx0XHRtYXg6IDI1NVxuXHRcdH0sXG5cdFx0XCJwZXJjZW50XCI6IHtcblx0XHRcdG1heDogMVxuXHRcdH0sXG5cdFx0XCJkZWdyZWVzXCI6IHtcblx0XHRcdG1vZDogMzYwLFxuXHRcdFx0Zmxvb3I6IHRydWVcblx0XHR9XG5cdH0sXG5cdHN1cHBvcnQgPSBjb2xvci5zdXBwb3J0ID0ge30sXG5cblx0Ly8gRWxlbWVudCBmb3Igc3VwcG9ydCB0ZXN0c1xuXHRzdXBwb3J0RWxlbSA9IGpRdWVyeSggXCI8cD5cIiApWyAwIF0sXG5cblx0Ly8gQ29sb3JzID0galF1ZXJ5LkNvbG9yLm5hbWVzXG5cdGNvbG9ycyxcblxuXHQvLyBMb2NhbCBhbGlhc2VzIG9mIGZ1bmN0aW9ucyBjYWxsZWQgb2Z0ZW5cblx0ZWFjaCA9IGpRdWVyeS5lYWNoO1xuXG4vLyBEZXRlcm1pbmUgcmdiYSBzdXBwb3J0IGltbWVkaWF0ZWx5XG5zdXBwb3J0RWxlbS5zdHlsZS5jc3NUZXh0ID0gXCJiYWNrZ3JvdW5kLWNvbG9yOnJnYmEoMSwxLDEsLjUpXCI7XG5zdXBwb3J0LnJnYmEgPSBzdXBwb3J0RWxlbS5zdHlsZS5iYWNrZ3JvdW5kQ29sb3IuaW5kZXhPZiggXCJyZ2JhXCIgKSA+IC0xO1xuXG4vLyBEZWZpbmUgY2FjaGUgbmFtZSBhbmQgYWxwaGEgcHJvcGVydGllc1xuLy8gZm9yIHJnYmEgYW5kIGhzbGEgc3BhY2VzXG5lYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBzcGFjZU5hbWUsIHNwYWNlICkge1xuXHRzcGFjZS5jYWNoZSA9IFwiX1wiICsgc3BhY2VOYW1lO1xuXHRzcGFjZS5wcm9wcy5hbHBoYSA9IHtcblx0XHRpZHg6IDMsXG5cdFx0dHlwZTogXCJwZXJjZW50XCIsXG5cdFx0ZGVmOiAxXG5cdH07XG59ICk7XG5cbmZ1bmN0aW9uIGNsYW1wKCB2YWx1ZSwgcHJvcCwgYWxsb3dFbXB0eSApIHtcblx0dmFyIHR5cGUgPSBwcm9wVHlwZXNbIHByb3AudHlwZSBdIHx8IHt9O1xuXG5cdGlmICggdmFsdWUgPT0gbnVsbCApIHtcblx0XHRyZXR1cm4gKCBhbGxvd0VtcHR5IHx8ICFwcm9wLmRlZiApID8gbnVsbCA6IHByb3AuZGVmO1xuXHR9XG5cblx0Ly8gfn4gaXMgYW4gc2hvcnQgd2F5IG9mIGRvaW5nIGZsb29yIGZvciBwb3NpdGl2ZSBudW1iZXJzXG5cdHZhbHVlID0gdHlwZS5mbG9vciA/IH5+dmFsdWUgOiBwYXJzZUZsb2F0KCB2YWx1ZSApO1xuXG5cdC8vIElFIHdpbGwgcGFzcyBpbiBlbXB0eSBzdHJpbmdzIGFzIHZhbHVlIGZvciBhbHBoYSxcblx0Ly8gd2hpY2ggd2lsbCBoaXQgdGhpcyBjYXNlXG5cdGlmICggaXNOYU4oIHZhbHVlICkgKSB7XG5cdFx0cmV0dXJuIHByb3AuZGVmO1xuXHR9XG5cblx0aWYgKCB0eXBlLm1vZCApIHtcblxuXHRcdC8vIFdlIGFkZCBtb2QgYmVmb3JlIG1vZGRpbmcgdG8gbWFrZSBzdXJlIHRoYXQgbmVnYXRpdmVzIHZhbHVlc1xuXHRcdC8vIGdldCBjb252ZXJ0ZWQgcHJvcGVybHk6IC0xMCAtPiAzNTBcblx0XHRyZXR1cm4gKCB2YWx1ZSArIHR5cGUubW9kICkgJSB0eXBlLm1vZDtcblx0fVxuXG5cdC8vIEZvciBub3cgYWxsIHByb3BlcnR5IHR5cGVzIHdpdGhvdXQgbW9kIGhhdmUgbWluIGFuZCBtYXhcblx0cmV0dXJuIDAgPiB2YWx1ZSA/IDAgOiB0eXBlLm1heCA8IHZhbHVlID8gdHlwZS5tYXggOiB2YWx1ZTtcbn1cblxuZnVuY3Rpb24gc3RyaW5nUGFyc2UoIHN0cmluZyApIHtcblx0dmFyIGluc3QgPSBjb2xvcigpLFxuXHRcdHJnYmEgPSBpbnN0Ll9yZ2JhID0gW107XG5cblx0c3RyaW5nID0gc3RyaW5nLnRvTG93ZXJDYXNlKCk7XG5cblx0ZWFjaCggc3RyaW5nUGFyc2VycywgZnVuY3Rpb24oIGksIHBhcnNlciApIHtcblx0XHR2YXIgcGFyc2VkLFxuXHRcdFx0bWF0Y2ggPSBwYXJzZXIucmUuZXhlYyggc3RyaW5nICksXG5cdFx0XHR2YWx1ZXMgPSBtYXRjaCAmJiBwYXJzZXIucGFyc2UoIG1hdGNoICksXG5cdFx0XHRzcGFjZU5hbWUgPSBwYXJzZXIuc3BhY2UgfHwgXCJyZ2JhXCI7XG5cblx0XHRpZiAoIHZhbHVlcyApIHtcblx0XHRcdHBhcnNlZCA9IGluc3RbIHNwYWNlTmFtZSBdKCB2YWx1ZXMgKTtcblxuXHRcdFx0Ly8gSWYgdGhpcyB3YXMgYW4gcmdiYSBwYXJzZSB0aGUgYXNzaWdubWVudCBtaWdodCBoYXBwZW4gdHdpY2Vcblx0XHRcdC8vIG9oIHdlbGwuLi4uXG5cdFx0XHRpbnN0WyBzcGFjZXNbIHNwYWNlTmFtZSBdLmNhY2hlIF0gPSBwYXJzZWRbIHNwYWNlc1sgc3BhY2VOYW1lIF0uY2FjaGUgXTtcblx0XHRcdHJnYmEgPSBpbnN0Ll9yZ2JhID0gcGFyc2VkLl9yZ2JhO1xuXG5cdFx0XHQvLyBFeGl0IGVhY2goIHN0cmluZ1BhcnNlcnMgKSBoZXJlIGJlY2F1c2Ugd2UgbWF0Y2hlZFxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0fSApO1xuXG5cdC8vIEZvdW5kIGEgc3RyaW5nUGFyc2VyIHRoYXQgaGFuZGxlZCBpdFxuXHRpZiAoIHJnYmEubGVuZ3RoICkge1xuXG5cdFx0Ly8gSWYgdGhpcyBjYW1lIGZyb20gYSBwYXJzZWQgc3RyaW5nLCBmb3JjZSBcInRyYW5zcGFyZW50XCIgd2hlbiBhbHBoYSBpcyAwXG5cdFx0Ly8gY2hyb21lLCAoYW5kIG1heWJlIG90aGVycykgcmV0dXJuIFwidHJhbnNwYXJlbnRcIiBhcyByZ2JhKDAsMCwwLDApXG5cdFx0aWYgKCByZ2JhLmpvaW4oKSA9PT0gXCIwLDAsMCwwXCIgKSB7XG5cdFx0XHRqUXVlcnkuZXh0ZW5kKCByZ2JhLCBjb2xvcnMudHJhbnNwYXJlbnQgKTtcblx0XHR9XG5cdFx0cmV0dXJuIGluc3Q7XG5cdH1cblxuXHQvLyBOYW1lZCBjb2xvcnNcblx0cmV0dXJuIGNvbG9yc1sgc3RyaW5nIF07XG59XG5cbmNvbG9yLmZuID0galF1ZXJ5LmV4dGVuZCggY29sb3IucHJvdG90eXBlLCB7XG5cdHBhcnNlOiBmdW5jdGlvbiggcmVkLCBncmVlbiwgYmx1ZSwgYWxwaGEgKSB7XG5cdFx0aWYgKCByZWQgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX3JnYmEgPSBbIG51bGwsIG51bGwsIG51bGwsIG51bGwgXTtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblx0XHRpZiAoIHJlZC5qcXVlcnkgfHwgcmVkLm5vZGVUeXBlICkge1xuXHRcdFx0cmVkID0galF1ZXJ5KCByZWQgKS5jc3MoIGdyZWVuICk7XG5cdFx0XHRncmVlbiA9IHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHR2YXIgaW5zdCA9IHRoaXMsXG5cdFx0XHR0eXBlID0galF1ZXJ5LnR5cGUoIHJlZCApLFxuXHRcdFx0cmdiYSA9IHRoaXMuX3JnYmEgPSBbXTtcblxuXHRcdC8vIE1vcmUgdGhhbiAxIGFyZ3VtZW50IHNwZWNpZmllZCAtIGFzc3VtZSAoIHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhIClcblx0XHRpZiAoIGdyZWVuICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZWQgPSBbIHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhIF07XG5cdFx0XHR0eXBlID0gXCJhcnJheVwiO1xuXHRcdH1cblxuXHRcdGlmICggdHlwZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiB0aGlzLnBhcnNlKCBzdHJpbmdQYXJzZSggcmVkICkgfHwgY29sb3JzLl9kZWZhdWx0ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0eXBlID09PSBcImFycmF5XCIgKSB7XG5cdFx0XHRlYWNoKCBzcGFjZXMucmdiYS5wcm9wcywgZnVuY3Rpb24oIGtleSwgcHJvcCApIHtcblx0XHRcdFx0cmdiYVsgcHJvcC5pZHggXSA9IGNsYW1wKCByZWRbIHByb3AuaWR4IF0sIHByb3AgKTtcblx0XHRcdH0gKTtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblxuXHRcdGlmICggdHlwZSA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRcdGlmICggcmVkIGluc3RhbmNlb2YgY29sb3IgKSB7XG5cdFx0XHRcdGVhY2goIHNwYWNlcywgZnVuY3Rpb24oIHNwYWNlTmFtZSwgc3BhY2UgKSB7XG5cdFx0XHRcdFx0aWYgKCByZWRbIHNwYWNlLmNhY2hlIF0gKSB7XG5cdFx0XHRcdFx0XHRpbnN0WyBzcGFjZS5jYWNoZSBdID0gcmVkWyBzcGFjZS5jYWNoZSBdLnNsaWNlKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBzcGFjZU5hbWUsIHNwYWNlICkge1xuXHRcdFx0XHRcdHZhciBjYWNoZSA9IHNwYWNlLmNhY2hlO1xuXHRcdFx0XHRcdGVhY2goIHNwYWNlLnByb3BzLCBmdW5jdGlvbigga2V5LCBwcm9wICkge1xuXG5cdFx0XHRcdFx0XHQvLyBJZiB0aGUgY2FjaGUgZG9lc24ndCBleGlzdCwgYW5kIHdlIGtub3cgaG93IHRvIGNvbnZlcnRcblx0XHRcdFx0XHRcdGlmICggIWluc3RbIGNhY2hlIF0gJiYgc3BhY2UudG8gKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gSWYgdGhlIHZhbHVlIHdhcyBudWxsLCB3ZSBkb24ndCBuZWVkIHRvIGNvcHkgaXRcblx0XHRcdFx0XHRcdFx0Ly8gaWYgdGhlIGtleSB3YXMgYWxwaGEsIHdlIGRvbid0IG5lZWQgdG8gY29weSBpdCBlaXRoZXJcblx0XHRcdFx0XHRcdFx0aWYgKCBrZXkgPT09IFwiYWxwaGFcIiB8fCByZWRbIGtleSBdID09IG51bGwgKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGluc3RbIGNhY2hlIF0gPSBzcGFjZS50byggaW5zdC5fcmdiYSApO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBUaGlzIGlzIHRoZSBvbmx5IGNhc2Ugd2hlcmUgd2UgYWxsb3cgbnVsbHMgZm9yIEFMTCBwcm9wZXJ0aWVzLlxuXHRcdFx0XHRcdFx0Ly8gY2FsbCBjbGFtcCB3aXRoIGFsd2F5c0FsbG93RW1wdHlcblx0XHRcdFx0XHRcdGluc3RbIGNhY2hlIF1bIHByb3AuaWR4IF0gPSBjbGFtcCggcmVkWyBrZXkgXSwgcHJvcCwgdHJ1ZSApO1xuXHRcdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRcdC8vIEV2ZXJ5dGhpbmcgZGVmaW5lZCBidXQgYWxwaGE/XG5cdFx0XHRcdFx0aWYgKCBpbnN0WyBjYWNoZSBdICYmXG5cdFx0XHRcdFx0XHRcdGpRdWVyeS5pbkFycmF5KCBudWxsLCBpbnN0WyBjYWNoZSBdLnNsaWNlKCAwLCAzICkgKSA8IDAgKSB7XG5cblx0XHRcdFx0XHRcdC8vIFVzZSB0aGUgZGVmYXVsdCBvZiAxXG5cdFx0XHRcdFx0XHRpbnN0WyBjYWNoZSBdWyAzIF0gPSAxO1xuXHRcdFx0XHRcdFx0aWYgKCBzcGFjZS5mcm9tICkge1xuXHRcdFx0XHRcdFx0XHRpbnN0Ll9yZ2JhID0gc3BhY2UuZnJvbSggaW5zdFsgY2FjaGUgXSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXHR9LFxuXHRpczogZnVuY3Rpb24oIGNvbXBhcmUgKSB7XG5cdFx0dmFyIGlzID0gY29sb3IoIGNvbXBhcmUgKSxcblx0XHRcdHNhbWUgPSB0cnVlLFxuXHRcdFx0aW5zdCA9IHRoaXM7XG5cblx0XHRlYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBfLCBzcGFjZSApIHtcblx0XHRcdHZhciBsb2NhbENhY2hlLFxuXHRcdFx0XHRpc0NhY2hlID0gaXNbIHNwYWNlLmNhY2hlIF07XG5cdFx0XHRpZiAoIGlzQ2FjaGUgKSB7XG5cdFx0XHRcdGxvY2FsQ2FjaGUgPSBpbnN0WyBzcGFjZS5jYWNoZSBdIHx8IHNwYWNlLnRvICYmIHNwYWNlLnRvKCBpbnN0Ll9yZ2JhICkgfHwgW107XG5cdFx0XHRcdGVhY2goIHNwYWNlLnByb3BzLCBmdW5jdGlvbiggXywgcHJvcCApIHtcblx0XHRcdFx0XHRpZiAoIGlzQ2FjaGVbIHByb3AuaWR4IF0gIT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdHNhbWUgPSAoIGlzQ2FjaGVbIHByb3AuaWR4IF0gPT09IGxvY2FsQ2FjaGVbIHByb3AuaWR4IF0gKTtcblx0XHRcdFx0XHRcdHJldHVybiBzYW1lO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHNhbWU7XG5cdFx0fSApO1xuXHRcdHJldHVybiBzYW1lO1xuXHR9LFxuXHRfc3BhY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB1c2VkID0gW10sXG5cdFx0XHRpbnN0ID0gdGhpcztcblx0XHRlYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBzcGFjZU5hbWUsIHNwYWNlICkge1xuXHRcdFx0aWYgKCBpbnN0WyBzcGFjZS5jYWNoZSBdICkge1xuXHRcdFx0XHR1c2VkLnB1c2goIHNwYWNlTmFtZSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHRyZXR1cm4gdXNlZC5wb3AoKTtcblx0fSxcblx0dHJhbnNpdGlvbjogZnVuY3Rpb24oIG90aGVyLCBkaXN0YW5jZSApIHtcblx0XHR2YXIgZW5kID0gY29sb3IoIG90aGVyICksXG5cdFx0XHRzcGFjZU5hbWUgPSBlbmQuX3NwYWNlKCksXG5cdFx0XHRzcGFjZSA9IHNwYWNlc1sgc3BhY2VOYW1lIF0sXG5cdFx0XHRzdGFydENvbG9yID0gdGhpcy5hbHBoYSgpID09PSAwID8gY29sb3IoIFwidHJhbnNwYXJlbnRcIiApIDogdGhpcyxcblx0XHRcdHN0YXJ0ID0gc3RhcnRDb2xvclsgc3BhY2UuY2FjaGUgXSB8fCBzcGFjZS50byggc3RhcnRDb2xvci5fcmdiYSApLFxuXHRcdFx0cmVzdWx0ID0gc3RhcnQuc2xpY2UoKTtcblxuXHRcdGVuZCA9IGVuZFsgc3BhY2UuY2FjaGUgXTtcblx0XHRlYWNoKCBzcGFjZS5wcm9wcywgZnVuY3Rpb24oIGtleSwgcHJvcCApIHtcblx0XHRcdHZhciBpbmRleCA9IHByb3AuaWR4LFxuXHRcdFx0XHRzdGFydFZhbHVlID0gc3RhcnRbIGluZGV4IF0sXG5cdFx0XHRcdGVuZFZhbHVlID0gZW5kWyBpbmRleCBdLFxuXHRcdFx0XHR0eXBlID0gcHJvcFR5cGVzWyBwcm9wLnR5cGUgXSB8fCB7fTtcblxuXHRcdFx0Ly8gSWYgbnVsbCwgZG9uJ3Qgb3ZlcnJpZGUgc3RhcnQgdmFsdWVcblx0XHRcdGlmICggZW5kVmFsdWUgPT09IG51bGwgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSWYgbnVsbCAtIHVzZSBlbmRcblx0XHRcdGlmICggc3RhcnRWYWx1ZSA9PT0gbnVsbCApIHtcblx0XHRcdFx0cmVzdWx0WyBpbmRleCBdID0gZW5kVmFsdWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAoIHR5cGUubW9kICkge1xuXHRcdFx0XHRcdGlmICggZW5kVmFsdWUgLSBzdGFydFZhbHVlID4gdHlwZS5tb2QgLyAyICkge1xuXHRcdFx0XHRcdFx0c3RhcnRWYWx1ZSArPSB0eXBlLm1vZDtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBzdGFydFZhbHVlIC0gZW5kVmFsdWUgPiB0eXBlLm1vZCAvIDIgKSB7XG5cdFx0XHRcdFx0XHRzdGFydFZhbHVlIC09IHR5cGUubW9kO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXN1bHRbIGluZGV4IF0gPSBjbGFtcCggKCBlbmRWYWx1ZSAtIHN0YXJ0VmFsdWUgKSAqIGRpc3RhbmNlICsgc3RhcnRWYWx1ZSwgcHJvcCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHRyZXR1cm4gdGhpc1sgc3BhY2VOYW1lIF0oIHJlc3VsdCApO1xuXHR9LFxuXHRibGVuZDogZnVuY3Rpb24oIG9wYXF1ZSApIHtcblxuXHRcdC8vIElmIHdlIGFyZSBhbHJlYWR5IG9wYXF1ZSAtIHJldHVybiBvdXJzZWxmXG5cdFx0aWYgKCB0aGlzLl9yZ2JhWyAzIF0gPT09IDEgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cblx0XHR2YXIgcmdiID0gdGhpcy5fcmdiYS5zbGljZSgpLFxuXHRcdFx0YSA9IHJnYi5wb3AoKSxcblx0XHRcdGJsZW5kID0gY29sb3IoIG9wYXF1ZSApLl9yZ2JhO1xuXG5cdFx0cmV0dXJuIGNvbG9yKCBqUXVlcnkubWFwKCByZ2IsIGZ1bmN0aW9uKCB2LCBpICkge1xuXHRcdFx0cmV0dXJuICggMSAtIGEgKSAqIGJsZW5kWyBpIF0gKyBhICogdjtcblx0XHR9ICkgKTtcblx0fSxcblx0dG9SZ2JhU3RyaW5nOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJlZml4ID0gXCJyZ2JhKFwiLFxuXHRcdFx0cmdiYSA9IGpRdWVyeS5tYXAoIHRoaXMuX3JnYmEsIGZ1bmN0aW9uKCB2LCBpICkge1xuXHRcdFx0XHRyZXR1cm4gdiA9PSBudWxsID8gKCBpID4gMiA/IDEgOiAwICkgOiB2O1xuXHRcdFx0fSApO1xuXG5cdFx0aWYgKCByZ2JhWyAzIF0gPT09IDEgKSB7XG5cdFx0XHRyZ2JhLnBvcCgpO1xuXHRcdFx0cHJlZml4ID0gXCJyZ2IoXCI7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHByZWZpeCArIHJnYmEuam9pbigpICsgXCIpXCI7XG5cdH0sXG5cdHRvSHNsYVN0cmluZzogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZWZpeCA9IFwiaHNsYShcIixcblx0XHRcdGhzbGEgPSBqUXVlcnkubWFwKCB0aGlzLmhzbGEoKSwgZnVuY3Rpb24oIHYsIGkgKSB7XG5cdFx0XHRcdGlmICggdiA9PSBudWxsICkge1xuXHRcdFx0XHRcdHYgPSBpID4gMiA/IDEgOiAwO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQ2F0Y2ggMSBhbmQgMlxuXHRcdFx0XHRpZiAoIGkgJiYgaSA8IDMgKSB7XG5cdFx0XHRcdFx0diA9IE1hdGgucm91bmQoIHYgKiAxMDAgKSArIFwiJVwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB2O1xuXHRcdFx0fSApO1xuXG5cdFx0aWYgKCBoc2xhWyAzIF0gPT09IDEgKSB7XG5cdFx0XHRoc2xhLnBvcCgpO1xuXHRcdFx0cHJlZml4ID0gXCJoc2woXCI7XG5cdFx0fVxuXHRcdHJldHVybiBwcmVmaXggKyBoc2xhLmpvaW4oKSArIFwiKVwiO1xuXHR9LFxuXHR0b0hleFN0cmluZzogZnVuY3Rpb24oIGluY2x1ZGVBbHBoYSApIHtcblx0XHR2YXIgcmdiYSA9IHRoaXMuX3JnYmEuc2xpY2UoKSxcblx0XHRcdGFscGhhID0gcmdiYS5wb3AoKTtcblxuXHRcdGlmICggaW5jbHVkZUFscGhhICkge1xuXHRcdFx0cmdiYS5wdXNoKCB+figgYWxwaGEgKiAyNTUgKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBcIiNcIiArIGpRdWVyeS5tYXAoIHJnYmEsIGZ1bmN0aW9uKCB2ICkge1xuXG5cdFx0XHQvLyBEZWZhdWx0IHRvIDAgd2hlbiBudWxscyBleGlzdFxuXHRcdFx0diA9ICggdiB8fCAwICkudG9TdHJpbmcoIDE2ICk7XG5cdFx0XHRyZXR1cm4gdi5sZW5ndGggPT09IDEgPyBcIjBcIiArIHYgOiB2O1xuXHRcdH0gKS5qb2luKCBcIlwiICk7XG5cdH0sXG5cdHRvU3RyaW5nOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5fcmdiYVsgMyBdID09PSAwID8gXCJ0cmFuc3BhcmVudFwiIDogdGhpcy50b1JnYmFTdHJpbmcoKTtcblx0fVxufSApO1xuY29sb3IuZm4ucGFyc2UucHJvdG90eXBlID0gY29sb3IuZm47XG5cbi8vIEhzbGEgY29udmVyc2lvbnMgYWRhcHRlZCBmcm9tOlxuLy8gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9tYWFzaGFhY2svc291cmNlL2Jyb3dzZS9wYWNrYWdlcy9ncmFwaGljcy90cnVuay9zcmMvZ3JhcGhpY3MvY29sb3JzL0hVRTJSR0IuYXM/cj01MDIxXG5cbmZ1bmN0aW9uIGh1ZTJyZ2IoIHAsIHEsIGggKSB7XG5cdGggPSAoIGggKyAxICkgJSAxO1xuXHRpZiAoIGggKiA2IDwgMSApIHtcblx0XHRyZXR1cm4gcCArICggcSAtIHAgKSAqIGggKiA2O1xuXHR9XG5cdGlmICggaCAqIDIgPCAxICkge1xuXHRcdHJldHVybiBxO1xuXHR9XG5cdGlmICggaCAqIDMgPCAyICkge1xuXHRcdHJldHVybiBwICsgKCBxIC0gcCApICogKCAoIDIgLyAzICkgLSBoICkgKiA2O1xuXHR9XG5cdHJldHVybiBwO1xufVxuXG5zcGFjZXMuaHNsYS50byA9IGZ1bmN0aW9uKCByZ2JhICkge1xuXHRpZiAoIHJnYmFbIDAgXSA9PSBudWxsIHx8IHJnYmFbIDEgXSA9PSBudWxsIHx8IHJnYmFbIDIgXSA9PSBudWxsICkge1xuXHRcdHJldHVybiBbIG51bGwsIG51bGwsIG51bGwsIHJnYmFbIDMgXSBdO1xuXHR9XG5cdHZhciByID0gcmdiYVsgMCBdIC8gMjU1LFxuXHRcdGcgPSByZ2JhWyAxIF0gLyAyNTUsXG5cdFx0YiA9IHJnYmFbIDIgXSAvIDI1NSxcblx0XHRhID0gcmdiYVsgMyBdLFxuXHRcdG1heCA9IE1hdGgubWF4KCByLCBnLCBiICksXG5cdFx0bWluID0gTWF0aC5taW4oIHIsIGcsIGIgKSxcblx0XHRkaWZmID0gbWF4IC0gbWluLFxuXHRcdGFkZCA9IG1heCArIG1pbixcblx0XHRsID0gYWRkICogMC41LFxuXHRcdGgsIHM7XG5cblx0aWYgKCBtaW4gPT09IG1heCApIHtcblx0XHRoID0gMDtcblx0fSBlbHNlIGlmICggciA9PT0gbWF4ICkge1xuXHRcdGggPSAoIDYwICogKCBnIC0gYiApIC8gZGlmZiApICsgMzYwO1xuXHR9IGVsc2UgaWYgKCBnID09PSBtYXggKSB7XG5cdFx0aCA9ICggNjAgKiAoIGIgLSByICkgLyBkaWZmICkgKyAxMjA7XG5cdH0gZWxzZSB7XG5cdFx0aCA9ICggNjAgKiAoIHIgLSBnICkgLyBkaWZmICkgKyAyNDA7XG5cdH1cblxuXHQvLyBDaHJvbWEgKGRpZmYpID09IDAgbWVhbnMgZ3JleXNjYWxlIHdoaWNoLCBieSBkZWZpbml0aW9uLCBzYXR1cmF0aW9uID0gMCVcblx0Ly8gb3RoZXJ3aXNlLCBzYXR1cmF0aW9uIGlzIGJhc2VkIG9uIHRoZSByYXRpbyBvZiBjaHJvbWEgKGRpZmYpIHRvIGxpZ2h0bmVzcyAoYWRkKVxuXHRpZiAoIGRpZmYgPT09IDAgKSB7XG5cdFx0cyA9IDA7XG5cdH0gZWxzZSBpZiAoIGwgPD0gMC41ICkge1xuXHRcdHMgPSBkaWZmIC8gYWRkO1xuXHR9IGVsc2Uge1xuXHRcdHMgPSBkaWZmIC8gKCAyIC0gYWRkICk7XG5cdH1cblx0cmV0dXJuIFsgTWF0aC5yb3VuZCggaCApICUgMzYwLCBzLCBsLCBhID09IG51bGwgPyAxIDogYSBdO1xufTtcblxuc3BhY2VzLmhzbGEuZnJvbSA9IGZ1bmN0aW9uKCBoc2xhICkge1xuXHRpZiAoIGhzbGFbIDAgXSA9PSBudWxsIHx8IGhzbGFbIDEgXSA9PSBudWxsIHx8IGhzbGFbIDIgXSA9PSBudWxsICkge1xuXHRcdHJldHVybiBbIG51bGwsIG51bGwsIG51bGwsIGhzbGFbIDMgXSBdO1xuXHR9XG5cdHZhciBoID0gaHNsYVsgMCBdIC8gMzYwLFxuXHRcdHMgPSBoc2xhWyAxIF0sXG5cdFx0bCA9IGhzbGFbIDIgXSxcblx0XHRhID0gaHNsYVsgMyBdLFxuXHRcdHEgPSBsIDw9IDAuNSA/IGwgKiAoIDEgKyBzICkgOiBsICsgcyAtIGwgKiBzLFxuXHRcdHAgPSAyICogbCAtIHE7XG5cblx0cmV0dXJuIFtcblx0XHRNYXRoLnJvdW5kKCBodWUycmdiKCBwLCBxLCBoICsgKCAxIC8gMyApICkgKiAyNTUgKSxcblx0XHRNYXRoLnJvdW5kKCBodWUycmdiKCBwLCBxLCBoICkgKiAyNTUgKSxcblx0XHRNYXRoLnJvdW5kKCBodWUycmdiKCBwLCBxLCBoIC0gKCAxIC8gMyApICkgKiAyNTUgKSxcblx0XHRhXG5cdF07XG59O1xuXG5lYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBzcGFjZU5hbWUsIHNwYWNlICkge1xuXHR2YXIgcHJvcHMgPSBzcGFjZS5wcm9wcyxcblx0XHRjYWNoZSA9IHNwYWNlLmNhY2hlLFxuXHRcdHRvID0gc3BhY2UudG8sXG5cdFx0ZnJvbSA9IHNwYWNlLmZyb207XG5cblx0Ly8gTWFrZXMgcmdiYSgpIGFuZCBoc2xhKClcblx0Y29sb3IuZm5bIHNwYWNlTmFtZSBdID0gZnVuY3Rpb24oIHZhbHVlICkge1xuXG5cdFx0Ly8gR2VuZXJhdGUgYSBjYWNoZSBmb3IgdGhpcyBzcGFjZSBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdFx0aWYgKCB0byAmJiAhdGhpc1sgY2FjaGUgXSApIHtcblx0XHRcdHRoaXNbIGNhY2hlIF0gPSB0byggdGhpcy5fcmdiYSApO1xuXHRcdH1cblx0XHRpZiAoIHZhbHVlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXR1cm4gdGhpc1sgY2FjaGUgXS5zbGljZSgpO1xuXHRcdH1cblxuXHRcdHZhciByZXQsXG5cdFx0XHR0eXBlID0galF1ZXJ5LnR5cGUoIHZhbHVlICksXG5cdFx0XHRhcnIgPSAoIHR5cGUgPT09IFwiYXJyYXlcIiB8fCB0eXBlID09PSBcIm9iamVjdFwiICkgPyB2YWx1ZSA6IGFyZ3VtZW50cyxcblx0XHRcdGxvY2FsID0gdGhpc1sgY2FjaGUgXS5zbGljZSgpO1xuXG5cdFx0ZWFjaCggcHJvcHMsIGZ1bmN0aW9uKCBrZXksIHByb3AgKSB7XG5cdFx0XHR2YXIgdmFsID0gYXJyWyB0eXBlID09PSBcIm9iamVjdFwiID8ga2V5IDogcHJvcC5pZHggXTtcblx0XHRcdGlmICggdmFsID09IG51bGwgKSB7XG5cdFx0XHRcdHZhbCA9IGxvY2FsWyBwcm9wLmlkeCBdO1xuXHRcdFx0fVxuXHRcdFx0bG9jYWxbIHByb3AuaWR4IF0gPSBjbGFtcCggdmFsLCBwcm9wICk7XG5cdFx0fSApO1xuXG5cdFx0aWYgKCBmcm9tICkge1xuXHRcdFx0cmV0ID0gY29sb3IoIGZyb20oIGxvY2FsICkgKTtcblx0XHRcdHJldFsgY2FjaGUgXSA9IGxvY2FsO1xuXHRcdFx0cmV0dXJuIHJldDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIGNvbG9yKCBsb2NhbCApO1xuXHRcdH1cblx0fTtcblxuXHQvLyBNYWtlcyByZWQoKSBncmVlbigpIGJsdWUoKSBhbHBoYSgpIGh1ZSgpIHNhdHVyYXRpb24oKSBsaWdodG5lc3MoKVxuXHRlYWNoKCBwcm9wcywgZnVuY3Rpb24oIGtleSwgcHJvcCApIHtcblxuXHRcdC8vIEFscGhhIGlzIGluY2x1ZGVkIGluIG1vcmUgdGhhbiBvbmUgc3BhY2Vcblx0XHRpZiAoIGNvbG9yLmZuWyBrZXkgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0Y29sb3IuZm5bIGtleSBdID0gZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0dmFyIHZ0eXBlID0galF1ZXJ5LnR5cGUoIHZhbHVlICksXG5cdFx0XHRcdGZuID0gKCBrZXkgPT09IFwiYWxwaGFcIiA/ICggdGhpcy5faHNsYSA/IFwiaHNsYVwiIDogXCJyZ2JhXCIgKSA6IHNwYWNlTmFtZSApLFxuXHRcdFx0XHRsb2NhbCA9IHRoaXNbIGZuIF0oKSxcblx0XHRcdFx0Y3VyID0gbG9jYWxbIHByb3AuaWR4IF0sXG5cdFx0XHRcdG1hdGNoO1xuXG5cdFx0XHRpZiAoIHZ0eXBlID09PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdFx0XHRyZXR1cm4gY3VyO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHZ0eXBlID09PSBcImZ1bmN0aW9uXCIgKSB7XG5cdFx0XHRcdHZhbHVlID0gdmFsdWUuY2FsbCggdGhpcywgY3VyICk7XG5cdFx0XHRcdHZ0eXBlID0galF1ZXJ5LnR5cGUoIHZhbHVlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHZhbHVlID09IG51bGwgJiYgcHJvcC5lbXB0eSApIHtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHZ0eXBlID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRtYXRjaCA9IHJwbHVzZXF1YWxzLmV4ZWMoIHZhbHVlICk7XG5cdFx0XHRcdGlmICggbWF0Y2ggKSB7XG5cdFx0XHRcdFx0dmFsdWUgPSBjdXIgKyBwYXJzZUZsb2F0KCBtYXRjaFsgMiBdICkgKiAoIG1hdGNoWyAxIF0gPT09IFwiK1wiID8gMSA6IC0xICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGxvY2FsWyBwcm9wLmlkeCBdID0gdmFsdWU7XG5cdFx0XHRyZXR1cm4gdGhpc1sgZm4gXSggbG9jYWwgKTtcblx0XHR9O1xuXHR9ICk7XG59ICk7XG5cbi8vIEFkZCBjc3NIb29rIGFuZCAuZnguc3RlcCBmdW5jdGlvbiBmb3IgZWFjaCBuYW1lZCBob29rLlxuLy8gYWNjZXB0IGEgc3BhY2Ugc2VwYXJhdGVkIHN0cmluZyBvZiBwcm9wZXJ0aWVzXG5jb2xvci5ob29rID0gZnVuY3Rpb24oIGhvb2sgKSB7XG5cdHZhciBob29rcyA9IGhvb2suc3BsaXQoIFwiIFwiICk7XG5cdGVhY2goIGhvb2tzLCBmdW5jdGlvbiggaSwgaG9vayApIHtcblx0XHRqUXVlcnkuY3NzSG9va3NbIGhvb2sgXSA9IHtcblx0XHRcdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkge1xuXHRcdFx0XHR2YXIgcGFyc2VkLCBjdXJFbGVtLFxuXHRcdFx0XHRcdGJhY2tncm91bmRDb2xvciA9IFwiXCI7XG5cblx0XHRcdFx0aWYgKCB2YWx1ZSAhPT0gXCJ0cmFuc3BhcmVudFwiICYmICggalF1ZXJ5LnR5cGUoIHZhbHVlICkgIT09IFwic3RyaW5nXCIgfHxcblx0XHRcdFx0XHRcdCggcGFyc2VkID0gc3RyaW5nUGFyc2UoIHZhbHVlICkgKSApICkge1xuXHRcdFx0XHRcdHZhbHVlID0gY29sb3IoIHBhcnNlZCB8fCB2YWx1ZSApO1xuXHRcdFx0XHRcdGlmICggIXN1cHBvcnQucmdiYSAmJiB2YWx1ZS5fcmdiYVsgMyBdICE9PSAxICkge1xuXHRcdFx0XHRcdFx0Y3VyRWxlbSA9IGhvb2sgPT09IFwiYmFja2dyb3VuZENvbG9yXCIgPyBlbGVtLnBhcmVudE5vZGUgOiBlbGVtO1xuXHRcdFx0XHRcdFx0d2hpbGUgKFxuXHRcdFx0XHRcdFx0XHQoIGJhY2tncm91bmRDb2xvciA9PT0gXCJcIiB8fCBiYWNrZ3JvdW5kQ29sb3IgPT09IFwidHJhbnNwYXJlbnRcIiApICYmXG5cdFx0XHRcdFx0XHRcdGN1ckVsZW0gJiYgY3VyRWxlbS5zdHlsZVxuXHRcdFx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdFx0YmFja2dyb3VuZENvbG9yID0galF1ZXJ5LmNzcyggY3VyRWxlbSwgXCJiYWNrZ3JvdW5kQ29sb3JcIiApO1xuXHRcdFx0XHRcdFx0XHRcdGN1ckVsZW0gPSBjdXJFbGVtLnBhcmVudE5vZGU7XG5cdFx0XHRcdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdHZhbHVlID0gdmFsdWUuYmxlbmQoIGJhY2tncm91bmRDb2xvciAmJiBiYWNrZ3JvdW5kQ29sb3IgIT09IFwidHJhbnNwYXJlbnRcIiA/XG5cdFx0XHRcdFx0XHRcdGJhY2tncm91bmRDb2xvciA6XG5cdFx0XHRcdFx0XHRcdFwiX2RlZmF1bHRcIiApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHZhbHVlID0gdmFsdWUudG9SZ2JhU3RyaW5nKCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRlbGVtLnN0eWxlWyBob29rIF0gPSB2YWx1ZTtcblx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0XHQvLyBXcmFwcGVkIHRvIHByZXZlbnQgSUUgZnJvbSB0aHJvd2luZyBlcnJvcnMgb24gXCJpbnZhbGlkXCIgdmFsdWVzIGxpa2Vcblx0XHRcdFx0XHQvLyAnYXV0bycgb3IgJ2luaGVyaXQnXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHRcdGpRdWVyeS5meC5zdGVwWyBob29rIF0gPSBmdW5jdGlvbiggZnggKSB7XG5cdFx0XHRpZiAoICFmeC5jb2xvckluaXQgKSB7XG5cdFx0XHRcdGZ4LnN0YXJ0ID0gY29sb3IoIGZ4LmVsZW0sIGhvb2sgKTtcblx0XHRcdFx0ZnguZW5kID0gY29sb3IoIGZ4LmVuZCApO1xuXHRcdFx0XHRmeC5jb2xvckluaXQgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0alF1ZXJ5LmNzc0hvb2tzWyBob29rIF0uc2V0KCBmeC5lbGVtLCBmeC5zdGFydC50cmFuc2l0aW9uKCBmeC5lbmQsIGZ4LnBvcyApICk7XG5cdFx0fTtcblx0fSApO1xuXG59O1xuXG5jb2xvci5ob29rKCBzdGVwSG9va3MgKTtcblxualF1ZXJ5LmNzc0hvb2tzLmJvcmRlckNvbG9yID0ge1xuXHRleHBhbmQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgZXhwYW5kZWQgPSB7fTtcblxuXHRcdGVhY2goIFsgXCJUb3BcIiwgXCJSaWdodFwiLCBcIkJvdHRvbVwiLCBcIkxlZnRcIiBdLCBmdW5jdGlvbiggaSwgcGFydCApIHtcblx0XHRcdGV4cGFuZGVkWyBcImJvcmRlclwiICsgcGFydCArIFwiQ29sb3JcIiBdID0gdmFsdWU7XG5cdFx0fSApO1xuXHRcdHJldHVybiBleHBhbmRlZDtcblx0fVxufTtcblxuLy8gQmFzaWMgY29sb3IgbmFtZXMgb25seS5cbi8vIFVzYWdlIG9mIGFueSBvZiB0aGUgb3RoZXIgY29sb3IgbmFtZXMgcmVxdWlyZXMgYWRkaW5nIHlvdXJzZWxmIG9yIGluY2x1ZGluZ1xuLy8ganF1ZXJ5LmNvbG9yLnN2Zy1uYW1lcy5qcy5cbmNvbG9ycyA9IGpRdWVyeS5Db2xvci5uYW1lcyA9IHtcblxuXHQvLyA0LjEuIEJhc2ljIGNvbG9yIGtleXdvcmRzXG5cdGFxdWE6IFwiIzAwZmZmZlwiLFxuXHRibGFjazogXCIjMDAwMDAwXCIsXG5cdGJsdWU6IFwiIzAwMDBmZlwiLFxuXHRmdWNoc2lhOiBcIiNmZjAwZmZcIixcblx0Z3JheTogXCIjODA4MDgwXCIsXG5cdGdyZWVuOiBcIiMwMDgwMDBcIixcblx0bGltZTogXCIjMDBmZjAwXCIsXG5cdG1hcm9vbjogXCIjODAwMDAwXCIsXG5cdG5hdnk6IFwiIzAwMDA4MFwiLFxuXHRvbGl2ZTogXCIjODA4MDAwXCIsXG5cdHB1cnBsZTogXCIjODAwMDgwXCIsXG5cdHJlZDogXCIjZmYwMDAwXCIsXG5cdHNpbHZlcjogXCIjYzBjMGMwXCIsXG5cdHRlYWw6IFwiIzAwODA4MFwiLFxuXHR3aGl0ZTogXCIjZmZmZmZmXCIsXG5cdHllbGxvdzogXCIjZmZmZjAwXCIsXG5cblx0Ly8gNC4yLjMuIFwidHJhbnNwYXJlbnRcIiBjb2xvciBrZXl3b3JkXG5cdHRyYW5zcGFyZW50OiBbIG51bGwsIG51bGwsIG51bGwsIDAgXSxcblxuXHRfZGVmYXVsdDogXCIjZmZmZmZmXCJcbn07XG5cbn0gKSggalF1ZXJ5ICk7XG5cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIENMQVNTIEFOSU1BVElPTlMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbiggZnVuY3Rpb24oKSB7XG5cbnZhciBjbGFzc0FuaW1hdGlvbkFjdGlvbnMgPSBbIFwiYWRkXCIsIFwicmVtb3ZlXCIsIFwidG9nZ2xlXCIgXSxcblx0c2hvcnRoYW5kU3R5bGVzID0ge1xuXHRcdGJvcmRlcjogMSxcblx0XHRib3JkZXJCb3R0b206IDEsXG5cdFx0Ym9yZGVyQ29sb3I6IDEsXG5cdFx0Ym9yZGVyTGVmdDogMSxcblx0XHRib3JkZXJSaWdodDogMSxcblx0XHRib3JkZXJUb3A6IDEsXG5cdFx0Ym9yZGVyV2lkdGg6IDEsXG5cdFx0bWFyZ2luOiAxLFxuXHRcdHBhZGRpbmc6IDFcblx0fTtcblxuJC5lYWNoKFxuXHRbIFwiYm9yZGVyTGVmdFN0eWxlXCIsIFwiYm9yZGVyUmlnaHRTdHlsZVwiLCBcImJvcmRlckJvdHRvbVN0eWxlXCIsIFwiYm9yZGVyVG9wU3R5bGVcIiBdLFxuXHRmdW5jdGlvbiggXywgcHJvcCApIHtcblx0XHQkLmZ4LnN0ZXBbIHByb3AgXSA9IGZ1bmN0aW9uKCBmeCApIHtcblx0XHRcdGlmICggZnguZW5kICE9PSBcIm5vbmVcIiAmJiAhZnguc2V0QXR0ciB8fCBmeC5wb3MgPT09IDEgJiYgIWZ4LnNldEF0dHIgKSB7XG5cdFx0XHRcdGpRdWVyeS5zdHlsZSggZnguZWxlbSwgcHJvcCwgZnguZW5kICk7XG5cdFx0XHRcdGZ4LnNldEF0dHIgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH07XG5cdH1cbik7XG5cbmZ1bmN0aW9uIGdldEVsZW1lbnRTdHlsZXMoIGVsZW0gKSB7XG5cdHZhciBrZXksIGxlbixcblx0XHRzdHlsZSA9IGVsZW0ub3duZXJEb2N1bWVudC5kZWZhdWx0VmlldyA/XG5cdFx0XHRlbGVtLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZSggZWxlbSwgbnVsbCApIDpcblx0XHRcdGVsZW0uY3VycmVudFN0eWxlLFxuXHRcdHN0eWxlcyA9IHt9O1xuXG5cdGlmICggc3R5bGUgJiYgc3R5bGUubGVuZ3RoICYmIHN0eWxlWyAwIF0gJiYgc3R5bGVbIHN0eWxlWyAwIF0gXSApIHtcblx0XHRsZW4gPSBzdHlsZS5sZW5ndGg7XG5cdFx0d2hpbGUgKCBsZW4tLSApIHtcblx0XHRcdGtleSA9IHN0eWxlWyBsZW4gXTtcblx0XHRcdGlmICggdHlwZW9mIHN0eWxlWyBrZXkgXSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0c3R5bGVzWyAkLmNhbWVsQ2FzZSgga2V5ICkgXSA9IHN0eWxlWyBrZXkgXTtcblx0XHRcdH1cblx0XHR9XG5cblx0Ly8gU3VwcG9ydDogT3BlcmEsIElFIDw5XG5cdH0gZWxzZSB7XG5cdFx0Zm9yICgga2V5IGluIHN0eWxlICkge1xuXHRcdFx0aWYgKCB0eXBlb2Ygc3R5bGVbIGtleSBdID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRzdHlsZXNbIGtleSBdID0gc3R5bGVbIGtleSBdO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBzdHlsZXM7XG59XG5cbmZ1bmN0aW9uIHN0eWxlRGlmZmVyZW5jZSggb2xkU3R5bGUsIG5ld1N0eWxlICkge1xuXHR2YXIgZGlmZiA9IHt9LFxuXHRcdG5hbWUsIHZhbHVlO1xuXG5cdGZvciAoIG5hbWUgaW4gbmV3U3R5bGUgKSB7XG5cdFx0dmFsdWUgPSBuZXdTdHlsZVsgbmFtZSBdO1xuXHRcdGlmICggb2xkU3R5bGVbIG5hbWUgXSAhPT0gdmFsdWUgKSB7XG5cdFx0XHRpZiAoICFzaG9ydGhhbmRTdHlsZXNbIG5hbWUgXSApIHtcblx0XHRcdFx0aWYgKCAkLmZ4LnN0ZXBbIG5hbWUgXSB8fCAhaXNOYU4oIHBhcnNlRmxvYXQoIHZhbHVlICkgKSApIHtcblx0XHRcdFx0XHRkaWZmWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdHJldHVybiBkaWZmO1xufVxuXG4vLyBTdXBwb3J0OiBqUXVlcnkgPDEuOFxuaWYgKCAhJC5mbi5hZGRCYWNrICkge1xuXHQkLmZuLmFkZEJhY2sgPSBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHRoaXMuYWRkKCBzZWxlY3RvciA9PSBudWxsID9cblx0XHRcdHRoaXMucHJldk9iamVjdCA6IHRoaXMucHJldk9iamVjdC5maWx0ZXIoIHNlbGVjdG9yIClcblx0XHQpO1xuXHR9O1xufVxuXG4kLmVmZmVjdHMuYW5pbWF0ZUNsYXNzID0gZnVuY3Rpb24oIHZhbHVlLCBkdXJhdGlvbiwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0dmFyIG8gPSAkLnNwZWVkKCBkdXJhdGlvbiwgZWFzaW5nLCBjYWxsYmFjayApO1xuXG5cdHJldHVybiB0aGlzLnF1ZXVlKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgYW5pbWF0ZWQgPSAkKCB0aGlzICksXG5cdFx0XHRiYXNlQ2xhc3MgPSBhbmltYXRlZC5hdHRyKCBcImNsYXNzXCIgKSB8fCBcIlwiLFxuXHRcdFx0YXBwbHlDbGFzc0NoYW5nZSxcblx0XHRcdGFsbEFuaW1hdGlvbnMgPSBvLmNoaWxkcmVuID8gYW5pbWF0ZWQuZmluZCggXCIqXCIgKS5hZGRCYWNrKCkgOiBhbmltYXRlZDtcblxuXHRcdC8vIE1hcCB0aGUgYW5pbWF0ZWQgb2JqZWN0cyB0byBzdG9yZSB0aGUgb3JpZ2luYWwgc3R5bGVzLlxuXHRcdGFsbEFuaW1hdGlvbnMgPSBhbGxBbmltYXRpb25zLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZWwgPSAkKCB0aGlzICk7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRlbDogZWwsXG5cdFx0XHRcdHN0YXJ0OiBnZXRFbGVtZW50U3R5bGVzKCB0aGlzIClcblx0XHRcdH07XG5cdFx0fSApO1xuXG5cdFx0Ly8gQXBwbHkgY2xhc3MgY2hhbmdlXG5cdFx0YXBwbHlDbGFzc0NoYW5nZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0JC5lYWNoKCBjbGFzc0FuaW1hdGlvbkFjdGlvbnMsIGZ1bmN0aW9uKCBpLCBhY3Rpb24gKSB7XG5cdFx0XHRcdGlmICggdmFsdWVbIGFjdGlvbiBdICkge1xuXHRcdFx0XHRcdGFuaW1hdGVkWyBhY3Rpb24gKyBcIkNsYXNzXCIgXSggdmFsdWVbIGFjdGlvbiBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9O1xuXHRcdGFwcGx5Q2xhc3NDaGFuZ2UoKTtcblxuXHRcdC8vIE1hcCBhbGwgYW5pbWF0ZWQgb2JqZWN0cyBhZ2FpbiAtIGNhbGN1bGF0ZSBuZXcgc3R5bGVzIGFuZCBkaWZmXG5cdFx0YWxsQW5pbWF0aW9ucyA9IGFsbEFuaW1hdGlvbnMubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuZW5kID0gZ2V0RWxlbWVudFN0eWxlcyggdGhpcy5lbFsgMCBdICk7XG5cdFx0XHR0aGlzLmRpZmYgPSBzdHlsZURpZmZlcmVuY2UoIHRoaXMuc3RhcnQsIHRoaXMuZW5kICk7XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9ICk7XG5cblx0XHQvLyBBcHBseSBvcmlnaW5hbCBjbGFzc1xuXHRcdGFuaW1hdGVkLmF0dHIoIFwiY2xhc3NcIiwgYmFzZUNsYXNzICk7XG5cblx0XHQvLyBNYXAgYWxsIGFuaW1hdGVkIG9iamVjdHMgYWdhaW4gLSB0aGlzIHRpbWUgY29sbGVjdGluZyBhIHByb21pc2Vcblx0XHRhbGxBbmltYXRpb25zID0gYWxsQW5pbWF0aW9ucy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHN0eWxlSW5mbyA9IHRoaXMsXG5cdFx0XHRcdGRmZCA9ICQuRGVmZXJyZWQoKSxcblx0XHRcdFx0b3B0cyA9ICQuZXh0ZW5kKCB7fSwgbywge1xuXHRcdFx0XHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRcdFx0XHRjb21wbGV0ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRkZmQucmVzb2x2ZSggc3R5bGVJbmZvICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuZWwuYW5pbWF0ZSggdGhpcy5kaWZmLCBvcHRzICk7XG5cdFx0XHRyZXR1cm4gZGZkLnByb21pc2UoKTtcblx0XHR9ICk7XG5cblx0XHQvLyBPbmNlIGFsbCBhbmltYXRpb25zIGhhdmUgY29tcGxldGVkOlxuXHRcdCQud2hlbi5hcHBseSggJCwgYWxsQW5pbWF0aW9ucy5nZXQoKSApLmRvbmUoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBTZXQgdGhlIGZpbmFsIGNsYXNzXG5cdFx0XHRhcHBseUNsYXNzQ2hhbmdlKCk7XG5cblx0XHRcdC8vIEZvciBlYWNoIGFuaW1hdGVkIGVsZW1lbnQsXG5cdFx0XHQvLyBjbGVhciBhbGwgY3NzIHByb3BlcnRpZXMgdGhhdCB3ZXJlIGFuaW1hdGVkXG5cdFx0XHQkLmVhY2goIGFyZ3VtZW50cywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbCA9IHRoaXMuZWw7XG5cdFx0XHRcdCQuZWFjaCggdGhpcy5kaWZmLCBmdW5jdGlvbigga2V5ICkge1xuXHRcdFx0XHRcdGVsLmNzcygga2V5LCBcIlwiICk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0Ly8gVGhpcyBpcyBndWFybnRlZWQgdG8gYmUgdGhlcmUgaWYgeW91IHVzZSBqUXVlcnkuc3BlZWQoKVxuXHRcdFx0Ly8gaXQgYWxzbyBoYW5kbGVzIGRlcXVldWluZyB0aGUgbmV4dCBhbmltLi4uXG5cdFx0XHRvLmNvbXBsZXRlLmNhbGwoIGFuaW1hdGVkWyAwIF0gKTtcblx0XHR9ICk7XG5cdH0gKTtcbn07XG5cbiQuZm4uZXh0ZW5kKCB7XG5cdGFkZENsYXNzOiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggY2xhc3NOYW1lcywgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0XHRyZXR1cm4gc3BlZWQgP1xuXHRcdFx0XHQkLmVmZmVjdHMuYW5pbWF0ZUNsYXNzLmNhbGwoIHRoaXMsXG5cdFx0XHRcdFx0eyBhZGQ6IGNsYXNzTmFtZXMgfSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSA6XG5cdFx0XHRcdG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH07XG5cdH0gKSggJC5mbi5hZGRDbGFzcyApLFxuXG5cdHJlbW92ZUNsYXNzOiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggY2xhc3NOYW1lcywgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0XHRyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA+IDEgP1xuXHRcdFx0XHQkLmVmZmVjdHMuYW5pbWF0ZUNsYXNzLmNhbGwoIHRoaXMsXG5cdFx0XHRcdFx0eyByZW1vdmU6IGNsYXNzTmFtZXMgfSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSA6XG5cdFx0XHRcdG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH07XG5cdH0gKSggJC5mbi5yZW1vdmVDbGFzcyApLFxuXG5cdHRvZ2dsZUNsYXNzOiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggY2xhc3NOYW1lcywgZm9yY2UsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgZm9yY2UgPT09IFwiYm9vbGVhblwiIHx8IGZvcmNlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGlmICggIXNwZWVkICkge1xuXG5cdFx0XHRcdFx0Ly8gV2l0aG91dCBzcGVlZCBwYXJhbWV0ZXJcblx0XHRcdFx0XHRyZXR1cm4gb3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuICQuZWZmZWN0cy5hbmltYXRlQ2xhc3MuY2FsbCggdGhpcyxcblx0XHRcdFx0XHRcdCggZm9yY2UgPyB7IGFkZDogY2xhc3NOYW1lcyB9IDogeyByZW1vdmU6IGNsYXNzTmFtZXMgfSApLFxuXHRcdFx0XHRcdFx0c3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBXaXRob3V0IGZvcmNlIHBhcmFtZXRlclxuXHRcdFx0XHRyZXR1cm4gJC5lZmZlY3RzLmFuaW1hdGVDbGFzcy5jYWxsKCB0aGlzLFxuXHRcdFx0XHRcdHsgdG9nZ2xlOiBjbGFzc05hbWVzIH0sIGZvcmNlLCBzcGVlZCwgZWFzaW5nICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSApKCAkLmZuLnRvZ2dsZUNsYXNzICksXG5cblx0c3dpdGNoQ2xhc3M6IGZ1bmN0aW9uKCByZW1vdmUsIGFkZCwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuICQuZWZmZWN0cy5hbmltYXRlQ2xhc3MuY2FsbCggdGhpcywge1xuXHRcdFx0YWRkOiBhZGQsXG5cdFx0XHRyZW1vdmU6IHJlbW92ZVxuXHRcdH0sIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH1cbn0gKTtcblxufSApKCk7XG5cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogRUZGRUNUUyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuKCBmdW5jdGlvbigpIHtcblxuaWYgKCAkLmV4cHIgJiYgJC5leHByLmZpbHRlcnMgJiYgJC5leHByLmZpbHRlcnMuYW5pbWF0ZWQgKSB7XG5cdCQuZXhwci5maWx0ZXJzLmFuaW1hdGVkID0gKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gISEkKCBlbGVtICkuZGF0YSggZGF0YVNwYWNlQW5pbWF0ZWQgKSB8fCBvcmlnKCBlbGVtICk7XG5cdFx0fTtcblx0fSApKCAkLmV4cHIuZmlsdGVycy5hbmltYXRlZCApO1xufVxuXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblx0JC5leHRlbmQoICQuZWZmZWN0cywge1xuXG5cdFx0Ly8gU2F2ZXMgYSBzZXQgb2YgcHJvcGVydGllcyBpbiBhIGRhdGEgc3RvcmFnZVxuXHRcdHNhdmU6IGZ1bmN0aW9uKCBlbGVtZW50LCBzZXQgKSB7XG5cdFx0XHR2YXIgaSA9IDAsIGxlbmd0aCA9IHNldC5sZW5ndGg7XG5cdFx0XHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBzZXRbIGkgXSAhPT0gbnVsbCApIHtcblx0XHRcdFx0XHRlbGVtZW50LmRhdGEoIGRhdGFTcGFjZSArIHNldFsgaSBdLCBlbGVtZW50WyAwIF0uc3R5bGVbIHNldFsgaSBdIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHQvLyBSZXN0b3JlcyBhIHNldCBvZiBwcmV2aW91c2x5IHNhdmVkIHByb3BlcnRpZXMgZnJvbSBhIGRhdGEgc3RvcmFnZVxuXHRcdHJlc3RvcmU6IGZ1bmN0aW9uKCBlbGVtZW50LCBzZXQgKSB7XG5cdFx0XHR2YXIgdmFsLCBpID0gMCwgbGVuZ3RoID0gc2V0Lmxlbmd0aDtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRpZiAoIHNldFsgaSBdICE9PSBudWxsICkge1xuXHRcdFx0XHRcdHZhbCA9IGVsZW1lbnQuZGF0YSggZGF0YVNwYWNlICsgc2V0WyBpIF0gKTtcblx0XHRcdFx0XHRlbGVtZW50LmNzcyggc2V0WyBpIF0sIHZhbCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdHNldE1vZGU6IGZ1bmN0aW9uKCBlbCwgbW9kZSApIHtcblx0XHRcdGlmICggbW9kZSA9PT0gXCJ0b2dnbGVcIiApIHtcblx0XHRcdFx0bW9kZSA9IGVsLmlzKCBcIjpoaWRkZW5cIiApID8gXCJzaG93XCIgOiBcImhpZGVcIjtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtb2RlO1xuXHRcdH0sXG5cblx0XHQvLyBXcmFwcyB0aGUgZWxlbWVudCBhcm91bmQgYSB3cmFwcGVyIHRoYXQgY29waWVzIHBvc2l0aW9uIHByb3BlcnRpZXNcblx0XHRjcmVhdGVXcmFwcGVyOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblxuXHRcdFx0Ly8gSWYgdGhlIGVsZW1lbnQgaXMgYWxyZWFkeSB3cmFwcGVkLCByZXR1cm4gaXRcblx0XHRcdGlmICggZWxlbWVudC5wYXJlbnQoKS5pcyggXCIudWktZWZmZWN0cy13cmFwcGVyXCIgKSApIHtcblx0XHRcdFx0cmV0dXJuIGVsZW1lbnQucGFyZW50KCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFdyYXAgdGhlIGVsZW1lbnRcblx0XHRcdHZhciBwcm9wcyA9IHtcblx0XHRcdFx0XHR3aWR0aDogZWxlbWVudC5vdXRlcldpZHRoKCB0cnVlICksXG5cdFx0XHRcdFx0aGVpZ2h0OiBlbGVtZW50Lm91dGVySGVpZ2h0KCB0cnVlICksXG5cdFx0XHRcdFx0XCJmbG9hdFwiOiBlbGVtZW50LmNzcyggXCJmbG9hdFwiIClcblx0XHRcdFx0fSxcblx0XHRcdFx0d3JhcHBlciA9ICQoIFwiPGRpdj48L2Rpdj5cIiApXG5cdFx0XHRcdFx0LmFkZENsYXNzKCBcInVpLWVmZmVjdHMtd3JhcHBlclwiIClcblx0XHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0XHRmb250U2l6ZTogXCIxMDAlXCIsXG5cdFx0XHRcdFx0XHRiYWNrZ3JvdW5kOiBcInRyYW5zcGFyZW50XCIsXG5cdFx0XHRcdFx0XHRib3JkZXI6IFwibm9uZVwiLFxuXHRcdFx0XHRcdFx0bWFyZ2luOiAwLFxuXHRcdFx0XHRcdFx0cGFkZGluZzogMFxuXHRcdFx0XHRcdH0gKSxcblxuXHRcdFx0XHQvLyBTdG9yZSB0aGUgc2l6ZSBpbiBjYXNlIHdpZHRoL2hlaWdodCBhcmUgZGVmaW5lZCBpbiAlIC0gRml4ZXMgIzUyNDVcblx0XHRcdFx0c2l6ZSA9IHtcblx0XHRcdFx0XHR3aWR0aDogZWxlbWVudC53aWR0aCgpLFxuXHRcdFx0XHRcdGhlaWdodDogZWxlbWVudC5oZWlnaHQoKVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRhY3RpdmUgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBGaXJlZm94XG5cdFx0XHQvLyBGaXJlZm94IGluY29ycmVjdGx5IGV4cG9zZXMgYW5vbnltb3VzIGNvbnRlbnRcblx0XHRcdC8vIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTU2MTY2NFxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YWN0aXZlLmlkO1xuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cdFx0XHRcdGFjdGl2ZSA9IGRvY3VtZW50LmJvZHk7XG5cdFx0XHR9XG5cblx0XHRcdGVsZW1lbnQud3JhcCggd3JhcHBlciApO1xuXG5cdFx0XHQvLyBGaXhlcyAjNzU5NSAtIEVsZW1lbnRzIGxvc2UgZm9jdXMgd2hlbiB3cmFwcGVkLlxuXHRcdFx0aWYgKCBlbGVtZW50WyAwIF0gPT09IGFjdGl2ZSB8fCAkLmNvbnRhaW5zKCBlbGVtZW50WyAwIF0sIGFjdGl2ZSApICkge1xuXHRcdFx0XHQkKCBhY3RpdmUgKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSG90Zml4IGZvciBqUXVlcnkgMS40IHNpbmNlIHNvbWUgY2hhbmdlIGluIHdyYXAoKSBzZWVtcyB0byBhY3R1YWxseVxuXHRcdFx0Ly8gbG9zZSB0aGUgcmVmZXJlbmNlIHRvIHRoZSB3cmFwcGVkIGVsZW1lbnRcblx0XHRcdHdyYXBwZXIgPSBlbGVtZW50LnBhcmVudCgpO1xuXG5cdFx0XHQvLyBUcmFuc2ZlciBwb3NpdGlvbmluZyBwcm9wZXJ0aWVzIHRvIHRoZSB3cmFwcGVyXG5cdFx0XHRpZiAoIGVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdFx0d3JhcHBlci5jc3MoIHsgcG9zaXRpb246IFwicmVsYXRpdmVcIiB9ICk7XG5cdFx0XHRcdGVsZW1lbnQuY3NzKCB7IHBvc2l0aW9uOiBcInJlbGF0aXZlXCIgfSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0JC5leHRlbmQoIHByb3BzLCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IGVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdFx0XHR6SW5kZXg6IGVsZW1lbnQuY3NzKCBcInotaW5kZXhcIiApXG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0JC5lYWNoKCBbIFwidG9wXCIsIFwibGVmdFwiLCBcImJvdHRvbVwiLCBcInJpZ2h0XCIgXSwgZnVuY3Rpb24oIGksIHBvcyApIHtcblx0XHRcdFx0XHRwcm9wc1sgcG9zIF0gPSBlbGVtZW50LmNzcyggcG9zICk7XG5cdFx0XHRcdFx0aWYgKCBpc05hTiggcGFyc2VJbnQoIHByb3BzWyBwb3MgXSwgMTAgKSApICkge1xuXHRcdFx0XHRcdFx0cHJvcHNbIHBvcyBdID0gXCJhdXRvXCI7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdGVsZW1lbnQuY3NzKCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IFwicmVsYXRpdmVcIixcblx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0bGVmdDogMCxcblx0XHRcdFx0XHRyaWdodDogXCJhdXRvXCIsXG5cdFx0XHRcdFx0Ym90dG9tOiBcImF1dG9cIlxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRlbGVtZW50LmNzcyggc2l6ZSApO1xuXG5cdFx0XHRyZXR1cm4gd3JhcHBlci5jc3MoIHByb3BzICkuc2hvdygpO1xuXHRcdH0sXG5cblx0XHRyZW1vdmVXcmFwcGVyOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRcdHZhciBhY3RpdmUgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXG5cdFx0XHRpZiAoIGVsZW1lbnQucGFyZW50KCkuaXMoIFwiLnVpLWVmZmVjdHMtd3JhcHBlclwiICkgKSB7XG5cdFx0XHRcdGVsZW1lbnQucGFyZW50KCkucmVwbGFjZVdpdGgoIGVsZW1lbnQgKTtcblxuXHRcdFx0XHQvLyBGaXhlcyAjNzU5NSAtIEVsZW1lbnRzIGxvc2UgZm9jdXMgd2hlbiB3cmFwcGVkLlxuXHRcdFx0XHRpZiAoIGVsZW1lbnRbIDAgXSA9PT0gYWN0aXZlIHx8ICQuY29udGFpbnMoIGVsZW1lbnRbIDAgXSwgYWN0aXZlICkgKSB7XG5cdFx0XHRcdFx0JCggYWN0aXZlICkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGVsZW1lbnQ7XG5cdFx0fVxuXHR9ICk7XG59XG5cbiQuZXh0ZW5kKCAkLmVmZmVjdHMsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblxuXHRkZWZpbmU6IGZ1bmN0aW9uKCBuYW1lLCBtb2RlLCBlZmZlY3QgKSB7XG5cdFx0aWYgKCAhZWZmZWN0ICkge1xuXHRcdFx0ZWZmZWN0ID0gbW9kZTtcblx0XHRcdG1vZGUgPSBcImVmZmVjdFwiO1xuXHRcdH1cblxuXHRcdCQuZWZmZWN0cy5lZmZlY3RbIG5hbWUgXSA9IGVmZmVjdDtcblx0XHQkLmVmZmVjdHMuZWZmZWN0WyBuYW1lIF0ubW9kZSA9IG1vZGU7XG5cblx0XHRyZXR1cm4gZWZmZWN0O1xuXHR9LFxuXG5cdHNjYWxlZERpbWVuc2lvbnM6IGZ1bmN0aW9uKCBlbGVtZW50LCBwZXJjZW50LCBkaXJlY3Rpb24gKSB7XG5cdFx0aWYgKCBwZXJjZW50ID09PSAwICkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0aGVpZ2h0OiAwLFxuXHRcdFx0XHR3aWR0aDogMCxcblx0XHRcdFx0b3V0ZXJIZWlnaHQ6IDAsXG5cdFx0XHRcdG91dGVyV2lkdGg6IDBcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0dmFyIHggPSBkaXJlY3Rpb24gIT09IFwiaG9yaXpvbnRhbFwiID8gKCAoIHBlcmNlbnQgfHwgMTAwICkgLyAxMDAgKSA6IDEsXG5cdFx0XHR5ID0gZGlyZWN0aW9uICE9PSBcInZlcnRpY2FsXCIgPyAoICggcGVyY2VudCB8fCAxMDAgKSAvIDEwMCApIDogMTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHRoZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0KCkgKiB5LFxuXHRcdFx0d2lkdGg6IGVsZW1lbnQud2lkdGgoKSAqIHgsXG5cdFx0XHRvdXRlckhlaWdodDogZWxlbWVudC5vdXRlckhlaWdodCgpICogeSxcblx0XHRcdG91dGVyV2lkdGg6IGVsZW1lbnQub3V0ZXJXaWR0aCgpICogeFxuXHRcdH07XG5cblx0fSxcblxuXHRjbGlwVG9Cb3g6IGZ1bmN0aW9uKCBhbmltYXRpb24gKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiBhbmltYXRpb24uY2xpcC5yaWdodCAtIGFuaW1hdGlvbi5jbGlwLmxlZnQsXG5cdFx0XHRoZWlnaHQ6IGFuaW1hdGlvbi5jbGlwLmJvdHRvbSAtIGFuaW1hdGlvbi5jbGlwLnRvcCxcblx0XHRcdGxlZnQ6IGFuaW1hdGlvbi5jbGlwLmxlZnQsXG5cdFx0XHR0b3A6IGFuaW1hdGlvbi5jbGlwLnRvcFxuXHRcdH07XG5cdH0sXG5cblx0Ly8gSW5qZWN0cyByZWNlbnRseSBxdWV1ZWQgZnVuY3Rpb25zIHRvIGJlIGZpcnN0IGluIGxpbmUgKGFmdGVyIFwiaW5wcm9ncmVzc1wiKVxuXHR1bnNoaWZ0OiBmdW5jdGlvbiggZWxlbWVudCwgcXVldWVMZW5ndGgsIGNvdW50ICkge1xuXHRcdHZhciBxdWV1ZSA9IGVsZW1lbnQucXVldWUoKTtcblxuXHRcdGlmICggcXVldWVMZW5ndGggPiAxICkge1xuXHRcdFx0cXVldWUuc3BsaWNlLmFwcGx5KCBxdWV1ZSxcblx0XHRcdFx0WyAxLCAwIF0uY29uY2F0KCBxdWV1ZS5zcGxpY2UoIHF1ZXVlTGVuZ3RoLCBjb3VudCApICkgKTtcblx0XHR9XG5cdFx0ZWxlbWVudC5kZXF1ZXVlKCk7XG5cdH0sXG5cblx0c2F2ZVN0eWxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRlbGVtZW50LmRhdGEoIGRhdGFTcGFjZVN0eWxlLCBlbGVtZW50WyAwIF0uc3R5bGUuY3NzVGV4dCApO1xuXHR9LFxuXG5cdHJlc3RvcmVTdHlsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0ZWxlbWVudFsgMCBdLnN0eWxlLmNzc1RleHQgPSBlbGVtZW50LmRhdGEoIGRhdGFTcGFjZVN0eWxlICkgfHwgXCJcIjtcblx0XHRlbGVtZW50LnJlbW92ZURhdGEoIGRhdGFTcGFjZVN0eWxlICk7XG5cdH0sXG5cblx0bW9kZTogZnVuY3Rpb24oIGVsZW1lbnQsIG1vZGUgKSB7XG5cdFx0dmFyIGhpZGRlbiA9IGVsZW1lbnQuaXMoIFwiOmhpZGRlblwiICk7XG5cblx0XHRpZiAoIG1vZGUgPT09IFwidG9nZ2xlXCIgKSB7XG5cdFx0XHRtb2RlID0gaGlkZGVuID8gXCJzaG93XCIgOiBcImhpZGVcIjtcblx0XHR9XG5cdFx0aWYgKCBoaWRkZW4gPyBtb2RlID09PSBcImhpZGVcIiA6IG1vZGUgPT09IFwic2hvd1wiICkge1xuXHRcdFx0bW9kZSA9IFwibm9uZVwiO1xuXHRcdH1cblx0XHRyZXR1cm4gbW9kZTtcblx0fSxcblxuXHQvLyBUcmFuc2xhdGVzIGEgW3RvcCxsZWZ0XSBhcnJheSBpbnRvIGEgYmFzZWxpbmUgdmFsdWVcblx0Z2V0QmFzZWxpbmU6IGZ1bmN0aW9uKCBvcmlnaW4sIG9yaWdpbmFsICkge1xuXHRcdHZhciB5LCB4O1xuXG5cdFx0c3dpdGNoICggb3JpZ2luWyAwIF0gKSB7XG5cdFx0Y2FzZSBcInRvcFwiOlxuXHRcdFx0eSA9IDA7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIFwibWlkZGxlXCI6XG5cdFx0XHR5ID0gMC41O1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBcImJvdHRvbVwiOlxuXHRcdFx0eSA9IDE7XG5cdFx0XHRicmVhaztcblx0XHRkZWZhdWx0OlxuXHRcdFx0eSA9IG9yaWdpblsgMCBdIC8gb3JpZ2luYWwuaGVpZ2h0O1xuXHRcdH1cblxuXHRcdHN3aXRjaCAoIG9yaWdpblsgMSBdICkge1xuXHRcdGNhc2UgXCJsZWZ0XCI6XG5cdFx0XHR4ID0gMDtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgXCJjZW50ZXJcIjpcblx0XHRcdHggPSAwLjU7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIFwicmlnaHRcIjpcblx0XHRcdHggPSAxO1xuXHRcdFx0YnJlYWs7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHggPSBvcmlnaW5bIDEgXSAvIG9yaWdpbmFsLndpZHRoO1xuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR4OiB4LFxuXHRcdFx0eTogeVxuXHRcdH07XG5cdH0sXG5cblx0Ly8gQ3JlYXRlcyBhIHBsYWNlaG9sZGVyIGVsZW1lbnQgc28gdGhhdCB0aGUgb3JpZ2luYWwgZWxlbWVudCBjYW4gYmUgbWFkZSBhYnNvbHV0ZVxuXHRjcmVhdGVQbGFjZWhvbGRlcjogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIHBsYWNlaG9sZGVyLFxuXHRcdFx0Y3NzUG9zaXRpb24gPSBlbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRwb3NpdGlvbiA9IGVsZW1lbnQucG9zaXRpb24oKTtcblxuXHRcdC8vIExvY2sgaW4gbWFyZ2lucyBmaXJzdCB0byBhY2NvdW50IGZvciBmb3JtIGVsZW1lbnRzLCB3aGljaFxuXHRcdC8vIHdpbGwgY2hhbmdlIG1hcmdpbiBpZiB5b3UgZXhwbGljaXRseSBzZXQgaGVpZ2h0XG5cdFx0Ly8gc2VlOiBodHRwOi8vanNmaWRkbGUubmV0L0paU010LzMvIGh0dHBzOi8vYnVncy53ZWJraXQub3JnL3Nob3dfYnVnLmNnaT9pZD0xMDczODBcblx0XHQvLyBTdXBwb3J0OiBTYWZhcmlcblx0XHRlbGVtZW50LmNzcygge1xuXHRcdFx0bWFyZ2luVG9wOiBlbGVtZW50LmNzcyggXCJtYXJnaW5Ub3BcIiApLFxuXHRcdFx0bWFyZ2luQm90dG9tOiBlbGVtZW50LmNzcyggXCJtYXJnaW5Cb3R0b21cIiApLFxuXHRcdFx0bWFyZ2luTGVmdDogZWxlbWVudC5jc3MoIFwibWFyZ2luTGVmdFwiICksXG5cdFx0XHRtYXJnaW5SaWdodDogZWxlbWVudC5jc3MoIFwibWFyZ2luUmlnaHRcIiApXG5cdFx0fSApXG5cdFx0Lm91dGVyV2lkdGgoIGVsZW1lbnQub3V0ZXJXaWR0aCgpIClcblx0XHQub3V0ZXJIZWlnaHQoIGVsZW1lbnQub3V0ZXJIZWlnaHQoKSApO1xuXG5cdFx0aWYgKCAvXihzdGF0aWN8cmVsYXRpdmUpLy50ZXN0KCBjc3NQb3NpdGlvbiApICkge1xuXHRcdFx0Y3NzUG9zaXRpb24gPSBcImFic29sdXRlXCI7XG5cblx0XHRcdHBsYWNlaG9sZGVyID0gJCggXCI8XCIgKyBlbGVtZW50WyAwIF0ubm9kZU5hbWUgKyBcIj5cIiApLmluc2VydEFmdGVyKCBlbGVtZW50ICkuY3NzKCB7XG5cblx0XHRcdFx0Ly8gQ29udmVydCBpbmxpbmUgdG8gaW5saW5lIGJsb2NrIHRvIGFjY291bnQgZm9yIGlubGluZSBlbGVtZW50c1xuXHRcdFx0XHQvLyB0aGF0IHR1cm4gdG8gaW5saW5lIGJsb2NrIGJhc2VkIG9uIGNvbnRlbnQgKGxpa2UgaW1nKVxuXHRcdFx0XHRkaXNwbGF5OiAvXihpbmxpbmV8cnVieSkvLnRlc3QoIGVsZW1lbnQuY3NzKCBcImRpc3BsYXlcIiApICkgP1xuXHRcdFx0XHRcdFwiaW5saW5lLWJsb2NrXCIgOlxuXHRcdFx0XHRcdFwiYmxvY2tcIixcblx0XHRcdFx0dmlzaWJpbGl0eTogXCJoaWRkZW5cIixcblxuXHRcdFx0XHQvLyBNYXJnaW5zIG5lZWQgdG8gYmUgc2V0IHRvIGFjY291bnQgZm9yIG1hcmdpbiBjb2xsYXBzZVxuXHRcdFx0XHRtYXJnaW5Ub3A6IGVsZW1lbnQuY3NzKCBcIm1hcmdpblRvcFwiICksXG5cdFx0XHRcdG1hcmdpbkJvdHRvbTogZWxlbWVudC5jc3MoIFwibWFyZ2luQm90dG9tXCIgKSxcblx0XHRcdFx0bWFyZ2luTGVmdDogZWxlbWVudC5jc3MoIFwibWFyZ2luTGVmdFwiICksXG5cdFx0XHRcdG1hcmdpblJpZ2h0OiBlbGVtZW50LmNzcyggXCJtYXJnaW5SaWdodFwiICksXG5cdFx0XHRcdFwiZmxvYXRcIjogZWxlbWVudC5jc3MoIFwiZmxvYXRcIiApXG5cdFx0XHR9IClcblx0XHRcdC5vdXRlcldpZHRoKCBlbGVtZW50Lm91dGVyV2lkdGgoKSApXG5cdFx0XHQub3V0ZXJIZWlnaHQoIGVsZW1lbnQub3V0ZXJIZWlnaHQoKSApXG5cdFx0XHQuYWRkQ2xhc3MoIFwidWktZWZmZWN0cy1wbGFjZWhvbGRlclwiICk7XG5cblx0XHRcdGVsZW1lbnQuZGF0YSggZGF0YVNwYWNlICsgXCJwbGFjZWhvbGRlclwiLCBwbGFjZWhvbGRlciApO1xuXHRcdH1cblxuXHRcdGVsZW1lbnQuY3NzKCB7XG5cdFx0XHRwb3NpdGlvbjogY3NzUG9zaXRpb24sXG5cdFx0XHRsZWZ0OiBwb3NpdGlvbi5sZWZ0LFxuXHRcdFx0dG9wOiBwb3NpdGlvbi50b3Bcblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gcGxhY2Vob2xkZXI7XG5cdH0sXG5cblx0cmVtb3ZlUGxhY2Vob2xkZXI6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciBkYXRhS2V5ID0gZGF0YVNwYWNlICsgXCJwbGFjZWhvbGRlclwiLFxuXHRcdFx0XHRwbGFjZWhvbGRlciA9IGVsZW1lbnQuZGF0YSggZGF0YUtleSApO1xuXG5cdFx0aWYgKCBwbGFjZWhvbGRlciApIHtcblx0XHRcdHBsYWNlaG9sZGVyLnJlbW92ZSgpO1xuXHRcdFx0ZWxlbWVudC5yZW1vdmVEYXRhKCBkYXRhS2V5ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIFJlbW92ZXMgYSBwbGFjZWhvbGRlciBpZiBpdCBleGlzdHMgYW5kIHJlc3RvcmVzXG5cdC8vIHByb3BlcnRpZXMgdGhhdCB3ZXJlIG1vZGlmaWVkIGR1cmluZyBwbGFjZWhvbGRlciBjcmVhdGlvblxuXHRjbGVhblVwOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHQkLmVmZmVjdHMucmVzdG9yZVN0eWxlKCBlbGVtZW50ICk7XG5cdFx0JC5lZmZlY3RzLnJlbW92ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cdH0sXG5cblx0c2V0VHJhbnNpdGlvbjogZnVuY3Rpb24oIGVsZW1lbnQsIGxpc3QsIGZhY3RvciwgdmFsdWUgKSB7XG5cdFx0dmFsdWUgPSB2YWx1ZSB8fCB7fTtcblx0XHQkLmVhY2goIGxpc3QsIGZ1bmN0aW9uKCBpLCB4ICkge1xuXHRcdFx0dmFyIHVuaXQgPSBlbGVtZW50LmNzc1VuaXQoIHggKTtcblx0XHRcdGlmICggdW5pdFsgMCBdID4gMCApIHtcblx0XHRcdFx0dmFsdWVbIHggXSA9IHVuaXRbIDAgXSAqIGZhY3RvciArIHVuaXRbIDEgXTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG59ICk7XG5cbi8vIFJldHVybiBhbiBlZmZlY3Qgb3B0aW9ucyBvYmplY3QgZm9yIHRoZSBnaXZlbiBwYXJhbWV0ZXJzOlxuZnVuY3Rpb24gX25vcm1hbGl6ZUFyZ3VtZW50cyggZWZmZWN0LCBvcHRpb25zLCBzcGVlZCwgY2FsbGJhY2sgKSB7XG5cblx0Ly8gQWxsb3cgcGFzc2luZyBhbGwgb3B0aW9ucyBhcyB0aGUgZmlyc3QgcGFyYW1ldGVyXG5cdGlmICggJC5pc1BsYWluT2JqZWN0KCBlZmZlY3QgKSApIHtcblx0XHRvcHRpb25zID0gZWZmZWN0O1xuXHRcdGVmZmVjdCA9IGVmZmVjdC5lZmZlY3Q7XG5cdH1cblxuXHQvLyBDb252ZXJ0IHRvIGFuIG9iamVjdFxuXHRlZmZlY3QgPSB7IGVmZmVjdDogZWZmZWN0IH07XG5cblx0Ly8gQ2F0Y2ggKGVmZmVjdCwgbnVsbCwgLi4uKVxuXHRpZiAoIG9wdGlvbnMgPT0gbnVsbCApIHtcblx0XHRvcHRpb25zID0ge307XG5cdH1cblxuXHQvLyBDYXRjaCAoZWZmZWN0LCBjYWxsYmFjaylcblx0aWYgKCAkLmlzRnVuY3Rpb24oIG9wdGlvbnMgKSApIHtcblx0XHRjYWxsYmFjayA9IG9wdGlvbnM7XG5cdFx0c3BlZWQgPSBudWxsO1xuXHRcdG9wdGlvbnMgPSB7fTtcblx0fVxuXG5cdC8vIENhdGNoIChlZmZlY3QsIHNwZWVkLCA/KVxuXHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcIm51bWJlclwiIHx8ICQuZnguc3BlZWRzWyBvcHRpb25zIF0gKSB7XG5cdFx0Y2FsbGJhY2sgPSBzcGVlZDtcblx0XHRzcGVlZCA9IG9wdGlvbnM7XG5cdFx0b3B0aW9ucyA9IHt9O1xuXHR9XG5cblx0Ly8gQ2F0Y2ggKGVmZmVjdCwgb3B0aW9ucywgY2FsbGJhY2spXG5cdGlmICggJC5pc0Z1bmN0aW9uKCBzcGVlZCApICkge1xuXHRcdGNhbGxiYWNrID0gc3BlZWQ7XG5cdFx0c3BlZWQgPSBudWxsO1xuXHR9XG5cblx0Ly8gQWRkIG9wdGlvbnMgdG8gZWZmZWN0XG5cdGlmICggb3B0aW9ucyApIHtcblx0XHQkLmV4dGVuZCggZWZmZWN0LCBvcHRpb25zICk7XG5cdH1cblxuXHRzcGVlZCA9IHNwZWVkIHx8IG9wdGlvbnMuZHVyYXRpb247XG5cdGVmZmVjdC5kdXJhdGlvbiA9ICQuZngub2ZmID8gMCA6XG5cdFx0dHlwZW9mIHNwZWVkID09PSBcIm51bWJlclwiID8gc3BlZWQgOlxuXHRcdHNwZWVkIGluICQuZnguc3BlZWRzID8gJC5meC5zcGVlZHNbIHNwZWVkIF0gOlxuXHRcdCQuZnguc3BlZWRzLl9kZWZhdWx0O1xuXG5cdGVmZmVjdC5jb21wbGV0ZSA9IGNhbGxiYWNrIHx8IG9wdGlvbnMuY29tcGxldGU7XG5cblx0cmV0dXJuIGVmZmVjdDtcbn1cblxuZnVuY3Rpb24gc3RhbmRhcmRBbmltYXRpb25PcHRpb24oIG9wdGlvbiApIHtcblxuXHQvLyBWYWxpZCBzdGFuZGFyZCBzcGVlZHMgKG5vdGhpbmcsIG51bWJlciwgbmFtZWQgc3BlZWQpXG5cdGlmICggIW9wdGlvbiB8fCB0eXBlb2Ygb3B0aW9uID09PSBcIm51bWJlclwiIHx8ICQuZnguc3BlZWRzWyBvcHRpb24gXSApIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdC8vIEludmFsaWQgc3RyaW5ncyAtIHRyZWF0IGFzIFwibm9ybWFsXCIgc3BlZWRcblx0aWYgKCB0eXBlb2Ygb3B0aW9uID09PSBcInN0cmluZ1wiICYmICEkLmVmZmVjdHMuZWZmZWN0WyBvcHRpb24gXSApIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdC8vIENvbXBsZXRlIGNhbGxiYWNrXG5cdGlmICggJC5pc0Z1bmN0aW9uKCBvcHRpb24gKSApIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdC8vIE9wdGlvbnMgaGFzaCAoYnV0IG5vdCBuYW1pbmcgYW4gZWZmZWN0KVxuXHRpZiAoIHR5cGVvZiBvcHRpb24gPT09IFwib2JqZWN0XCIgJiYgIW9wdGlvbi5lZmZlY3QgKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHQvLyBEaWRuJ3QgbWF0Y2ggYW55IHN0YW5kYXJkIEFQSVxuXHRyZXR1cm4gZmFsc2U7XG59XG5cbiQuZm4uZXh0ZW5kKCB7XG5cdGVmZmVjdDogZnVuY3Rpb24oIC8qIGVmZmVjdCwgb3B0aW9ucywgc3BlZWQsIGNhbGxiYWNrICovICkge1xuXHRcdHZhciBhcmdzID0gX25vcm1hbGl6ZUFyZ3VtZW50cy5hcHBseSggdGhpcywgYXJndW1lbnRzICksXG5cdFx0XHRlZmZlY3RNZXRob2QgPSAkLmVmZmVjdHMuZWZmZWN0WyBhcmdzLmVmZmVjdCBdLFxuXHRcdFx0ZGVmYXVsdE1vZGUgPSBlZmZlY3RNZXRob2QubW9kZSxcblx0XHRcdHF1ZXVlID0gYXJncy5xdWV1ZSxcblx0XHRcdHF1ZXVlTmFtZSA9IHF1ZXVlIHx8IFwiZnhcIixcblx0XHRcdGNvbXBsZXRlID0gYXJncy5jb21wbGV0ZSxcblx0XHRcdG1vZGUgPSBhcmdzLm1vZGUsXG5cdFx0XHRtb2RlcyA9IFtdLFxuXHRcdFx0cHJlZmlsdGVyID0gZnVuY3Rpb24oIG5leHQgKSB7XG5cdFx0XHRcdHZhciBlbCA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRub3JtYWxpemVkTW9kZSA9ICQuZWZmZWN0cy5tb2RlKCBlbCwgbW9kZSApIHx8IGRlZmF1bHRNb2RlO1xuXG5cdFx0XHRcdC8vIFNlbnRpbmVsIGZvciBkdWNrLXB1bmNoaW5nIHRoZSA6YW5pbWF0ZWQgcHN1ZWRvLXNlbGVjdG9yXG5cdFx0XHRcdGVsLmRhdGEoIGRhdGFTcGFjZUFuaW1hdGVkLCB0cnVlICk7XG5cblx0XHRcdFx0Ly8gU2F2ZSBlZmZlY3QgbW9kZSBmb3IgbGF0ZXIgdXNlLFxuXHRcdFx0XHQvLyB3ZSBjYW4ndCBqdXN0IGNhbGwgJC5lZmZlY3RzLm1vZGUgYWdhaW4gbGF0ZXIsXG5cdFx0XHRcdC8vIGFzIHRoZSAuc2hvdygpIGJlbG93IGRlc3Ryb3lzIHRoZSBpbml0aWFsIHN0YXRlXG5cdFx0XHRcdG1vZGVzLnB1c2goIG5vcm1hbGl6ZWRNb2RlICk7XG5cblx0XHRcdFx0Ly8gU2VlICQudWlCYWNrQ29tcGF0IGluc2lkZSBvZiBydW4oKSBmb3IgcmVtb3ZhbCBvZiBkZWZhdWx0TW9kZSBpbiAxLjEzXG5cdFx0XHRcdGlmICggZGVmYXVsdE1vZGUgJiYgKCBub3JtYWxpemVkTW9kZSA9PT0gXCJzaG93XCIgfHxcblx0XHRcdFx0XHRcdCggbm9ybWFsaXplZE1vZGUgPT09IGRlZmF1bHRNb2RlICYmIG5vcm1hbGl6ZWRNb2RlID09PSBcImhpZGVcIiApICkgKSB7XG5cdFx0XHRcdFx0ZWwuc2hvdygpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAhZGVmYXVsdE1vZGUgfHwgbm9ybWFsaXplZE1vZGUgIT09IFwibm9uZVwiICkge1xuXHRcdFx0XHRcdCQuZWZmZWN0cy5zYXZlU3R5bGUoIGVsICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoICQuaXNGdW5jdGlvbiggbmV4dCApICkge1xuXHRcdFx0XHRcdG5leHQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fTtcblxuXHRcdGlmICggJC5meC5vZmYgfHwgIWVmZmVjdE1ldGhvZCApIHtcblxuXHRcdFx0Ly8gRGVsZWdhdGUgdG8gdGhlIG9yaWdpbmFsIG1ldGhvZCAoZS5nLiwgLnNob3coKSkgaWYgcG9zc2libGVcblx0XHRcdGlmICggbW9kZSApIHtcblx0XHRcdFx0cmV0dXJuIHRoaXNbIG1vZGUgXSggYXJncy5kdXJhdGlvbiwgY29tcGxldGUgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggY29tcGxldGUgKSB7XG5cdFx0XHRcdFx0XHRjb21wbGV0ZS5jYWxsKCB0aGlzICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcnVuKCBuZXh0ICkge1xuXHRcdFx0dmFyIGVsZW0gPSAkKCB0aGlzICk7XG5cblx0XHRcdGZ1bmN0aW9uIGNsZWFudXAoKSB7XG5cdFx0XHRcdGVsZW0ucmVtb3ZlRGF0YSggZGF0YVNwYWNlQW5pbWF0ZWQgKTtcblxuXHRcdFx0XHQkLmVmZmVjdHMuY2xlYW5VcCggZWxlbSApO1xuXG5cdFx0XHRcdGlmICggYXJncy5tb2RlID09PSBcImhpZGVcIiApIHtcblx0XHRcdFx0XHRlbGVtLmhpZGUoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRvbmUoKTtcblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gZG9uZSgpIHtcblx0XHRcdFx0aWYgKCAkLmlzRnVuY3Rpb24oIGNvbXBsZXRlICkgKSB7XG5cdFx0XHRcdFx0Y29tcGxldGUuY2FsbCggZWxlbVsgMCBdICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoICQuaXNGdW5jdGlvbiggbmV4dCApICkge1xuXHRcdFx0XHRcdG5leHQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdmVycmlkZSBtb2RlIG9wdGlvbiBvbiBhIHBlciBlbGVtZW50IGJhc2lzLFxuXHRcdFx0Ly8gYXMgdG9nZ2xlIGNhbiBiZSBlaXRoZXIgc2hvdyBvciBoaWRlIGRlcGVuZGluZyBvbiBlbGVtZW50IHN0YXRlXG5cdFx0XHRhcmdzLm1vZGUgPSBtb2Rlcy5zaGlmdCgpO1xuXG5cdFx0XHRpZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSAmJiAhZGVmYXVsdE1vZGUgKSB7XG5cdFx0XHRcdGlmICggZWxlbS5pcyggXCI6aGlkZGVuXCIgKSA/IG1vZGUgPT09IFwiaGlkZVwiIDogbW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cblx0XHRcdFx0XHQvLyBDYWxsIHRoZSBjb3JlIG1ldGhvZCB0byB0cmFjayBcIm9sZGRpc3BsYXlcIiBwcm9wZXJseVxuXHRcdFx0XHRcdGVsZW1bIG1vZGUgXSgpO1xuXHRcdFx0XHRcdGRvbmUoKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRlZmZlY3RNZXRob2QuY2FsbCggZWxlbVsgMCBdLCBhcmdzLCBkb25lICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGlmICggYXJncy5tb2RlID09PSBcIm5vbmVcIiApIHtcblxuXHRcdFx0XHRcdC8vIENhbGwgdGhlIGNvcmUgbWV0aG9kIHRvIHRyYWNrIFwib2xkZGlzcGxheVwiIHByb3Blcmx5XG5cdFx0XHRcdFx0ZWxlbVsgbW9kZSBdKCk7XG5cdFx0XHRcdFx0ZG9uZSgpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGVmZmVjdE1ldGhvZC5jYWxsKCBlbGVtWyAwIF0sIGFyZ3MsIGNsZWFudXAgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFJ1biBwcmVmaWx0ZXIgb24gYWxsIGVsZW1lbnRzIGZpcnN0IHRvIGVuc3VyZSB0aGF0XG5cdFx0Ly8gYW55IHNob3dpbmcgb3IgaGlkaW5nIGhhcHBlbnMgYmVmb3JlIHBsYWNlaG9sZGVyIGNyZWF0aW9uLFxuXHRcdC8vIHdoaWNoIGVuc3VyZXMgdGhhdCBhbnkgbGF5b3V0IGNoYW5nZXMgYXJlIGNvcnJlY3RseSBjYXB0dXJlZC5cblx0XHRyZXR1cm4gcXVldWUgPT09IGZhbHNlID9cblx0XHRcdHRoaXMuZWFjaCggcHJlZmlsdGVyICkuZWFjaCggcnVuICkgOlxuXHRcdFx0dGhpcy5xdWV1ZSggcXVldWVOYW1lLCBwcmVmaWx0ZXIgKS5xdWV1ZSggcXVldWVOYW1lLCBydW4gKTtcblx0fSxcblxuXHRzaG93OiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggb3B0aW9uICkge1xuXHRcdFx0aWYgKCBzdGFuZGFyZEFuaW1hdGlvbk9wdGlvbiggb3B0aW9uICkgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHZhciBhcmdzID0gX25vcm1hbGl6ZUFyZ3VtZW50cy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdGFyZ3MubW9kZSA9IFwic2hvd1wiO1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5lZmZlY3QuY2FsbCggdGhpcywgYXJncyApO1xuXHRcdFx0fVxuXHRcdH07XG5cdH0gKSggJC5mbi5zaG93ICksXG5cblx0aGlkZTogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIG9wdGlvbiApIHtcblx0XHRcdGlmICggc3RhbmRhcmRBbmltYXRpb25PcHRpb24oIG9wdGlvbiApICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR2YXIgYXJncyA9IF9ub3JtYWxpemVBcmd1bWVudHMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRhcmdzLm1vZGUgPSBcImhpZGVcIjtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZWZmZWN0LmNhbGwoIHRoaXMsIGFyZ3MgKTtcblx0XHRcdH1cblx0XHR9O1xuXHR9ICkoICQuZm4uaGlkZSApLFxuXG5cdHRvZ2dsZTogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIG9wdGlvbiApIHtcblx0XHRcdGlmICggc3RhbmRhcmRBbmltYXRpb25PcHRpb24oIG9wdGlvbiApIHx8IHR5cGVvZiBvcHRpb24gPT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR2YXIgYXJncyA9IF9ub3JtYWxpemVBcmd1bWVudHMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRhcmdzLm1vZGUgPSBcInRvZ2dsZVwiO1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5lZmZlY3QuY2FsbCggdGhpcywgYXJncyApO1xuXHRcdFx0fVxuXHRcdH07XG5cdH0gKSggJC5mbi50b2dnbGUgKSxcblxuXHRjc3NVbml0OiBmdW5jdGlvbigga2V5ICkge1xuXHRcdHZhciBzdHlsZSA9IHRoaXMuY3NzKCBrZXkgKSxcblx0XHRcdHZhbCA9IFtdO1xuXG5cdFx0JC5lYWNoKCBbIFwiZW1cIiwgXCJweFwiLCBcIiVcIiwgXCJwdFwiIF0sIGZ1bmN0aW9uKCBpLCB1bml0ICkge1xuXHRcdFx0aWYgKCBzdHlsZS5pbmRleE9mKCB1bml0ICkgPiAwICkge1xuXHRcdFx0XHR2YWwgPSBbIHBhcnNlRmxvYXQoIHN0eWxlICksIHVuaXQgXTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0cmV0dXJuIHZhbDtcblx0fSxcblxuXHRjc3NDbGlwOiBmdW5jdGlvbiggY2xpcE9iaiApIHtcblx0XHRpZiAoIGNsaXBPYmogKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jc3MoIFwiY2xpcFwiLCBcInJlY3QoXCIgKyBjbGlwT2JqLnRvcCArIFwicHggXCIgKyBjbGlwT2JqLnJpZ2h0ICsgXCJweCBcIiArXG5cdFx0XHRcdGNsaXBPYmouYm90dG9tICsgXCJweCBcIiArIGNsaXBPYmoubGVmdCArIFwicHgpXCIgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHBhcnNlQ2xpcCggdGhpcy5jc3MoIFwiY2xpcFwiICksIHRoaXMgKTtcblx0fSxcblxuXHR0cmFuc2ZlcjogZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0XHR0YXJnZXQgPSAkKCBvcHRpb25zLnRvICksXG5cdFx0XHR0YXJnZXRGaXhlZCA9IHRhcmdldC5jc3MoIFwicG9zaXRpb25cIiApID09PSBcImZpeGVkXCIsXG5cdFx0XHRib2R5ID0gJCggXCJib2R5XCIgKSxcblx0XHRcdGZpeFRvcCA9IHRhcmdldEZpeGVkID8gYm9keS5zY3JvbGxUb3AoKSA6IDAsXG5cdFx0XHRmaXhMZWZ0ID0gdGFyZ2V0Rml4ZWQgPyBib2R5LnNjcm9sbExlZnQoKSA6IDAsXG5cdFx0XHRlbmRQb3NpdGlvbiA9IHRhcmdldC5vZmZzZXQoKSxcblx0XHRcdGFuaW1hdGlvbiA9IHtcblx0XHRcdFx0dG9wOiBlbmRQb3NpdGlvbi50b3AgLSBmaXhUb3AsXG5cdFx0XHRcdGxlZnQ6IGVuZFBvc2l0aW9uLmxlZnQgLSBmaXhMZWZ0LFxuXHRcdFx0XHRoZWlnaHQ6IHRhcmdldC5pbm5lckhlaWdodCgpLFxuXHRcdFx0XHR3aWR0aDogdGFyZ2V0LmlubmVyV2lkdGgoKVxuXHRcdFx0fSxcblx0XHRcdHN0YXJ0UG9zaXRpb24gPSBlbGVtZW50Lm9mZnNldCgpLFxuXHRcdFx0dHJhbnNmZXIgPSAkKCBcIjxkaXYgY2xhc3M9J3VpLWVmZmVjdHMtdHJhbnNmZXInPjwvZGl2PlwiIClcblx0XHRcdFx0LmFwcGVuZFRvKCBcImJvZHlcIiApXG5cdFx0XHRcdC5hZGRDbGFzcyggb3B0aW9ucy5jbGFzc05hbWUgKVxuXHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0dG9wOiBzdGFydFBvc2l0aW9uLnRvcCAtIGZpeFRvcCxcblx0XHRcdFx0XHRsZWZ0OiBzdGFydFBvc2l0aW9uLmxlZnQgLSBmaXhMZWZ0LFxuXHRcdFx0XHRcdGhlaWdodDogZWxlbWVudC5pbm5lckhlaWdodCgpLFxuXHRcdFx0XHRcdHdpZHRoOiBlbGVtZW50LmlubmVyV2lkdGgoKSxcblx0XHRcdFx0XHRwb3NpdGlvbjogdGFyZ2V0Rml4ZWQgPyBcImZpeGVkXCIgOiBcImFic29sdXRlXCJcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5hbmltYXRlKCBhbmltYXRpb24sIG9wdGlvbnMuZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR0cmFuc2Zlci5yZW1vdmUoKTtcblx0XHRcdFx0XHRpZiAoICQuaXNGdW5jdGlvbiggZG9uZSApICkge1xuXHRcdFx0XHRcdFx0ZG9uZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHR9XG59ICk7XG5cbmZ1bmN0aW9uIHBhcnNlQ2xpcCggc3RyLCBlbGVtZW50ICkge1xuXHRcdHZhciBvdXRlcldpZHRoID0gZWxlbWVudC5vdXRlcldpZHRoKCksXG5cdFx0XHRvdXRlckhlaWdodCA9IGVsZW1lbnQub3V0ZXJIZWlnaHQoKSxcblx0XHRcdGNsaXBSZWdleCA9IC9ecmVjdFxcKCgtP1xcZCpcXC4/XFxkKnB4fC0/XFxkKyV8YXV0byksP1xccyooLT9cXGQqXFwuP1xcZCpweHwtP1xcZCslfGF1dG8pLD9cXHMqKC0/XFxkKlxcLj9cXGQqcHh8LT9cXGQrJXxhdXRvKSw/XFxzKigtP1xcZCpcXC4/XFxkKnB4fC0/XFxkKyV8YXV0bylcXCkkLyxcblx0XHRcdHZhbHVlcyA9IGNsaXBSZWdleC5leGVjKCBzdHIgKSB8fCBbIFwiXCIsIDAsIG91dGVyV2lkdGgsIG91dGVySGVpZ2h0LCAwIF07XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiBwYXJzZUZsb2F0KCB2YWx1ZXNbIDEgXSApIHx8IDAsXG5cdFx0XHRyaWdodDogdmFsdWVzWyAyIF0gPT09IFwiYXV0b1wiID8gb3V0ZXJXaWR0aCA6IHBhcnNlRmxvYXQoIHZhbHVlc1sgMiBdICksXG5cdFx0XHRib3R0b206IHZhbHVlc1sgMyBdID09PSBcImF1dG9cIiA/IG91dGVySGVpZ2h0IDogcGFyc2VGbG9hdCggdmFsdWVzWyAzIF0gKSxcblx0XHRcdGxlZnQ6IHBhcnNlRmxvYXQoIHZhbHVlc1sgNCBdICkgfHwgMFxuXHRcdH07XG59XG5cbiQuZnguc3RlcC5jbGlwID0gZnVuY3Rpb24oIGZ4ICkge1xuXHRpZiAoICFmeC5jbGlwSW5pdCApIHtcblx0XHRmeC5zdGFydCA9ICQoIGZ4LmVsZW0gKS5jc3NDbGlwKCk7XG5cdFx0aWYgKCB0eXBlb2YgZnguZW5kID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0ZnguZW5kID0gcGFyc2VDbGlwKCBmeC5lbmQsIGZ4LmVsZW0gKTtcblx0XHR9XG5cdFx0ZnguY2xpcEluaXQgPSB0cnVlO1xuXHR9XG5cblx0JCggZnguZWxlbSApLmNzc0NsaXAoIHtcblx0XHR0b3A6IGZ4LnBvcyAqICggZnguZW5kLnRvcCAtIGZ4LnN0YXJ0LnRvcCApICsgZnguc3RhcnQudG9wLFxuXHRcdHJpZ2h0OiBmeC5wb3MgKiAoIGZ4LmVuZC5yaWdodCAtIGZ4LnN0YXJ0LnJpZ2h0ICkgKyBmeC5zdGFydC5yaWdodCxcblx0XHRib3R0b206IGZ4LnBvcyAqICggZnguZW5kLmJvdHRvbSAtIGZ4LnN0YXJ0LmJvdHRvbSApICsgZnguc3RhcnQuYm90dG9tLFxuXHRcdGxlZnQ6IGZ4LnBvcyAqICggZnguZW5kLmxlZnQgLSBmeC5zdGFydC5sZWZ0ICkgKyBmeC5zdGFydC5sZWZ0XG5cdH0gKTtcbn07XG5cbn0gKSgpO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIEVBU0lORyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiggZnVuY3Rpb24oKSB7XG5cbi8vIEJhc2VkIG9uIGVhc2luZyBlcXVhdGlvbnMgZnJvbSBSb2JlcnQgUGVubmVyIChodHRwOi8vd3d3LnJvYmVydHBlbm5lci5jb20vZWFzaW5nKVxuXG52YXIgYmFzZUVhc2luZ3MgPSB7fTtcblxuJC5lYWNoKCBbIFwiUXVhZFwiLCBcIkN1YmljXCIsIFwiUXVhcnRcIiwgXCJRdWludFwiLCBcIkV4cG9cIiBdLCBmdW5jdGlvbiggaSwgbmFtZSApIHtcblx0YmFzZUVhc2luZ3NbIG5hbWUgXSA9IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBNYXRoLnBvdyggcCwgaSArIDIgKTtcblx0fTtcbn0gKTtcblxuJC5leHRlbmQoIGJhc2VFYXNpbmdzLCB7XG5cdFNpbmU6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiAxIC0gTWF0aC5jb3MoIHAgKiBNYXRoLlBJIC8gMiApO1xuXHR9LFxuXHRDaXJjOiBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gMSAtIE1hdGguc3FydCggMSAtIHAgKiBwICk7XG5cdH0sXG5cdEVsYXN0aWM6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBwID09PSAwIHx8IHAgPT09IDEgPyBwIDpcblx0XHRcdC1NYXRoLnBvdyggMiwgOCAqICggcCAtIDEgKSApICogTWF0aC5zaW4oICggKCBwIC0gMSApICogODAgLSA3LjUgKSAqIE1hdGguUEkgLyAxNSApO1xuXHR9LFxuXHRCYWNrOiBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gcCAqIHAgKiAoIDMgKiBwIC0gMiApO1xuXHR9LFxuXHRCb3VuY2U6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHZhciBwb3cyLFxuXHRcdFx0Ym91bmNlID0gNDtcblxuXHRcdHdoaWxlICggcCA8ICggKCBwb3cyID0gTWF0aC5wb3coIDIsIC0tYm91bmNlICkgKSAtIDEgKSAvIDExICkge31cblx0XHRyZXR1cm4gMSAvIE1hdGgucG93KCA0LCAzIC0gYm91bmNlICkgLSA3LjU2MjUgKiBNYXRoLnBvdyggKCBwb3cyICogMyAtIDIgKSAvIDIyIC0gcCwgMiApO1xuXHR9XG59ICk7XG5cbiQuZWFjaCggYmFzZUVhc2luZ3MsIGZ1bmN0aW9uKCBuYW1lLCBlYXNlSW4gKSB7XG5cdCQuZWFzaW5nWyBcImVhc2VJblwiICsgbmFtZSBdID0gZWFzZUluO1xuXHQkLmVhc2luZ1sgXCJlYXNlT3V0XCIgKyBuYW1lIF0gPSBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gMSAtIGVhc2VJbiggMSAtIHAgKTtcblx0fTtcblx0JC5lYXNpbmdbIFwiZWFzZUluT3V0XCIgKyBuYW1lIF0gPSBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gcCA8IDAuNSA/XG5cdFx0XHRlYXNlSW4oIHAgKiAyICkgLyAyIDpcblx0XHRcdDEgLSBlYXNlSW4oIHAgKiAtMiArIDIgKSAvIDI7XG5cdH07XG59ICk7XG5cbn0gKSgpO1xuXG52YXIgZWZmZWN0ID0gJC5lZmZlY3RzO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgQmxpbmQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEJsaW5kIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEJsaW5kcyB0aGUgZWxlbWVudC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9ibGluZC1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RCbGluZCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiYmxpbmRcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgbWFwID0ge1xuXHRcdFx0dXA6IFsgXCJib3R0b21cIiwgXCJ0b3BcIiBdLFxuXHRcdFx0dmVydGljYWw6IFsgXCJib3R0b21cIiwgXCJ0b3BcIiBdLFxuXHRcdFx0ZG93bjogWyBcInRvcFwiLCBcImJvdHRvbVwiIF0sXG5cdFx0XHRsZWZ0OiBbIFwicmlnaHRcIiwgXCJsZWZ0XCIgXSxcblx0XHRcdGhvcml6b250YWw6IFsgXCJyaWdodFwiLCBcImxlZnRcIiBdLFxuXHRcdFx0cmlnaHQ6IFsgXCJsZWZ0XCIsIFwicmlnaHRcIiBdXG5cdFx0fSxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwidXBcIixcblx0XHRzdGFydCA9IGVsZW1lbnQuY3NzQ2xpcCgpLFxuXHRcdGFuaW1hdGUgPSB7IGNsaXA6ICQuZXh0ZW5kKCB7fSwgc3RhcnQgKSB9LFxuXHRcdHBsYWNlaG9sZGVyID0gJC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0YW5pbWF0ZS5jbGlwWyBtYXBbIGRpcmVjdGlvbiBdWyAwIF0gXSA9IGFuaW1hdGUuY2xpcFsgbWFwWyBkaXJlY3Rpb24gXVsgMSBdIF07XG5cblx0aWYgKCBvcHRpb25zLm1vZGUgPT09IFwic2hvd1wiICkge1xuXHRcdGVsZW1lbnQuY3NzQ2xpcCggYW5pbWF0ZS5jbGlwICk7XG5cdFx0aWYgKCBwbGFjZWhvbGRlciApIHtcblx0XHRcdHBsYWNlaG9sZGVyLmNzcyggJC5lZmZlY3RzLmNsaXBUb0JveCggYW5pbWF0ZSApICk7XG5cdFx0fVxuXG5cdFx0YW5pbWF0ZS5jbGlwID0gc3RhcnQ7XG5cdH1cblxuXHRpZiAoIHBsYWNlaG9sZGVyICkge1xuXHRcdHBsYWNlaG9sZGVyLmFuaW1hdGUoICQuZWZmZWN0cy5jbGlwVG9Cb3goIGFuaW1hdGUgKSwgb3B0aW9ucy5kdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKTtcblx0fVxuXG5cdGVsZW1lbnQuYW5pbWF0ZSggYW5pbWF0ZSwge1xuXHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdGNvbXBsZXRlOiBkb25lXG5cdH0gKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEJvdW5jZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQm91bmNlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEJvdW5jZXMgYW4gZWxlbWVudCBob3Jpem9udGFsbHkgb3IgdmVydGljYWxseSBuIHRpbWVzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2JvdW5jZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RCb3VuY2UgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImJvdW5jZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIHVwQW5pbSwgZG93bkFuaW0sIHJlZlZhbHVlLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cblx0XHQvLyBEZWZhdWx0czpcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdGhpZGUgPSBtb2RlID09PSBcImhpZGVcIixcblx0XHRzaG93ID0gbW9kZSA9PT0gXCJzaG93XCIsXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJ1cFwiLFxuXHRcdGRpc3RhbmNlID0gb3B0aW9ucy5kaXN0YW5jZSxcblx0XHR0aW1lcyA9IG9wdGlvbnMudGltZXMgfHwgNSxcblxuXHRcdC8vIE51bWJlciBvZiBpbnRlcm5hbCBhbmltYXRpb25zXG5cdFx0YW5pbXMgPSB0aW1lcyAqIDIgKyAoIHNob3cgfHwgaGlkZSA/IDEgOiAwICksXG5cdFx0c3BlZWQgPSBvcHRpb25zLmR1cmF0aW9uIC8gYW5pbXMsXG5cdFx0ZWFzaW5nID0gb3B0aW9ucy5lYXNpbmcsXG5cblx0XHQvLyBVdGlsaXR5OlxuXHRcdHJlZiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImRvd25cIiApID8gXCJ0b3BcIiA6IFwibGVmdFwiLFxuXHRcdG1vdGlvbiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImxlZnRcIiApLFxuXHRcdGkgPSAwLFxuXG5cdFx0cXVldWVsZW4gPSBlbGVtZW50LnF1ZXVlKCkubGVuZ3RoO1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdHJlZlZhbHVlID0gZWxlbWVudC5jc3MoIHJlZiApO1xuXG5cdC8vIERlZmF1bHQgZGlzdGFuY2UgZm9yIHRoZSBCSUdHRVNUIGJvdW5jZSBpcyB0aGUgb3V0ZXIgRGlzdGFuY2UgLyAzXG5cdGlmICggIWRpc3RhbmNlICkge1xuXHRcdGRpc3RhbmNlID0gZWxlbWVudFsgcmVmID09PSBcInRvcFwiID8gXCJvdXRlckhlaWdodFwiIDogXCJvdXRlcldpZHRoXCIgXSgpIC8gMztcblx0fVxuXG5cdGlmICggc2hvdyApIHtcblx0XHRkb3duQW5pbSA9IHsgb3BhY2l0eTogMSB9O1xuXHRcdGRvd25BbmltWyByZWYgXSA9IHJlZlZhbHVlO1xuXG5cdFx0Ly8gSWYgd2UgYXJlIHNob3dpbmcsIGZvcmNlIG9wYWNpdHkgMCBhbmQgc2V0IHRoZSBpbml0aWFsIHBvc2l0aW9uXG5cdFx0Ly8gdGhlbiBkbyB0aGUgXCJmaXJzdFwiIGFuaW1hdGlvblxuXHRcdGVsZW1lbnRcblx0XHRcdC5jc3MoIFwib3BhY2l0eVwiLCAwIClcblx0XHRcdC5jc3MoIHJlZiwgbW90aW9uID8gLWRpc3RhbmNlICogMiA6IGRpc3RhbmNlICogMiApXG5cdFx0XHQuYW5pbWF0ZSggZG93bkFuaW0sIHNwZWVkLCBlYXNpbmcgKTtcblx0fVxuXG5cdC8vIFN0YXJ0IGF0IHRoZSBzbWFsbGVzdCBkaXN0YW5jZSBpZiB3ZSBhcmUgaGlkaW5nXG5cdGlmICggaGlkZSApIHtcblx0XHRkaXN0YW5jZSA9IGRpc3RhbmNlIC8gTWF0aC5wb3coIDIsIHRpbWVzIC0gMSApO1xuXHR9XG5cblx0ZG93bkFuaW0gPSB7fTtcblx0ZG93bkFuaW1bIHJlZiBdID0gcmVmVmFsdWU7XG5cblx0Ly8gQm91bmNlcyB1cC9kb3duL2xlZnQvcmlnaHQgdGhlbiBiYWNrIHRvIDAgLS0gdGltZXMgKiAyIGFuaW1hdGlvbnMgaGFwcGVuIGhlcmVcblx0Zm9yICggOyBpIDwgdGltZXM7IGkrKyApIHtcblx0XHR1cEFuaW0gPSB7fTtcblx0XHR1cEFuaW1bIHJlZiBdID0gKCBtb3Rpb24gPyBcIi09XCIgOiBcIis9XCIgKSArIGRpc3RhbmNlO1xuXG5cdFx0ZWxlbWVudFxuXHRcdFx0LmFuaW1hdGUoIHVwQW5pbSwgc3BlZWQsIGVhc2luZyApXG5cdFx0XHQuYW5pbWF0ZSggZG93bkFuaW0sIHNwZWVkLCBlYXNpbmcgKTtcblxuXHRcdGRpc3RhbmNlID0gaGlkZSA/IGRpc3RhbmNlICogMiA6IGRpc3RhbmNlIC8gMjtcblx0fVxuXG5cdC8vIExhc3QgQm91bmNlIHdoZW4gSGlkaW5nXG5cdGlmICggaGlkZSApIHtcblx0XHR1cEFuaW0gPSB7IG9wYWNpdHk6IDAgfTtcblx0XHR1cEFuaW1bIHJlZiBdID0gKCBtb3Rpb24gPyBcIi09XCIgOiBcIis9XCIgKSArIGRpc3RhbmNlO1xuXG5cdFx0ZWxlbWVudC5hbmltYXRlKCB1cEFuaW0sIHNwZWVkLCBlYXNpbmcgKTtcblx0fVxuXG5cdGVsZW1lbnQucXVldWUoIGRvbmUgKTtcblxuXHQkLmVmZmVjdHMudW5zaGlmdCggZWxlbWVudCwgcXVldWVsZW4sIGFuaW1zICsgMSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgQ2xpcCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQ2xpcCBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBDbGlwcyB0aGUgZWxlbWVudCBvbiBhbmQgb2ZmIGxpa2UgYW4gb2xkIFRWLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2NsaXAtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0Q2xpcCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiY2xpcFwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBzdGFydCxcblx0XHRhbmltYXRlID0ge30sXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcInZlcnRpY2FsXCIsXG5cdFx0Ym90aCA9IGRpcmVjdGlvbiA9PT0gXCJib3RoXCIsXG5cdFx0aG9yaXpvbnRhbCA9IGJvdGggfHwgZGlyZWN0aW9uID09PSBcImhvcml6b250YWxcIixcblx0XHR2ZXJ0aWNhbCA9IGJvdGggfHwgZGlyZWN0aW9uID09PSBcInZlcnRpY2FsXCI7XG5cblx0c3RhcnQgPSBlbGVtZW50LmNzc0NsaXAoKTtcblx0YW5pbWF0ZS5jbGlwID0ge1xuXHRcdHRvcDogdmVydGljYWwgPyAoIHN0YXJ0LmJvdHRvbSAtIHN0YXJ0LnRvcCApIC8gMiA6IHN0YXJ0LnRvcCxcblx0XHRyaWdodDogaG9yaXpvbnRhbCA/ICggc3RhcnQucmlnaHQgLSBzdGFydC5sZWZ0ICkgLyAyIDogc3RhcnQucmlnaHQsXG5cdFx0Ym90dG9tOiB2ZXJ0aWNhbCA/ICggc3RhcnQuYm90dG9tIC0gc3RhcnQudG9wICkgLyAyIDogc3RhcnQuYm90dG9tLFxuXHRcdGxlZnQ6IGhvcml6b250YWwgPyAoIHN0YXJ0LnJpZ2h0IC0gc3RhcnQubGVmdCApIC8gMiA6IHN0YXJ0LmxlZnRcblx0fTtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRpZiAoIG9wdGlvbnMubW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cdFx0ZWxlbWVudC5jc3NDbGlwKCBhbmltYXRlLmNsaXAgKTtcblx0XHRhbmltYXRlLmNsaXAgPSBzdGFydDtcblx0fVxuXG5cdGVsZW1lbnQuYW5pbWF0ZSggYW5pbWF0ZSwge1xuXHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdGNvbXBsZXRlOiBkb25lXG5cdH0gKTtcblxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgRHJvcCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRHJvcCBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBNb3ZlcyBhbiBlbGVtZW50IGluIG9uZSBkaXJlY3Rpb24gYW5kIGhpZGVzIGl0IGF0IHRoZSBzYW1lIHRpbWUuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZHJvcC1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3REcm9wID0gJC5lZmZlY3RzLmRlZmluZSggXCJkcm9wXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHR2YXIgZGlzdGFuY2UsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHNob3cgPSBtb2RlID09PSBcInNob3dcIixcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcImxlZnRcIixcblx0XHRyZWYgPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJkb3duXCIgKSA/IFwidG9wXCIgOiBcImxlZnRcIixcblx0XHRtb3Rpb24gPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsZWZ0XCIgKSA/IFwiLT1cIiA6IFwiKz1cIixcblx0XHRvcHBvc2l0ZU1vdGlvbiA9ICggbW90aW9uID09PSBcIis9XCIgKSA/IFwiLT1cIiA6IFwiKz1cIixcblx0XHRhbmltYXRpb24gPSB7XG5cdFx0XHRvcGFjaXR5OiAwXG5cdFx0fTtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRkaXN0YW5jZSA9IG9wdGlvbnMuZGlzdGFuY2UgfHxcblx0XHRlbGVtZW50WyByZWYgPT09IFwidG9wXCIgPyBcIm91dGVySGVpZ2h0XCIgOiBcIm91dGVyV2lkdGhcIiBdKCB0cnVlICkgLyAyO1xuXG5cdGFuaW1hdGlvblsgcmVmIF0gPSBtb3Rpb24gKyBkaXN0YW5jZTtcblxuXHRpZiAoIHNob3cgKSB7XG5cdFx0ZWxlbWVudC5jc3MoIGFuaW1hdGlvbiApO1xuXG5cdFx0YW5pbWF0aW9uWyByZWYgXSA9IG9wcG9zaXRlTW90aW9uICsgZGlzdGFuY2U7XG5cdFx0YW5pbWF0aW9uLm9wYWNpdHkgPSAxO1xuXHR9XG5cblx0Ly8gQW5pbWF0ZVxuXHRlbGVtZW50LmFuaW1hdGUoIGFuaW1hdGlvbiwge1xuXHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdGNvbXBsZXRlOiBkb25lXG5cdH0gKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEV4cGxvZGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEV4cGxvZGUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRlc2NyaXB0aW9uOiBFeHBsb2RlcyBhbiBlbGVtZW50IGluIGFsbCBkaXJlY3Rpb25zIGludG8gbiBwaWVjZXMuIEltcGxvZGVzIGFuIGVsZW1lbnQgdG8gaXRzIG9yaWdpbmFsIHdob2xlbmVzcy5cbi8vIGpzY3M6ZW5hYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZXhwbG9kZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RFeHBsb2RlID0gJC5lZmZlY3RzLmRlZmluZSggXCJleHBsb2RlXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHR2YXIgaSwgaiwgbGVmdCwgdG9wLCBteCwgbXksXG5cdFx0cm93cyA9IG9wdGlvbnMucGllY2VzID8gTWF0aC5yb3VuZCggTWF0aC5zcXJ0KCBvcHRpb25zLnBpZWNlcyApICkgOiAzLFxuXHRcdGNlbGxzID0gcm93cyxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0c2hvdyA9IG1vZGUgPT09IFwic2hvd1wiLFxuXG5cdFx0Ly8gU2hvdyBhbmQgdGhlbiB2aXNpYmlsaXR5OmhpZGRlbiB0aGUgZWxlbWVudCBiZWZvcmUgY2FsY3VsYXRpbmcgb2Zmc2V0XG5cdFx0b2Zmc2V0ID0gZWxlbWVudC5zaG93KCkuY3NzKCBcInZpc2liaWxpdHlcIiwgXCJoaWRkZW5cIiApLm9mZnNldCgpLFxuXG5cdFx0Ly8gV2lkdGggYW5kIGhlaWdodCBvZiBhIHBpZWNlXG5cdFx0d2lkdGggPSBNYXRoLmNlaWwoIGVsZW1lbnQub3V0ZXJXaWR0aCgpIC8gY2VsbHMgKSxcblx0XHRoZWlnaHQgPSBNYXRoLmNlaWwoIGVsZW1lbnQub3V0ZXJIZWlnaHQoKSAvIHJvd3MgKSxcblx0XHRwaWVjZXMgPSBbXTtcblxuXHQvLyBDaGlsZHJlbiBhbmltYXRlIGNvbXBsZXRlOlxuXHRmdW5jdGlvbiBjaGlsZENvbXBsZXRlKCkge1xuXHRcdHBpZWNlcy5wdXNoKCB0aGlzICk7XG5cdFx0aWYgKCBwaWVjZXMubGVuZ3RoID09PSByb3dzICogY2VsbHMgKSB7XG5cdFx0XHRhbmltQ29tcGxldGUoKTtcblx0XHR9XG5cdH1cblxuXHQvLyBDbG9uZSB0aGUgZWxlbWVudCBmb3IgZWFjaCByb3cgYW5kIGNlbGwuXG5cdGZvciAoIGkgPSAwOyBpIDwgcm93czsgaSsrICkgeyAvLyA9PT0+XG5cdFx0dG9wID0gb2Zmc2V0LnRvcCArIGkgKiBoZWlnaHQ7XG5cdFx0bXkgPSBpIC0gKCByb3dzIC0gMSApIC8gMjtcblxuXHRcdGZvciAoIGogPSAwOyBqIDwgY2VsbHM7IGorKyApIHsgLy8gfHx8XG5cdFx0XHRsZWZ0ID0gb2Zmc2V0LmxlZnQgKyBqICogd2lkdGg7XG5cdFx0XHRteCA9IGogLSAoIGNlbGxzIC0gMSApIC8gMjtcblxuXHRcdFx0Ly8gQ3JlYXRlIGEgY2xvbmUgb2YgdGhlIG5vdyBoaWRkZW4gbWFpbiBlbGVtZW50IHRoYXQgd2lsbCBiZSBhYnNvbHV0ZSBwb3NpdGlvbmVkXG5cdFx0XHQvLyB3aXRoaW4gYSB3cmFwcGVyIGRpdiBvZmYgdGhlIC1sZWZ0IGFuZCAtdG9wIGVxdWFsIHRvIHNpemUgb2Ygb3VyIHBpZWNlc1xuXHRcdFx0ZWxlbWVudFxuXHRcdFx0XHQuY2xvbmUoKVxuXHRcdFx0XHQuYXBwZW5kVG8oIFwiYm9keVwiIClcblx0XHRcdFx0LndyYXAoIFwiPGRpdj48L2Rpdj5cIiApXG5cdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLFxuXHRcdFx0XHRcdHZpc2liaWxpdHk6IFwidmlzaWJsZVwiLFxuXHRcdFx0XHRcdGxlZnQ6IC1qICogd2lkdGgsXG5cdFx0XHRcdFx0dG9wOiAtaSAqIGhlaWdodFxuXHRcdFx0XHR9IClcblxuXHRcdFx0XHQvLyBTZWxlY3QgdGhlIHdyYXBwZXIgLSBtYWtlIGl0IG92ZXJmbG93OiBoaWRkZW4gYW5kIGFic29sdXRlIHBvc2l0aW9uZWQgYmFzZWQgb25cblx0XHRcdFx0Ly8gd2hlcmUgdGhlIG9yaWdpbmFsIHdhcyBsb2NhdGVkICtsZWZ0IGFuZCArdG9wIGVxdWFsIHRvIHRoZSBzaXplIG9mIHBpZWNlc1xuXHRcdFx0XHQucGFyZW50KClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoIFwidWktZWZmZWN0cy1leHBsb2RlXCIgKVxuXHRcdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uOiBcImFic29sdXRlXCIsXG5cdFx0XHRcdFx0XHRvdmVyZmxvdzogXCJoaWRkZW5cIixcblx0XHRcdFx0XHRcdHdpZHRoOiB3aWR0aCxcblx0XHRcdFx0XHRcdGhlaWdodDogaGVpZ2h0LFxuXHRcdFx0XHRcdFx0bGVmdDogbGVmdCArICggc2hvdyA/IG14ICogd2lkdGggOiAwICksXG5cdFx0XHRcdFx0XHR0b3A6IHRvcCArICggc2hvdyA/IG15ICogaGVpZ2h0IDogMCApLFxuXHRcdFx0XHRcdFx0b3BhY2l0eTogc2hvdyA/IDAgOiAxXG5cdFx0XHRcdFx0fSApXG5cdFx0XHRcdFx0LmFuaW1hdGUoIHtcblx0XHRcdFx0XHRcdGxlZnQ6IGxlZnQgKyAoIHNob3cgPyAwIDogbXggKiB3aWR0aCApLFxuXHRcdFx0XHRcdFx0dG9wOiB0b3AgKyAoIHNob3cgPyAwIDogbXkgKiBoZWlnaHQgKSxcblx0XHRcdFx0XHRcdG9wYWNpdHk6IHNob3cgPyAxIDogMFxuXHRcdFx0XHRcdH0sIG9wdGlvbnMuZHVyYXRpb24gfHwgNTAwLCBvcHRpb25zLmVhc2luZywgY2hpbGRDb21wbGV0ZSApO1xuXHRcdH1cblx0fVxuXG5cdGZ1bmN0aW9uIGFuaW1Db21wbGV0ZSgpIHtcblx0XHRlbGVtZW50LmNzcygge1xuXHRcdFx0dmlzaWJpbGl0eTogXCJ2aXNpYmxlXCJcblx0XHR9ICk7XG5cdFx0JCggcGllY2VzICkucmVtb3ZlKCk7XG5cdFx0ZG9uZSgpO1xuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBGYWRlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBGYWRlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEZhZGVzIHRoZSBlbGVtZW50LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2ZhZGUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0RmFkZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiZmFkZVwiLCBcInRvZ2dsZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIHNob3cgPSBvcHRpb25zLm1vZGUgPT09IFwic2hvd1wiO1xuXG5cdCQoIHRoaXMgKVxuXHRcdC5jc3MoIFwib3BhY2l0eVwiLCBzaG93ID8gMCA6IDEgKVxuXHRcdC5hbmltYXRlKCB7XG5cdFx0XHRvcGFjaXR5OiBzaG93ID8gMSA6IDBcblx0XHR9LCB7XG5cdFx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0XHRjb21wbGV0ZTogZG9uZVxuXHRcdH0gKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEZvbGQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEZvbGQgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogRm9sZHMgYW4gZWxlbWVudCBmaXJzdCBob3Jpem9udGFsbHkgYW5kIHRoZW4gdmVydGljYWxseS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9mb2xkLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEZvbGQgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImZvbGRcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdC8vIENyZWF0ZSBlbGVtZW50XG5cdHZhciBlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0c2hvdyA9IG1vZGUgPT09IFwic2hvd1wiLFxuXHRcdGhpZGUgPSBtb2RlID09PSBcImhpZGVcIixcblx0XHRzaXplID0gb3B0aW9ucy5zaXplIHx8IDE1LFxuXHRcdHBlcmNlbnQgPSAvKFswLTldKyklLy5leGVjKCBzaXplICksXG5cdFx0aG9yaXpGaXJzdCA9ICEhb3B0aW9ucy5ob3JpekZpcnN0LFxuXHRcdHJlZiA9IGhvcml6Rmlyc3QgPyBbIFwicmlnaHRcIiwgXCJib3R0b21cIiBdIDogWyBcImJvdHRvbVwiLCBcInJpZ2h0XCIgXSxcblx0XHRkdXJhdGlvbiA9IG9wdGlvbnMuZHVyYXRpb24gLyAyLFxuXG5cdFx0cGxhY2Vob2xkZXIgPSAkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKSxcblxuXHRcdHN0YXJ0ID0gZWxlbWVudC5jc3NDbGlwKCksXG5cdFx0YW5pbWF0aW9uMSA9IHsgY2xpcDogJC5leHRlbmQoIHt9LCBzdGFydCApIH0sXG5cdFx0YW5pbWF0aW9uMiA9IHsgY2xpcDogJC5leHRlbmQoIHt9LCBzdGFydCApIH0sXG5cblx0XHRkaXN0YW5jZSA9IFsgc3RhcnRbIHJlZlsgMCBdIF0sIHN0YXJ0WyByZWZbIDEgXSBdIF0sXG5cblx0XHRxdWV1ZWxlbiA9IGVsZW1lbnQucXVldWUoKS5sZW5ndGg7XG5cblx0aWYgKCBwZXJjZW50ICkge1xuXHRcdHNpemUgPSBwYXJzZUludCggcGVyY2VudFsgMSBdLCAxMCApIC8gMTAwICogZGlzdGFuY2VbIGhpZGUgPyAwIDogMSBdO1xuXHR9XG5cdGFuaW1hdGlvbjEuY2xpcFsgcmVmWyAwIF0gXSA9IHNpemU7XG5cdGFuaW1hdGlvbjIuY2xpcFsgcmVmWyAwIF0gXSA9IHNpemU7XG5cdGFuaW1hdGlvbjIuY2xpcFsgcmVmWyAxIF0gXSA9IDA7XG5cblx0aWYgKCBzaG93ICkge1xuXHRcdGVsZW1lbnQuY3NzQ2xpcCggYW5pbWF0aW9uMi5jbGlwICk7XG5cdFx0aWYgKCBwbGFjZWhvbGRlciApIHtcblx0XHRcdHBsYWNlaG9sZGVyLmNzcyggJC5lZmZlY3RzLmNsaXBUb0JveCggYW5pbWF0aW9uMiApICk7XG5cdFx0fVxuXG5cdFx0YW5pbWF0aW9uMi5jbGlwID0gc3RhcnQ7XG5cdH1cblxuXHQvLyBBbmltYXRlXG5cdGVsZW1lbnRcblx0XHQucXVldWUoIGZ1bmN0aW9uKCBuZXh0ICkge1xuXHRcdFx0aWYgKCBwbGFjZWhvbGRlciApIHtcblx0XHRcdFx0cGxhY2Vob2xkZXJcblx0XHRcdFx0XHQuYW5pbWF0ZSggJC5lZmZlY3RzLmNsaXBUb0JveCggYW5pbWF0aW9uMSApLCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdFx0XHRcdC5hbmltYXRlKCAkLmVmZmVjdHMuY2xpcFRvQm94KCBhbmltYXRpb24yICksIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApO1xuXHRcdFx0fVxuXG5cdFx0XHRuZXh0KCk7XG5cdFx0fSApXG5cdFx0LmFuaW1hdGUoIGFuaW1hdGlvbjEsIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApXG5cdFx0LmFuaW1hdGUoIGFuaW1hdGlvbjIsIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApXG5cdFx0LnF1ZXVlKCBkb25lICk7XG5cblx0JC5lZmZlY3RzLnVuc2hpZnQoIGVsZW1lbnQsIHF1ZXVlbGVuLCA0ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBIaWdobGlnaHQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEhpZ2hsaWdodCBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBIaWdobGlnaHRzIHRoZSBiYWNrZ3JvdW5kIG9mIGFuIGVsZW1lbnQgaW4gYSBkZWZpbmVkIGNvbG9yIGZvciBhIGN1c3RvbSBkdXJhdGlvbi5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9oaWdobGlnaHQtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0SGlnaGxpZ2h0ID0gJC5lZmZlY3RzLmRlZmluZSggXCJoaWdobGlnaHRcIiwgXCJzaG93XCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRhbmltYXRpb24gPSB7XG5cdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IGVsZW1lbnQuY3NzKCBcImJhY2tncm91bmRDb2xvclwiIClcblx0XHR9O1xuXG5cdGlmICggb3B0aW9ucy5tb2RlID09PSBcImhpZGVcIiApIHtcblx0XHRhbmltYXRpb24ub3BhY2l0eSA9IDA7XG5cdH1cblxuXHQkLmVmZmVjdHMuc2F2ZVN0eWxlKCBlbGVtZW50ICk7XG5cblx0ZWxlbWVudFxuXHRcdC5jc3MoIHtcblx0XHRcdGJhY2tncm91bmRJbWFnZTogXCJub25lXCIsXG5cdFx0XHRiYWNrZ3JvdW5kQ29sb3I6IG9wdGlvbnMuY29sb3IgfHwgXCIjZmZmZjk5XCJcblx0XHR9IClcblx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uLCB7XG5cdFx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0XHRjb21wbGV0ZTogZG9uZVxuXHRcdH0gKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFNpemUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNpemUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogUmVzaXplIGFuIGVsZW1lbnQgdG8gYSBzcGVjaWZpZWQgd2lkdGggYW5kIGhlaWdodC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zaXplLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFNpemUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInNpemVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0Ly8gQ3JlYXRlIGVsZW1lbnRcblx0dmFyIGJhc2VsaW5lLCBmYWN0b3IsIHRlbXAsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblxuXHRcdC8vIENvcHkgZm9yIGNoaWxkcmVuXG5cdFx0Y1Byb3BzID0gWyBcImZvbnRTaXplXCIgXSxcblx0XHR2UHJvcHMgPSBbIFwiYm9yZGVyVG9wV2lkdGhcIiwgXCJib3JkZXJCb3R0b21XaWR0aFwiLCBcInBhZGRpbmdUb3BcIiwgXCJwYWRkaW5nQm90dG9tXCIgXSxcblx0XHRoUHJvcHMgPSBbIFwiYm9yZGVyTGVmdFdpZHRoXCIsIFwiYm9yZGVyUmlnaHRXaWR0aFwiLCBcInBhZGRpbmdMZWZ0XCIsIFwicGFkZGluZ1JpZ2h0XCIgXSxcblxuXHRcdC8vIFNldCBvcHRpb25zXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRyZXN0b3JlID0gbW9kZSAhPT0gXCJlZmZlY3RcIixcblx0XHRzY2FsZSA9IG9wdGlvbnMuc2NhbGUgfHwgXCJib3RoXCIsXG5cdFx0b3JpZ2luID0gb3B0aW9ucy5vcmlnaW4gfHwgWyBcIm1pZGRsZVwiLCBcImNlbnRlclwiIF0sXG5cdFx0cG9zaXRpb24gPSBlbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0cG9zID0gZWxlbWVudC5wb3NpdGlvbigpLFxuXHRcdG9yaWdpbmFsID0gJC5lZmZlY3RzLnNjYWxlZERpbWVuc2lvbnMoIGVsZW1lbnQgKSxcblx0XHRmcm9tID0gb3B0aW9ucy5mcm9tIHx8IG9yaWdpbmFsLFxuXHRcdHRvID0gb3B0aW9ucy50byB8fCAkLmVmZmVjdHMuc2NhbGVkRGltZW5zaW9ucyggZWxlbWVudCwgMCApO1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdGlmICggbW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cdFx0dGVtcCA9IGZyb207XG5cdFx0ZnJvbSA9IHRvO1xuXHRcdHRvID0gdGVtcDtcblx0fVxuXG5cdC8vIFNldCBzY2FsaW5nIGZhY3RvclxuXHRmYWN0b3IgPSB7XG5cdFx0ZnJvbToge1xuXHRcdFx0eTogZnJvbS5oZWlnaHQgLyBvcmlnaW5hbC5oZWlnaHQsXG5cdFx0XHR4OiBmcm9tLndpZHRoIC8gb3JpZ2luYWwud2lkdGhcblx0XHR9LFxuXHRcdHRvOiB7XG5cdFx0XHR5OiB0by5oZWlnaHQgLyBvcmlnaW5hbC5oZWlnaHQsXG5cdFx0XHR4OiB0by53aWR0aCAvIG9yaWdpbmFsLndpZHRoXG5cdFx0fVxuXHR9O1xuXG5cdC8vIFNjYWxlIHRoZSBjc3MgYm94XG5cdGlmICggc2NhbGUgPT09IFwiYm94XCIgfHwgc2NhbGUgPT09IFwiYm90aFwiICkge1xuXG5cdFx0Ly8gVmVydGljYWwgcHJvcHMgc2NhbGluZ1xuXHRcdGlmICggZmFjdG9yLmZyb20ueSAhPT0gZmFjdG9yLnRvLnkgKSB7XG5cdFx0XHRmcm9tID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIHZQcm9wcywgZmFjdG9yLmZyb20ueSwgZnJvbSApO1xuXHRcdFx0dG8gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgdlByb3BzLCBmYWN0b3IudG8ueSwgdG8gKTtcblx0XHR9XG5cblx0XHQvLyBIb3Jpem9udGFsIHByb3BzIHNjYWxpbmdcblx0XHRpZiAoIGZhY3Rvci5mcm9tLnggIT09IGZhY3Rvci50by54ICkge1xuXHRcdFx0ZnJvbSA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCBoUHJvcHMsIGZhY3Rvci5mcm9tLngsIGZyb20gKTtcblx0XHRcdHRvID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIGhQcm9wcywgZmFjdG9yLnRvLngsIHRvICk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gU2NhbGUgdGhlIGNvbnRlbnRcblx0aWYgKCBzY2FsZSA9PT0gXCJjb250ZW50XCIgfHwgc2NhbGUgPT09IFwiYm90aFwiICkge1xuXG5cdFx0Ly8gVmVydGljYWwgcHJvcHMgc2NhbGluZ1xuXHRcdGlmICggZmFjdG9yLmZyb20ueSAhPT0gZmFjdG9yLnRvLnkgKSB7XG5cdFx0XHRmcm9tID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIGNQcm9wcywgZmFjdG9yLmZyb20ueSwgZnJvbSApO1xuXHRcdFx0dG8gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgY1Byb3BzLCBmYWN0b3IudG8ueSwgdG8gKTtcblx0XHR9XG5cdH1cblxuXHQvLyBBZGp1c3QgdGhlIHBvc2l0aW9uIHByb3BlcnRpZXMgYmFzZWQgb24gdGhlIHByb3ZpZGVkIG9yaWdpbiBwb2ludHNcblx0aWYgKCBvcmlnaW4gKSB7XG5cdFx0YmFzZWxpbmUgPSAkLmVmZmVjdHMuZ2V0QmFzZWxpbmUoIG9yaWdpbiwgb3JpZ2luYWwgKTtcblx0XHRmcm9tLnRvcCA9ICggb3JpZ2luYWwub3V0ZXJIZWlnaHQgLSBmcm9tLm91dGVySGVpZ2h0ICkgKiBiYXNlbGluZS55ICsgcG9zLnRvcDtcblx0XHRmcm9tLmxlZnQgPSAoIG9yaWdpbmFsLm91dGVyV2lkdGggLSBmcm9tLm91dGVyV2lkdGggKSAqIGJhc2VsaW5lLnggKyBwb3MubGVmdDtcblx0XHR0by50b3AgPSAoIG9yaWdpbmFsLm91dGVySGVpZ2h0IC0gdG8ub3V0ZXJIZWlnaHQgKSAqIGJhc2VsaW5lLnkgKyBwb3MudG9wO1xuXHRcdHRvLmxlZnQgPSAoIG9yaWdpbmFsLm91dGVyV2lkdGggLSB0by5vdXRlcldpZHRoICkgKiBiYXNlbGluZS54ICsgcG9zLmxlZnQ7XG5cdH1cblx0ZWxlbWVudC5jc3MoIGZyb20gKTtcblxuXHQvLyBBbmltYXRlIHRoZSBjaGlsZHJlbiBpZiBkZXNpcmVkXG5cdGlmICggc2NhbGUgPT09IFwiY29udGVudFwiIHx8IHNjYWxlID09PSBcImJvdGhcIiApIHtcblxuXHRcdHZQcm9wcyA9IHZQcm9wcy5jb25jYXQoIFsgXCJtYXJnaW5Ub3BcIiwgXCJtYXJnaW5Cb3R0b21cIiBdICkuY29uY2F0KCBjUHJvcHMgKTtcblx0XHRoUHJvcHMgPSBoUHJvcHMuY29uY2F0KCBbIFwibWFyZ2luTGVmdFwiLCBcIm1hcmdpblJpZ2h0XCIgXSApO1xuXG5cdFx0Ly8gT25seSBhbmltYXRlIGNoaWxkcmVuIHdpdGggd2lkdGggYXR0cmlidXRlcyBzcGVjaWZpZWRcblx0XHQvLyBUT0RPOiBpcyB0aGlzIHJpZ2h0PyBzaG91bGQgd2UgaW5jbHVkZSBhbnl0aGluZyB3aXRoIGNzcyB3aWR0aCBzcGVjaWZpZWQgYXMgd2VsbFxuXHRcdGVsZW1lbnQuZmluZCggXCIqW3dpZHRoXVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgY2hpbGQgPSAkKCB0aGlzICksXG5cdFx0XHRcdGNoaWxkT3JpZ2luYWwgPSAkLmVmZmVjdHMuc2NhbGVkRGltZW5zaW9ucyggY2hpbGQgKSxcblx0XHRcdFx0Y2hpbGRGcm9tID0ge1xuXHRcdFx0XHRcdGhlaWdodDogY2hpbGRPcmlnaW5hbC5oZWlnaHQgKiBmYWN0b3IuZnJvbS55LFxuXHRcdFx0XHRcdHdpZHRoOiBjaGlsZE9yaWdpbmFsLndpZHRoICogZmFjdG9yLmZyb20ueCxcblx0XHRcdFx0XHRvdXRlckhlaWdodDogY2hpbGRPcmlnaW5hbC5vdXRlckhlaWdodCAqIGZhY3Rvci5mcm9tLnksXG5cdFx0XHRcdFx0b3V0ZXJXaWR0aDogY2hpbGRPcmlnaW5hbC5vdXRlcldpZHRoICogZmFjdG9yLmZyb20ueFxuXHRcdFx0XHR9LFxuXHRcdFx0XHRjaGlsZFRvID0ge1xuXHRcdFx0XHRcdGhlaWdodDogY2hpbGRPcmlnaW5hbC5oZWlnaHQgKiBmYWN0b3IudG8ueSxcblx0XHRcdFx0XHR3aWR0aDogY2hpbGRPcmlnaW5hbC53aWR0aCAqIGZhY3Rvci50by54LFxuXHRcdFx0XHRcdG91dGVySGVpZ2h0OiBjaGlsZE9yaWdpbmFsLmhlaWdodCAqIGZhY3Rvci50by55LFxuXHRcdFx0XHRcdG91dGVyV2lkdGg6IGNoaWxkT3JpZ2luYWwud2lkdGggKiBmYWN0b3IudG8ueFxuXHRcdFx0XHR9O1xuXG5cdFx0XHQvLyBWZXJ0aWNhbCBwcm9wcyBzY2FsaW5nXG5cdFx0XHRpZiAoIGZhY3Rvci5mcm9tLnkgIT09IGZhY3Rvci50by55ICkge1xuXHRcdFx0XHRjaGlsZEZyb20gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggY2hpbGQsIHZQcm9wcywgZmFjdG9yLmZyb20ueSwgY2hpbGRGcm9tICk7XG5cdFx0XHRcdGNoaWxkVG8gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggY2hpbGQsIHZQcm9wcywgZmFjdG9yLnRvLnksIGNoaWxkVG8gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSG9yaXpvbnRhbCBwcm9wcyBzY2FsaW5nXG5cdFx0XHRpZiAoIGZhY3Rvci5mcm9tLnggIT09IGZhY3Rvci50by54ICkge1xuXHRcdFx0XHRjaGlsZEZyb20gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggY2hpbGQsIGhQcm9wcywgZmFjdG9yLmZyb20ueCwgY2hpbGRGcm9tICk7XG5cdFx0XHRcdGNoaWxkVG8gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggY2hpbGQsIGhQcm9wcywgZmFjdG9yLnRvLngsIGNoaWxkVG8gKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZXN0b3JlICkge1xuXHRcdFx0XHQkLmVmZmVjdHMuc2F2ZVN0eWxlKCBjaGlsZCApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBbmltYXRlIGNoaWxkcmVuXG5cdFx0XHRjaGlsZC5jc3MoIGNoaWxkRnJvbSApO1xuXHRcdFx0Y2hpbGQuYW5pbWF0ZSggY2hpbGRUbywgb3B0aW9ucy5kdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcsIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdC8vIFJlc3RvcmUgY2hpbGRyZW5cblx0XHRcdFx0aWYgKCByZXN0b3JlICkge1xuXHRcdFx0XHRcdCQuZWZmZWN0cy5yZXN0b3JlU3R5bGUoIGNoaWxkICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdH1cblxuXHQvLyBBbmltYXRlXG5cdGVsZW1lbnQuYW5pbWF0ZSggdG8sIHtcblx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRjb21wbGV0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHRcdHZhciBvZmZzZXQgPSBlbGVtZW50Lm9mZnNldCgpO1xuXG5cdFx0XHRpZiAoIHRvLm9wYWNpdHkgPT09IDAgKSB7XG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcIm9wYWNpdHlcIiwgZnJvbS5vcGFjaXR5ICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIXJlc3RvcmUgKSB7XG5cdFx0XHRcdGVsZW1lbnRcblx0XHRcdFx0XHQuY3NzKCBcInBvc2l0aW9uXCIsIHBvc2l0aW9uID09PSBcInN0YXRpY1wiID8gXCJyZWxhdGl2ZVwiIDogcG9zaXRpb24gKVxuXHRcdFx0XHRcdC5vZmZzZXQoIG9mZnNldCApO1xuXG5cdFx0XHRcdC8vIE5lZWQgdG8gc2F2ZSBzdHlsZSBoZXJlIHNvIHRoYXQgYXV0b21hdGljIHN0eWxlIHJlc3RvcmF0aW9uXG5cdFx0XHRcdC8vIGRvZXNuJ3QgcmVzdG9yZSB0byB0aGUgb3JpZ2luYWwgc3R5bGVzIGZyb20gYmVmb3JlIHRoZSBhbmltYXRpb24uXG5cdFx0XHRcdCQuZWZmZWN0cy5zYXZlU3R5bGUoIGVsZW1lbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0ZG9uZSgpO1xuXHRcdH1cblx0fSApO1xuXG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBTY2FsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2NhbGUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogR3Jvd3Mgb3Igc2hyaW5rcyBhbiBlbGVtZW50IGFuZCBpdHMgY29udGVudC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zY2FsZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RTY2FsZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwic2NhbGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0Ly8gQ3JlYXRlIGVsZW1lbnRcblx0dmFyIGVsID0gJCggdGhpcyApLFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0cGVyY2VudCA9IHBhcnNlSW50KCBvcHRpb25zLnBlcmNlbnQsIDEwICkgfHxcblx0XHRcdCggcGFyc2VJbnQoIG9wdGlvbnMucGVyY2VudCwgMTAgKSA9PT0gMCA/IDAgOiAoIG1vZGUgIT09IFwiZWZmZWN0XCIgPyAwIDogMTAwICkgKSxcblxuXHRcdG5ld09wdGlvbnMgPSAkLmV4dGVuZCggdHJ1ZSwge1xuXHRcdFx0ZnJvbTogJC5lZmZlY3RzLnNjYWxlZERpbWVuc2lvbnMoIGVsICksXG5cdFx0XHR0bzogJC5lZmZlY3RzLnNjYWxlZERpbWVuc2lvbnMoIGVsLCBwZXJjZW50LCBvcHRpb25zLmRpcmVjdGlvbiB8fCBcImJvdGhcIiApLFxuXHRcdFx0b3JpZ2luOiBvcHRpb25zLm9yaWdpbiB8fCBbIFwibWlkZGxlXCIsIFwiY2VudGVyXCIgXVxuXHRcdH0sIG9wdGlvbnMgKTtcblxuXHQvLyBGYWRlIG9wdGlvbiB0byBzdXBwb3J0IHB1ZmZcblx0aWYgKCBvcHRpb25zLmZhZGUgKSB7XG5cdFx0bmV3T3B0aW9ucy5mcm9tLm9wYWNpdHkgPSAxO1xuXHRcdG5ld09wdGlvbnMudG8ub3BhY2l0eSA9IDA7XG5cdH1cblxuXHQkLmVmZmVjdHMuZWZmZWN0LnNpemUuY2FsbCggdGhpcywgbmV3T3B0aW9ucywgZG9uZSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgUHVmZiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogUHVmZiBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBDcmVhdGVzIGEgcHVmZiBlZmZlY3QgYnkgc2NhbGluZyB0aGUgZWxlbWVudCB1cCBhbmQgaGlkaW5nIGl0IGF0IHRoZSBzYW1lIHRpbWUuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcHVmZi1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RQdWZmID0gJC5lZmZlY3RzLmRlZmluZSggXCJwdWZmXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIG5ld09wdGlvbnMgPSAkLmV4dGVuZCggdHJ1ZSwge30sIG9wdGlvbnMsIHtcblx0XHRmYWRlOiB0cnVlLFxuXHRcdHBlcmNlbnQ6IHBhcnNlSW50KCBvcHRpb25zLnBlcmNlbnQsIDEwICkgfHwgMTUwXG5cdH0gKTtcblxuXHQkLmVmZmVjdHMuZWZmZWN0LnNjYWxlLmNhbGwoIHRoaXMsIG5ld09wdGlvbnMsIGRvbmUgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFB1bHNhdGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFB1bHNhdGUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogUHVsc2F0ZXMgYW4gZWxlbWVudCBuIHRpbWVzIGJ5IGNoYW5naW5nIHRoZSBvcGFjaXR5IHRvIHplcm8gYW5kIGJhY2suXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcHVsc2F0ZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RQdWxzYXRlID0gJC5lZmZlY3RzLmRlZmluZSggXCJwdWxzYXRlXCIsIFwic2hvd1wiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRzaG93ID0gbW9kZSA9PT0gXCJzaG93XCIsXG5cdFx0aGlkZSA9IG1vZGUgPT09IFwiaGlkZVwiLFxuXHRcdHNob3doaWRlID0gc2hvdyB8fCBoaWRlLFxuXG5cdFx0Ly8gU2hvd2luZyBvciBoaWRpbmcgbGVhdmVzIG9mZiB0aGUgXCJsYXN0XCIgYW5pbWF0aW9uXG5cdFx0YW5pbXMgPSAoICggb3B0aW9ucy50aW1lcyB8fCA1ICkgKiAyICkgKyAoIHNob3doaWRlID8gMSA6IDAgKSxcblx0XHRkdXJhdGlvbiA9IG9wdGlvbnMuZHVyYXRpb24gLyBhbmltcyxcblx0XHRhbmltYXRlVG8gPSAwLFxuXHRcdGkgPSAxLFxuXHRcdHF1ZXVlbGVuID0gZWxlbWVudC5xdWV1ZSgpLmxlbmd0aDtcblxuXHRpZiAoIHNob3cgfHwgIWVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdGVsZW1lbnQuY3NzKCBcIm9wYWNpdHlcIiwgMCApLnNob3coKTtcblx0XHRhbmltYXRlVG8gPSAxO1xuXHR9XG5cblx0Ly8gQW5pbXMgLSAxIG9wYWNpdHkgXCJ0b2dnbGVzXCJcblx0Zm9yICggOyBpIDwgYW5pbXM7IGkrKyApIHtcblx0XHRlbGVtZW50LmFuaW1hdGUoIHsgb3BhY2l0eTogYW5pbWF0ZVRvIH0sIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApO1xuXHRcdGFuaW1hdGVUbyA9IDEgLSBhbmltYXRlVG87XG5cdH1cblxuXHRlbGVtZW50LmFuaW1hdGUoIHsgb3BhY2l0eTogYW5pbWF0ZVRvIH0sIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApO1xuXG5cdGVsZW1lbnQucXVldWUoIGRvbmUgKTtcblxuXHQkLmVmZmVjdHMudW5zaGlmdCggZWxlbWVudCwgcXVldWVsZW4sIGFuaW1zICsgMSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgU2hha2UgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNoYWtlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IFNoYWtlcyBhbiBlbGVtZW50IGhvcml6b250YWxseSBvciB2ZXJ0aWNhbGx5IG4gdGltZXMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2hha2UtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0U2hha2UgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInNoYWtlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdHZhciBpID0gMSxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwibGVmdFwiLFxuXHRcdGRpc3RhbmNlID0gb3B0aW9ucy5kaXN0YW5jZSB8fCAyMCxcblx0XHR0aW1lcyA9IG9wdGlvbnMudGltZXMgfHwgMyxcblx0XHRhbmltcyA9IHRpbWVzICogMiArIDEsXG5cdFx0c3BlZWQgPSBNYXRoLnJvdW5kKCBvcHRpb25zLmR1cmF0aW9uIC8gYW5pbXMgKSxcblx0XHRyZWYgPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJkb3duXCIgKSA/IFwidG9wXCIgOiBcImxlZnRcIixcblx0XHRwb3NpdGl2ZU1vdGlvbiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImxlZnRcIiApLFxuXHRcdGFuaW1hdGlvbiA9IHt9LFxuXHRcdGFuaW1hdGlvbjEgPSB7fSxcblx0XHRhbmltYXRpb24yID0ge30sXG5cblx0XHRxdWV1ZWxlbiA9IGVsZW1lbnQucXVldWUoKS5sZW5ndGg7XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0Ly8gQW5pbWF0aW9uXG5cdGFuaW1hdGlvblsgcmVmIF0gPSAoIHBvc2l0aXZlTW90aW9uID8gXCItPVwiIDogXCIrPVwiICkgKyBkaXN0YW5jZTtcblx0YW5pbWF0aW9uMVsgcmVmIF0gPSAoIHBvc2l0aXZlTW90aW9uID8gXCIrPVwiIDogXCItPVwiICkgKyBkaXN0YW5jZSAqIDI7XG5cdGFuaW1hdGlvbjJbIHJlZiBdID0gKCBwb3NpdGl2ZU1vdGlvbiA/IFwiLT1cIiA6IFwiKz1cIiApICsgZGlzdGFuY2UgKiAyO1xuXG5cdC8vIEFuaW1hdGVcblx0ZWxlbWVudC5hbmltYXRlKCBhbmltYXRpb24sIHNwZWVkLCBvcHRpb25zLmVhc2luZyApO1xuXG5cdC8vIFNoYWtlc1xuXHRmb3IgKCA7IGkgPCB0aW1lczsgaSsrICkge1xuXHRcdGVsZW1lbnRcblx0XHRcdC5hbmltYXRlKCBhbmltYXRpb24xLCBzcGVlZCwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdFx0LmFuaW1hdGUoIGFuaW1hdGlvbjIsIHNwZWVkLCBvcHRpb25zLmVhc2luZyApO1xuXHR9XG5cblx0ZWxlbWVudFxuXHRcdC5hbmltYXRlKCBhbmltYXRpb24xLCBzcGVlZCwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdC5hbmltYXRlKCBhbmltYXRpb24sIHNwZWVkIC8gMiwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdC5xdWV1ZSggZG9uZSApO1xuXG5cdCQuZWZmZWN0cy51bnNoaWZ0KCBlbGVtZW50LCBxdWV1ZWxlbiwgYW5pbXMgKyAxICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBTbGlkZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2xpZGUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogU2xpZGVzIGFuIGVsZW1lbnQgaW4gYW5kIG91dCBvZiB0aGUgdmlld3BvcnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2xpZGUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0U2xpZGUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInNsaWRlXCIsIFwic2hvd1wiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIHN0YXJ0Q2xpcCwgc3RhcnRSZWYsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRtYXAgPSB7XG5cdFx0XHR1cDogWyBcImJvdHRvbVwiLCBcInRvcFwiIF0sXG5cdFx0XHRkb3duOiBbIFwidG9wXCIsIFwiYm90dG9tXCIgXSxcblx0XHRcdGxlZnQ6IFsgXCJyaWdodFwiLCBcImxlZnRcIiBdLFxuXHRcdFx0cmlnaHQ6IFsgXCJsZWZ0XCIsIFwicmlnaHRcIiBdXG5cdFx0fSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwibGVmdFwiLFxuXHRcdHJlZiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImRvd25cIiApID8gXCJ0b3BcIiA6IFwibGVmdFwiLFxuXHRcdHBvc2l0aXZlTW90aW9uID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwibGVmdFwiICksXG5cdFx0ZGlzdGFuY2UgPSBvcHRpb25zLmRpc3RhbmNlIHx8XG5cdFx0XHRlbGVtZW50WyByZWYgPT09IFwidG9wXCIgPyBcIm91dGVySGVpZ2h0XCIgOiBcIm91dGVyV2lkdGhcIiBdKCB0cnVlICksXG5cdFx0YW5pbWF0aW9uID0ge307XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0c3RhcnRDbGlwID0gZWxlbWVudC5jc3NDbGlwKCk7XG5cdHN0YXJ0UmVmID0gZWxlbWVudC5wb3NpdGlvbigpWyByZWYgXTtcblxuXHQvLyBEZWZpbmUgaGlkZSBhbmltYXRpb25cblx0YW5pbWF0aW9uWyByZWYgXSA9ICggcG9zaXRpdmVNb3Rpb24gPyAtMSA6IDEgKSAqIGRpc3RhbmNlICsgc3RhcnRSZWY7XG5cdGFuaW1hdGlvbi5jbGlwID0gZWxlbWVudC5jc3NDbGlwKCk7XG5cdGFuaW1hdGlvbi5jbGlwWyBtYXBbIGRpcmVjdGlvbiBdWyAxIF0gXSA9IGFuaW1hdGlvbi5jbGlwWyBtYXBbIGRpcmVjdGlvbiBdWyAwIF0gXTtcblxuXHQvLyBSZXZlcnNlIHRoZSBhbmltYXRpb24gaWYgd2UncmUgc2hvd2luZ1xuXHRpZiAoIG1vZGUgPT09IFwic2hvd1wiICkge1xuXHRcdGVsZW1lbnQuY3NzQ2xpcCggYW5pbWF0aW9uLmNsaXAgKTtcblx0XHRlbGVtZW50LmNzcyggcmVmLCBhbmltYXRpb25bIHJlZiBdICk7XG5cdFx0YW5pbWF0aW9uLmNsaXAgPSBzdGFydENsaXA7XG5cdFx0YW5pbWF0aW9uWyByZWYgXSA9IHN0YXJ0UmVmO1xuXHR9XG5cblx0Ly8gQWN0dWFsbHkgYW5pbWF0ZVxuXHRlbGVtZW50LmFuaW1hdGUoIGFuaW1hdGlvbiwge1xuXHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdGNvbXBsZXRlOiBkb25lXG5cdH0gKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFRyYW5zZmVyIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBUcmFuc2ZlciBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBhIHRyYW5zZmVyIGVmZmVjdCBmcm9tIG9uZSBlbGVtZW50IHRvIGFub3RoZXIuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vdHJhbnNmZXItZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3Q7XG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblx0ZWZmZWN0ID0gJC5lZmZlY3RzLmRlZmluZSggXCJ0cmFuc2ZlclwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0XHQkKCB0aGlzICkudHJhbnNmZXIoIG9wdGlvbnMsIGRvbmUgKTtcblx0fSApO1xufVxudmFyIGVmZmVjdHNFZmZlY3RUcmFuc2ZlciA9IGVmZmVjdDtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBGb2N1c2FibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IDpmb2N1c2FibGUgU2VsZWN0b3Jcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBTZWxlY3RzIGVsZW1lbnRzIHdoaWNoIGNhbiBiZSBmb2N1c2VkLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2ZvY3VzYWJsZS1zZWxlY3Rvci9cblxuXG5cbi8vIFNlbGVjdG9yc1xuJC51aS5mb2N1c2FibGUgPSBmdW5jdGlvbiggZWxlbWVudCwgaGFzVGFiaW5kZXggKSB7XG5cdHZhciBtYXAsIG1hcE5hbWUsIGltZywgZm9jdXNhYmxlSWZWaXNpYmxlLCBmaWVsZHNldCxcblx0XHRub2RlTmFtZSA9IGVsZW1lbnQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblxuXHRpZiAoIFwiYXJlYVwiID09PSBub2RlTmFtZSApIHtcblx0XHRtYXAgPSBlbGVtZW50LnBhcmVudE5vZGU7XG5cdFx0bWFwTmFtZSA9IG1hcC5uYW1lO1xuXHRcdGlmICggIWVsZW1lbnQuaHJlZiB8fCAhbWFwTmFtZSB8fCBtYXAubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJtYXBcIiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0aW1nID0gJCggXCJpbWdbdXNlbWFwPScjXCIgKyBtYXBOYW1lICsgXCInXVwiICk7XG5cdFx0cmV0dXJuIGltZy5sZW5ndGggPiAwICYmIGltZy5pcyggXCI6dmlzaWJsZVwiICk7XG5cdH1cblxuXHRpZiAoIC9eKGlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b258b2JqZWN0KSQvLnRlc3QoIG5vZGVOYW1lICkgKSB7XG5cdFx0Zm9jdXNhYmxlSWZWaXNpYmxlID0gIWVsZW1lbnQuZGlzYWJsZWQ7XG5cblx0XHRpZiAoIGZvY3VzYWJsZUlmVmlzaWJsZSApIHtcblxuXHRcdFx0Ly8gRm9ybSBjb250cm9scyB3aXRoaW4gYSBkaXNhYmxlZCBmaWVsZHNldCBhcmUgZGlzYWJsZWQuXG5cdFx0XHQvLyBIb3dldmVyLCBjb250cm9scyB3aXRoaW4gdGhlIGZpZWxkc2V0J3MgbGVnZW5kIGRvIG5vdCBnZXQgZGlzYWJsZWQuXG5cdFx0XHQvLyBTaW5jZSBjb250cm9scyBnZW5lcmFsbHkgYXJlbid0IHBsYWNlZCBpbnNpZGUgbGVnZW5kcywgd2Ugc2tpcFxuXHRcdFx0Ly8gdGhpcyBwb3J0aW9uIG9mIHRoZSBjaGVjay5cblx0XHRcdGZpZWxkc2V0ID0gJCggZWxlbWVudCApLmNsb3Nlc3QoIFwiZmllbGRzZXRcIiApWyAwIF07XG5cdFx0XHRpZiAoIGZpZWxkc2V0ICkge1xuXHRcdFx0XHRmb2N1c2FibGVJZlZpc2libGUgPSAhZmllbGRzZXQuZGlzYWJsZWQ7XG5cdFx0XHR9XG5cdFx0fVxuXHR9IGVsc2UgaWYgKCBcImFcIiA9PT0gbm9kZU5hbWUgKSB7XG5cdFx0Zm9jdXNhYmxlSWZWaXNpYmxlID0gZWxlbWVudC5ocmVmIHx8IGhhc1RhYmluZGV4O1xuXHR9IGVsc2Uge1xuXHRcdGZvY3VzYWJsZUlmVmlzaWJsZSA9IGhhc1RhYmluZGV4O1xuXHR9XG5cblx0cmV0dXJuIGZvY3VzYWJsZUlmVmlzaWJsZSAmJiAkKCBlbGVtZW50ICkuaXMoIFwiOnZpc2libGVcIiApICYmIHZpc2libGUoICQoIGVsZW1lbnQgKSApO1xufTtcblxuLy8gU3VwcG9ydDogSUUgOCBvbmx5XG4vLyBJRSA4IGRvZXNuJ3QgcmVzb2x2ZSBpbmhlcml0IHRvIHZpc2libGUvaGlkZGVuIGZvciBjb21wdXRlZCB2YWx1ZXNcbmZ1bmN0aW9uIHZpc2libGUoIGVsZW1lbnQgKSB7XG5cdHZhciB2aXNpYmlsaXR5ID0gZWxlbWVudC5jc3MoIFwidmlzaWJpbGl0eVwiICk7XG5cdHdoaWxlICggdmlzaWJpbGl0eSA9PT0gXCJpbmhlcml0XCIgKSB7XG5cdFx0ZWxlbWVudCA9IGVsZW1lbnQucGFyZW50KCk7XG5cdFx0dmlzaWJpbGl0eSA9IGVsZW1lbnQuY3NzKCBcInZpc2liaWxpdHlcIiApO1xuXHR9XG5cdHJldHVybiB2aXNpYmlsaXR5ICE9PSBcImhpZGRlblwiO1xufVxuXG4kLmV4dGVuZCggJC5leHByWyBcIjpcIiBdLCB7XG5cdGZvY3VzYWJsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0cmV0dXJuICQudWkuZm9jdXNhYmxlKCBlbGVtZW50LCAkLmF0dHIoIGVsZW1lbnQsIFwidGFiaW5kZXhcIiApICE9IG51bGwgKTtcblx0fVxufSApO1xuXG52YXIgZm9jdXNhYmxlID0gJC51aS5mb2N1c2FibGU7XG5cblxuXG5cbi8vIFN1cHBvcnQ6IElFOCBPbmx5XG4vLyBJRTggZG9lcyBub3Qgc3VwcG9ydCB0aGUgZm9ybSBhdHRyaWJ1dGUgYW5kIHdoZW4gaXQgaXMgc3VwcGxpZWQuIEl0IG92ZXJ3cml0ZXMgdGhlIGZvcm0gcHJvcFxuLy8gd2l0aCBhIHN0cmluZywgc28gd2UgbmVlZCB0byBmaW5kIHRoZSBwcm9wZXIgZm9ybS5cbnZhciBmb3JtID0gJC5mbi5mb3JtID0gZnVuY3Rpb24oKSB7XG5cdHJldHVybiB0eXBlb2YgdGhpc1sgMCBdLmZvcm0gPT09IFwic3RyaW5nXCIgPyB0aGlzLmNsb3Nlc3QoIFwiZm9ybVwiICkgOiAkKCB0aGlzWyAwIF0uZm9ybSApO1xufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBGb3JtIFJlc2V0IE1peGluIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBGb3JtIFJlc2V0IE1peGluXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogUmVmcmVzaCBpbnB1dCB3aWRnZXRzIHdoZW4gdGhlaXIgZm9ybSBpcyByZXNldFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2Zvcm0tcmVzZXQtbWl4aW4vXG5cblxuXG52YXIgZm9ybVJlc2V0TWl4aW4gPSAkLnVpLmZvcm1SZXNldE1peGluID0ge1xuXHRfZm9ybVJlc2V0SGFuZGxlcjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGZvcm0gPSAkKCB0aGlzICk7XG5cblx0XHQvLyBXYWl0IGZvciB0aGUgZm9ybSByZXNldCB0byBhY3R1YWxseSBoYXBwZW4gYmVmb3JlIHJlZnJlc2hpbmdcblx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpbnN0YW5jZXMgPSBmb3JtLmRhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiApO1xuXHRcdFx0JC5lYWNoKCBpbnN0YW5jZXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLnJlZnJlc2goKTtcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X2JpbmRGb3JtUmVzZXRIYW5kbGVyOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmZvcm0gPSB0aGlzLmVsZW1lbnQuZm9ybSgpO1xuXHRcdGlmICggIXRoaXMuZm9ybS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGluc3RhbmNlcyA9IHRoaXMuZm9ybS5kYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIgKSB8fCBbXTtcblx0XHRpZiAoICFpbnN0YW5jZXMubGVuZ3RoICkge1xuXG5cdFx0XHQvLyBXZSBkb24ndCB1c2UgX29uKCkgaGVyZSBiZWNhdXNlIHdlIHVzZSBhIHNpbmdsZSBldmVudCBoYW5kbGVyIHBlciBmb3JtXG5cdFx0XHR0aGlzLmZvcm0ub24oIFwicmVzZXQudWktZm9ybS1yZXNldFwiLCB0aGlzLl9mb3JtUmVzZXRIYW5kbGVyICk7XG5cdFx0fVxuXHRcdGluc3RhbmNlcy5wdXNoKCB0aGlzICk7XG5cdFx0dGhpcy5mb3JtLmRhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiwgaW5zdGFuY2VzICk7XG5cdH0sXG5cblx0X3VuYmluZEZvcm1SZXNldEhhbmRsZXI6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXMuZm9ybS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGluc3RhbmNlcyA9IHRoaXMuZm9ybS5kYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIgKTtcblx0XHRpbnN0YW5jZXMuc3BsaWNlKCAkLmluQXJyYXkoIHRoaXMsIGluc3RhbmNlcyApLCAxICk7XG5cdFx0aWYgKCBpbnN0YW5jZXMubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5mb3JtLmRhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiwgaW5zdGFuY2VzICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZm9ybVxuXHRcdFx0XHQucmVtb3ZlRGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiIClcblx0XHRcdFx0Lm9mZiggXCJyZXNldC51aS1mb3JtLXJlc2V0XCIgKTtcblx0XHR9XG5cdH1cbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU3VwcG9ydCBmb3IgalF1ZXJ5IGNvcmUgMS43LnggMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqXG4gKi9cblxuLy8+PmxhYmVsOiBqUXVlcnkgMS43IFN1cHBvcnRcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBTdXBwb3J0IHZlcnNpb24gMS43Lnggb2YgalF1ZXJ5IGNvcmVcblxuXG5cbi8vIFN1cHBvcnQ6IGpRdWVyeSAxLjcgb25seVxuLy8gTm90IGEgZ3JlYXQgd2F5IHRvIGNoZWNrIHZlcnNpb25zLCBidXQgc2luY2Ugd2Ugb25seSBzdXBwb3J0IDEuNysgYW5kIG9ubHlcbi8vIG5lZWQgdG8gZGV0ZWN0IDwxLjgsIHRoaXMgaXMgYSBzaW1wbGUgY2hlY2sgdGhhdCBzaG91bGQgc3VmZmljZS4gQ2hlY2tpbmdcbi8vIGZvciBcIjEuNy5cIiB3b3VsZCBiZSBhIGJpdCBzYWZlciwgYnV0IHRoZSB2ZXJzaW9uIHN0cmluZyBpcyAxLjcsIG5vdCAxLjcuMFxuLy8gYW5kIHdlJ2xsIG5ldmVyIHJlYWNoIDEuNzAuMCAoaWYgd2UgZG8sIHdlIGNlcnRhaW5seSB3b24ndCBiZSBzdXBwb3J0aW5nXG4vLyAxLjcgYW55bW9yZSkuIFNlZSAjMTExOTcgZm9yIHdoeSB3ZSdyZSBub3QgdXNpbmcgZmVhdHVyZSBkZXRlY3Rpb24uXG5pZiAoICQuZm4uanF1ZXJ5LnN1YnN0cmluZyggMCwgMyApID09PSBcIjEuN1wiICkge1xuXG5cdC8vIFNldHRlcnMgZm9yIC5pbm5lcldpZHRoKCksIC5pbm5lckhlaWdodCgpLCAub3V0ZXJXaWR0aCgpLCAub3V0ZXJIZWlnaHQoKVxuXHQvLyBVbmxpa2UgalF1ZXJ5IENvcmUgMS44KywgdGhlc2Ugb25seSBzdXBwb3J0IG51bWVyaWMgdmFsdWVzIHRvIHNldCB0aGVcblx0Ly8gZGltZW5zaW9ucyBpbiBwaXhlbHNcblx0JC5lYWNoKCBbIFwiV2lkdGhcIiwgXCJIZWlnaHRcIiBdLCBmdW5jdGlvbiggaSwgbmFtZSApIHtcblx0XHR2YXIgc2lkZSA9IG5hbWUgPT09IFwiV2lkdGhcIiA/IFsgXCJMZWZ0XCIsIFwiUmlnaHRcIiBdIDogWyBcIlRvcFwiLCBcIkJvdHRvbVwiIF0sXG5cdFx0XHR0eXBlID0gbmFtZS50b0xvd2VyQ2FzZSgpLFxuXHRcdFx0b3JpZyA9IHtcblx0XHRcdFx0aW5uZXJXaWR0aDogJC5mbi5pbm5lcldpZHRoLFxuXHRcdFx0XHRpbm5lckhlaWdodDogJC5mbi5pbm5lckhlaWdodCxcblx0XHRcdFx0b3V0ZXJXaWR0aDogJC5mbi5vdXRlcldpZHRoLFxuXHRcdFx0XHRvdXRlckhlaWdodDogJC5mbi5vdXRlckhlaWdodFxuXHRcdFx0fTtcblxuXHRcdGZ1bmN0aW9uIHJlZHVjZSggZWxlbSwgc2l6ZSwgYm9yZGVyLCBtYXJnaW4gKSB7XG5cdFx0XHQkLmVhY2goIHNpZGUsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRzaXplIC09IHBhcnNlRmxvYXQoICQuY3NzKCBlbGVtLCBcInBhZGRpbmdcIiArIHRoaXMgKSApIHx8IDA7XG5cdFx0XHRcdGlmICggYm9yZGVyICkge1xuXHRcdFx0XHRcdHNpemUgLT0gcGFyc2VGbG9hdCggJC5jc3MoIGVsZW0sIFwiYm9yZGVyXCIgKyB0aGlzICsgXCJXaWR0aFwiICkgKSB8fCAwO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggbWFyZ2luICkge1xuXHRcdFx0XHRcdHNpemUgLT0gcGFyc2VGbG9hdCggJC5jc3MoIGVsZW0sIFwibWFyZ2luXCIgKyB0aGlzICkgKSB8fCAwO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0XHRyZXR1cm4gc2l6ZTtcblx0XHR9XG5cblx0XHQkLmZuWyBcImlubmVyXCIgKyBuYW1lIF0gPSBmdW5jdGlvbiggc2l6ZSApIHtcblx0XHRcdGlmICggc2l6ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZ1sgXCJpbm5lclwiICsgbmFtZSBdLmNhbGwoIHRoaXMgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5jc3MoIHR5cGUsIHJlZHVjZSggdGhpcywgc2l6ZSApICsgXCJweFwiICk7XG5cdFx0XHR9ICk7XG5cdFx0fTtcblxuXHRcdCQuZm5bIFwib3V0ZXJcIiArIG5hbWUgXSA9IGZ1bmN0aW9uKCBzaXplLCBtYXJnaW4gKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBzaXplICE9PSBcIm51bWJlclwiICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZ1sgXCJvdXRlclwiICsgbmFtZSBdLmNhbGwoIHRoaXMsIHNpemUgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5jc3MoIHR5cGUsIHJlZHVjZSggdGhpcywgc2l6ZSwgdHJ1ZSwgbWFyZ2luICkgKyBcInB4XCIgKTtcblx0XHRcdH0gKTtcblx0XHR9O1xuXHR9ICk7XG5cblx0JC5mbi5hZGRCYWNrID0gZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLmFkZCggc2VsZWN0b3IgPT0gbnVsbCA/XG5cdFx0XHR0aGlzLnByZXZPYmplY3QgOiB0aGlzLnByZXZPYmplY3QuZmlsdGVyKCBzZWxlY3RvciApXG5cdFx0KTtcblx0fTtcbn1cblxuO1xuLyohXG4gKiBqUXVlcnkgVUkgS2V5Y29kZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogS2V5Y29kZVxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFByb3ZpZGUga2V5Y29kZXMgYXMga2V5bmFtZXNcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9qUXVlcnkudWkua2V5Q29kZS9cblxuXG52YXIga2V5Y29kZSA9ICQudWkua2V5Q29kZSA9IHtcblx0QkFDS1NQQUNFOiA4LFxuXHRDT01NQTogMTg4LFxuXHRERUxFVEU6IDQ2LFxuXHRET1dOOiA0MCxcblx0RU5EOiAzNSxcblx0RU5URVI6IDEzLFxuXHRFU0NBUEU6IDI3LFxuXHRIT01FOiAzNixcblx0TEVGVDogMzcsXG5cdFBBR0VfRE9XTjogMzQsXG5cdFBBR0VfVVA6IDMzLFxuXHRQRVJJT0Q6IDE5MCxcblx0UklHSFQ6IDM5LFxuXHRTUEFDRTogMzIsXG5cdFRBQjogOSxcblx0VVA6IDM4XG59O1xuXG5cblxuXG4vLyBJbnRlcm5hbCB1c2Ugb25seVxudmFyIGVzY2FwZVNlbGVjdG9yID0gJC51aS5lc2NhcGVTZWxlY3RvciA9ICggZnVuY3Rpb24oKSB7XG5cdHZhciBzZWxlY3RvckVzY2FwZSA9IC8oWyFcIiMkJSYnKCkqKywuLzo7PD0+P0BbXFxdXmB7fH1+XSkvZztcblx0cmV0dXJuIGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gc2VsZWN0b3IucmVwbGFjZSggc2VsZWN0b3JFc2NhcGUsIFwiXFxcXCQxXCIgKTtcblx0fTtcbn0gKSgpO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIExhYmVscyAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogbGFiZWxzXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogRmluZCBhbGwgdGhlIGxhYmVscyBhc3NvY2lhdGVkIHdpdGggYSBnaXZlbiBpbnB1dFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2xhYmVscy9cblxuXG5cbnZhciBsYWJlbHMgPSAkLmZuLmxhYmVscyA9IGZ1bmN0aW9uKCkge1xuXHR2YXIgYW5jZXN0b3IsIHNlbGVjdG9yLCBpZCwgbGFiZWxzLCBhbmNlc3RvcnM7XG5cblx0Ly8gQ2hlY2sgY29udHJvbC5sYWJlbHMgZmlyc3Rcblx0aWYgKCB0aGlzWyAwIF0ubGFiZWxzICYmIHRoaXNbIDAgXS5sYWJlbHMubGVuZ3RoICkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggdGhpc1sgMCBdLmxhYmVscyApO1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgPD0gMTEsIEZGIDw9IDM3LCBBbmRyb2lkIDw9IDIuMyBvbmx5XG5cdC8vIEFib3ZlIGJyb3dzZXJzIGRvIG5vdCBzdXBwb3J0IGNvbnRyb2wubGFiZWxzLiBFdmVyeXRoaW5nIGJlbG93IGlzIHRvIHN1cHBvcnQgdGhlbVxuXHQvLyBhcyB3ZWxsIGFzIGRvY3VtZW50IGZyYWdtZW50cy4gY29udHJvbC5sYWJlbHMgZG9lcyBub3Qgd29yayBvbiBkb2N1bWVudCBmcmFnbWVudHNcblx0bGFiZWxzID0gdGhpcy5lcSggMCApLnBhcmVudHMoIFwibGFiZWxcIiApO1xuXG5cdC8vIExvb2sgZm9yIHRoZSBsYWJlbCBiYXNlZCBvbiB0aGUgaWRcblx0aWQgPSB0aGlzLmF0dHIoIFwiaWRcIiApO1xuXHRpZiAoIGlkICkge1xuXG5cdFx0Ly8gV2UgZG9uJ3Qgc2VhcmNoIGFnYWluc3QgdGhlIGRvY3VtZW50IGluIGNhc2UgdGhlIGVsZW1lbnRcblx0XHQvLyBpcyBkaXNjb25uZWN0ZWQgZnJvbSB0aGUgRE9NXG5cdFx0YW5jZXN0b3IgPSB0aGlzLmVxKCAwICkucGFyZW50cygpLmxhc3QoKTtcblxuXHRcdC8vIEdldCBhIGZ1bGwgc2V0IG9mIHRvcCBsZXZlbCBhbmNlc3RvcnNcblx0XHRhbmNlc3RvcnMgPSBhbmNlc3Rvci5hZGQoIGFuY2VzdG9yLmxlbmd0aCA/IGFuY2VzdG9yLnNpYmxpbmdzKCkgOiB0aGlzLnNpYmxpbmdzKCkgKTtcblxuXHRcdC8vIENyZWF0ZSBhIHNlbGVjdG9yIGZvciB0aGUgbGFiZWwgYmFzZWQgb24gdGhlIGlkXG5cdFx0c2VsZWN0b3IgPSBcImxhYmVsW2Zvcj0nXCIgKyAkLnVpLmVzY2FwZVNlbGVjdG9yKCBpZCApICsgXCInXVwiO1xuXG5cdFx0bGFiZWxzID0gbGFiZWxzLmFkZCggYW5jZXN0b3JzLmZpbmQoIHNlbGVjdG9yICkuYWRkQmFjayggc2VsZWN0b3IgKSApO1xuXG5cdH1cblxuXHQvLyBSZXR1cm4gd2hhdGV2ZXIgd2UgaGF2ZSBmb3VuZCBmb3IgbGFiZWxzXG5cdHJldHVybiB0aGlzLnB1c2hTdGFjayggbGFiZWxzICk7XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNjcm9sbCBQYXJlbnQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IHNjcm9sbFBhcmVudFxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IEdldCB0aGUgY2xvc2VzdCBhbmNlc3RvciBlbGVtZW50IHRoYXQgaXMgc2Nyb2xsYWJsZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zY3JvbGxQYXJlbnQvXG5cblxuXG52YXIgc2Nyb2xsUGFyZW50ID0gJC5mbi5zY3JvbGxQYXJlbnQgPSBmdW5jdGlvbiggaW5jbHVkZUhpZGRlbiApIHtcblx0dmFyIHBvc2l0aW9uID0gdGhpcy5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdGV4Y2x1ZGVTdGF0aWNQYXJlbnQgPSBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiLFxuXHRcdG92ZXJmbG93UmVnZXggPSBpbmNsdWRlSGlkZGVuID8gLyhhdXRvfHNjcm9sbHxoaWRkZW4pLyA6IC8oYXV0b3xzY3JvbGwpLyxcblx0XHRzY3JvbGxQYXJlbnQgPSB0aGlzLnBhcmVudHMoKS5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHBhcmVudCA9ICQoIHRoaXMgKTtcblx0XHRcdGlmICggZXhjbHVkZVN0YXRpY1BhcmVudCAmJiBwYXJlbnQuY3NzKCBcInBvc2l0aW9uXCIgKSA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG92ZXJmbG93UmVnZXgudGVzdCggcGFyZW50LmNzcyggXCJvdmVyZmxvd1wiICkgKyBwYXJlbnQuY3NzKCBcIm92ZXJmbG93LXlcIiApICtcblx0XHRcdFx0cGFyZW50LmNzcyggXCJvdmVyZmxvdy14XCIgKSApO1xuXHRcdH0gKS5lcSggMCApO1xuXG5cdHJldHVybiBwb3NpdGlvbiA9PT0gXCJmaXhlZFwiIHx8ICFzY3JvbGxQYXJlbnQubGVuZ3RoID9cblx0XHQkKCB0aGlzWyAwIF0ub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudCApIDpcblx0XHRzY3JvbGxQYXJlbnQ7XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFRhYmJhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiA6dGFiYmFibGUgU2VsZWN0b3Jcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBTZWxlY3RzIGVsZW1lbnRzIHdoaWNoIGNhbiBiZSB0YWJiZWQgdG8uXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vdGFiYmFibGUtc2VsZWN0b3IvXG5cblxuXG52YXIgdGFiYmFibGUgPSAkLmV4dGVuZCggJC5leHByWyBcIjpcIiBdLCB7XG5cdHRhYmJhYmxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgdGFiSW5kZXggPSAkLmF0dHIoIGVsZW1lbnQsIFwidGFiaW5kZXhcIiApLFxuXHRcdFx0aGFzVGFiaW5kZXggPSB0YWJJbmRleCAhPSBudWxsO1xuXHRcdHJldHVybiAoICFoYXNUYWJpbmRleCB8fCB0YWJJbmRleCA+PSAwICkgJiYgJC51aS5mb2N1c2FibGUoIGVsZW1lbnQsIGhhc1RhYmluZGV4ICk7XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBVbmlxdWUgSUQgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IHVuaXF1ZUlkXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogRnVuY3Rpb25zIHRvIGdlbmVyYXRlIGFuZCByZW1vdmUgdW5pcXVlSWQnc1xuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3VuaXF1ZUlkL1xuXG5cblxudmFyIHVuaXF1ZUlkID0gJC5mbi5leHRlbmQoIHtcblx0dW5pcXVlSWQ6ICggZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHV1aWQgPSAwO1xuXG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggIXRoaXMuaWQgKSB7XG5cdFx0XHRcdFx0dGhpcy5pZCA9IFwidWktaWQtXCIgKyAoICsrdXVpZCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fTtcblx0fSApKCksXG5cblx0cmVtb3ZlVW5pcXVlSWQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAvXnVpLWlkLVxcZCskLy50ZXN0KCB0aGlzLmlkICkgKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5yZW1vdmVBdHRyKCBcImlkXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBBY2NvcmRpb24gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEFjY29yZGlvblxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgY29sbGFwc2libGUgY29udGVudCBwYW5lbHMgZm9yIHByZXNlbnRpbmcgaW5mb3JtYXRpb24gaW4gYSBsaW1pdGVkIGFtb3VudCBvZiBzcGFjZS5cbi8vIGpzY3M6ZW5hYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vYWNjb3JkaW9uL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2FjY29yZGlvbi9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2FjY29yZGlvbi5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxudmFyIHdpZGdldHNBY2NvcmRpb24gPSAkLndpZGdldCggXCJ1aS5hY2NvcmRpb25cIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YWN0aXZlOiAwLFxuXHRcdGFuaW1hdGU6IHt9LFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktYWNjb3JkaW9uLWhlYWRlclwiOiBcInVpLWNvcm5lci10b3BcIixcblx0XHRcdFwidWktYWNjb3JkaW9uLWhlYWRlci1jb2xsYXBzZWRcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLWFjY29yZGlvbi1jb250ZW50XCI6IFwidWktY29ybmVyLWJvdHRvbVwiXG5cdFx0fSxcblx0XHRjb2xsYXBzaWJsZTogZmFsc2UsXG5cdFx0ZXZlbnQ6IFwiY2xpY2tcIixcblx0XHRoZWFkZXI6IFwiPiBsaSA+IDpmaXJzdC1jaGlsZCwgPiA6bm90KGxpKTpldmVuXCIsXG5cdFx0aGVpZ2h0U3R5bGU6IFwiYXV0b1wiLFxuXHRcdGljb25zOiB7XG5cdFx0XHRhY3RpdmVIZWFkZXI6IFwidWktaWNvbi10cmlhbmdsZS0xLXNcIixcblx0XHRcdGhlYWRlcjogXCJ1aS1pY29uLXRyaWFuZ2xlLTEtZVwiXG5cdFx0fSxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGFjdGl2YXRlOiBudWxsLFxuXHRcdGJlZm9yZUFjdGl2YXRlOiBudWxsXG5cdH0sXG5cblx0aGlkZVByb3BzOiB7XG5cdFx0Ym9yZGVyVG9wV2lkdGg6IFwiaGlkZVwiLFxuXHRcdGJvcmRlckJvdHRvbVdpZHRoOiBcImhpZGVcIixcblx0XHRwYWRkaW5nVG9wOiBcImhpZGVcIixcblx0XHRwYWRkaW5nQm90dG9tOiBcImhpZGVcIixcblx0XHRoZWlnaHQ6IFwiaGlkZVwiXG5cdH0sXG5cblx0c2hvd1Byb3BzOiB7XG5cdFx0Ym9yZGVyVG9wV2lkdGg6IFwic2hvd1wiLFxuXHRcdGJvcmRlckJvdHRvbVdpZHRoOiBcInNob3dcIixcblx0XHRwYWRkaW5nVG9wOiBcInNob3dcIixcblx0XHRwYWRkaW5nQm90dG9tOiBcInNob3dcIixcblx0XHRoZWlnaHQ6IFwic2hvd1wiXG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLnByZXZTaG93ID0gdGhpcy5wcmV2SGlkZSA9ICQoKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1hY2NvcmRpb25cIiwgXCJ1aS13aWRnZXQgdWktaGVscGVyLXJlc2V0XCIgKTtcblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJyb2xlXCIsIFwidGFibGlzdFwiICk7XG5cblx0XHQvLyBEb24ndCBhbGxvdyBjb2xsYXBzaWJsZTogZmFsc2UgYW5kIGFjdGl2ZTogZmFsc2UgLyBudWxsXG5cdFx0aWYgKCAhb3B0aW9ucy5jb2xsYXBzaWJsZSAmJiAoIG9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSB8fCBvcHRpb25zLmFjdGl2ZSA9PSBudWxsICkgKSB7XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSA9IDA7XG5cdFx0fVxuXG5cdFx0dGhpcy5fcHJvY2Vzc1BhbmVscygpO1xuXG5cdFx0Ly8gaGFuZGxlIG5lZ2F0aXZlIHZhbHVlc1xuXHRcdGlmICggb3B0aW9ucy5hY3RpdmUgPCAwICkge1xuXHRcdFx0b3B0aW9ucy5hY3RpdmUgKz0gdGhpcy5oZWFkZXJzLmxlbmd0aDtcblx0XHR9XG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVFdmVudERhdGE6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRoZWFkZXI6IHRoaXMuYWN0aXZlLFxuXHRcdFx0cGFuZWw6ICF0aGlzLmFjdGl2ZS5sZW5ndGggPyAkKCkgOiB0aGlzLmFjdGl2ZS5uZXh0KClcblx0XHR9O1xuXHR9LFxuXG5cdF9jcmVhdGVJY29uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGljb24sIGNoaWxkcmVuLFxuXHRcdFx0aWNvbnMgPSB0aGlzLm9wdGlvbnMuaWNvbnM7XG5cblx0XHRpZiAoIGljb25zICkge1xuXHRcdFx0aWNvbiA9ICQoIFwiPHNwYW4+XCIgKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBpY29uLCBcInVpLWFjY29yZGlvbi1oZWFkZXItaWNvblwiLCBcInVpLWljb24gXCIgKyBpY29ucy5oZWFkZXIgKTtcblx0XHRcdGljb24ucHJlcGVuZFRvKCB0aGlzLmhlYWRlcnMgKTtcblx0XHRcdGNoaWxkcmVuID0gdGhpcy5hY3RpdmUuY2hpbGRyZW4oIFwiLnVpLWFjY29yZGlvbi1oZWFkZXItaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY2hpbGRyZW4sIGljb25zLmhlYWRlciApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIGNoaWxkcmVuLCBudWxsLCBpY29ucy5hY3RpdmVIZWFkZXIgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCB0aGlzLmhlYWRlcnMsIFwidWktYWNjb3JkaW9uLWljb25zXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X2Rlc3Ryb3lJY29uczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaGVhZGVycywgXCJ1aS1hY2NvcmRpb24taWNvbnNcIiApO1xuXHRcdHRoaXMuaGVhZGVycy5jaGlsZHJlbiggXCIudWktYWNjb3JkaW9uLWhlYWRlci1pY29uXCIgKS5yZW1vdmUoKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNvbnRlbnRzO1xuXG5cdFx0Ly8gQ2xlYW4gdXAgbWFpbiBlbGVtZW50XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwicm9sZVwiICk7XG5cblx0XHQvLyBDbGVhbiB1cCBoZWFkZXJzXG5cdFx0dGhpcy5oZWFkZXJzXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlIGFyaWEtZXhwYW5kZWQgYXJpYS1zZWxlY3RlZCBhcmlhLWNvbnRyb2xzIHRhYkluZGV4XCIgKVxuXHRcdFx0LnJlbW92ZVVuaXF1ZUlkKCk7XG5cblx0XHR0aGlzLl9kZXN0cm95SWNvbnMoKTtcblxuXHRcdC8vIENsZWFuIHVwIGNvbnRlbnQgcGFuZWxzXG5cdFx0Y29udGVudHMgPSB0aGlzLmhlYWRlcnMubmV4dCgpXG5cdFx0XHQuY3NzKCBcImRpc3BsYXlcIiwgXCJcIiApXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlIGFyaWEtaGlkZGVuIGFyaWEtbGFiZWxsZWRieVwiIClcblx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGVpZ2h0U3R5bGUgIT09IFwiY29udGVudFwiICkge1xuXHRcdFx0Y29udGVudHMuY3NzKCBcImhlaWdodFwiLCBcIlwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImFjdGl2ZVwiICkge1xuXG5cdFx0XHQvLyBfYWN0aXZhdGUoKSB3aWxsIGhhbmRsZSBpbnZhbGlkIHZhbHVlcyBhbmQgdXBkYXRlIHRoaXMub3B0aW9uc1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHZhbHVlICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiZXZlbnRcIiApIHtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9vZmYoIHRoaXMuaGVhZGVycywgdGhpcy5vcHRpb25zLmV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9zZXR1cEV2ZW50cyggdmFsdWUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0Ly8gU2V0dGluZyBjb2xsYXBzaWJsZTogZmFsc2Ugd2hpbGUgY29sbGFwc2VkOyBvcGVuIGZpcnN0IHBhbmVsXG5cdFx0aWYgKCBrZXkgPT09IFwiY29sbGFwc2libGVcIiAmJiAhdmFsdWUgJiYgdGhpcy5vcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggMCApO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImljb25zXCIgKSB7XG5cdFx0XHR0aGlzLl9kZXN0cm95SWNvbnMoKTtcblx0XHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHRcdHRoaXMuX2NyZWF0ZUljb25zKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXG5cdFx0Ly8gU3VwcG9ydDogSUU4IE9ubHlcblx0XHQvLyAjNTMzMiAvICM2MDU5IC0gb3BhY2l0eSBkb2Vzbid0IGNhc2NhZGUgdG8gcG9zaXRpb25lZCBlbGVtZW50cyBpbiBJRVxuXHRcdC8vIHNvIHdlIG5lZWQgdG8gYWRkIHRoZSBkaXNhYmxlZCBjbGFzcyB0byB0aGUgaGVhZGVycyBhbmQgcGFuZWxzXG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmhlYWRlcnMuYWRkKCB0aGlzLmhlYWRlcnMubmV4dCgpICksIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIixcblx0XHRcdCEhdmFsdWUgKTtcblx0fSxcblxuXHRfa2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggZXZlbnQuYWx0S2V5IHx8IGV2ZW50LmN0cmxLZXkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGtleUNvZGUgPSAkLnVpLmtleUNvZGUsXG5cdFx0XHRsZW5ndGggPSB0aGlzLmhlYWRlcnMubGVuZ3RoLFxuXHRcdFx0Y3VycmVudEluZGV4ID0gdGhpcy5oZWFkZXJzLmluZGV4KCBldmVudC50YXJnZXQgKSxcblx0XHRcdHRvRm9jdXMgPSBmYWxzZTtcblxuXHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0Y2FzZSBrZXlDb2RlLlJJR0hUOlxuXHRcdGNhc2Uga2V5Q29kZS5ET1dOOlxuXHRcdFx0dG9Gb2N1cyA9IHRoaXMuaGVhZGVyc1sgKCBjdXJyZW50SW5kZXggKyAxICkgJSBsZW5ndGggXTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2Uga2V5Q29kZS5MRUZUOlxuXHRcdGNhc2Uga2V5Q29kZS5VUDpcblx0XHRcdHRvRm9jdXMgPSB0aGlzLmhlYWRlcnNbICggY3VycmVudEluZGV4IC0gMSArIGxlbmd0aCApICUgbGVuZ3RoIF07XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIGtleUNvZGUuU1BBQ0U6XG5cdFx0Y2FzZSBrZXlDb2RlLkVOVEVSOlxuXHRcdFx0dGhpcy5fZXZlbnRIYW5kbGVyKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBrZXlDb2RlLkhPTUU6XG5cdFx0XHR0b0ZvY3VzID0gdGhpcy5oZWFkZXJzWyAwIF07XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIGtleUNvZGUuRU5EOlxuXHRcdFx0dG9Gb2N1cyA9IHRoaXMuaGVhZGVyc1sgbGVuZ3RoIC0gMSBdO1xuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXG5cdFx0aWYgKCB0b0ZvY3VzICkge1xuXHRcdFx0JCggZXZlbnQudGFyZ2V0ICkuYXR0ciggXCJ0YWJJbmRleFwiLCAtMSApO1xuXHRcdFx0JCggdG9Gb2N1cyApLmF0dHIoIFwidGFiSW5kZXhcIiwgMCApO1xuXHRcdFx0JCggdG9Gb2N1cyApLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR9XG5cdH0sXG5cblx0X3BhbmVsS2V5RG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLlVQICYmIGV2ZW50LmN0cmxLZXkgKSB7XG5cdFx0XHQkKCBldmVudC5jdXJyZW50VGFyZ2V0ICkucHJldigpLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdH1cblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblx0XHR0aGlzLl9wcm9jZXNzUGFuZWxzKCk7XG5cblx0XHQvLyBXYXMgY29sbGFwc2VkIG9yIG5vIHBhbmVsXG5cdFx0aWYgKCAoIG9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSAmJiBvcHRpb25zLmNvbGxhcHNpYmxlID09PSB0cnVlICkgfHxcblx0XHRcdFx0IXRoaXMuaGVhZGVycy5sZW5ndGggKSB7XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSA9IGZhbHNlO1xuXHRcdFx0dGhpcy5hY3RpdmUgPSAkKCk7XG5cblx0XHQvLyBhY3RpdmUgZmFsc2Ugb25seSB3aGVuIGNvbGxhcHNpYmxlIGlzIHRydWVcblx0XHR9IGVsc2UgaWYgKCBvcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggMCApO1xuXG5cdFx0Ly8gd2FzIGFjdGl2ZSwgYnV0IGFjdGl2ZSBwYW5lbCBpcyBnb25lXG5cdFx0fSBlbHNlIGlmICggdGhpcy5hY3RpdmUubGVuZ3RoICYmICEkLmNvbnRhaW5zKCB0aGlzLmVsZW1lbnRbIDAgXSwgdGhpcy5hY3RpdmVbIDAgXSApICkge1xuXG5cdFx0XHQvLyBhbGwgcmVtYWluaW5nIHBhbmVsIGFyZSBkaXNhYmxlZFxuXHRcdFx0aWYgKCB0aGlzLmhlYWRlcnMubGVuZ3RoID09PSB0aGlzLmhlYWRlcnMuZmluZCggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApLmxlbmd0aCApIHtcblx0XHRcdFx0b3B0aW9ucy5hY3RpdmUgPSBmYWxzZTtcblx0XHRcdFx0dGhpcy5hY3RpdmUgPSAkKCk7XG5cblx0XHRcdC8vIGFjdGl2YXRlIHByZXZpb3VzIHBhbmVsXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLl9hY3RpdmF0ZSggTWF0aC5tYXgoIDAsIG9wdGlvbnMuYWN0aXZlIC0gMSApICk7XG5cdFx0XHR9XG5cblx0XHQvLyB3YXMgYWN0aXZlLCBhY3RpdmUgcGFuZWwgc3RpbGwgZXhpc3RzXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gbWFrZSBzdXJlIGFjdGl2ZSBpbmRleCBpcyBjb3JyZWN0XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSA9IHRoaXMuaGVhZGVycy5pbmRleCggdGhpcy5hY3RpdmUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9kZXN0cm95SWNvbnMoKTtcblxuXHRcdHRoaXMuX3JlZnJlc2goKTtcblx0fSxcblxuXHRfcHJvY2Vzc1BhbmVsczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZXZIZWFkZXJzID0gdGhpcy5oZWFkZXJzLFxuXHRcdFx0cHJldlBhbmVscyA9IHRoaXMucGFuZWxzO1xuXG5cdFx0dGhpcy5oZWFkZXJzID0gdGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5oZWFkZXIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oZWFkZXJzLCBcInVpLWFjY29yZGlvbi1oZWFkZXIgdWktYWNjb3JkaW9uLWhlYWRlci1jb2xsYXBzZWRcIixcblx0XHRcdFwidWktc3RhdGUtZGVmYXVsdFwiICk7XG5cblx0XHR0aGlzLnBhbmVscyA9IHRoaXMuaGVhZGVycy5uZXh0KCkuZmlsdGVyKCBcIjpub3QoLnVpLWFjY29yZGlvbi1jb250ZW50LWFjdGl2ZSlcIiApLmhpZGUoKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5wYW5lbHMsIFwidWktYWNjb3JkaW9uLWNvbnRlbnRcIiwgXCJ1aS1oZWxwZXItcmVzZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0Ly8gQXZvaWQgbWVtb3J5IGxlYWtzICgjMTAwNTYpXG5cdFx0aWYgKCBwcmV2UGFuZWxzICkge1xuXHRcdFx0dGhpcy5fb2ZmKCBwcmV2SGVhZGVycy5ub3QoIHRoaXMuaGVhZGVycyApICk7XG5cdFx0XHR0aGlzLl9vZmYoIHByZXZQYW5lbHMubm90KCB0aGlzLnBhbmVscyApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbWF4SGVpZ2h0LFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGhlaWdodFN0eWxlID0gb3B0aW9ucy5oZWlnaHRTdHlsZSxcblx0XHRcdHBhcmVudCA9IHRoaXMuZWxlbWVudC5wYXJlbnQoKTtcblxuXHRcdHRoaXMuYWN0aXZlID0gdGhpcy5fZmluZEFjdGl2ZSggb3B0aW9ucy5hY3RpdmUgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5hY3RpdmUsIFwidWktYWNjb3JkaW9uLWhlYWRlci1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApXG5cdFx0XHQuX3JlbW92ZUNsYXNzKCB0aGlzLmFjdGl2ZSwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWNvbGxhcHNlZFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYWN0aXZlLm5leHQoKSwgXCJ1aS1hY2NvcmRpb24tY29udGVudC1hY3RpdmVcIiApO1xuXHRcdHRoaXMuYWN0aXZlLm5leHQoKS5zaG93KCk7XG5cblx0XHR0aGlzLmhlYWRlcnNcblx0XHRcdC5hdHRyKCBcInJvbGVcIiwgXCJ0YWJcIiApXG5cdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBoZWFkZXIgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0aGVhZGVySWQgPSBoZWFkZXIudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKSxcblx0XHRcdFx0XHRwYW5lbCA9IGhlYWRlci5uZXh0KCksXG5cdFx0XHRcdFx0cGFuZWxJZCA9IHBhbmVsLnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiICk7XG5cdFx0XHRcdGhlYWRlci5hdHRyKCBcImFyaWEtY29udHJvbHNcIiwgcGFuZWxJZCApO1xuXHRcdFx0XHRwYW5lbC5hdHRyKCBcImFyaWEtbGFiZWxsZWRieVwiLCBoZWFkZXJJZCApO1xuXHRcdFx0fSApXG5cdFx0XHQubmV4dCgpXG5cdFx0XHRcdC5hdHRyKCBcInJvbGVcIiwgXCJ0YWJwYW5lbFwiICk7XG5cblx0XHR0aGlzLmhlYWRlcnNcblx0XHRcdC5ub3QoIHRoaXMuYWN0aXZlIClcblx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcdFx0dGFiSW5kZXg6IC0xXG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQubmV4dCgpXG5cdFx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJ0cnVlXCJcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHQuaGlkZSgpO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIGF0IGxlYXN0IG9uZSBoZWFkZXIgaXMgaW4gdGhlIHRhYiBvcmRlclxuXHRcdGlmICggIXRoaXMuYWN0aXZlLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuaGVhZGVycy5lcSggMCApLmF0dHIoIFwidGFiSW5kZXhcIiwgMCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmFjdGl2ZS5hdHRyKCB7XG5cdFx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcInRydWVcIixcblx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHR0YWJJbmRleDogMFxuXHRcdFx0fSApXG5cdFx0XHRcdC5uZXh0KClcblx0XHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcImZhbHNlXCJcblx0XHRcdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fY3JlYXRlSWNvbnMoKTtcblxuXHRcdHRoaXMuX3NldHVwRXZlbnRzKCBvcHRpb25zLmV2ZW50ICk7XG5cblx0XHRpZiAoIGhlaWdodFN0eWxlID09PSBcImZpbGxcIiApIHtcblx0XHRcdG1heEhlaWdodCA9IHBhcmVudC5oZWlnaHQoKTtcblx0XHRcdHRoaXMuZWxlbWVudC5zaWJsaW5ncyggXCI6dmlzaWJsZVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbGVtID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdHBvc2l0aW9uID0gZWxlbS5jc3MoIFwicG9zaXRpb25cIiApO1xuXG5cdFx0XHRcdGlmICggcG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiB8fCBwb3NpdGlvbiA9PT0gXCJmaXhlZFwiICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRtYXhIZWlnaHQgLT0gZWxlbS5vdXRlckhlaWdodCggdHJ1ZSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmhlYWRlcnMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdG1heEhlaWdodCAtPSAkKCB0aGlzICkub3V0ZXJIZWlnaHQoIHRydWUgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5oZWFkZXJzLm5leHQoKVxuXHRcdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JCggdGhpcyApLmhlaWdodCggTWF0aC5tYXgoIDAsIG1heEhlaWdodCAtXG5cdFx0XHRcdFx0XHQkKCB0aGlzICkuaW5uZXJIZWlnaHQoKSArICQoIHRoaXMgKS5oZWlnaHQoKSApICk7XG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQuY3NzKCBcIm92ZXJmbG93XCIsIFwiYXV0b1wiICk7XG5cdFx0fSBlbHNlIGlmICggaGVpZ2h0U3R5bGUgPT09IFwiYXV0b1wiICkge1xuXHRcdFx0bWF4SGVpZ2h0ID0gMDtcblx0XHRcdHRoaXMuaGVhZGVycy5uZXh0KClcblx0XHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBpc1Zpc2libGUgPSAkKCB0aGlzICkuaXMoIFwiOnZpc2libGVcIiApO1xuXHRcdFx0XHRcdGlmICggIWlzVmlzaWJsZSApIHtcblx0XHRcdFx0XHRcdCQoIHRoaXMgKS5zaG93KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG1heEhlaWdodCA9IE1hdGgubWF4KCBtYXhIZWlnaHQsICQoIHRoaXMgKS5jc3MoIFwiaGVpZ2h0XCIsIFwiXCIgKS5oZWlnaHQoKSApO1xuXHRcdFx0XHRcdGlmICggIWlzVmlzaWJsZSApIHtcblx0XHRcdFx0XHRcdCQoIHRoaXMgKS5oaWRlKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IClcblx0XHRcdFx0LmhlaWdodCggbWF4SGVpZ2h0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hY3RpdmF0ZTogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHZhciBhY3RpdmUgPSB0aGlzLl9maW5kQWN0aXZlKCBpbmRleCApWyAwIF07XG5cblx0XHQvLyBUcnlpbmcgdG8gYWN0aXZhdGUgdGhlIGFscmVhZHkgYWN0aXZlIHBhbmVsXG5cdFx0aWYgKCBhY3RpdmUgPT09IHRoaXMuYWN0aXZlWyAwIF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gVHJ5aW5nIHRvIGNvbGxhcHNlLCBzaW11bGF0ZSBhIGNsaWNrIG9uIHRoZSBjdXJyZW50bHkgYWN0aXZlIGhlYWRlclxuXHRcdGFjdGl2ZSA9IGFjdGl2ZSB8fCB0aGlzLmFjdGl2ZVsgMCBdO1xuXG5cdFx0dGhpcy5fZXZlbnRIYW5kbGVyKCB7XG5cdFx0XHR0YXJnZXQ6IGFjdGl2ZSxcblx0XHRcdGN1cnJlbnRUYXJnZXQ6IGFjdGl2ZSxcblx0XHRcdHByZXZlbnREZWZhdWx0OiAkLm5vb3Bcblx0XHR9ICk7XG5cdH0sXG5cblx0X2ZpbmRBY3RpdmU6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdHlwZW9mIHNlbGVjdG9yID09PSBcIm51bWJlclwiID8gdGhpcy5oZWFkZXJzLmVxKCBzZWxlY3RvciApIDogJCgpO1xuXHR9LFxuXG5cdF9zZXR1cEV2ZW50czogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBldmVudHMgPSB7XG5cdFx0XHRrZXlkb3duOiBcIl9rZXlkb3duXCJcblx0XHR9O1xuXHRcdGlmICggZXZlbnQgKSB7XG5cdFx0XHQkLmVhY2goIGV2ZW50LnNwbGl0KCBcIiBcIiApLCBmdW5jdGlvbiggaW5kZXgsIGV2ZW50TmFtZSApIHtcblx0XHRcdFx0ZXZlbnRzWyBldmVudE5hbWUgXSA9IFwiX2V2ZW50SGFuZGxlclwiO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX29mZiggdGhpcy5oZWFkZXJzLmFkZCggdGhpcy5oZWFkZXJzLm5leHQoKSApICk7XG5cdFx0dGhpcy5fb24oIHRoaXMuaGVhZGVycywgZXZlbnRzICk7XG5cdFx0dGhpcy5fb24oIHRoaXMuaGVhZGVycy5uZXh0KCksIHsga2V5ZG93bjogXCJfcGFuZWxLZXlEb3duXCIgfSApO1xuXHRcdHRoaXMuX2hvdmVyYWJsZSggdGhpcy5oZWFkZXJzICk7XG5cdFx0dGhpcy5fZm9jdXNhYmxlKCB0aGlzLmhlYWRlcnMgKTtcblx0fSxcblxuXHRfZXZlbnRIYW5kbGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGFjdGl2ZUNoaWxkcmVuLCBjbGlja2VkQ2hpbGRyZW4sXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0YWN0aXZlID0gdGhpcy5hY3RpdmUsXG5cdFx0XHRjbGlja2VkID0gJCggZXZlbnQuY3VycmVudFRhcmdldCApLFxuXHRcdFx0Y2xpY2tlZElzQWN0aXZlID0gY2xpY2tlZFsgMCBdID09PSBhY3RpdmVbIDAgXSxcblx0XHRcdGNvbGxhcHNpbmcgPSBjbGlja2VkSXNBY3RpdmUgJiYgb3B0aW9ucy5jb2xsYXBzaWJsZSxcblx0XHRcdHRvU2hvdyA9IGNvbGxhcHNpbmcgPyAkKCkgOiBjbGlja2VkLm5leHQoKSxcblx0XHRcdHRvSGlkZSA9IGFjdGl2ZS5uZXh0KCksXG5cdFx0XHRldmVudERhdGEgPSB7XG5cdFx0XHRcdG9sZEhlYWRlcjogYWN0aXZlLFxuXHRcdFx0XHRvbGRQYW5lbDogdG9IaWRlLFxuXHRcdFx0XHRuZXdIZWFkZXI6IGNvbGxhcHNpbmcgPyAkKCkgOiBjbGlja2VkLFxuXHRcdFx0XHRuZXdQYW5lbDogdG9TaG93XG5cdFx0XHR9O1xuXG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdGlmIChcblxuXHRcdFx0XHQvLyBjbGljayBvbiBhY3RpdmUgaGVhZGVyLCBidXQgbm90IGNvbGxhcHNpYmxlXG5cdFx0XHRcdCggY2xpY2tlZElzQWN0aXZlICYmICFvcHRpb25zLmNvbGxhcHNpYmxlICkgfHxcblxuXHRcdFx0XHQvLyBhbGxvdyBjYW5jZWxpbmcgYWN0aXZhdGlvblxuXHRcdFx0XHQoIHRoaXMuX3RyaWdnZXIoIFwiYmVmb3JlQWN0aXZhdGVcIiwgZXZlbnQsIGV2ZW50RGF0YSApID09PSBmYWxzZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdG9wdGlvbnMuYWN0aXZlID0gY29sbGFwc2luZyA/IGZhbHNlIDogdGhpcy5oZWFkZXJzLmluZGV4KCBjbGlja2VkICk7XG5cblx0XHQvLyBXaGVuIHRoZSBjYWxsIHRvIC5fdG9nZ2xlKCkgY29tZXMgYWZ0ZXIgdGhlIGNsYXNzIGNoYW5nZXNcblx0XHQvLyBpdCBjYXVzZXMgYSB2ZXJ5IG9kZCBidWcgaW4gSUUgOCAoc2VlICM2NzIwKVxuXHRcdHRoaXMuYWN0aXZlID0gY2xpY2tlZElzQWN0aXZlID8gJCgpIDogY2xpY2tlZDtcblx0XHR0aGlzLl90b2dnbGUoIGV2ZW50RGF0YSApO1xuXG5cdFx0Ly8gU3dpdGNoIGNsYXNzZXNcblx0XHQvLyBjb3JuZXIgY2xhc3NlcyBvbiB0aGUgcHJldmlvdXNseSBhY3RpdmUgaGVhZGVyIHN0YXkgYWZ0ZXIgdGhlIGFuaW1hdGlvblxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBhY3RpdmUsIFwidWktYWNjb3JkaW9uLWhlYWRlci1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdGlmICggb3B0aW9ucy5pY29ucyApIHtcblx0XHRcdGFjdGl2ZUNoaWxkcmVuID0gYWN0aXZlLmNoaWxkcmVuKCBcIi51aS1hY2NvcmRpb24taGVhZGVyLWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGFjdGl2ZUNoaWxkcmVuLCBudWxsLCBvcHRpb25zLmljb25zLmFjdGl2ZUhlYWRlciApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIGFjdGl2ZUNoaWxkcmVuLCBudWxsLCBvcHRpb25zLmljb25zLmhlYWRlciApO1xuXHRcdH1cblxuXHRcdGlmICggIWNsaWNrZWRJc0FjdGl2ZSApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjbGlja2VkLCBcInVpLWFjY29yZGlvbi1oZWFkZXItY29sbGFwc2VkXCIgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBjbGlja2VkLCBcInVpLWFjY29yZGlvbi1oZWFkZXItYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdGlmICggb3B0aW9ucy5pY29ucyApIHtcblx0XHRcdFx0Y2xpY2tlZENoaWxkcmVuID0gY2xpY2tlZC5jaGlsZHJlbiggXCIudWktYWNjb3JkaW9uLWhlYWRlci1pY29uXCIgKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGNsaWNrZWRDaGlsZHJlbiwgbnVsbCwgb3B0aW9ucy5pY29ucy5oZWFkZXIgKVxuXHRcdFx0XHRcdC5fYWRkQ2xhc3MoIGNsaWNrZWRDaGlsZHJlbiwgbnVsbCwgb3B0aW9ucy5pY29ucy5hY3RpdmVIZWFkZXIgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGNsaWNrZWQubmV4dCgpLCBcInVpLWFjY29yZGlvbi1jb250ZW50LWFjdGl2ZVwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF90b2dnbGU6IGZ1bmN0aW9uKCBkYXRhICkge1xuXHRcdHZhciB0b1Nob3cgPSBkYXRhLm5ld1BhbmVsLFxuXHRcdFx0dG9IaWRlID0gdGhpcy5wcmV2U2hvdy5sZW5ndGggPyB0aGlzLnByZXZTaG93IDogZGF0YS5vbGRQYW5lbDtcblxuXHRcdC8vIEhhbmRsZSBhY3RpdmF0aW5nIGEgcGFuZWwgZHVyaW5nIHRoZSBhbmltYXRpb24gZm9yIGFub3RoZXIgYWN0aXZhdGlvblxuXHRcdHRoaXMucHJldlNob3cuYWRkKCB0aGlzLnByZXZIaWRlICkuc3RvcCggdHJ1ZSwgdHJ1ZSApO1xuXHRcdHRoaXMucHJldlNob3cgPSB0b1Nob3c7XG5cdFx0dGhpcy5wcmV2SGlkZSA9IHRvSGlkZTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmFuaW1hdGUgKSB7XG5cdFx0XHR0aGlzLl9hbmltYXRlKCB0b1Nob3csIHRvSGlkZSwgZGF0YSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0b0hpZGUuaGlkZSgpO1xuXHRcdFx0dG9TaG93LnNob3coKTtcblx0XHRcdHRoaXMuX3RvZ2dsZUNvbXBsZXRlKCBkYXRhICk7XG5cdFx0fVxuXG5cdFx0dG9IaWRlLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJ0cnVlXCJcblx0XHR9ICk7XG5cdFx0dG9IaWRlLnByZXYoKS5hdHRyKCB7XG5cdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIlxuXHRcdH0gKTtcblxuXHRcdC8vIGlmIHdlJ3JlIHN3aXRjaGluZyBwYW5lbHMsIHJlbW92ZSB0aGUgb2xkIGhlYWRlciBmcm9tIHRoZSB0YWIgb3JkZXJcblx0XHQvLyBpZiB3ZSdyZSBvcGVuaW5nIGZyb20gY29sbGFwc2VkIHN0YXRlLCByZW1vdmUgdGhlIHByZXZpb3VzIGhlYWRlciBmcm9tIHRoZSB0YWIgb3JkZXJcblx0XHQvLyBpZiB3ZSdyZSBjb2xsYXBzaW5nLCB0aGVuIGtlZXAgdGhlIGNvbGxhcHNpbmcgaGVhZGVyIGluIHRoZSB0YWIgb3JkZXJcblx0XHRpZiAoIHRvU2hvdy5sZW5ndGggJiYgdG9IaWRlLmxlbmd0aCApIHtcblx0XHRcdHRvSGlkZS5wcmV2KCkuYXR0cigge1xuXHRcdFx0XHRcInRhYkluZGV4XCI6IC0xLFxuXHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiXG5cdFx0XHR9ICk7XG5cdFx0fSBlbHNlIGlmICggdG9TaG93Lmxlbmd0aCApIHtcblx0XHRcdHRoaXMuaGVhZGVycy5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gcGFyc2VJbnQoICQoIHRoaXMgKS5hdHRyKCBcInRhYkluZGV4XCIgKSwgMTAgKSA9PT0gMDtcblx0XHRcdH0gKVxuXHRcdFx0XHQuYXR0ciggXCJ0YWJJbmRleFwiLCAtMSApO1xuXHRcdH1cblxuXHRcdHRvU2hvd1xuXHRcdFx0LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgXCJmYWxzZVwiIClcblx0XHRcdC5wcmV2KClcblx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcdHRhYkluZGV4OiAwXG5cdFx0XHRcdH0gKTtcblx0fSxcblxuXHRfYW5pbWF0ZTogZnVuY3Rpb24oIHRvU2hvdywgdG9IaWRlLCBkYXRhICkge1xuXHRcdHZhciB0b3RhbCwgZWFzaW5nLCBkdXJhdGlvbixcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0YWRqdXN0ID0gMCxcblx0XHRcdGJveFNpemluZyA9IHRvU2hvdy5jc3MoIFwiYm94LXNpemluZ1wiICksXG5cdFx0XHRkb3duID0gdG9TaG93Lmxlbmd0aCAmJlxuXHRcdFx0XHQoICF0b0hpZGUubGVuZ3RoIHx8ICggdG9TaG93LmluZGV4KCkgPCB0b0hpZGUuaW5kZXgoKSApICksXG5cdFx0XHRhbmltYXRlID0gdGhpcy5vcHRpb25zLmFuaW1hdGUgfHwge30sXG5cdFx0XHRvcHRpb25zID0gZG93biAmJiBhbmltYXRlLmRvd24gfHwgYW5pbWF0ZSxcblx0XHRcdGNvbXBsZXRlID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoYXQuX3RvZ2dsZUNvbXBsZXRlKCBkYXRhICk7XG5cdFx0XHR9O1xuXG5cdFx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJudW1iZXJcIiApIHtcblx0XHRcdGR1cmF0aW9uID0gb3B0aW9ucztcblx0XHR9XG5cdFx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGVhc2luZyA9IG9wdGlvbnM7XG5cdFx0fVxuXG5cdFx0Ly8gZmFsbCBiYWNrIGZyb20gb3B0aW9ucyB0byBhbmltYXRpb24gaW4gY2FzZSBvZiBwYXJ0aWFsIGRvd24gc2V0dGluZ3Ncblx0XHRlYXNpbmcgPSBlYXNpbmcgfHwgb3B0aW9ucy5lYXNpbmcgfHwgYW5pbWF0ZS5lYXNpbmc7XG5cdFx0ZHVyYXRpb24gPSBkdXJhdGlvbiB8fCBvcHRpb25zLmR1cmF0aW9uIHx8IGFuaW1hdGUuZHVyYXRpb247XG5cblx0XHRpZiAoICF0b0hpZGUubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRvU2hvdy5hbmltYXRlKCB0aGlzLnNob3dQcm9wcywgZHVyYXRpb24sIGVhc2luZywgY29tcGxldGUgKTtcblx0XHR9XG5cdFx0aWYgKCAhdG9TaG93Lmxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0b0hpZGUuYW5pbWF0ZSggdGhpcy5oaWRlUHJvcHMsIGR1cmF0aW9uLCBlYXNpbmcsIGNvbXBsZXRlICk7XG5cdFx0fVxuXG5cdFx0dG90YWwgPSB0b1Nob3cuc2hvdygpLm91dGVySGVpZ2h0KCk7XG5cdFx0dG9IaWRlLmFuaW1hdGUoIHRoaXMuaGlkZVByb3BzLCB7XG5cdFx0XHRkdXJhdGlvbjogZHVyYXRpb24sXG5cdFx0XHRlYXNpbmc6IGVhc2luZyxcblx0XHRcdHN0ZXA6IGZ1bmN0aW9uKCBub3csIGZ4ICkge1xuXHRcdFx0XHRmeC5ub3cgPSBNYXRoLnJvdW5kKCBub3cgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0dG9TaG93XG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYW5pbWF0ZSggdGhpcy5zaG93UHJvcHMsIHtcblx0XHRcdFx0ZHVyYXRpb246IGR1cmF0aW9uLFxuXHRcdFx0XHRlYXNpbmc6IGVhc2luZyxcblx0XHRcdFx0Y29tcGxldGU6IGNvbXBsZXRlLFxuXHRcdFx0XHRzdGVwOiBmdW5jdGlvbiggbm93LCBmeCApIHtcblx0XHRcdFx0XHRmeC5ub3cgPSBNYXRoLnJvdW5kKCBub3cgKTtcblx0XHRcdFx0XHRpZiAoIGZ4LnByb3AgIT09IFwiaGVpZ2h0XCIgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGJveFNpemluZyA9PT0gXCJjb250ZW50LWJveFwiICkge1xuXHRcdFx0XHRcdFx0XHRhZGp1c3QgKz0gZngubm93O1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHRoYXQub3B0aW9ucy5oZWlnaHRTdHlsZSAhPT0gXCJjb250ZW50XCIgKSB7XG5cdFx0XHRcdFx0XHRmeC5ub3cgPSBNYXRoLnJvdW5kKCB0b3RhbCAtIHRvSGlkZS5vdXRlckhlaWdodCgpIC0gYWRqdXN0ICk7XG5cdFx0XHRcdFx0XHRhZGp1c3QgPSAwO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHR9LFxuXG5cdF90b2dnbGVDb21wbGV0ZTogZnVuY3Rpb24oIGRhdGEgKSB7XG5cdFx0dmFyIHRvSGlkZSA9IGRhdGEub2xkUGFuZWwsXG5cdFx0XHRwcmV2ID0gdG9IaWRlLnByZXYoKTtcblxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0b0hpZGUsIFwidWktYWNjb3JkaW9uLWNvbnRlbnQtYWN0aXZlXCIgKTtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggcHJldiwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWFjdGl2ZVwiIClcblx0XHRcdC5fYWRkQ2xhc3MoIHByZXYsIFwidWktYWNjb3JkaW9uLWhlYWRlci1jb2xsYXBzZWRcIiApO1xuXG5cdFx0Ly8gV29yayBhcm91bmQgZm9yIHJlbmRlcmluZyBidWcgaW4gSUUgKCM1NDIxKVxuXHRcdGlmICggdG9IaWRlLmxlbmd0aCApIHtcblx0XHRcdHRvSGlkZS5wYXJlbnQoKVsgMCBdLmNsYXNzTmFtZSA9IHRvSGlkZS5wYXJlbnQoKVsgMCBdLmNsYXNzTmFtZTtcblx0XHR9XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJhY3RpdmF0ZVwiLCBudWxsLCBkYXRhICk7XG5cdH1cbn0gKTtcblxuXG5cbnZhciBzYWZlQWN0aXZlRWxlbWVudCA9ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQgPSBmdW5jdGlvbiggZG9jdW1lbnQgKSB7XG5cdHZhciBhY3RpdmVFbGVtZW50O1xuXG5cdC8vIFN1cHBvcnQ6IElFIDkgb25seVxuXHQvLyBJRTkgdGhyb3dzIGFuIFwiVW5zcGVjaWZpZWQgZXJyb3JcIiBhY2Nlc3NpbmcgZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBmcm9tIGFuIDxpZnJhbWU+XG5cdHRyeSB7XG5cdFx0YWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cdH0gY2F0Y2ggKCBlcnJvciApIHtcblx0XHRhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYm9keTtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IElFIDkgLSAxMSBvbmx5XG5cdC8vIElFIG1heSByZXR1cm4gbnVsbCBpbnN0ZWFkIG9mIGFuIGVsZW1lbnRcblx0Ly8gSW50ZXJlc3RpbmdseSwgdGhpcyBvbmx5IHNlZW1zIHRvIG9jY3VyIHdoZW4gTk9UIGluIGFuIGlmcmFtZVxuXHRpZiAoICFhY3RpdmVFbGVtZW50ICkge1xuXHRcdGFjdGl2ZUVsZW1lbnQgPSBkb2N1bWVudC5ib2R5O1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgMTEgb25seVxuXHQvLyBJRTExIHJldHVybnMgYSBzZWVtaW5nbHkgZW1wdHkgb2JqZWN0IGluIHNvbWUgY2FzZXMgd2hlbiBhY2Nlc3Npbmdcblx0Ly8gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCBmcm9tIGFuIDxpZnJhbWU+XG5cdGlmICggIWFjdGl2ZUVsZW1lbnQubm9kZU5hbWUgKSB7XG5cdFx0YWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmJvZHk7XG5cdH1cblxuXHRyZXR1cm4gYWN0aXZlRWxlbWVudDtcbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgTWVudSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogTWVudVxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IENyZWF0ZXMgbmVzdGFibGUgbWVudXMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vbWVudS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9tZW51L1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvbWVudS5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxudmFyIHdpZGdldHNNZW51ID0gJC53aWRnZXQoIFwidWkubWVudVwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjx1bD5cIixcblx0ZGVsYXk6IDMwMCxcblx0b3B0aW9uczoge1xuXHRcdGljb25zOiB7XG5cdFx0XHRzdWJtZW51OiBcInVpLWljb24tY2FyZXQtMS1lXCJcblx0XHR9LFxuXHRcdGl0ZW1zOiBcIj4gKlwiLFxuXHRcdG1lbnVzOiBcInVsXCIsXG5cdFx0cG9zaXRpb246IHtcblx0XHRcdG15OiBcImxlZnQgdG9wXCIsXG5cdFx0XHRhdDogXCJyaWdodCB0b3BcIlxuXHRcdH0sXG5cdFx0cm9sZTogXCJtZW51XCIsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRibHVyOiBudWxsLFxuXHRcdGZvY3VzOiBudWxsLFxuXHRcdHNlbGVjdDogbnVsbFxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuYWN0aXZlTWVudSA9IHRoaXMuZWxlbWVudDtcblxuXHRcdC8vIEZsYWcgdXNlZCB0byBwcmV2ZW50IGZpcmluZyBvZiB0aGUgY2xpY2sgaGFuZGxlclxuXHRcdC8vIGFzIHRoZSBldmVudCBidWJibGVzIHVwIHRocm91Z2ggbmVzdGVkIG1lbnVzXG5cdFx0dGhpcy5tb3VzZUhhbmRsZWQgPSBmYWxzZTtcblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC51bmlxdWVJZCgpXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRyb2xlOiB0aGlzLm9wdGlvbnMucm9sZSxcblx0XHRcdFx0dGFiSW5kZXg6IDBcblx0XHRcdH0gKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLW1lbnVcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXHRcdHRoaXMuX29uKCB7XG5cblx0XHRcdC8vIFByZXZlbnQgZm9jdXMgZnJvbSBzdGlja2luZyB0byBsaW5rcyBpbnNpZGUgbWVudSBhZnRlciBjbGlja2luZ1xuXHRcdFx0Ly8gdGhlbSAoZm9jdXMgc2hvdWxkIGFsd2F5cyBzdGF5IG9uIFVMIGR1cmluZyBuYXZpZ2F0aW9uKS5cblx0XHRcdFwibW91c2Vkb3duIC51aS1tZW51LWl0ZW1cIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fSxcblx0XHRcdFwiY2xpY2sgLnVpLW1lbnUtaXRlbVwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHZhciB0YXJnZXQgPSAkKCBldmVudC50YXJnZXQgKTtcblx0XHRcdFx0dmFyIGFjdGl2ZSA9ICQoICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICk7XG5cdFx0XHRcdGlmICggIXRoaXMubW91c2VIYW5kbGVkICYmIHRhcmdldC5ub3QoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdFx0dGhpcy5zZWxlY3QoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHQvLyBPbmx5IHNldCB0aGUgbW91c2VIYW5kbGVkIGZsYWcgaWYgdGhlIGV2ZW50IHdpbGwgYnViYmxlLCBzZWUgIzk0NjkuXG5cdFx0XHRcdFx0aWYgKCAhZXZlbnQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSApIHtcblx0XHRcdFx0XHRcdHRoaXMubW91c2VIYW5kbGVkID0gdHJ1ZTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBPcGVuIHN1Ym1lbnUgb24gY2xpY2tcblx0XHRcdFx0XHRpZiAoIHRhcmdldC5oYXMoIFwiLnVpLW1lbnVcIiApLmxlbmd0aCApIHtcblx0XHRcdFx0XHRcdHRoaXMuZXhwYW5kKCBldmVudCApO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoICF0aGlzLmVsZW1lbnQuaXMoIFwiOmZvY3VzXCIgKSAmJlxuXHRcdFx0XHRcdFx0XHRhY3RpdmUuY2xvc2VzdCggXCIudWktbWVudVwiICkubGVuZ3RoICkge1xuXG5cdFx0XHRcdFx0XHQvLyBSZWRpcmVjdCBmb2N1cyB0byB0aGUgbWVudVxuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiZm9jdXNcIiwgWyB0cnVlIF0gKTtcblxuXHRcdFx0XHRcdFx0Ly8gSWYgdGhlIGFjdGl2ZSBpdGVtIGlzIG9uIHRoZSB0b3AgbGV2ZWwsIGxldCBpdCBzdGF5IGFjdGl2ZS5cblx0XHRcdFx0XHRcdC8vIE90aGVyd2lzZSwgYmx1ciB0aGUgYWN0aXZlIGl0ZW0gc2luY2UgaXQgaXMgbm8gbG9uZ2VyIHZpc2libGUuXG5cdFx0XHRcdFx0XHRpZiAoIHRoaXMuYWN0aXZlICYmIHRoaXMuYWN0aXZlLnBhcmVudHMoIFwiLnVpLW1lbnVcIiApLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdFx0XHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0XCJtb3VzZWVudGVyIC51aS1tZW51LWl0ZW1cIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHRcdC8vIElnbm9yZSBtb3VzZSBldmVudHMgd2hpbGUgdHlwZWFoZWFkIGlzIGFjdGl2ZSwgc2VlICMxMDQ1OC5cblx0XHRcdFx0Ly8gUHJldmVudHMgZm9jdXNpbmcgdGhlIHdyb25nIGl0ZW0gd2hlbiB0eXBlYWhlYWQgY2F1c2VzIGEgc2Nyb2xsIHdoaWxlIHRoZSBtb3VzZVxuXHRcdFx0XHQvLyBpcyBvdmVyIGFuIGl0ZW0gaW4gdGhlIG1lbnVcblx0XHRcdFx0aWYgKCB0aGlzLnByZXZpb3VzRmlsdGVyICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHZhciBhY3R1YWxUYXJnZXQgPSAkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1tZW51LWl0ZW1cIiApLFxuXHRcdFx0XHRcdHRhcmdldCA9ICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKTtcblxuXHRcdFx0XHQvLyBJZ25vcmUgYnViYmxlZCBldmVudHMgb24gcGFyZW50IGl0ZW1zLCBzZWUgIzExNjQxXG5cdFx0XHRcdGlmICggYWN0dWFsVGFyZ2V0WyAwIF0gIT09IHRhcmdldFsgMCBdICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlbW92ZSB1aS1zdGF0ZS1hY3RpdmUgY2xhc3MgZnJvbSBzaWJsaW5ncyBvZiB0aGUgbmV3bHkgZm9jdXNlZCBtZW51IGl0ZW1cblx0XHRcdFx0Ly8gdG8gYXZvaWQgYSBqdW1wIGNhdXNlZCBieSBhZGphY2VudCBlbGVtZW50cyBib3RoIGhhdmluZyBhIGNsYXNzIHdpdGggYSBib3JkZXJcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRhcmdldC5zaWJsaW5ncygpLmNoaWxkcmVuKCBcIi51aS1zdGF0ZS1hY3RpdmVcIiApLFxuXHRcdFx0XHRcdG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIHRhcmdldCApO1xuXHRcdFx0fSxcblx0XHRcdG1vdXNlbGVhdmU6IFwiY29sbGFwc2VBbGxcIixcblx0XHRcdFwibW91c2VsZWF2ZSAudWktbWVudVwiOiBcImNvbGxhcHNlQWxsXCIsXG5cdFx0XHRmb2N1czogZnVuY3Rpb24oIGV2ZW50LCBrZWVwQWN0aXZlSXRlbSApIHtcblxuXHRcdFx0XHQvLyBJZiB0aGVyZSdzIGFscmVhZHkgYW4gYWN0aXZlIGl0ZW0sIGtlZXAgaXQgYWN0aXZlXG5cdFx0XHRcdC8vIElmIG5vdCwgYWN0aXZhdGUgdGhlIGZpcnN0IGl0ZW1cblx0XHRcdFx0dmFyIGl0ZW0gPSB0aGlzLmFjdGl2ZSB8fCB0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zICkuZXEoIDAgKTtcblxuXHRcdFx0XHRpZiAoICFrZWVwQWN0aXZlSXRlbSApIHtcblx0XHRcdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgaXRlbSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Ymx1cjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIG5vdENvbnRhaW5lZCA9ICEkLmNvbnRhaW5zKFxuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50WyAwIF0sXG5cdFx0XHRcdFx0XHQkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0aWYgKCBub3RDb250YWluZWQgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmNvbGxhcHNlQWxsKCBldmVudCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fSxcblx0XHRcdGtleWRvd246IFwiX2tleWRvd25cIlxuXHRcdH0gKTtcblxuXHRcdHRoaXMucmVmcmVzaCgpO1xuXG5cdFx0Ly8gQ2xpY2tzIG91dHNpZGUgb2YgYSBtZW51IGNvbGxhcHNlIGFueSBvcGVuIG1lbnVzXG5cdFx0dGhpcy5fb24oIHRoaXMuZG9jdW1lbnQsIHtcblx0XHRcdGNsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5fY2xvc2VPbkRvY3VtZW50Q2xpY2soIGV2ZW50ICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5jb2xsYXBzZUFsbCggZXZlbnQgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlc2V0IHRoZSBtb3VzZUhhbmRsZWQgZmxhZ1xuXHRcdFx0XHR0aGlzLm1vdXNlSGFuZGxlZCA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGl0ZW1zID0gdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLW1lbnUtaXRlbVwiIClcblx0XHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZSBhcmlhLWRpc2FibGVkXCIgKSxcblx0XHRcdHN1Ym1lbnVzID0gaXRlbXMuY2hpbGRyZW4oIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKVxuXHRcdFx0XHQucmVtb3ZlVW5pcXVlSWQoKVxuXHRcdFx0XHQucmVtb3ZlQXR0ciggXCJ0YWJJbmRleCByb2xlIGFyaWEtaGFzcG9wdXBcIiApO1xuXG5cdFx0Ly8gRGVzdHJveSAoc3ViKW1lbnVzXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQucmVtb3ZlQXR0ciggXCJhcmlhLWFjdGl2ZWRlc2NlbmRhbnRcIiApXG5cdFx0XHQuZmluZCggXCIudWktbWVudVwiICkuYWRkQmFjaygpXG5cdFx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGUgYXJpYS1sYWJlbGxlZGJ5IGFyaWEtZXhwYW5kZWQgYXJpYS1oaWRkZW4gYXJpYS1kaXNhYmxlZCBcIiArXG5cdFx0XHRcdFx0XCJ0YWJJbmRleFwiIClcblx0XHRcdFx0LnJlbW92ZVVuaXF1ZUlkKClcblx0XHRcdFx0LnNob3coKTtcblxuXHRcdHN1Ym1lbnVzLmNoaWxkcmVuKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZWxlbSA9ICQoIHRoaXMgKTtcblx0XHRcdGlmICggZWxlbS5kYXRhKCBcInVpLW1lbnUtc3VibWVudS1jYXJldFwiICkgKSB7XG5cdFx0XHRcdGVsZW0ucmVtb3ZlKCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9rZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG1hdGNoLCBwcmV2LCBjaGFyYWN0ZXIsIHNraXAsXG5cdFx0XHRwcmV2ZW50RGVmYXVsdCA9IHRydWU7XG5cblx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHR0aGlzLnByZXZpb3VzUGFnZSggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdHRoaXMubmV4dFBhZ2UoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5IT01FOlxuXHRcdFx0dGhpcy5fbW92ZSggXCJmaXJzdFwiLCBcImZpcnN0XCIsIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5FTkQ6XG5cdFx0XHR0aGlzLl9tb3ZlKCBcImxhc3RcIiwgXCJsYXN0XCIsIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5VUDpcblx0XHRcdHRoaXMucHJldmlvdXMoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5ET1dOOlxuXHRcdFx0dGhpcy5uZXh0KCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuTEVGVDpcblx0XHRcdHRoaXMuY29sbGFwc2UoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5SSUdIVDpcblx0XHRcdGlmICggdGhpcy5hY3RpdmUgJiYgIXRoaXMuYWN0aXZlLmlzKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSB7XG5cdFx0XHRcdHRoaXMuZXhwYW5kKCBldmVudCApO1xuXHRcdFx0fVxuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5URVI6XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuU1BBQ0U6XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkVTQ0FQRTpcblx0XHRcdHRoaXMuY29sbGFwc2UoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRkZWZhdWx0OlxuXHRcdFx0cHJldmVudERlZmF1bHQgPSBmYWxzZTtcblx0XHRcdHByZXYgPSB0aGlzLnByZXZpb3VzRmlsdGVyIHx8IFwiXCI7XG5cdFx0XHRza2lwID0gZmFsc2U7XG5cblx0XHRcdC8vIFN1cHBvcnQgbnVtYmVyIHBhZCB2YWx1ZXNcblx0XHRcdGNoYXJhY3RlciA9IGV2ZW50LmtleUNvZGUgPj0gOTYgJiYgZXZlbnQua2V5Q29kZSA8PSAxMDUgP1xuXHRcdFx0XHQoIGV2ZW50LmtleUNvZGUgLSA5NiApLnRvU3RyaW5nKCkgOiBTdHJpbmcuZnJvbUNoYXJDb2RlKCBldmVudC5rZXlDb2RlICk7XG5cblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5maWx0ZXJUaW1lciApO1xuXG5cdFx0XHRpZiAoIGNoYXJhY3RlciA9PT0gcHJldiApIHtcblx0XHRcdFx0c2tpcCA9IHRydWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjaGFyYWN0ZXIgPSBwcmV2ICsgY2hhcmFjdGVyO1xuXHRcdFx0fVxuXG5cdFx0XHRtYXRjaCA9IHRoaXMuX2ZpbHRlck1lbnVJdGVtcyggY2hhcmFjdGVyICk7XG5cdFx0XHRtYXRjaCA9IHNraXAgJiYgbWF0Y2guaW5kZXgoIHRoaXMuYWN0aXZlLm5leHQoKSApICE9PSAtMSA/XG5cdFx0XHRcdHRoaXMuYWN0aXZlLm5leHRBbGwoIFwiLnVpLW1lbnUtaXRlbVwiICkgOlxuXHRcdFx0XHRtYXRjaDtcblxuXHRcdFx0Ly8gSWYgbm8gbWF0Y2hlcyBvbiB0aGUgY3VycmVudCBmaWx0ZXIsIHJlc2V0IHRvIHRoZSBsYXN0IGNoYXJhY3RlciBwcmVzc2VkXG5cdFx0XHQvLyB0byBtb3ZlIGRvd24gdGhlIG1lbnUgdG8gdGhlIGZpcnN0IGl0ZW0gdGhhdCBzdGFydHMgd2l0aCB0aGF0IGNoYXJhY3RlclxuXHRcdFx0aWYgKCAhbWF0Y2gubGVuZ3RoICkge1xuXHRcdFx0XHRjaGFyYWN0ZXIgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCBldmVudC5rZXlDb2RlICk7XG5cdFx0XHRcdG1hdGNoID0gdGhpcy5fZmlsdGVyTWVudUl0ZW1zKCBjaGFyYWN0ZXIgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBtYXRjaC5sZW5ndGggKSB7XG5cdFx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBtYXRjaCApO1xuXHRcdFx0XHR0aGlzLnByZXZpb3VzRmlsdGVyID0gY2hhcmFjdGVyO1xuXHRcdFx0XHR0aGlzLmZpbHRlclRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGRlbGV0ZSB0aGlzLnByZXZpb3VzRmlsdGVyO1xuXHRcdFx0XHR9LCAxMDAwICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkZWxldGUgdGhpcy5wcmV2aW91c0ZpbHRlcjtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIHByZXZlbnREZWZhdWx0ICkge1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR9XG5cdH0sXG5cblx0X2FjdGl2YXRlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCB0aGlzLmFjdGl2ZSAmJiAhdGhpcy5hY3RpdmUuaXMoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSApIHtcblx0XHRcdGlmICggdGhpcy5hY3RpdmUuY2hpbGRyZW4oIFwiW2FyaWEtaGFzcG9wdXA9J3RydWUnXVwiICkubGVuZ3RoICkge1xuXHRcdFx0XHR0aGlzLmV4cGFuZCggZXZlbnQgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuc2VsZWN0KCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbWVudXMsIGl0ZW1zLCBuZXdTdWJtZW51cywgbmV3SXRlbXMsIG5ld1dyYXBwZXJzLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRpY29uID0gdGhpcy5vcHRpb25zLmljb25zLnN1Ym1lbnUsXG5cdFx0XHRzdWJtZW51cyA9IHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMubWVudXMgKTtcblxuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBcInVpLW1lbnUtaWNvbnNcIiwgbnVsbCwgISF0aGlzLmVsZW1lbnQuZmluZCggXCIudWktaWNvblwiICkubGVuZ3RoICk7XG5cblx0XHQvLyBJbml0aWFsaXplIG5lc3RlZCBtZW51c1xuXHRcdG5ld1N1Ym1lbnVzID0gc3VibWVudXMuZmlsdGVyKCBcIjpub3QoLnVpLW1lbnUpXCIgKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0cm9sZTogdGhpcy5vcHRpb25zLnJvbGUsXG5cdFx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCJcblx0XHRcdH0gKVxuXHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgbWVudSA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRpdGVtID0gbWVudS5wcmV2KCksXG5cdFx0XHRcdFx0c3VibWVudUNhcmV0ID0gJCggXCI8c3Bhbj5cIiApLmRhdGEoIFwidWktbWVudS1zdWJtZW51LWNhcmV0XCIsIHRydWUgKTtcblxuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc3VibWVudUNhcmV0LCBcInVpLW1lbnUtaWNvblwiLCBcInVpLWljb24gXCIgKyBpY29uICk7XG5cdFx0XHRcdGl0ZW1cblx0XHRcdFx0XHQuYXR0ciggXCJhcmlhLWhhc3BvcHVwXCIsIFwidHJ1ZVwiIClcblx0XHRcdFx0XHQucHJlcGVuZCggc3VibWVudUNhcmV0ICk7XG5cdFx0XHRcdG1lbnUuYXR0ciggXCJhcmlhLWxhYmVsbGVkYnlcIiwgaXRlbS5hdHRyKCBcImlkXCIgKSApO1xuXHRcdFx0fSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIG5ld1N1Ym1lbnVzLCBcInVpLW1lbnVcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnQgdWktZnJvbnRcIiApO1xuXG5cdFx0bWVudXMgPSBzdWJtZW51cy5hZGQoIHRoaXMuZWxlbWVudCApO1xuXHRcdGl0ZW1zID0gbWVudXMuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zICk7XG5cblx0XHQvLyBJbml0aWFsaXplIG1lbnUtaXRlbXMgY29udGFpbmluZyBzcGFjZXMgYW5kL29yIGRhc2hlcyBvbmx5IGFzIGRpdmlkZXJzXG5cdFx0aXRlbXMubm90KCBcIi51aS1tZW51LWl0ZW1cIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGl0ZW0gPSAkKCB0aGlzICk7XG5cdFx0XHRpZiAoIHRoYXQuX2lzRGl2aWRlciggaXRlbSApICkge1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggaXRlbSwgXCJ1aS1tZW51LWRpdmlkZXJcIiwgXCJ1aS13aWRnZXQtY29udGVudFwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0Ly8gRG9uJ3QgcmVmcmVzaCBsaXN0IGl0ZW1zIHRoYXQgYXJlIGFscmVhZHkgYWRhcHRlZFxuXHRcdG5ld0l0ZW1zID0gaXRlbXMubm90KCBcIi51aS1tZW51LWl0ZW0sIC51aS1tZW51LWRpdmlkZXJcIiApO1xuXHRcdG5ld1dyYXBwZXJzID0gbmV3SXRlbXMuY2hpbGRyZW4oKVxuXHRcdFx0Lm5vdCggXCIudWktbWVudVwiIClcblx0XHRcdFx0LnVuaXF1ZUlkKClcblx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHR0YWJJbmRleDogLTEsXG5cdFx0XHRcdFx0cm9sZTogdGhpcy5faXRlbVJvbGUoKVxuXHRcdFx0XHR9ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIG5ld0l0ZW1zLCBcInVpLW1lbnUtaXRlbVwiIClcblx0XHRcdC5fYWRkQ2xhc3MoIG5ld1dyYXBwZXJzLCBcInVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKTtcblxuXHRcdC8vIEFkZCBhcmlhLWRpc2FibGVkIGF0dHJpYnV0ZSB0byBhbnkgZGlzYWJsZWQgbWVudSBpdGVtXG5cdFx0aXRlbXMuZmlsdGVyKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkuYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIFwidHJ1ZVwiICk7XG5cblx0XHQvLyBJZiB0aGUgYWN0aXZlIGl0ZW0gaGFzIGJlZW4gcmVtb3ZlZCwgYmx1ciB0aGUgbWVudVxuXHRcdGlmICggdGhpcy5hY3RpdmUgJiYgISQuY29udGFpbnMoIHRoaXMuZWxlbWVudFsgMCBdLCB0aGlzLmFjdGl2ZVsgMCBdICkgKSB7XG5cdFx0XHR0aGlzLmJsdXIoKTtcblx0XHR9XG5cdH0sXG5cblx0X2l0ZW1Sb2xlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0bWVudTogXCJtZW51aXRlbVwiLFxuXHRcdFx0bGlzdGJveDogXCJvcHRpb25cIlxuXHRcdH1bIHRoaXMub3B0aW9ucy5yb2xlIF07XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvbnNcIiApIHtcblx0XHRcdHZhciBpY29ucyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1tZW51LWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGljb25zLCBudWxsLCB0aGlzLm9wdGlvbnMuaWNvbnMuc3VibWVudSApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIGljb25zLCBudWxsLCB2YWx1ZS5zdWJtZW51ICk7XG5cdFx0fVxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIFN0cmluZyggdmFsdWUgKSApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0fSxcblxuXHRmb2N1czogZnVuY3Rpb24oIGV2ZW50LCBpdGVtICkge1xuXHRcdHZhciBuZXN0ZWQsIGZvY3VzZWQsIGFjdGl2ZVBhcmVudDtcblx0XHR0aGlzLmJsdXIoIGV2ZW50LCBldmVudCAmJiBldmVudC50eXBlID09PSBcImZvY3VzXCIgKTtcblxuXHRcdHRoaXMuX3Njcm9sbEludG9WaWV3KCBpdGVtICk7XG5cblx0XHR0aGlzLmFjdGl2ZSA9IGl0ZW0uZmlyc3QoKTtcblxuXHRcdGZvY3VzZWQgPSB0aGlzLmFjdGl2ZS5jaGlsZHJlbiggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBmb2N1c2VkLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cblx0XHQvLyBPbmx5IHVwZGF0ZSBhcmlhLWFjdGl2ZWRlc2NlbmRhbnQgaWYgdGhlcmUncyBhIHJvbGVcblx0XHQvLyBvdGhlcndpc2Ugd2UgYXNzdW1lIGZvY3VzIGlzIG1hbmFnZWQgZWxzZXdoZXJlXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMucm9sZSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcImFyaWEtYWN0aXZlZGVzY2VuZGFudFwiLCBmb2N1c2VkLmF0dHIoIFwiaWRcIiApICk7XG5cdFx0fVxuXG5cdFx0Ly8gSGlnaGxpZ2h0IGFjdGl2ZSBwYXJlbnQgbWVudSBpdGVtLCBpZiBhbnlcblx0XHRhY3RpdmVQYXJlbnQgPSB0aGlzLmFjdGl2ZVxuXHRcdFx0LnBhcmVudCgpXG5cdFx0XHRcdC5jbG9zZXN0KCBcIi51aS1tZW51LWl0ZW1cIiApXG5cdFx0XHRcdFx0LmNoaWxkcmVuKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGFjdGl2ZVBhcmVudCwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXG5cdFx0aWYgKCBldmVudCAmJiBldmVudC50eXBlID09PSBcImtleWRvd25cIiApIHtcblx0XHRcdHRoaXMuX2Nsb3NlKCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMudGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuX2Nsb3NlKCk7XG5cdFx0XHR9LCB0aGlzLmRlbGF5ICk7XG5cdFx0fVxuXG5cdFx0bmVzdGVkID0gaXRlbS5jaGlsZHJlbiggXCIudWktbWVudVwiICk7XG5cdFx0aWYgKCBuZXN0ZWQubGVuZ3RoICYmIGV2ZW50ICYmICggL15tb3VzZS8udGVzdCggZXZlbnQudHlwZSApICkgKSB7XG5cdFx0XHR0aGlzLl9zdGFydE9wZW5pbmcoIG5lc3RlZCApO1xuXHRcdH1cblx0XHR0aGlzLmFjdGl2ZU1lbnUgPSBpdGVtLnBhcmVudCgpO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJmb2N1c1wiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKTtcblx0fSxcblxuXHRfc2Nyb2xsSW50b1ZpZXc6IGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdHZhciBib3JkZXJUb3AsIHBhZGRpbmdUb3AsIG9mZnNldCwgc2Nyb2xsLCBlbGVtZW50SGVpZ2h0LCBpdGVtSGVpZ2h0O1xuXHRcdGlmICggdGhpcy5faGFzU2Nyb2xsKCkgKSB7XG5cdFx0XHRib3JkZXJUb3AgPSBwYXJzZUZsb2F0KCAkLmNzcyggdGhpcy5hY3RpdmVNZW51WyAwIF0sIFwiYm9yZGVyVG9wV2lkdGhcIiApICkgfHwgMDtcblx0XHRcdHBhZGRpbmdUb3AgPSBwYXJzZUZsb2F0KCAkLmNzcyggdGhpcy5hY3RpdmVNZW51WyAwIF0sIFwicGFkZGluZ1RvcFwiICkgKSB8fCAwO1xuXHRcdFx0b2Zmc2V0ID0gaXRlbS5vZmZzZXQoKS50b3AgLSB0aGlzLmFjdGl2ZU1lbnUub2Zmc2V0KCkudG9wIC0gYm9yZGVyVG9wIC0gcGFkZGluZ1RvcDtcblx0XHRcdHNjcm9sbCA9IHRoaXMuYWN0aXZlTWVudS5zY3JvbGxUb3AoKTtcblx0XHRcdGVsZW1lbnRIZWlnaHQgPSB0aGlzLmFjdGl2ZU1lbnUuaGVpZ2h0KCk7XG5cdFx0XHRpdGVtSGVpZ2h0ID0gaXRlbS5vdXRlckhlaWdodCgpO1xuXG5cdFx0XHRpZiAoIG9mZnNldCA8IDAgKSB7XG5cdFx0XHRcdHRoaXMuYWN0aXZlTWVudS5zY3JvbGxUb3AoIHNjcm9sbCArIG9mZnNldCApO1xuXHRcdFx0fSBlbHNlIGlmICggb2Zmc2V0ICsgaXRlbUhlaWdodCA+IGVsZW1lbnRIZWlnaHQgKSB7XG5cdFx0XHRcdHRoaXMuYWN0aXZlTWVudS5zY3JvbGxUb3AoIHNjcm9sbCArIG9mZnNldCAtIGVsZW1lbnRIZWlnaHQgKyBpdGVtSGVpZ2h0ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdGJsdXI6IGZ1bmN0aW9uKCBldmVudCwgZnJvbUZvY3VzICkge1xuXHRcdGlmICggIWZyb21Gb2N1cyApIHtcblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdH1cblxuXHRcdGlmICggIXRoaXMuYWN0aXZlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmFjdGl2ZS5jaGlsZHJlbiggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApLFxuXHRcdFx0bnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJibHVyXCIsIGV2ZW50LCB7IGl0ZW06IHRoaXMuYWN0aXZlIH0gKTtcblx0XHR0aGlzLmFjdGl2ZSA9IG51bGw7XG5cdH0sXG5cblx0X3N0YXJ0T3BlbmluZzogZnVuY3Rpb24oIHN1Ym1lbnUgKSB7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cblx0XHQvLyBEb24ndCBvcGVuIGlmIGFscmVhZHkgb3BlbiBmaXhlcyBhIEZpcmVmb3ggYnVnIHRoYXQgY2F1c2VkIGEgLjUgcGl4ZWxcblx0XHQvLyBzaGlmdCBpbiB0aGUgc3VibWVudSBwb3NpdGlvbiB3aGVuIG1vdXNpbmcgb3ZlciB0aGUgY2FyZXQgaWNvblxuXHRcdGlmICggc3VibWVudS5hdHRyKCBcImFyaWEtaGlkZGVuXCIgKSAhPT0gXCJ0cnVlXCIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy50aW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX2Nsb3NlKCk7XG5cdFx0XHR0aGlzLl9vcGVuKCBzdWJtZW51ICk7XG5cdFx0fSwgdGhpcy5kZWxheSApO1xuXHR9LFxuXG5cdF9vcGVuOiBmdW5jdGlvbiggc3VibWVudSApIHtcblx0XHR2YXIgcG9zaXRpb24gPSAkLmV4dGVuZCgge1xuXHRcdFx0b2Y6IHRoaXMuYWN0aXZlXG5cdFx0fSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uICk7XG5cblx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHR0aGlzLmVsZW1lbnQuZmluZCggXCIudWktbWVudVwiICkubm90KCBzdWJtZW51LnBhcmVudHMoIFwiLnVpLW1lbnVcIiApIClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIFwidHJ1ZVwiICk7XG5cblx0XHRzdWJtZW51XG5cdFx0XHQuc2hvdygpXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJhcmlhLWhpZGRlblwiIClcblx0XHRcdC5hdHRyKCBcImFyaWEtZXhwYW5kZWRcIiwgXCJ0cnVlXCIgKVxuXHRcdFx0LnBvc2l0aW9uKCBwb3NpdGlvbiApO1xuXHR9LFxuXG5cdGNvbGxhcHNlQWxsOiBmdW5jdGlvbiggZXZlbnQsIGFsbCApIHtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHR0aGlzLnRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBJZiB3ZSB3ZXJlIHBhc3NlZCBhbiBldmVudCwgbG9vayBmb3IgdGhlIHN1Ym1lbnUgdGhhdCBjb250YWlucyB0aGUgZXZlbnRcblx0XHRcdHZhciBjdXJyZW50TWVudSA9IGFsbCA/IHRoaXMuZWxlbWVudCA6XG5cdFx0XHRcdCQoIGV2ZW50ICYmIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1tZW51XCIgKSApO1xuXG5cdFx0XHQvLyBJZiB3ZSBmb3VuZCBubyB2YWxpZCBzdWJtZW51IGFuY2VzdG9yLCB1c2UgdGhlIG1haW4gbWVudSB0byBjbG9zZSBhbGxcblx0XHRcdC8vIHN1YiBtZW51cyBhbnl3YXlcblx0XHRcdGlmICggIWN1cnJlbnRNZW51Lmxlbmd0aCApIHtcblx0XHRcdFx0Y3VycmVudE1lbnUgPSB0aGlzLmVsZW1lbnQ7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2Nsb3NlKCBjdXJyZW50TWVudSApO1xuXG5cdFx0XHR0aGlzLmJsdXIoIGV2ZW50ICk7XG5cblx0XHRcdC8vIFdvcmsgYXJvdW5kIGFjdGl2ZSBpdGVtIHN0YXlpbmcgYWN0aXZlIGFmdGVyIG1lbnUgaXMgYmx1cnJlZFxuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGN1cnJlbnRNZW51LmZpbmQoIFwiLnVpLXN0YXRlLWFjdGl2ZVwiICksIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblxuXHRcdFx0dGhpcy5hY3RpdmVNZW51ID0gY3VycmVudE1lbnU7XG5cdFx0fSwgdGhpcy5kZWxheSApO1xuXHR9LFxuXG5cdC8vIFdpdGggbm8gYXJndW1lbnRzLCBjbG9zZXMgdGhlIGN1cnJlbnRseSBhY3RpdmUgbWVudSAtIGlmIG5vdGhpbmcgaXMgYWN0aXZlXG5cdC8vIGl0IGNsb3NlcyBhbGwgbWVudXMuICBJZiBwYXNzZWQgYW4gYXJndW1lbnQsIGl0IHdpbGwgc2VhcmNoIGZvciBtZW51cyBCRUxPV1xuXHRfY2xvc2U6IGZ1bmN0aW9uKCBzdGFydE1lbnUgKSB7XG5cdFx0aWYgKCAhc3RhcnRNZW51ICkge1xuXHRcdFx0c3RhcnRNZW51ID0gdGhpcy5hY3RpdmUgPyB0aGlzLmFjdGl2ZS5wYXJlbnQoKSA6IHRoaXMuZWxlbWVudDtcblx0XHR9XG5cblx0XHRzdGFydE1lbnUuZmluZCggXCIudWktbWVudVwiIClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIFwidHJ1ZVwiIClcblx0XHRcdC5hdHRyKCBcImFyaWEtZXhwYW5kZWRcIiwgXCJmYWxzZVwiICk7XG5cdH0sXG5cblx0X2Nsb3NlT25Eb2N1bWVudENsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0cmV0dXJuICEkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1tZW51XCIgKS5sZW5ndGg7XG5cdH0sXG5cblx0X2lzRGl2aWRlcjogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cblx0XHQvLyBNYXRjaCBoeXBoZW4sIGVtIGRhc2gsIGVuIGRhc2hcblx0XHRyZXR1cm4gIS9bXlxcLVxcdTIwMTRcXHUyMDEzXFxzXS8udGVzdCggaXRlbS50ZXh0KCkgKTtcblx0fSxcblxuXHRjb2xsYXBzZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBuZXdJdGVtID0gdGhpcy5hY3RpdmUgJiZcblx0XHRcdHRoaXMuYWN0aXZlLnBhcmVudCgpLmNsb3Nlc3QoIFwiLnVpLW1lbnUtaXRlbVwiLCB0aGlzLmVsZW1lbnQgKTtcblx0XHRpZiAoIG5ld0l0ZW0gJiYgbmV3SXRlbS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLl9jbG9zZSgpO1xuXHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIG5ld0l0ZW0gKTtcblx0XHR9XG5cdH0sXG5cblx0ZXhwYW5kOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG5ld0l0ZW0gPSB0aGlzLmFjdGl2ZSAmJlxuXHRcdFx0dGhpcy5hY3RpdmVcblx0XHRcdFx0LmNoaWxkcmVuKCBcIi51aS1tZW51IFwiIClcblx0XHRcdFx0XHQuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zIClcblx0XHRcdFx0XHRcdC5maXJzdCgpO1xuXG5cdFx0aWYgKCBuZXdJdGVtICYmIG5ld0l0ZW0ubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5fb3BlbiggbmV3SXRlbS5wYXJlbnQoKSApO1xuXG5cdFx0XHQvLyBEZWxheSBzbyBGaXJlZm94IHdpbGwgbm90IGhpZGUgYWN0aXZlZGVzY2VuZGFudCBjaGFuZ2UgaW4gZXhwYW5kaW5nIHN1Ym1lbnUgZnJvbSBBVFxuXHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgbmV3SXRlbSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRuZXh0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5fbW92ZSggXCJuZXh0XCIsIFwiZmlyc3RcIiwgZXZlbnQgKTtcblx0fSxcblxuXHRwcmV2aW91czogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuX21vdmUoIFwicHJldlwiLCBcImxhc3RcIiwgZXZlbnQgKTtcblx0fSxcblxuXHRpc0ZpcnN0SXRlbTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuYWN0aXZlICYmICF0aGlzLmFjdGl2ZS5wcmV2QWxsKCBcIi51aS1tZW51LWl0ZW1cIiApLmxlbmd0aDtcblx0fSxcblxuXHRpc0xhc3RJdGVtOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5hY3RpdmUgJiYgIXRoaXMuYWN0aXZlLm5leHRBbGwoIFwiLnVpLW1lbnUtaXRlbVwiICkubGVuZ3RoO1xuXHR9LFxuXG5cdF9tb3ZlOiBmdW5jdGlvbiggZGlyZWN0aW9uLCBmaWx0ZXIsIGV2ZW50ICkge1xuXHRcdHZhciBuZXh0O1xuXHRcdGlmICggdGhpcy5hY3RpdmUgKSB7XG5cdFx0XHRpZiAoIGRpcmVjdGlvbiA9PT0gXCJmaXJzdFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsYXN0XCIgKSB7XG5cdFx0XHRcdG5leHQgPSB0aGlzLmFjdGl2ZVxuXHRcdFx0XHRcdFsgZGlyZWN0aW9uID09PSBcImZpcnN0XCIgPyBcInByZXZBbGxcIiA6IFwibmV4dEFsbFwiIF0oIFwiLnVpLW1lbnUtaXRlbVwiIClcblx0XHRcdFx0XHQuZXEoIC0xICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRuZXh0ID0gdGhpcy5hY3RpdmVcblx0XHRcdFx0XHRbIGRpcmVjdGlvbiArIFwiQWxsXCIgXSggXCIudWktbWVudS1pdGVtXCIgKVxuXHRcdFx0XHRcdC5lcSggMCApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoICFuZXh0IHx8ICFuZXh0Lmxlbmd0aCB8fCAhdGhpcy5hY3RpdmUgKSB7XG5cdFx0XHRuZXh0ID0gdGhpcy5hY3RpdmVNZW51LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApWyBmaWx0ZXIgXSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBuZXh0ICk7XG5cdH0sXG5cblx0bmV4dFBhZ2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaXRlbSwgYmFzZSwgaGVpZ2h0O1xuXG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUgKSB7XG5cdFx0XHR0aGlzLm5leHQoIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggdGhpcy5pc0xhc3RJdGVtKCkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggdGhpcy5faGFzU2Nyb2xsKCkgKSB7XG5cdFx0XHRiYXNlID0gdGhpcy5hY3RpdmUub2Zmc2V0KCkudG9wO1xuXHRcdFx0aGVpZ2h0ID0gdGhpcy5lbGVtZW50LmhlaWdodCgpO1xuXHRcdFx0dGhpcy5hY3RpdmUubmV4dEFsbCggXCIudWktbWVudS1pdGVtXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aXRlbSA9ICQoIHRoaXMgKTtcblx0XHRcdFx0cmV0dXJuIGl0ZW0ub2Zmc2V0KCkudG9wIC0gYmFzZSAtIGhlaWdodCA8IDA7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBpdGVtICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCB0aGlzLmFjdGl2ZU1lbnUuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zIClcblx0XHRcdFx0WyAhdGhpcy5hY3RpdmUgPyBcImZpcnN0XCIgOiBcImxhc3RcIiBdKCkgKTtcblx0XHR9XG5cdH0sXG5cblx0cHJldmlvdXNQYWdlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGl0ZW0sIGJhc2UsIGhlaWdodDtcblx0XHRpZiAoICF0aGlzLmFjdGl2ZSApIHtcblx0XHRcdHRoaXMubmV4dCggZXZlbnQgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLmlzRmlyc3RJdGVtKCkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggdGhpcy5faGFzU2Nyb2xsKCkgKSB7XG5cdFx0XHRiYXNlID0gdGhpcy5hY3RpdmUub2Zmc2V0KCkudG9wO1xuXHRcdFx0aGVpZ2h0ID0gdGhpcy5lbGVtZW50LmhlaWdodCgpO1xuXHRcdFx0dGhpcy5hY3RpdmUucHJldkFsbCggXCIudWktbWVudS1pdGVtXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aXRlbSA9ICQoIHRoaXMgKTtcblx0XHRcdFx0cmV0dXJuIGl0ZW0ub2Zmc2V0KCkudG9wIC0gYmFzZSArIGhlaWdodCA+IDA7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBpdGVtICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCB0aGlzLmFjdGl2ZU1lbnUuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zICkuZmlyc3QoKSApO1xuXHRcdH1cblx0fSxcblxuXHRfaGFzU2Nyb2xsOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5lbGVtZW50Lm91dGVySGVpZ2h0KCkgPCB0aGlzLmVsZW1lbnQucHJvcCggXCJzY3JvbGxIZWlnaHRcIiApO1xuXHR9LFxuXG5cdHNlbGVjdDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0Ly8gVE9ETzogSXQgc2hvdWxkIG5ldmVyIGJlIHBvc3NpYmxlIHRvIG5vdCBoYXZlIGFuIGFjdGl2ZSBpdGVtIGF0IHRoaXNcblx0XHQvLyBwb2ludCwgYnV0IHRoZSB0ZXN0cyBkb24ndCB0cmlnZ2VyIG1vdXNlZW50ZXIgYmVmb3JlIGNsaWNrLlxuXHRcdHRoaXMuYWN0aXZlID0gdGhpcy5hY3RpdmUgfHwgJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktbWVudS1pdGVtXCIgKTtcblx0XHR2YXIgdWkgPSB7IGl0ZW06IHRoaXMuYWN0aXZlIH07XG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUuaGFzKCBcIi51aS1tZW51XCIgKS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmNvbGxhcHNlQWxsKCBldmVudCwgdHJ1ZSApO1xuXHRcdH1cblx0XHR0aGlzLl90cmlnZ2VyKCBcInNlbGVjdFwiLCBldmVudCwgdWkgKTtcblx0fSxcblxuXHRfZmlsdGVyTWVudUl0ZW1zOiBmdW5jdGlvbiggY2hhcmFjdGVyICkge1xuXHRcdHZhciBlc2NhcGVkQ2hhcmFjdGVyID0gY2hhcmFjdGVyLnJlcGxhY2UoIC9bXFwtXFxbXFxde30oKSorPy4sXFxcXFxcXiR8I1xcc10vZywgXCJcXFxcJCZcIiApLFxuXHRcdFx0cmVnZXggPSBuZXcgUmVnRXhwKCBcIl5cIiArIGVzY2FwZWRDaGFyYWN0ZXIsIFwiaVwiICk7XG5cblx0XHRyZXR1cm4gdGhpcy5hY3RpdmVNZW51XG5cdFx0XHQuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zIClcblxuXHRcdFx0XHQvLyBPbmx5IG1hdGNoIG9uIGl0ZW1zLCBub3QgZGl2aWRlcnMgb3Igb3RoZXIgY29udGVudCAoIzEwNTcxKVxuXHRcdFx0XHQuZmlsdGVyKCBcIi51aS1tZW51LWl0ZW1cIiApXG5cdFx0XHRcdFx0LmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVnZXgudGVzdChcblx0XHRcdFx0XHRcdFx0JC50cmltKCAkKCB0aGlzICkuY2hpbGRyZW4oIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKS50ZXh0KCkgKSApO1xuXHRcdFx0XHRcdH0gKTtcblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEF1dG9jb21wbGV0ZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQXV0b2NvbXBsZXRlXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogTGlzdHMgc3VnZ2VzdGVkIHdvcmRzIGFzIHRoZSB1c2VyIGlzIHR5cGluZy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9hdXRvY29tcGxldGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vYXV0b2NvbXBsZXRlL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvYXV0b2NvbXBsZXRlLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5hdXRvY29tcGxldGVcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8aW5wdXQ+XCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhcHBlbmRUbzogbnVsbCxcblx0XHRhdXRvRm9jdXM6IGZhbHNlLFxuXHRcdGRlbGF5OiAzMDAsXG5cdFx0bWluTGVuZ3RoOiAxLFxuXHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRteTogXCJsZWZ0IHRvcFwiLFxuXHRcdFx0YXQ6IFwibGVmdCBib3R0b21cIixcblx0XHRcdGNvbGxpc2lvbjogXCJub25lXCJcblx0XHR9LFxuXHRcdHNvdXJjZTogbnVsbCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRjbG9zZTogbnVsbCxcblx0XHRmb2N1czogbnVsbCxcblx0XHRvcGVuOiBudWxsLFxuXHRcdHJlc3BvbnNlOiBudWxsLFxuXHRcdHNlYXJjaDogbnVsbCxcblx0XHRzZWxlY3Q6IG51bGxcblx0fSxcblxuXHRyZXF1ZXN0SW5kZXg6IDAsXG5cdHBlbmRpbmc6IDAsXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBTb21lIGJyb3dzZXJzIG9ubHkgcmVwZWF0IGtleWRvd24gZXZlbnRzLCBub3Qga2V5cHJlc3MgZXZlbnRzLFxuXHRcdC8vIHNvIHdlIHVzZSB0aGUgc3VwcHJlc3NLZXlQcmVzcyBmbGFnIHRvIGRldGVybWluZSBpZiB3ZSd2ZSBhbHJlYWR5XG5cdFx0Ly8gaGFuZGxlZCB0aGUga2V5ZG93biBldmVudC4gIzcyNjlcblx0XHQvLyBVbmZvcnR1bmF0ZWx5IHRoZSBjb2RlIGZvciAmIGluIGtleXByZXNzIGlzIHRoZSBzYW1lIGFzIHRoZSB1cCBhcnJvdyxcblx0XHQvLyBzbyB3ZSB1c2UgdGhlIHN1cHByZXNzS2V5UHJlc3NSZXBlYXQgZmxhZyB0byBhdm9pZCBoYW5kbGluZyBrZXlwcmVzc1xuXHRcdC8vIGV2ZW50cyB3aGVuIHdlIGtub3cgdGhlIGtleWRvd24gZXZlbnQgd2FzIHVzZWQgdG8gbW9kaWZ5IHRoZVxuXHRcdC8vIHNlYXJjaCB0ZXJtLiAjNzc5OVxuXHRcdHZhciBzdXBwcmVzc0tleVByZXNzLCBzdXBwcmVzc0tleVByZXNzUmVwZWF0LCBzdXBwcmVzc0lucHV0LFxuXHRcdFx0bm9kZU5hbWUgPSB0aGlzLmVsZW1lbnRbIDAgXS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLFxuXHRcdFx0aXNUZXh0YXJlYSA9IG5vZGVOYW1lID09PSBcInRleHRhcmVhXCIsXG5cdFx0XHRpc0lucHV0ID0gbm9kZU5hbWUgPT09IFwiaW5wdXRcIjtcblxuXHRcdC8vIFRleHRhcmVhcyBhcmUgYWx3YXlzIG11bHRpLWxpbmVcblx0XHQvLyBJbnB1dHMgYXJlIGFsd2F5cyBzaW5nbGUtbGluZSwgZXZlbiBpZiBpbnNpZGUgYSBjb250ZW50RWRpdGFibGUgZWxlbWVudFxuXHRcdC8vIElFIGFsc28gdHJlYXRzIGlucHV0cyBhcyBjb250ZW50RWRpdGFibGVcblx0XHQvLyBBbGwgb3RoZXIgZWxlbWVudCB0eXBlcyBhcmUgZGV0ZXJtaW5lZCBieSB3aGV0aGVyIG9yIG5vdCB0aGV5J3JlIGNvbnRlbnRFZGl0YWJsZVxuXHRcdHRoaXMuaXNNdWx0aUxpbmUgPSBpc1RleHRhcmVhIHx8ICFpc0lucHV0ICYmIHRoaXMuX2lzQ29udGVudEVkaXRhYmxlKCB0aGlzLmVsZW1lbnQgKTtcblxuXHRcdHRoaXMudmFsdWVNZXRob2QgPSB0aGlzLmVsZW1lbnRbIGlzVGV4dGFyZWEgfHwgaXNJbnB1dCA/IFwidmFsXCIgOiBcInRleHRcIiBdO1xuXHRcdHRoaXMuaXNOZXdNZW51ID0gdHJ1ZTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWF1dG9jb21wbGV0ZS1pbnB1dFwiICk7XG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwiYXV0b2NvbXBsZXRlXCIsIFwib2ZmXCIgKTtcblxuXHRcdHRoaXMuX29uKCB0aGlzLmVsZW1lbnQsIHtcblx0XHRcdGtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLmVsZW1lbnQucHJvcCggXCJyZWFkT25seVwiICkgKSB7XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0c3VwcHJlc3NJbnB1dCA9IHRydWU7XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzc1JlcGVhdCA9IHRydWU7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IGZhbHNlO1xuXHRcdFx0XHRzdXBwcmVzc0lucHV0ID0gZmFsc2U7XG5cdFx0XHRcdHN1cHByZXNzS2V5UHJlc3NSZXBlYXQgPSBmYWxzZTtcblx0XHRcdFx0dmFyIGtleUNvZGUgPSAkLnVpLmtleUNvZGU7XG5cdFx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwicHJldmlvdXNQYWdlXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJuZXh0UGFnZVwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuVVA6XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0dGhpcy5fa2V5RXZlbnQoIFwicHJldmlvdXNcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLkRPV046XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0dGhpcy5fa2V5RXZlbnQoIFwibmV4dFwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuRU5URVI6XG5cblx0XHRcdFx0XHQvLyB3aGVuIG1lbnUgaXMgb3BlbiBhbmQgaGFzIGZvY3VzXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1lbnUuYWN0aXZlICkge1xuXG5cdFx0XHRcdFx0XHQvLyAjNjA1NSAtIE9wZXJhIHN0aWxsIGFsbG93cyB0aGUga2V5cHJlc3MgdG8gb2NjdXJcblx0XHRcdFx0XHRcdC8vIHdoaWNoIGNhdXNlcyBmb3JtcyB0byBzdWJtaXRcblx0XHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdHRoaXMubWVudS5zZWxlY3QoIGV2ZW50ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuVEFCOlxuXHRcdFx0XHRcdGlmICggdGhpcy5tZW51LmFjdGl2ZSApIHtcblx0XHRcdFx0XHRcdHRoaXMubWVudS5zZWxlY3QoIGV2ZW50ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuRVNDQVBFOlxuXHRcdFx0XHRcdGlmICggdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0XHRcdFx0aWYgKCAhdGhpcy5pc011bHRpTGluZSApIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5fdmFsdWUoIHRoaXMudGVybSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdFx0Ly8gRGlmZmVyZW50IGJyb3dzZXJzIGhhdmUgZGlmZmVyZW50IGRlZmF1bHQgYmVoYXZpb3IgZm9yIGVzY2FwZVxuXHRcdFx0XHRcdFx0Ly8gU2luZ2xlIHByZXNzIGNhbiBtZWFuIHVuZG8gb3IgY2xlYXJcblx0XHRcdFx0XHRcdC8vIERvdWJsZSBwcmVzcyBpbiBJRSBtZWFucyBjbGVhciB0aGUgd2hvbGUgZm9ybVxuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzc1JlcGVhdCA9IHRydWU7XG5cblx0XHRcdFx0XHQvLyBzZWFyY2ggdGltZW91dCBzaG91bGQgYmUgdHJpZ2dlcmVkIGJlZm9yZSB0aGUgaW5wdXQgdmFsdWUgaXMgY2hhbmdlZFxuXHRcdFx0XHRcdHRoaXMuX3NlYXJjaFRpbWVvdXQoIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRrZXlwcmVzczogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHN1cHByZXNzS2V5UHJlc3MgKSB7XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IGZhbHNlO1xuXHRcdFx0XHRcdGlmICggIXRoaXMuaXNNdWx0aUxpbmUgfHwgdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggc3VwcHJlc3NLZXlQcmVzc1JlcGVhdCApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZXBsaWNhdGUgc29tZSBrZXkgaGFuZGxlcnMgdG8gYWxsb3cgdGhlbSB0byByZXBlYXQgaW4gRmlyZWZveCBhbmQgT3BlcmFcblx0XHRcdFx0dmFyIGtleUNvZGUgPSAkLnVpLmtleUNvZGU7XG5cdFx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwicHJldmlvdXNQYWdlXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJuZXh0UGFnZVwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuVVA6XG5cdFx0XHRcdFx0dGhpcy5fa2V5RXZlbnQoIFwicHJldmlvdXNcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLkRPV046XG5cdFx0XHRcdFx0dGhpcy5fa2V5RXZlbnQoIFwibmV4dFwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0aW5wdXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCBzdXBwcmVzc0lucHV0ICkge1xuXHRcdFx0XHRcdHN1cHByZXNzSW5wdXQgPSBmYWxzZTtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9zZWFyY2hUaW1lb3V0KCBldmVudCApO1xuXHRcdFx0fSxcblx0XHRcdGZvY3VzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSBudWxsO1xuXHRcdFx0XHR0aGlzLnByZXZpb3VzID0gdGhpcy5fdmFsdWUoKTtcblx0XHRcdH0sXG5cdFx0XHRibHVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5jYW5jZWxCbHVyICkge1xuXHRcdFx0XHRcdGRlbGV0ZSB0aGlzLmNhbmNlbEJsdXI7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnNlYXJjaGluZyApO1xuXHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0XHR0aGlzLl9jaGFuZ2UoIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5faW5pdFNvdXJjZSgpO1xuXHRcdHRoaXMubWVudSA9ICQoIFwiPHVsPlwiIClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApXG5cdFx0XHQubWVudSgge1xuXG5cdFx0XHRcdC8vIGRpc2FibGUgQVJJQSBzdXBwb3J0LCB0aGUgbGl2ZSByZWdpb24gdGFrZXMgY2FyZSBvZiB0aGF0XG5cdFx0XHRcdHJvbGU6IG51bGxcblx0XHRcdH0gKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0Lm1lbnUoIFwiaW5zdGFuY2VcIiApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubWVudS5lbGVtZW50LCBcInVpLWF1dG9jb21wbGV0ZVwiLCBcInVpLWZyb250XCIgKTtcblx0XHR0aGlzLl9vbiggdGhpcy5tZW51LmVsZW1lbnQsIHtcblx0XHRcdG1vdXNlZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHRcdC8vIHByZXZlbnQgbW92aW5nIGZvY3VzIG91dCBvZiB0aGUgdGV4dCBmaWVsZFxuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdC8vIElFIGRvZXNuJ3QgcHJldmVudCBtb3ZpbmcgZm9jdXMgZXZlbiB3aXRoIGV2ZW50LnByZXZlbnREZWZhdWx0KClcblx0XHRcdFx0Ly8gc28gd2Ugc2V0IGEgZmxhZyB0byBrbm93IHdoZW4gd2Ugc2hvdWxkIGlnbm9yZSB0aGUgYmx1ciBldmVudFxuXHRcdFx0XHR0aGlzLmNhbmNlbEJsdXIgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIHRoaXMuY2FuY2VsQmx1cjtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDggb25seVxuXHRcdFx0XHRcdC8vIFJpZ2h0IGNsaWNraW5nIGEgbWVudSBpdGVtIG9yIHNlbGVjdGluZyB0ZXh0IGZyb20gdGhlIG1lbnUgaXRlbXMgd2lsbFxuXHRcdFx0XHRcdC8vIHJlc3VsdCBpbiBmb2N1cyBtb3Zpbmcgb3V0IG9mIHRoZSBpbnB1dC4gSG93ZXZlciwgd2UndmUgYWxyZWFkeSByZWNlaXZlZFxuXHRcdFx0XHRcdC8vIGFuZCBpZ25vcmVkIHRoZSBibHVyIGV2ZW50IGJlY2F1c2Ugb2YgdGhlIGNhbmNlbEJsdXIgZmxhZyBzZXQgYWJvdmUuIFNvXG5cdFx0XHRcdFx0Ly8gd2UgcmVzdG9yZSBmb2N1cyB0byBlbnN1cmUgdGhhdCB0aGUgbWVudSBjbG9zZXMgcHJvcGVybHkgYmFzZWQgb24gdGhlIHVzZXInc1xuXHRcdFx0XHRcdC8vIG5leHQgYWN0aW9ucy5cblx0XHRcdFx0XHRpZiAoIHRoaXMuZWxlbWVudFsgMCBdICE9PSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApIHtcblx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0sXG5cdFx0XHRtZW51Zm9jdXM6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHZhciBsYWJlbCwgaXRlbTtcblxuXHRcdFx0XHQvLyBzdXBwb3J0OiBGaXJlZm94XG5cdFx0XHRcdC8vIFByZXZlbnQgYWNjaWRlbnRhbCBhY3RpdmF0aW9uIG9mIG1lbnUgaXRlbXMgaW4gRmlyZWZveCAoIzcwMjQgIzkxMTgpXG5cdFx0XHRcdGlmICggdGhpcy5pc05ld01lbnUgKSB7XG5cdFx0XHRcdFx0dGhpcy5pc05ld01lbnUgPSBmYWxzZTtcblx0XHRcdFx0XHRpZiAoIGV2ZW50Lm9yaWdpbmFsRXZlbnQgJiYgL15tb3VzZS8udGVzdCggZXZlbnQub3JpZ2luYWxFdmVudC50eXBlICkgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1lbnUuYmx1cigpO1xuXG5cdFx0XHRcdFx0XHR0aGlzLmRvY3VtZW50Lm9uZSggXCJtb3VzZW1vdmVcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdCQoIGV2ZW50LnRhcmdldCApLnRyaWdnZXIoIGV2ZW50Lm9yaWdpbmFsRXZlbnQgKTtcblx0XHRcdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGl0ZW0gPSB1aS5pdGVtLmRhdGEoIFwidWktYXV0b2NvbXBsZXRlLWl0ZW1cIiApO1xuXHRcdFx0XHRpZiAoIGZhbHNlICE9PSB0aGlzLl90cmlnZ2VyKCBcImZvY3VzXCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApICkge1xuXG5cdFx0XHRcdFx0Ly8gdXNlIHZhbHVlIHRvIG1hdGNoIHdoYXQgd2lsbCBlbmQgdXAgaW4gdGhlIGlucHV0LCBpZiBpdCB3YXMgYSBrZXkgZXZlbnRcblx0XHRcdFx0XHRpZiAoIGV2ZW50Lm9yaWdpbmFsRXZlbnQgJiYgL15rZXkvLnRlc3QoIGV2ZW50Lm9yaWdpbmFsRXZlbnQudHlwZSApICkge1xuXHRcdFx0XHRcdFx0dGhpcy5fdmFsdWUoIGl0ZW0udmFsdWUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBBbm5vdW5jZSB0aGUgdmFsdWUgaW4gdGhlIGxpdmVSZWdpb25cblx0XHRcdFx0bGFiZWwgPSB1aS5pdGVtLmF0dHIoIFwiYXJpYS1sYWJlbFwiICkgfHwgaXRlbS52YWx1ZTtcblx0XHRcdFx0aWYgKCBsYWJlbCAmJiAkLnRyaW0oIGxhYmVsICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdHRoaXMubGl2ZVJlZ2lvbi5jaGlsZHJlbigpLmhpZGUoKTtcblx0XHRcdFx0XHQkKCBcIjxkaXY+XCIgKS50ZXh0KCBsYWJlbCApLmFwcGVuZFRvKCB0aGlzLmxpdmVSZWdpb24gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdG1lbnVzZWxlY3Q6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHZhciBpdGVtID0gdWkuaXRlbS5kYXRhKCBcInVpLWF1dG9jb21wbGV0ZS1pdGVtXCIgKSxcblx0XHRcdFx0XHRwcmV2aW91cyA9IHRoaXMucHJldmlvdXM7XG5cblx0XHRcdFx0Ly8gT25seSB0cmlnZ2VyIHdoZW4gZm9jdXMgd2FzIGxvc3QgKGNsaWNrIG9uIG1lbnUpXG5cdFx0XHRcdGlmICggdGhpcy5lbGVtZW50WyAwIF0gIT09ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICkge1xuXHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0XHR0aGlzLnByZXZpb3VzID0gcHJldmlvdXM7XG5cblx0XHRcdFx0XHQvLyAjNjEwOSAtIElFIHRyaWdnZXJzIHR3byBmb2N1cyBldmVudHMgYW5kIHRoZSBzZWNvbmRcblx0XHRcdFx0XHQvLyBpcyBhc3luY2hyb25vdXMsIHNvIHdlIG5lZWQgdG8gcmVzZXQgdGhlIHByZXZpb3VzXG5cdFx0XHRcdFx0Ly8gdGVybSBzeW5jaHJvbm91c2x5IGFuZCBhc3luY2hyb25vdXNseSA6LShcblx0XHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnByZXZpb3VzID0gcHJldmlvdXM7XG5cdFx0XHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbSA9IGl0ZW07XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBmYWxzZSAhPT0gdGhpcy5fdHJpZ2dlciggXCJzZWxlY3RcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fdmFsdWUoIGl0ZW0udmFsdWUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlc2V0IHRoZSB0ZXJtIGFmdGVyIHRoZSBzZWxlY3QgZXZlbnRcblx0XHRcdFx0Ly8gdGhpcyBhbGxvd3MgY3VzdG9tIHNlbGVjdCBoYW5kbGluZyB0byB3b3JrIHByb3Blcmx5XG5cdFx0XHRcdHRoaXMudGVybSA9IHRoaXMuX3ZhbHVlKCk7XG5cblx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSBpdGVtO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMubGl2ZVJlZ2lvbiA9ICQoIFwiPGRpdj5cIiwge1xuXHRcdFx0cm9sZTogXCJzdGF0dXNcIixcblx0XHRcdFwiYXJpYS1saXZlXCI6IFwiYXNzZXJ0aXZlXCIsXG5cdFx0XHRcImFyaWEtcmVsZXZhbnRcIjogXCJhZGRpdGlvbnNcIlxuXHRcdH0gKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLmRvY3VtZW50WyAwIF0uYm9keSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGl2ZVJlZ2lvbiwgbnVsbCwgXCJ1aS1oZWxwZXItaGlkZGVuLWFjY2Vzc2libGVcIiApO1xuXG5cdFx0Ly8gVHVybmluZyBvZmYgYXV0b2NvbXBsZXRlIHByZXZlbnRzIHRoZSBicm93c2VyIGZyb20gcmVtZW1iZXJpbmcgdGhlXG5cdFx0Ly8gdmFsdWUgd2hlbiBuYXZpZ2F0aW5nIHRocm91Z2ggaGlzdG9yeSwgc28gd2UgcmUtZW5hYmxlIGF1dG9jb21wbGV0ZVxuXHRcdC8vIGlmIHRoZSBwYWdlIGlzIHVubG9hZGVkIGJlZm9yZSB0aGUgd2lkZ2V0IGlzIGRlc3Ryb3llZC4gIzc3OTBcblx0XHR0aGlzLl9vbiggdGhpcy53aW5kb3csIHtcblx0XHRcdGJlZm9yZXVubG9hZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcImF1dG9jb21wbGV0ZVwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMuc2VhcmNoaW5nICk7XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwiYXV0b2NvbXBsZXRlXCIgKTtcblx0XHR0aGlzLm1lbnUuZWxlbWVudC5yZW1vdmUoKTtcblx0XHR0aGlzLmxpdmVSZWdpb24ucmVtb3ZlKCk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0XHRpZiAoIGtleSA9PT0gXCJzb3VyY2VcIiApIHtcblx0XHRcdHRoaXMuX2luaXRTb3VyY2UoKTtcblx0XHR9XG5cdFx0aWYgKCBrZXkgPT09IFwiYXBwZW5kVG9cIiApIHtcblx0XHRcdHRoaXMubWVudS5lbGVtZW50LmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cdFx0fVxuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgJiYgdmFsdWUgJiYgdGhpcy54aHIgKSB7XG5cdFx0XHR0aGlzLnhoci5hYm9ydCgpO1xuXHRcdH1cblx0fSxcblxuXHRfaXNFdmVudFRhcmdldEluV2lkZ2V0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG1lbnVFbGVtZW50ID0gdGhpcy5tZW51LmVsZW1lbnRbIDAgXTtcblxuXHRcdHJldHVybiBldmVudC50YXJnZXQgPT09IHRoaXMuZWxlbWVudFsgMCBdIHx8XG5cdFx0XHRldmVudC50YXJnZXQgPT09IG1lbnVFbGVtZW50IHx8XG5cdFx0XHQkLmNvbnRhaW5zKCBtZW51RWxlbWVudCwgZXZlbnQudGFyZ2V0ICk7XG5cdH0sXG5cblx0X2Nsb3NlT25DbGlja091dHNpZGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLl9pc0V2ZW50VGFyZ2V0SW5XaWRnZXQoIGV2ZW50ICkgKSB7XG5cdFx0XHR0aGlzLmNsb3NlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hcHBlbmRUbzogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW1lbnQgPSB0aGlzLm9wdGlvbnMuYXBwZW5kVG87XG5cblx0XHRpZiAoIGVsZW1lbnQgKSB7XG5cdFx0XHRlbGVtZW50ID0gZWxlbWVudC5qcXVlcnkgfHwgZWxlbWVudC5ub2RlVHlwZSA/XG5cdFx0XHRcdCQoIGVsZW1lbnQgKSA6XG5cdFx0XHRcdHRoaXMuZG9jdW1lbnQuZmluZCggZWxlbWVudCApLmVxKCAwICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhZWxlbWVudCB8fCAhZWxlbWVudFsgMCBdICkge1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZWxlbWVudC5jbG9zZXN0KCBcIi51aS1mcm9udCwgZGlhbG9nXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoICFlbGVtZW50Lmxlbmd0aCApIHtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZWxlbWVudDtcblx0fSxcblxuXHRfaW5pdFNvdXJjZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGFycmF5LCB1cmwsXG5cdFx0XHR0aGF0ID0gdGhpcztcblx0XHRpZiAoICQuaXNBcnJheSggdGhpcy5vcHRpb25zLnNvdXJjZSApICkge1xuXHRcdFx0YXJyYXkgPSB0aGlzLm9wdGlvbnMuc291cmNlO1xuXHRcdFx0dGhpcy5zb3VyY2UgPSBmdW5jdGlvbiggcmVxdWVzdCwgcmVzcG9uc2UgKSB7XG5cdFx0XHRcdHJlc3BvbnNlKCAkLnVpLmF1dG9jb21wbGV0ZS5maWx0ZXIoIGFycmF5LCByZXF1ZXN0LnRlcm0gKSApO1xuXHRcdFx0fTtcblx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdGhpcy5vcHRpb25zLnNvdXJjZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHVybCA9IHRoaXMub3B0aW9ucy5zb3VyY2U7XG5cdFx0XHR0aGlzLnNvdXJjZSA9IGZ1bmN0aW9uKCByZXF1ZXN0LCByZXNwb25zZSApIHtcblx0XHRcdFx0aWYgKCB0aGF0LnhociApIHtcblx0XHRcdFx0XHR0aGF0Lnhoci5hYm9ydCgpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoYXQueGhyID0gJC5hamF4KCB7XG5cdFx0XHRcdFx0dXJsOiB1cmwsXG5cdFx0XHRcdFx0ZGF0YTogcmVxdWVzdCxcblx0XHRcdFx0XHRkYXRhVHlwZTogXCJqc29uXCIsXG5cdFx0XHRcdFx0c3VjY2VzczogZnVuY3Rpb24oIGRhdGEgKSB7XG5cdFx0XHRcdFx0XHRyZXNwb25zZSggZGF0YSApO1xuXHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0ZXJyb3I6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cmVzcG9uc2UoIFtdICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnNvdXJjZSA9IHRoaXMub3B0aW9ucy5zb3VyY2U7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZWFyY2hUaW1lb3V0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnNlYXJjaGluZyApO1xuXHRcdHRoaXMuc2VhcmNoaW5nID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBTZWFyY2ggaWYgdGhlIHZhbHVlIGhhcyBjaGFuZ2VkLCBvciBpZiB0aGUgdXNlciByZXR5cGVzIHRoZSBzYW1lIHZhbHVlIChzZWUgIzc0MzQpXG5cdFx0XHR2YXIgZXF1YWxWYWx1ZXMgPSB0aGlzLnRlcm0gPT09IHRoaXMuX3ZhbHVlKCksXG5cdFx0XHRcdG1lbnVWaXNpYmxlID0gdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApLFxuXHRcdFx0XHRtb2RpZmllcktleSA9IGV2ZW50LmFsdEtleSB8fCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXk7XG5cblx0XHRcdGlmICggIWVxdWFsVmFsdWVzIHx8ICggZXF1YWxWYWx1ZXMgJiYgIW1lbnVWaXNpYmxlICYmICFtb2RpZmllcktleSApICkge1xuXHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbSA9IG51bGw7XG5cdFx0XHRcdHRoaXMuc2VhcmNoKCBudWxsLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0sIHRoaXMub3B0aW9ucy5kZWxheSApO1xuXHR9LFxuXG5cdHNlYXJjaDogZnVuY3Rpb24oIHZhbHVlLCBldmVudCApIHtcblx0XHR2YWx1ZSA9IHZhbHVlICE9IG51bGwgPyB2YWx1ZSA6IHRoaXMuX3ZhbHVlKCk7XG5cblx0XHQvLyBBbHdheXMgc2F2ZSB0aGUgYWN0dWFsIHZhbHVlLCBub3QgdGhlIG9uZSBwYXNzZWQgYXMgYW4gYXJndW1lbnRcblx0XHR0aGlzLnRlcm0gPSB0aGlzLl92YWx1ZSgpO1xuXG5cdFx0aWYgKCB2YWx1ZS5sZW5ndGggPCB0aGlzLm9wdGlvbnMubWluTGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl90cmlnZ2VyKCBcInNlYXJjaFwiLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5fc2VhcmNoKCB2YWx1ZSApO1xuXHR9LFxuXG5cdF9zZWFyY2g6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLnBlbmRpbmcrKztcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1hdXRvY29tcGxldGUtbG9hZGluZ1wiICk7XG5cdFx0dGhpcy5jYW5jZWxTZWFyY2ggPSBmYWxzZTtcblxuXHRcdHRoaXMuc291cmNlKCB7IHRlcm06IHZhbHVlIH0sIHRoaXMuX3Jlc3BvbnNlKCkgKTtcblx0fSxcblxuXHRfcmVzcG9uc2U6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpbmRleCA9ICsrdGhpcy5yZXF1ZXN0SW5kZXg7XG5cblx0XHRyZXR1cm4gJC5wcm94eSggZnVuY3Rpb24oIGNvbnRlbnQgKSB7XG5cdFx0XHRpZiAoIGluZGV4ID09PSB0aGlzLnJlcXVlc3RJbmRleCApIHtcblx0XHRcdFx0dGhpcy5fX3Jlc3BvbnNlKCBjb250ZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMucGVuZGluZy0tO1xuXHRcdFx0aWYgKCAhdGhpcy5wZW5kaW5nICkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1hdXRvY29tcGxldGUtbG9hZGluZ1wiICk7XG5cdFx0XHR9XG5cdFx0fSwgdGhpcyApO1xuXHR9LFxuXG5cdF9fcmVzcG9uc2U6IGZ1bmN0aW9uKCBjb250ZW50ICkge1xuXHRcdGlmICggY29udGVudCApIHtcblx0XHRcdGNvbnRlbnQgPSB0aGlzLl9ub3JtYWxpemUoIGNvbnRlbnQgKTtcblx0XHR9XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJyZXNwb25zZVwiLCBudWxsLCB7IGNvbnRlbnQ6IGNvbnRlbnQgfSApO1xuXHRcdGlmICggIXRoaXMub3B0aW9ucy5kaXNhYmxlZCAmJiBjb250ZW50ICYmIGNvbnRlbnQubGVuZ3RoICYmICF0aGlzLmNhbmNlbFNlYXJjaCApIHtcblx0XHRcdHRoaXMuX3N1Z2dlc3QoIGNvbnRlbnQgKTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwib3BlblwiICk7XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gdXNlIC5fY2xvc2UoKSBpbnN0ZWFkIG9mIC5jbG9zZSgpIHNvIHdlIGRvbid0IGNhbmNlbCBmdXR1cmUgc2VhcmNoZXNcblx0XHRcdHRoaXMuX2Nsb3NlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdGNsb3NlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5jYW5jZWxTZWFyY2ggPSB0cnVlO1xuXHRcdHRoaXMuX2Nsb3NlKCBldmVudCApO1xuXHR9LFxuXG5cdF9jbG9zZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0Ly8gUmVtb3ZlIHRoZSBoYW5kbGVyIHRoYXQgY2xvc2VzIHRoZSBtZW51IG9uIG91dHNpZGUgY2xpY2tzXG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmRvY3VtZW50LCBcIm1vdXNlZG93blwiICk7XG5cblx0XHRpZiAoIHRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdHRoaXMubWVudS5lbGVtZW50LmhpZGUoKTtcblx0XHRcdHRoaXMubWVudS5ibHVyKCk7XG5cdFx0XHR0aGlzLmlzTmV3TWVudSA9IHRydWU7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNsb3NlXCIsIGV2ZW50ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9jaGFuZ2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIHRoaXMucHJldmlvdXMgIT09IHRoaXMuX3ZhbHVlKCkgKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgeyBpdGVtOiB0aGlzLnNlbGVjdGVkSXRlbSB9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9ub3JtYWxpemU6IGZ1bmN0aW9uKCBpdGVtcyApIHtcblxuXHRcdC8vIGFzc3VtZSBhbGwgaXRlbXMgaGF2ZSB0aGUgcmlnaHQgZm9ybWF0IHdoZW4gdGhlIGZpcnN0IGl0ZW0gaXMgY29tcGxldGVcblx0XHRpZiAoIGl0ZW1zLmxlbmd0aCAmJiBpdGVtc1sgMCBdLmxhYmVsICYmIGl0ZW1zWyAwIF0udmFsdWUgKSB7XG5cdFx0XHRyZXR1cm4gaXRlbXM7XG5cdFx0fVxuXHRcdHJldHVybiAkLm1hcCggaXRlbXMsIGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgaXRlbSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0XHRsYWJlbDogaXRlbSxcblx0XHRcdFx0XHR2YWx1ZTogaXRlbVxuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuICQuZXh0ZW5kKCB7fSwgaXRlbSwge1xuXHRcdFx0XHRsYWJlbDogaXRlbS5sYWJlbCB8fCBpdGVtLnZhbHVlLFxuXHRcdFx0XHR2YWx1ZTogaXRlbS52YWx1ZSB8fCBpdGVtLmxhYmVsXG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9zdWdnZXN0OiBmdW5jdGlvbiggaXRlbXMgKSB7XG5cdFx0dmFyIHVsID0gdGhpcy5tZW51LmVsZW1lbnQuZW1wdHkoKTtcblx0XHR0aGlzLl9yZW5kZXJNZW51KCB1bCwgaXRlbXMgKTtcblx0XHR0aGlzLmlzTmV3TWVudSA9IHRydWU7XG5cdFx0dGhpcy5tZW51LnJlZnJlc2goKTtcblxuXHRcdC8vIFNpemUgYW5kIHBvc2l0aW9uIG1lbnVcblx0XHR1bC5zaG93KCk7XG5cdFx0dGhpcy5fcmVzaXplTWVudSgpO1xuXHRcdHVsLnBvc2l0aW9uKCAkLmV4dGVuZCgge1xuXHRcdFx0b2Y6IHRoaXMuZWxlbWVudFxuXHRcdH0sIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5hdXRvRm9jdXMgKSB7XG5cdFx0XHR0aGlzLm1lbnUubmV4dCgpO1xuXHRcdH1cblxuXHRcdC8vIExpc3RlbiBmb3IgaW50ZXJhY3Rpb25zIG91dHNpZGUgb2YgdGhlIHdpZGdldCAoIzY2NDIpXG5cdFx0dGhpcy5fb24oIHRoaXMuZG9jdW1lbnQsIHtcblx0XHRcdG1vdXNlZG93bjogXCJfY2xvc2VPbkNsaWNrT3V0c2lkZVwiXG5cdFx0fSApO1xuXHR9LFxuXG5cdF9yZXNpemVNZW51OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdWwgPSB0aGlzLm1lbnUuZWxlbWVudDtcblx0XHR1bC5vdXRlcldpZHRoKCBNYXRoLm1heChcblxuXHRcdFx0Ly8gRmlyZWZveCB3cmFwcyBsb25nIHRleHQgKHBvc3NpYmx5IGEgcm91bmRpbmcgYnVnKVxuXHRcdFx0Ly8gc28gd2UgYWRkIDFweCB0byBhdm9pZCB0aGUgd3JhcHBpbmcgKCM3NTEzKVxuXHRcdFx0dWwud2lkdGgoIFwiXCIgKS5vdXRlcldpZHRoKCkgKyAxLFxuXHRcdFx0dGhpcy5lbGVtZW50Lm91dGVyV2lkdGgoKVxuXHRcdCkgKTtcblx0fSxcblxuXHRfcmVuZGVyTWVudTogZnVuY3Rpb24oIHVsLCBpdGVtcyApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0JC5lYWNoKCBpdGVtcywgZnVuY3Rpb24oIGluZGV4LCBpdGVtICkge1xuXHRcdFx0dGhhdC5fcmVuZGVySXRlbURhdGEoIHVsLCBpdGVtICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9yZW5kZXJJdGVtRGF0YTogZnVuY3Rpb24oIHVsLCBpdGVtICkge1xuXHRcdHJldHVybiB0aGlzLl9yZW5kZXJJdGVtKCB1bCwgaXRlbSApLmRhdGEoIFwidWktYXV0b2NvbXBsZXRlLWl0ZW1cIiwgaXRlbSApO1xuXHR9LFxuXG5cdF9yZW5kZXJJdGVtOiBmdW5jdGlvbiggdWwsIGl0ZW0gKSB7XG5cdFx0cmV0dXJuICQoIFwiPGxpPlwiIClcblx0XHRcdC5hcHBlbmQoICQoIFwiPGRpdj5cIiApLnRleHQoIGl0ZW0ubGFiZWwgKSApXG5cdFx0XHQuYXBwZW5kVG8oIHVsICk7XG5cdH0sXG5cblx0X21vdmU6IGZ1bmN0aW9uKCBkaXJlY3Rpb24sIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdHRoaXMuc2VhcmNoKCBudWxsLCBldmVudCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMubWVudS5pc0ZpcnN0SXRlbSgpICYmIC9ecHJldmlvdXMvLnRlc3QoIGRpcmVjdGlvbiApIHx8XG5cdFx0XHRcdHRoaXMubWVudS5pc0xhc3RJdGVtKCkgJiYgL15uZXh0Ly50ZXN0KCBkaXJlY3Rpb24gKSApIHtcblxuXHRcdFx0aWYgKCAhdGhpcy5pc011bHRpTGluZSApIHtcblx0XHRcdFx0dGhpcy5fdmFsdWUoIHRoaXMudGVybSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLm1lbnUuYmx1cigpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLm1lbnVbIGRpcmVjdGlvbiBdKCBldmVudCApO1xuXHR9LFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubWVudS5lbGVtZW50O1xuXHR9LFxuXG5cdF92YWx1ZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMudmFsdWVNZXRob2QuYXBwbHkoIHRoaXMuZWxlbWVudCwgYXJndW1lbnRzICk7XG5cdH0sXG5cblx0X2tleUV2ZW50OiBmdW5jdGlvbigga2V5RXZlbnQsIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMuaXNNdWx0aUxpbmUgfHwgdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0dGhpcy5fbW92ZSgga2V5RXZlbnQsIGV2ZW50ICk7XG5cblx0XHRcdC8vIFByZXZlbnRzIG1vdmluZyBjdXJzb3IgdG8gYmVnaW5uaW5nL2VuZCBvZiB0aGUgdGV4dCBmaWVsZCBpbiBzb21lIGJyb3dzZXJzXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH1cblx0fSxcblxuXHQvLyBTdXBwb3J0OiBDaHJvbWUgPD01MFxuXHQvLyBXZSBzaG91bGQgYmUgYWJsZSB0byBqdXN0IHVzZSB0aGlzLmVsZW1lbnQucHJvcCggXCJpc0NvbnRlbnRFZGl0YWJsZVwiIClcblx0Ly8gYnV0IGhpZGRlbiBlbGVtZW50cyBhbHdheXMgcmVwb3J0IGZhbHNlIGluIENocm9tZS5cblx0Ly8gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTMxMzA4MlxuXHRfaXNDb250ZW50RWRpdGFibGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdGlmICggIWVsZW1lbnQubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZhciBlZGl0YWJsZSA9IGVsZW1lbnQucHJvcCggXCJjb250ZW50RWRpdGFibGVcIiApO1xuXG5cdFx0aWYgKCBlZGl0YWJsZSA9PT0gXCJpbmhlcml0XCIgKSB7XG5cdFx0ICByZXR1cm4gdGhpcy5faXNDb250ZW50RWRpdGFibGUoIGVsZW1lbnQucGFyZW50KCkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZWRpdGFibGUgPT09IFwidHJ1ZVwiO1xuXHR9XG59ICk7XG5cbiQuZXh0ZW5kKCAkLnVpLmF1dG9jb21wbGV0ZSwge1xuXHRlc2NhcGVSZWdleDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiB2YWx1ZS5yZXBsYWNlKCAvW1xcLVxcW1xcXXt9KCkqKz8uLFxcXFxcXF4kfCNcXHNdL2csIFwiXFxcXCQmXCIgKTtcblx0fSxcblx0ZmlsdGVyOiBmdW5jdGlvbiggYXJyYXksIHRlcm0gKSB7XG5cdFx0dmFyIG1hdGNoZXIgPSBuZXcgUmVnRXhwKCAkLnVpLmF1dG9jb21wbGV0ZS5lc2NhcGVSZWdleCggdGVybSApLCBcImlcIiApO1xuXHRcdHJldHVybiAkLmdyZXAoIGFycmF5LCBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHRyZXR1cm4gbWF0Y2hlci50ZXN0KCB2YWx1ZS5sYWJlbCB8fCB2YWx1ZS52YWx1ZSB8fCB2YWx1ZSApO1xuXHRcdH0gKTtcblx0fVxufSApO1xuXG4vLyBMaXZlIHJlZ2lvbiBleHRlbnNpb24sIGFkZGluZyBhIGBtZXNzYWdlc2Agb3B0aW9uXG4vLyBOT1RFOiBUaGlzIGlzIGFuIGV4cGVyaW1lbnRhbCBBUEkuIFdlIGFyZSBzdGlsbCBpbnZlc3RpZ2F0aW5nXG4vLyBhIGZ1bGwgc29sdXRpb24gZm9yIHN0cmluZyBtYW5pcHVsYXRpb24gYW5kIGludGVybmF0aW9uYWxpemF0aW9uLlxuJC53aWRnZXQoIFwidWkuYXV0b2NvbXBsZXRlXCIsICQudWkuYXV0b2NvbXBsZXRlLCB7XG5cdG9wdGlvbnM6IHtcblx0XHRtZXNzYWdlczoge1xuXHRcdFx0bm9SZXN1bHRzOiBcIk5vIHNlYXJjaCByZXN1bHRzLlwiLFxuXHRcdFx0cmVzdWx0czogZnVuY3Rpb24oIGFtb3VudCApIHtcblx0XHRcdFx0cmV0dXJuIGFtb3VudCArICggYW1vdW50ID4gMSA/IFwiIHJlc3VsdHMgYXJlXCIgOiBcIiByZXN1bHQgaXNcIiApICtcblx0XHRcdFx0XHRcIiBhdmFpbGFibGUsIHVzZSB1cCBhbmQgZG93biBhcnJvdyBrZXlzIHRvIG5hdmlnYXRlLlwiO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfX3Jlc3BvbnNlOiBmdW5jdGlvbiggY29udGVudCApIHtcblx0XHR2YXIgbWVzc2FnZTtcblx0XHR0aGlzLl9zdXBlckFwcGx5KCBhcmd1bWVudHMgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCB8fCB0aGlzLmNhbmNlbFNlYXJjaCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCBjb250ZW50ICYmIGNvbnRlbnQubGVuZ3RoICkge1xuXHRcdFx0bWVzc2FnZSA9IHRoaXMub3B0aW9ucy5tZXNzYWdlcy5yZXN1bHRzKCBjb250ZW50Lmxlbmd0aCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRtZXNzYWdlID0gdGhpcy5vcHRpb25zLm1lc3NhZ2VzLm5vUmVzdWx0cztcblx0XHR9XG5cdFx0dGhpcy5saXZlUmVnaW9uLmNoaWxkcmVuKCkuaGlkZSgpO1xuXHRcdCQoIFwiPGRpdj5cIiApLnRleHQoIG1lc3NhZ2UgKS5hcHBlbmRUbyggdGhpcy5saXZlUmVnaW9uICk7XG5cdH1cbn0gKTtcblxudmFyIHdpZGdldHNBdXRvY29tcGxldGUgPSAkLnVpLmF1dG9jb21wbGV0ZTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBDb250cm9sZ3JvdXAgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IENvbnRyb2xncm91cFxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IFZpc3VhbGx5IGdyb3VwcyBmb3JtIGNvbnRyb2wgd2lkZ2V0c1xuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2NvbnRyb2xncm91cC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9jb250cm9sZ3JvdXAvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb250cm9sZ3JvdXAuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG52YXIgY29udHJvbGdyb3VwQ29ybmVyUmVnZXggPSAvdWktY29ybmVyLShbYS16XSl7Miw2fS9nO1xuXG52YXIgd2lkZ2V0c0NvbnRyb2xncm91cCA9ICQud2lkZ2V0KCBcInVpLmNvbnRyb2xncm91cFwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxkaXY+XCIsXG5cdG9wdGlvbnM6IHtcblx0XHRkaXJlY3Rpb246IFwiaG9yaXpvbnRhbFwiLFxuXHRcdGRpc2FibGVkOiBudWxsLFxuXHRcdG9ubHlWaXNpYmxlOiB0cnVlLFxuXHRcdGl0ZW1zOiB7XG5cdFx0XHRcImJ1dHRvblwiOiBcImlucHV0W3R5cGU9YnV0dG9uXSwgaW5wdXRbdHlwZT1zdWJtaXRdLCBpbnB1dFt0eXBlPXJlc2V0XSwgYnV0dG9uLCBhXCIsXG5cdFx0XHRcImNvbnRyb2xncm91cExhYmVsXCI6IFwiLnVpLWNvbnRyb2xncm91cC1sYWJlbFwiLFxuXHRcdFx0XCJjaGVja2JveHJhZGlvXCI6IFwiaW5wdXRbdHlwZT0nY2hlY2tib3gnXSwgaW5wdXRbdHlwZT0ncmFkaW8nXVwiLFxuXHRcdFx0XCJzZWxlY3RtZW51XCI6IFwic2VsZWN0XCIsXG5cdFx0XHRcInNwaW5uZXJcIjogXCIudWktc3Bpbm5lci1pbnB1dFwiXG5cdFx0fVxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2VuaGFuY2UoKTtcblx0fSxcblxuXHQvLyBUbyBzdXBwb3J0IHRoZSBlbmhhbmNlZCBvcHRpb24gaW4galF1ZXJ5IE1vYmlsZSwgd2UgaXNvbGF0ZSBET00gbWFuaXB1bGF0aW9uXG5cdF9lbmhhbmNlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJyb2xlXCIsIFwidG9vbGJhclwiICk7XG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2NhbGxDaGlsZE1ldGhvZCggXCJkZXN0cm95XCIgKTtcblx0XHR0aGlzLmNoaWxkV2lkZ2V0cy5yZW1vdmVEYXRhKCBcInVpLWNvbnRyb2xncm91cC1kYXRhXCIgKTtcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJyb2xlXCIgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5pdGVtcy5jb250cm9sZ3JvdXBMYWJlbCApIHtcblx0XHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0XHQuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zLmNvbnRyb2xncm91cExhYmVsIClcblx0XHRcdFx0LmZpbmQoIFwiLnVpLWNvbnRyb2xncm91cC1sYWJlbC1jb250ZW50c1wiIClcblx0XHRcdFx0LmNvbnRlbnRzKCkudW53cmFwKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pbml0V2lkZ2V0czogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0Y2hpbGRXaWRnZXRzID0gW107XG5cblx0XHQvLyBGaXJzdCB3ZSBpdGVyYXRlIG92ZXIgZWFjaCBvZiB0aGUgaXRlbXMgb3B0aW9uc1xuXHRcdCQuZWFjaCggdGhpcy5vcHRpb25zLml0ZW1zLCBmdW5jdGlvbiggd2lkZ2V0LCBzZWxlY3RvciApIHtcblx0XHRcdHZhciBsYWJlbHM7XG5cdFx0XHR2YXIgb3B0aW9ucyA9IHt9O1xuXG5cdFx0XHQvLyBNYWtlIHN1cmUgdGhlIHdpZGdldCBoYXMgYSBzZWxlY3RvciBzZXRcblx0XHRcdGlmICggIXNlbGVjdG9yICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggd2lkZ2V0ID09PSBcImNvbnRyb2xncm91cExhYmVsXCIgKSB7XG5cdFx0XHRcdGxhYmVscyA9IHRoYXQuZWxlbWVudC5maW5kKCBzZWxlY3RvciApO1xuXHRcdFx0XHRsYWJlbHMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICk7XG5cblx0XHRcdFx0XHRpZiAoIGVsZW1lbnQuY2hpbGRyZW4oIFwiLnVpLWNvbnRyb2xncm91cC1sYWJlbC1jb250ZW50c1wiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbGVtZW50LmNvbnRlbnRzKClcblx0XHRcdFx0XHRcdC53cmFwQWxsKCBcIjxzcGFuIGNsYXNzPSd1aS1jb250cm9sZ3JvdXAtbGFiZWwtY29udGVudHMnPjwvc3Bhbj5cIiApO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBsYWJlbHMsIG51bGwsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50IHVpLXN0YXRlLWRlZmF1bHRcIiApO1xuXHRcdFx0XHRjaGlsZFdpZGdldHMgPSBjaGlsZFdpZGdldHMuY29uY2F0KCBsYWJlbHMuZ2V0KCkgKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBNYWtlIHN1cmUgdGhlIHdpZGdldCBhY3R1YWxseSBleGlzdHNcblx0XHRcdGlmICggISQuZm5bIHdpZGdldCBdICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIFdlIGFzc3VtZSBldmVyeXRoaW5nIGlzIGluIHRoZSBtaWRkbGUgdG8gc3RhcnQgYmVjYXVzZSB3ZSBjYW4ndCBkZXRlcm1pbmVcblx0XHRcdC8vIGZpcnN0IC8gbGFzdCBlbGVtZW50cyB1bnRpbCBhbGwgZW5oYW5jbWVudHMgYXJlIGRvbmUuXG5cdFx0XHRpZiAoIHRoYXRbIFwiX1wiICsgd2lkZ2V0ICsgXCJPcHRpb25zXCIgXSApIHtcblx0XHRcdFx0b3B0aW9ucyA9IHRoYXRbIFwiX1wiICsgd2lkZ2V0ICsgXCJPcHRpb25zXCIgXSggXCJtaWRkbGVcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0b3B0aW9ucyA9IHsgY2xhc3Nlczoge30gfTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gRmluZCBpbnN0YW5jZXMgb2YgdGhpcyB3aWRnZXQgaW5zaWRlIGNvbnRyb2xncm91cCBhbmQgaW5pdCB0aGVtXG5cdFx0XHR0aGF0LmVsZW1lbnRcblx0XHRcdFx0LmZpbmQoIHNlbGVjdG9yIClcblx0XHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApO1xuXHRcdFx0XHRcdHZhciBpbnN0YW5jZSA9IGVsZW1lbnRbIHdpZGdldCBdKCBcImluc3RhbmNlXCIgKTtcblxuXHRcdFx0XHRcdC8vIFdlIG5lZWQgdG8gY2xvbmUgdGhlIGRlZmF1bHQgb3B0aW9ucyBmb3IgdGhpcyB0eXBlIG9mIHdpZGdldCB0byBhdm9pZFxuXHRcdFx0XHRcdC8vIHBvbGx1dGluZyB0aGUgdmFyaWFibGUgb3B0aW9ucyB3aGljaCBoYXMgYSB3aWRlciBzY29wZSB0aGFuIGEgc2luZ2xlIHdpZGdldC5cblx0XHRcdFx0XHR2YXIgaW5zdGFuY2VPcHRpb25zID0gJC53aWRnZXQuZXh0ZW5kKCB7fSwgb3B0aW9ucyApO1xuXG5cdFx0XHRcdFx0Ly8gSWYgdGhlIGJ1dHRvbiBpcyB0aGUgY2hpbGQgb2YgYSBzcGlubmVyIGlnbm9yZSBpdFxuXHRcdFx0XHRcdC8vIFRPRE86IEZpbmQgYSBtb3JlIGdlbmVyaWMgc29sdXRpb25cblx0XHRcdFx0XHRpZiAoIHdpZGdldCA9PT0gXCJidXR0b25cIiAmJiBlbGVtZW50LnBhcmVudCggXCIudWktc3Bpbm5lclwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIENyZWF0ZSB0aGUgd2lkZ2V0IGlmIGl0IGRvZXNuJ3QgZXhpc3Rcblx0XHRcdFx0XHRpZiAoICFpbnN0YW5jZSApIHtcblx0XHRcdFx0XHRcdGluc3RhbmNlID0gZWxlbWVudFsgd2lkZ2V0IF0oKVsgd2lkZ2V0IF0oIFwiaW5zdGFuY2VcIiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAoIGluc3RhbmNlICkge1xuXHRcdFx0XHRcdFx0aW5zdGFuY2VPcHRpb25zLmNsYXNzZXMgPVxuXHRcdFx0XHRcdFx0XHR0aGF0Ll9yZXNvbHZlQ2xhc3Nlc1ZhbHVlcyggaW5zdGFuY2VPcHRpb25zLmNsYXNzZXMsIGluc3RhbmNlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsZW1lbnRbIHdpZGdldCBdKCBpbnN0YW5jZU9wdGlvbnMgKTtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGFuIGluc3RhbmNlIG9mIHRoZSBjb250cm9sZ3JvdXAgdG8gYmUgYWJsZSB0byByZWZlcmVuY2Vcblx0XHRcdFx0XHQvLyBmcm9tIHRoZSBvdXRlcm1vc3QgZWxlbWVudCBmb3IgY2hhbmdpbmcgb3B0aW9ucyBhbmQgcmVmcmVzaFxuXHRcdFx0XHRcdHZhciB3aWRnZXRFbGVtZW50ID0gZWxlbWVudFsgd2lkZ2V0IF0oIFwid2lkZ2V0XCIgKTtcblx0XHRcdFx0XHQkLmRhdGEoIHdpZGdldEVsZW1lbnRbIDAgXSwgXCJ1aS1jb250cm9sZ3JvdXAtZGF0YVwiLFxuXHRcdFx0XHRcdFx0aW5zdGFuY2UgPyBpbnN0YW5jZSA6IGVsZW1lbnRbIHdpZGdldCBdKCBcImluc3RhbmNlXCIgKSApO1xuXG5cdFx0XHRcdFx0Y2hpbGRXaWRnZXRzLnB1c2goIHdpZGdldEVsZW1lbnRbIDAgXSApO1xuXHRcdFx0XHR9ICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5jaGlsZFdpZGdldHMgPSAkKCAkLnVuaXF1ZSggY2hpbGRXaWRnZXRzICkgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5jaGlsZFdpZGdldHMsIFwidWktY29udHJvbGdyb3VwLWl0ZW1cIiApO1xuXHR9LFxuXG5cdF9jYWxsQ2hpbGRNZXRob2Q6IGZ1bmN0aW9uKCBtZXRob2QgKSB7XG5cdFx0dGhpcy5jaGlsZFdpZGdldHMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRcdFx0ZGF0YSA9IGVsZW1lbnQuZGF0YSggXCJ1aS1jb250cm9sZ3JvdXAtZGF0YVwiICk7XG5cdFx0XHRpZiAoIGRhdGEgJiYgZGF0YVsgbWV0aG9kIF0gKSB7XG5cdFx0XHRcdGRhdGFbIG1ldGhvZCBdKCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF91cGRhdGVDb3JuZXJDbGFzczogZnVuY3Rpb24oIGVsZW1lbnQsIHBvc2l0aW9uICkge1xuXHRcdHZhciByZW1vdmUgPSBcInVpLWNvcm5lci10b3AgdWktY29ybmVyLWJvdHRvbSB1aS1jb3JuZXItbGVmdCB1aS1jb3JuZXItcmlnaHQgdWktY29ybmVyLWFsbFwiO1xuXHRcdHZhciBhZGQgPSB0aGlzLl9idWlsZFNpbXBsZU9wdGlvbnMoIHBvc2l0aW9uLCBcImxhYmVsXCIgKS5jbGFzc2VzLmxhYmVsO1xuXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGVsZW1lbnQsIG51bGwsIHJlbW92ZSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBlbGVtZW50LCBudWxsLCBhZGQgKTtcblx0fSxcblxuXHRfYnVpbGRTaW1wbGVPcHRpb25zOiBmdW5jdGlvbiggcG9zaXRpb24sIGtleSApIHtcblx0XHR2YXIgZGlyZWN0aW9uID0gdGhpcy5vcHRpb25zLmRpcmVjdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiO1xuXHRcdHZhciByZXN1bHQgPSB7XG5cdFx0XHRjbGFzc2VzOiB7fVxuXHRcdH07XG5cdFx0cmVzdWx0LmNsYXNzZXNbIGtleSBdID0ge1xuXHRcdFx0XCJtaWRkbGVcIjogXCJcIixcblx0XHRcdFwiZmlyc3RcIjogXCJ1aS1jb3JuZXItXCIgKyAoIGRpcmVjdGlvbiA/IFwidG9wXCIgOiBcImxlZnRcIiApLFxuXHRcdFx0XCJsYXN0XCI6IFwidWktY29ybmVyLVwiICsgKCBkaXJlY3Rpb24gPyBcImJvdHRvbVwiIDogXCJyaWdodFwiICksXG5cdFx0XHRcIm9ubHlcIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHR9WyBwb3NpdGlvbiBdO1xuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHRfc3Bpbm5lck9wdGlvbnM6IGZ1bmN0aW9uKCBwb3NpdGlvbiApIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMuX2J1aWxkU2ltcGxlT3B0aW9ucyggcG9zaXRpb24sIFwidWktc3Bpbm5lclwiICk7XG5cblx0XHRvcHRpb25zLmNsYXNzZXNbIFwidWktc3Bpbm5lci11cFwiIF0gPSBcIlwiO1xuXHRcdG9wdGlvbnMuY2xhc3Nlc1sgXCJ1aS1zcGlubmVyLWRvd25cIiBdID0gXCJcIjtcblxuXHRcdHJldHVybiBvcHRpb25zO1xuXHR9LFxuXG5cdF9idXR0b25PcHRpb25zOiBmdW5jdGlvbiggcG9zaXRpb24gKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2J1aWxkU2ltcGxlT3B0aW9ucyggcG9zaXRpb24sIFwidWktYnV0dG9uXCIgKTtcblx0fSxcblxuXHRfY2hlY2tib3hyYWRpb09wdGlvbnM6IGZ1bmN0aW9uKCBwb3NpdGlvbiApIHtcblx0XHRyZXR1cm4gdGhpcy5fYnVpbGRTaW1wbGVPcHRpb25zKCBwb3NpdGlvbiwgXCJ1aS1jaGVja2JveHJhZGlvLWxhYmVsXCIgKTtcblx0fSxcblxuXHRfc2VsZWN0bWVudU9wdGlvbnM6IGZ1bmN0aW9uKCBwb3NpdGlvbiApIHtcblx0XHR2YXIgZGlyZWN0aW9uID0gdGhpcy5vcHRpb25zLmRpcmVjdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiO1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogZGlyZWN0aW9uID8gXCJhdXRvXCIgOiBmYWxzZSxcblx0XHRcdGNsYXNzZXM6IHtcblx0XHRcdFx0bWlkZGxlOiB7XG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1vcGVuXCI6IFwiXCIsXG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIjogXCJcIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRmaXJzdDoge1xuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tb3BlblwiOiBcInVpLWNvcm5lci1cIiArICggZGlyZWN0aW9uID8gXCJ0b3BcIiA6IFwidGxcIiApLFxuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCI6IFwidWktY29ybmVyLVwiICsgKCBkaXJlY3Rpb24gPyBcInRvcFwiIDogXCJsZWZ0XCIgKVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsYXN0OiB7XG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1vcGVuXCI6IGRpcmVjdGlvbiA/IFwiXCIgOiBcInVpLWNvcm5lci10clwiLFxuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCI6IFwidWktY29ybmVyLVwiICsgKCBkaXJlY3Rpb24gPyBcImJvdHRvbVwiIDogXCJyaWdodFwiIClcblx0XHRcdFx0fSxcblx0XHRcdFx0b25seToge1xuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tb3BlblwiOiBcInVpLWNvcm5lci10b3BcIixcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdFx0XHR9XG5cblx0XHRcdH1bIHBvc2l0aW9uIF1cblx0XHR9O1xuXHR9LFxuXG5cdF9yZXNvbHZlQ2xhc3Nlc1ZhbHVlczogZnVuY3Rpb24oIGNsYXNzZXMsIGluc3RhbmNlICkge1xuXHRcdHZhciByZXN1bHQgPSB7fTtcblx0XHQkLmVhY2goIGNsYXNzZXMsIGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0XHR2YXIgY3VycmVudCA9IGluc3RhbmNlLm9wdGlvbnMuY2xhc3Nlc1sga2V5IF0gfHwgXCJcIjtcblx0XHRcdGN1cnJlbnQgPSAkLnRyaW0oIGN1cnJlbnQucmVwbGFjZSggY29udHJvbGdyb3VwQ29ybmVyUmVnZXgsIFwiXCIgKSApO1xuXHRcdFx0cmVzdWx0WyBrZXkgXSA9ICggY3VycmVudCArIFwiIFwiICsgY2xhc3Nlc1sga2V5IF0gKS5yZXBsYWNlKCAvXFxzKy9nLCBcIiBcIiApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImRpcmVjdGlvblwiICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktY29udHJvbGdyb3VwLVwiICsgdGhpcy5vcHRpb25zLmRpcmVjdGlvbiApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiApIHtcblx0XHRcdHRoaXMuX2NhbGxDaGlsZE1ldGhvZCggdmFsdWUgPyBcImRpc2FibGVcIiA6IFwiZW5hYmxlXCIgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLnJlZnJlc2goKTtcblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY2hpbGRyZW4sXG5cdFx0XHR0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWNvbnRyb2xncm91cCB1aS1jb250cm9sZ3JvdXAtXCIgKyB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXJlY3Rpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIG51bGwsIFwidWktaGVscGVyLWNsZWFyZml4XCIgKTtcblx0XHR9XG5cdFx0dGhpcy5faW5pdFdpZGdldHMoKTtcblxuXHRcdGNoaWxkcmVuID0gdGhpcy5jaGlsZFdpZGdldHM7XG5cblx0XHQvLyBXZSBmaWx0ZXIgaGVyZSBiZWNhdXNlIHdlIG5lZWQgdG8gdHJhY2sgYWxsIGNoaWxkV2lkZ2V0cyBub3QganVzdCB0aGUgdmlzaWJsZSBvbmVzXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMub25seVZpc2libGUgKSB7XG5cdFx0XHRjaGlsZHJlbiA9IGNoaWxkcmVuLmZpbHRlciggXCI6dmlzaWJsZVwiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBjaGlsZHJlbi5sZW5ndGggKSB7XG5cblx0XHRcdC8vIFdlIGRvIHRoaXMgbGFzdCBiZWNhdXNlIHdlIG5lZWQgdG8gbWFrZSBzdXJlIGFsbCBlbmhhbmNtZW50IGlzIGRvbmVcblx0XHRcdC8vIGJlZm9yZSBkZXRlcm1pbmluZyBmaXJzdCBhbmQgbGFzdFxuXHRcdFx0JC5lYWNoKCBbIFwiZmlyc3RcIiwgXCJsYXN0XCIgXSwgZnVuY3Rpb24oIGluZGV4LCB2YWx1ZSApIHtcblx0XHRcdFx0dmFyIGluc3RhbmNlID0gY2hpbGRyZW5bIHZhbHVlIF0oKS5kYXRhKCBcInVpLWNvbnRyb2xncm91cC1kYXRhXCIgKTtcblxuXHRcdFx0XHRpZiAoIGluc3RhbmNlICYmIHRoYXRbIFwiX1wiICsgaW5zdGFuY2Uud2lkZ2V0TmFtZSArIFwiT3B0aW9uc1wiIF0gKSB7XG5cdFx0XHRcdFx0dmFyIG9wdGlvbnMgPSB0aGF0WyBcIl9cIiArIGluc3RhbmNlLndpZGdldE5hbWUgKyBcIk9wdGlvbnNcIiBdKFxuXHRcdFx0XHRcdFx0Y2hpbGRyZW4ubGVuZ3RoID09PSAxID8gXCJvbmx5XCIgOiB2YWx1ZVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0b3B0aW9ucy5jbGFzc2VzID0gdGhhdC5fcmVzb2x2ZUNsYXNzZXNWYWx1ZXMoIG9wdGlvbnMuY2xhc3NlcywgaW5zdGFuY2UgKTtcblx0XHRcdFx0XHRpbnN0YW5jZS5lbGVtZW50WyBpbnN0YW5jZS53aWRnZXROYW1lIF0oIG9wdGlvbnMgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGF0Ll91cGRhdGVDb3JuZXJDbGFzcyggY2hpbGRyZW5bIHZhbHVlIF0oKSwgdmFsdWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXG5cdFx0XHQvLyBGaW5hbGx5IGNhbGwgdGhlIHJlZnJlc2ggbWV0aG9kIG9uIGVhY2ggb2YgdGhlIGNoaWxkIHdpZGdldHMuXG5cdFx0XHR0aGlzLl9jYWxsQ2hpbGRNZXRob2QoIFwicmVmcmVzaFwiICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbi8qIVxuICogalF1ZXJ5IFVJIENoZWNrYm94cmFkaW8gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IENoZWNrYm94cmFkaW9cbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBFbmhhbmNlcyBhIGZvcm0gd2l0aCBtdWx0aXBsZSB0aGVtZWFibGUgY2hlY2tib3hlcyBvciByYWRpbyBidXR0b25zLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2NoZWNrYm94cmFkaW8vXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vY2hlY2tib3hyYWRpby9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2J1dHRvbi5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jaGVja2JveHJhZGlvLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5jaGVja2JveHJhZGlvXCIsIFsgJC51aS5mb3JtUmVzZXRNaXhpbiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0ZGlzYWJsZWQ6IG51bGwsXG5cdFx0bGFiZWw6IG51bGwsXG5cdFx0aWNvbjogdHJ1ZSxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLWNoZWNrYm94cmFkaW8tbGFiZWxcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLWNoZWNrYm94cmFkaW8taWNvblwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdH1cblx0fSxcblxuXHRfZ2V0Q3JlYXRlT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGRpc2FibGVkLCBsYWJlbHM7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5fc3VwZXIoKSB8fCB7fTtcblxuXHRcdC8vIFdlIHJlYWQgdGhlIHR5cGUgaGVyZSwgYmVjYXVzZSBpdCBtYWtlcyBtb3JlIHNlbnNlIHRvIHRocm93IGEgZWxlbWVudCB0eXBlIGVycm9yIGZpcnN0LFxuXHRcdC8vIHJhdGhlciB0aGVuIHRoZSBlcnJvciBmb3IgbGFjayBvZiBhIGxhYmVsLiBPZnRlbiBpZiBpdHMgdGhlIHdyb25nIHR5cGUsIGl0XG5cdFx0Ly8gd29uJ3QgaGF2ZSBhIGxhYmVsIChlLmcuIGNhbGxpbmcgb24gYSBkaXYsIGJ0biwgZXRjKVxuXHRcdHRoaXMuX3JlYWRUeXBlKCk7XG5cblx0XHRsYWJlbHMgPSB0aGlzLmVsZW1lbnQubGFiZWxzKCk7XG5cblx0XHQvLyBJZiB0aGVyZSBhcmUgbXVsdGlwbGUgbGFiZWxzLCB1c2UgdGhlIGxhc3Qgb25lXG5cdFx0dGhpcy5sYWJlbCA9ICQoIGxhYmVsc1sgbGFiZWxzLmxlbmd0aCAtIDEgXSApO1xuXHRcdGlmICggIXRoaXMubGFiZWwubGVuZ3RoICkge1xuXHRcdFx0JC5lcnJvciggXCJObyBsYWJlbCBmb3VuZCBmb3IgY2hlY2tib3hyYWRpbyB3aWRnZXRcIiApO1xuXHRcdH1cblxuXHRcdHRoaXMub3JpZ2luYWxMYWJlbCA9IFwiXCI7XG5cblx0XHQvLyBXZSBuZWVkIHRvIGdldCB0aGUgbGFiZWwgdGV4dCBidXQgdGhpcyBtYXkgYWxzbyBuZWVkIHRvIG1ha2Ugc3VyZSBpdCBkb2VzIG5vdCBjb250YWluIHRoZVxuXHRcdC8vIGlucHV0IGl0c2VsZi5cblx0XHR0aGlzLmxhYmVsLmNvbnRlbnRzKCkubm90KCB0aGlzLmVsZW1lbnRbIDAgXSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBUaGUgbGFiZWwgY29udGVudHMgY291bGQgYmUgdGV4dCwgaHRtbCwgb3IgYSBtaXguIFdlIGNvbmNhdCBlYWNoIGVsZW1lbnQgdG8gZ2V0IGFcblx0XHRcdC8vIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgbGFiZWwsIHdpdGhvdXQgdGhlIGlucHV0IGFzIHBhcnQgb2YgaXQuXG5cdFx0XHR0aGF0Lm9yaWdpbmFsTGFiZWwgKz0gdGhpcy5ub2RlVHlwZSA9PT0gMyA/ICQoIHRoaXMgKS50ZXh0KCkgOiB0aGlzLm91dGVySFRNTDtcblx0XHR9ICk7XG5cblx0XHQvLyBTZXQgdGhlIGxhYmVsIG9wdGlvbiBpZiB3ZSBmb3VuZCBsYWJlbCB0ZXh0XG5cdFx0aWYgKCB0aGlzLm9yaWdpbmFsTGFiZWwgKSB7XG5cdFx0XHRvcHRpb25zLmxhYmVsID0gdGhpcy5vcmlnaW5hbExhYmVsO1xuXHRcdH1cblxuXHRcdGRpc2FibGVkID0gdGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQ7XG5cdFx0aWYgKCBkaXNhYmxlZCAhPSBudWxsICkge1xuXHRcdFx0b3B0aW9ucy5kaXNhYmxlZCA9IGRpc2FibGVkO1xuXHRcdH1cblx0XHRyZXR1cm4gb3B0aW9ucztcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY2hlY2tlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmNoZWNrZWQ7XG5cblx0XHR0aGlzLl9iaW5kRm9ybVJlc2V0SGFuZGxlcigpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPT0gbnVsbCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkO1xuXHRcdH1cblxuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJkaXNhYmxlZFwiLCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1jaGVja2JveHJhZGlvXCIsIFwidWktaGVscGVyLWhpZGRlbi1hY2Nlc3NpYmxlXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5sYWJlbCwgXCJ1aS1jaGVja2JveHJhZGlvLWxhYmVsXCIsIFwidWktYnV0dG9uIHVpLXdpZGdldFwiICk7XG5cblx0XHRpZiAoIHRoaXMudHlwZSA9PT0gXCJyYWRpb1wiICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGFiZWwsIFwidWktY2hlY2tib3hyYWRpby1yYWRpby1sYWJlbFwiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMubGFiZWwgJiYgdGhpcy5vcHRpb25zLmxhYmVsICE9PSB0aGlzLm9yaWdpbmFsTGFiZWwgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVMYWJlbCgpO1xuXHRcdH0gZWxzZSBpZiAoIHRoaXMub3JpZ2luYWxMYWJlbCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5sYWJlbCA9IHRoaXMub3JpZ2luYWxMYWJlbDtcblx0XHR9XG5cblx0XHR0aGlzLl9lbmhhbmNlKCk7XG5cblx0XHRpZiAoIGNoZWNrZWQgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5sYWJlbCwgXCJ1aS1jaGVja2JveHJhZGlvLWNoZWNrZWRcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0aWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX29uKCB7XG5cdFx0XHRjaGFuZ2U6IFwiX3RvZ2dsZUNsYXNzZXNcIixcblx0XHRcdGZvY3VzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGFiZWwsIG51bGwsIFwidWktc3RhdGUtZm9jdXMgdWktdmlzdWFsLWZvY3VzXCIgKTtcblx0XHRcdH0sXG5cdFx0XHRibHVyOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMubGFiZWwsIG51bGwsIFwidWktc3RhdGUtZm9jdXMgdWktdmlzdWFsLWZvY3VzXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X3JlYWRUeXBlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbm9kZU5hbWUgPSB0aGlzLmVsZW1lbnRbIDAgXS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdHRoaXMudHlwZSA9IHRoaXMuZWxlbWVudFsgMCBdLnR5cGU7XG5cdFx0aWYgKCBub2RlTmFtZSAhPT0gXCJpbnB1dFwiIHx8ICEvcmFkaW98Y2hlY2tib3gvLnRlc3QoIHRoaXMudHlwZSApICkge1xuXHRcdFx0JC5lcnJvciggXCJDYW4ndCBjcmVhdGUgY2hlY2tib3hyYWRpbyBvbiBlbGVtZW50Lm5vZGVOYW1lPVwiICsgbm9kZU5hbWUgK1xuXHRcdFx0XHRcIiBhbmQgZWxlbWVudC50eXBlPVwiICsgdGhpcy50eXBlICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIFN1cHBvcnQgalF1ZXJ5IE1vYmlsZSBlbmhhbmNlZCBvcHRpb25cblx0X2VuaGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3VwZGF0ZUljb24oIHRoaXMuZWxlbWVudFsgMCBdLmNoZWNrZWQgKTtcblx0fSxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmxhYmVsO1xuXHR9LFxuXG5cdF9nZXRSYWRpb0dyb3VwOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZ3JvdXA7XG5cdFx0dmFyIG5hbWUgPSB0aGlzLmVsZW1lbnRbIDAgXS5uYW1lO1xuXHRcdHZhciBuYW1lU2VsZWN0b3IgPSBcImlucHV0W25hbWU9J1wiICsgJC51aS5lc2NhcGVTZWxlY3RvciggbmFtZSApICsgXCInXVwiO1xuXG5cdFx0aWYgKCAhbmFtZSApIHtcblx0XHRcdHJldHVybiAkKCBbXSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5mb3JtLmxlbmd0aCApIHtcblx0XHRcdGdyb3VwID0gJCggdGhpcy5mb3JtWyAwIF0uZWxlbWVudHMgKS5maWx0ZXIoIG5hbWVTZWxlY3RvciApO1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIE5vdCBpbnNpZGUgYSBmb3JtLCBjaGVjayBhbGwgaW5wdXRzIHRoYXQgYWxzbyBhcmUgbm90IGluc2lkZSBhIGZvcm1cblx0XHRcdGdyb3VwID0gJCggbmFtZVNlbGVjdG9yICkuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICQoIHRoaXMgKS5mb3JtKCkubGVuZ3RoID09PSAwO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBncm91cC5ub3QoIHRoaXMuZWxlbWVudCApO1xuXHR9LFxuXG5cdF90b2dnbGVDbGFzc2VzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY2hlY2tlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmNoZWNrZWQ7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMubGFiZWwsIFwidWktY2hlY2tib3hyYWRpby1jaGVja2VkXCIsIFwidWktc3RhdGUtYWN0aXZlXCIsIGNoZWNrZWQgKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmljb24gJiYgdGhpcy50eXBlID09PSBcImNoZWNrYm94XCIgKSB7XG5cdFx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLWljb24tY2hlY2sgdWktc3RhdGUtY2hlY2tlZFwiLCBjaGVja2VkIClcblx0XHRcdFx0Ll90b2dnbGVDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLWljb24tYmxhbmtcIiwgIWNoZWNrZWQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMudHlwZSA9PT0gXCJyYWRpb1wiICkge1xuXHRcdFx0dGhpcy5fZ2V0UmFkaW9Hcm91cCgpXG5cdFx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgaW5zdGFuY2UgPSAkKCB0aGlzICkuY2hlY2tib3hyYWRpbyggXCJpbnN0YW5jZVwiICk7XG5cblx0XHRcdFx0XHRpZiAoIGluc3RhbmNlICkge1xuXHRcdFx0XHRcdFx0aW5zdGFuY2UuX3JlbW92ZUNsYXNzKCBpbnN0YW5jZS5sYWJlbCxcblx0XHRcdFx0XHRcdFx0XCJ1aS1jaGVja2JveHJhZGlvLWNoZWNrZWRcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fdW5iaW5kRm9ybVJlc2V0SGFuZGxlcigpO1xuXG5cdFx0aWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHR0aGlzLmljb24ucmVtb3ZlKCk7XG5cdFx0XHR0aGlzLmljb25TcGFjZS5yZW1vdmUoKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cblx0XHQvLyBXZSBkb24ndCBhbGxvdyB0aGUgdmFsdWUgdG8gYmUgc2V0IHRvIG5vdGhpbmdcblx0XHRpZiAoIGtleSA9PT0gXCJsYWJlbFwiICYmICF2YWx1ZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiApIHtcblx0XHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmxhYmVsLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZCA9IHZhbHVlO1xuXG5cdFx0XHQvLyBEb24ndCByZWZyZXNoIHdoZW4gc2V0dGluZyBkaXNhYmxlZFxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLnJlZnJlc2goKTtcblx0fSxcblxuXHRfdXBkYXRlSWNvbjogZnVuY3Rpb24oIGNoZWNrZWQgKSB7XG5cdFx0dmFyIHRvQWRkID0gXCJ1aS1pY29uIHVpLWljb24tYmFja2dyb3VuZCBcIjtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmljb24gKSB7XG5cdFx0XHRpZiAoICF0aGlzLmljb24gKSB7XG5cdFx0XHRcdHRoaXMuaWNvbiA9ICQoIFwiPHNwYW4+XCIgKTtcblx0XHRcdFx0dGhpcy5pY29uU3BhY2UgPSAkKCBcIjxzcGFuPiA8L3NwYW4+XCIgKTtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvblNwYWNlLCBcInVpLWNoZWNrYm94cmFkaW8taWNvbi1zcGFjZVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy50eXBlID09PSBcImNoZWNrYm94XCIgKSB7XG5cdFx0XHRcdHRvQWRkICs9IGNoZWNrZWQgPyBcInVpLWljb24tY2hlY2sgdWktc3RhdGUtY2hlY2tlZFwiIDogXCJ1aS1pY29uLWJsYW5rXCI7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIGNoZWNrZWQgPyBcInVpLWljb24tYmxhbmtcIiA6IFwidWktaWNvbi1jaGVja1wiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0b0FkZCArPSBcInVpLWljb24tYmxhbmtcIjtcblx0XHRcdH1cblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb24sIFwidWktY2hlY2tib3hyYWRpby1pY29uXCIsIHRvQWRkICk7XG5cdFx0XHRpZiAoICFjaGVja2VkICkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLWljb24tY2hlY2sgdWktc3RhdGUtY2hlY2tlZFwiICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmljb24ucHJlcGVuZFRvKCB0aGlzLmxhYmVsICkuYWZ0ZXIoIHRoaXMuaWNvblNwYWNlICk7XG5cdFx0fSBlbHNlIGlmICggdGhpcy5pY29uICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLmljb24ucmVtb3ZlKCk7XG5cdFx0XHR0aGlzLmljb25TcGFjZS5yZW1vdmUoKTtcblx0XHRcdGRlbGV0ZSB0aGlzLmljb247XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVMYWJlbDogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBSZW1vdmUgdGhlIGNvbnRlbnRzIG9mIHRoZSBsYWJlbCAoIG1pbnVzIHRoZSBpY29uLCBpY29uIHNwYWNlLCBhbmQgaW5wdXQgKVxuXHRcdHZhciBjb250ZW50cyA9IHRoaXMubGFiZWwuY29udGVudHMoKS5ub3QoIHRoaXMuZWxlbWVudFsgMCBdICk7XG5cdFx0aWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHRjb250ZW50cyA9IGNvbnRlbnRzLm5vdCggdGhpcy5pY29uWyAwIF0gKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLmljb25TcGFjZSApIHtcblx0XHRcdGNvbnRlbnRzID0gY29udGVudHMubm90KCB0aGlzLmljb25TcGFjZVsgMCBdICk7XG5cdFx0fVxuXHRcdGNvbnRlbnRzLnJlbW92ZSgpO1xuXG5cdFx0dGhpcy5sYWJlbC5hcHBlbmQoIHRoaXMub3B0aW9ucy5sYWJlbCApO1xuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjaGVja2VkID0gdGhpcy5lbGVtZW50WyAwIF0uY2hlY2tlZCxcblx0XHRcdGlzRGlzYWJsZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZDtcblxuXHRcdHRoaXMuX3VwZGF0ZUljb24oIGNoZWNrZWQgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5sYWJlbCwgXCJ1aS1jaGVja2JveHJhZGlvLWNoZWNrZWRcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiwgY2hlY2tlZCApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLmxhYmVsICE9PSBudWxsICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlTGFiZWwoKTtcblx0XHR9XG5cblx0XHRpZiAoIGlzRGlzYWJsZWQgIT09IHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbnMoIHsgXCJkaXNhYmxlZFwiOiBpc0Rpc2FibGVkIH0gKTtcblx0XHR9XG5cdH1cblxufSBdICk7XG5cbnZhciB3aWRnZXRzQ2hlY2tib3hyYWRpbyA9ICQudWkuY2hlY2tib3hyYWRpbztcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBCdXR0b24gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEJ1dHRvblxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IEVuaGFuY2VzIGEgZm9ybSB3aXRoIHRoZW1lYWJsZSBidXR0b25zLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2J1dHRvbi9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9idXR0b24vXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9idXR0b24uY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLmJ1dHRvblwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxidXR0b24+XCIsXG5cdG9wdGlvbnM6IHtcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLWJ1dHRvblwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdH0sXG5cdFx0ZGlzYWJsZWQ6IG51bGwsXG5cdFx0aWNvbjogbnVsbCxcblx0XHRpY29uUG9zaXRpb246IFwiYmVnaW5uaW5nXCIsXG5cdFx0bGFiZWw6IG51bGwsXG5cdFx0c2hvd0xhYmVsOiB0cnVlXG5cdH0sXG5cblx0X2dldENyZWF0ZU9wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBkaXNhYmxlZCxcblxuXHRcdFx0Ly8gVGhpcyBpcyB0byBzdXBwb3J0IGNhc2VzIGxpa2UgaW4galF1ZXJ5IE1vYmlsZSB3aGVyZSB0aGUgYmFzZSB3aWRnZXQgZG9lcyBoYXZlXG5cdFx0XHQvLyBhbiBpbXBsZW1lbnRhdGlvbiBvZiBfZ2V0Q3JlYXRlT3B0aW9uc1xuXHRcdFx0b3B0aW9ucyA9IHRoaXMuX3N1cGVyKCkgfHwge307XG5cblx0XHR0aGlzLmlzSW5wdXQgPSB0aGlzLmVsZW1lbnQuaXMoIFwiaW5wdXRcIiApO1xuXG5cdFx0ZGlzYWJsZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZDtcblx0XHRpZiAoIGRpc2FibGVkICE9IG51bGwgKSB7XG5cdFx0XHRvcHRpb25zLmRpc2FibGVkID0gZGlzYWJsZWQ7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcmlnaW5hbExhYmVsID0gdGhpcy5pc0lucHV0ID8gdGhpcy5lbGVtZW50LnZhbCgpIDogdGhpcy5lbGVtZW50Lmh0bWwoKTtcblx0XHRpZiAoIHRoaXMub3JpZ2luYWxMYWJlbCApIHtcblx0XHRcdG9wdGlvbnMubGFiZWwgPSB0aGlzLm9yaWdpbmFsTGFiZWw7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIG9wdGlvbnM7XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpcy5vcHRpb24uc2hvd0xhYmVsICYgIXRoaXMub3B0aW9ucy5pY29uICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLnNob3dMYWJlbCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0Ly8gV2UgaGF2ZSB0byBjaGVjayB0aGUgb3B0aW9uIGFnYWluIGhlcmUgZXZlbiB0aG91Z2ggd2UgZGlkIGluIF9nZXRDcmVhdGVPcHRpb25zLFxuXHRcdC8vIGJlY2F1c2UgbnVsbCBtYXkgaGF2ZSBiZWVuIHBhc3NlZCBvbiBpbml0IHdoaWNoIHdvdWxkIG92ZXJyaWRlIHdoYXQgd2FzIHNldCBpblxuXHRcdC8vIF9nZXRDcmVhdGVPcHRpb25zXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPT0gbnVsbCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkIHx8IGZhbHNlO1xuXHRcdH1cblxuXHRcdHRoaXMuaGFzVGl0bGUgPSAhIXRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKTtcblxuXHRcdC8vIENoZWNrIHRvIHNlZSBpZiB0aGUgbGFiZWwgbmVlZHMgdG8gYmUgc2V0IG9yIGlmIGl0cyBhbHJlYWR5IGNvcnJlY3Rcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5sYWJlbCAmJiB0aGlzLm9wdGlvbnMubGFiZWwgIT09IHRoaXMub3JpZ2luYWxMYWJlbCApIHtcblx0XHRcdGlmICggdGhpcy5pc0lucHV0ICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQudmFsKCB0aGlzLm9wdGlvbnMubGFiZWwgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5odG1sKCB0aGlzLm9wdGlvbnMubGFiZWwgKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktYnV0dG9uXCIsIFwidWktd2lkZ2V0XCIgKTtcblx0XHR0aGlzLl9zZXRPcHRpb24oIFwiZGlzYWJsZWRcIiwgdGhpcy5vcHRpb25zLmRpc2FibGVkICk7XG5cdFx0dGhpcy5fZW5oYW5jZSgpO1xuXG5cdFx0aWYgKCB0aGlzLmVsZW1lbnQuaXMoIFwiYVwiICkgKSB7XG5cdFx0XHR0aGlzLl9vbigge1xuXHRcdFx0XHRcImtleXVwXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHRpZiAoIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5TUEFDRSApIHtcblx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IFBoYW50b21KUyA8PSAxLjksIElFIDggT25seVxuXHRcdFx0XHRcdFx0Ly8gSWYgYSBuYXRpdmUgY2xpY2sgaXMgYXZhaWxhYmxlIHVzZSBpdCBzbyB3ZSBhY3R1YWxseSBjYXVzZSBuYXZpZ2F0aW9uXG5cdFx0XHRcdFx0XHQvLyBvdGhlcndpc2UganVzdCB0cmlnZ2VyIGEgY2xpY2sgZXZlbnRcblx0XHRcdFx0XHRcdGlmICggdGhpcy5lbGVtZW50WyAwIF0uY2xpY2sgKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLmNsaWNrKCk7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJjbGlja1wiICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9lbmhhbmNlOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzLmVsZW1lbnQuaXMoIFwiYnV0dG9uXCIgKSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInJvbGVcIiwgXCJidXR0b25cIiApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmljb24gKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVJY29uKCBcImljb25cIiwgdGhpcy5vcHRpb25zLmljb24gKTtcblx0XHRcdHRoaXMuX3VwZGF0ZVRvb2x0aXAoKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZVRvb2x0aXA6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMudGl0bGUgPSB0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiICk7XG5cblx0XHRpZiAoICF0aGlzLm9wdGlvbnMuc2hvd0xhYmVsICYmICF0aGlzLnRpdGxlICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiwgdGhpcy5vcHRpb25zLmxhYmVsICk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVJY29uOiBmdW5jdGlvbiggb3B0aW9uLCB2YWx1ZSApIHtcblx0XHR2YXIgaWNvbiA9IG9wdGlvbiAhPT0gXCJpY29uUG9zaXRpb25cIixcblx0XHRcdHBvc2l0aW9uID0gaWNvbiA/IHRoaXMub3B0aW9ucy5pY29uUG9zaXRpb24gOiB2YWx1ZSxcblx0XHRcdGRpc3BsYXlCbG9jayA9IHBvc2l0aW9uID09PSBcInRvcFwiIHx8IHBvc2l0aW9uID09PSBcImJvdHRvbVwiO1xuXG5cdFx0Ly8gQ3JlYXRlIGljb25cblx0XHRpZiAoICF0aGlzLmljb24gKSB7XG5cdFx0XHR0aGlzLmljb24gPSAkKCBcIjxzcGFuPlwiICk7XG5cblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb24sIFwidWktYnV0dG9uLWljb25cIiwgXCJ1aS1pY29uXCIgKTtcblxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zLnNob3dMYWJlbCApIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktYnV0dG9uLWljb24tb25seVwiICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmICggaWNvbiApIHtcblxuXHRcdFx0Ly8gSWYgd2UgYXJlIHVwZGF0aW5nIHRoZSBpY29uIHJlbW92ZSB0aGUgb2xkIGljb24gY2xhc3Ncblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIHRoaXMub3B0aW9ucy5pY29uICk7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgd2UgYXJlIHVwZGF0aW5nIHRoZSBpY29uIGFkZCB0aGUgbmV3IGljb24gY2xhc3Ncblx0XHRpZiAoIGljb24gKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uLCBudWxsLCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX2F0dGFjaEljb24oIHBvc2l0aW9uICk7XG5cblx0XHQvLyBJZiB0aGUgaWNvbiBpcyBvbiB0b3Agb3IgYm90dG9tIHdlIG5lZWQgdG8gYWRkIHRoZSB1aS13aWRnZXQtaWNvbi1ibG9jayBjbGFzcyBhbmQgcmVtb3ZlXG5cdFx0Ly8gdGhlIGljb25TcGFjZSBpZiB0aGVyZSBpcyBvbmUuXG5cdFx0aWYgKCBkaXNwbGF5QmxvY2sgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLXdpZGdldC1pY29uLWJsb2NrXCIgKTtcblx0XHRcdGlmICggdGhpcy5pY29uU3BhY2UgKSB7XG5cdFx0XHRcdHRoaXMuaWNvblNwYWNlLnJlbW92ZSgpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIFBvc2l0aW9uIGlzIGJlZ2lubmluZyBvciBlbmQgc28gcmVtb3ZlIHRoZSB1aS13aWRnZXQtaWNvbi1ibG9jayBjbGFzcyBhbmQgYWRkIHRoZVxuXHRcdFx0Ly8gc3BhY2UgaWYgaXQgZG9lcyBub3QgZXhpc3Rcblx0XHRcdGlmICggIXRoaXMuaWNvblNwYWNlICkge1xuXHRcdFx0XHR0aGlzLmljb25TcGFjZSA9ICQoIFwiPHNwYW4+IDwvc3Bhbj5cIiApO1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uU3BhY2UsIFwidWktYnV0dG9uLWljb24tc3BhY2VcIiApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS13aWdldC1pY29uLWJsb2NrXCIgKTtcblx0XHRcdHRoaXMuX2F0dGFjaEljb25TcGFjZSggcG9zaXRpb24gKTtcblx0XHR9XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcInJvbGVcIiApO1xuXG5cdFx0aWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHR0aGlzLmljb24ucmVtb3ZlKCk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5pY29uU3BhY2UgKSB7XG5cdFx0XHR0aGlzLmljb25TcGFjZS5yZW1vdmUoKTtcblx0XHR9XG5cdFx0aWYgKCAhdGhpcy5oYXNUaXRsZSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcInRpdGxlXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X2F0dGFjaEljb25TcGFjZTogZnVuY3Rpb24oIGljb25Qb3NpdGlvbiApIHtcblx0XHR0aGlzLmljb25bIC9eKD86ZW5kfGJvdHRvbSkvLnRlc3QoIGljb25Qb3NpdGlvbiApID8gXCJiZWZvcmVcIiA6IFwiYWZ0ZXJcIiBdKCB0aGlzLmljb25TcGFjZSApO1xuXHR9LFxuXG5cdF9hdHRhY2hJY29uOiBmdW5jdGlvbiggaWNvblBvc2l0aW9uICkge1xuXHRcdHRoaXMuZWxlbWVudFsgL14oPzplbmR8Ym90dG9tKS8udGVzdCggaWNvblBvc2l0aW9uICkgPyBcImFwcGVuZFwiIDogXCJwcmVwZW5kXCIgXSggdGhpcy5pY29uICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbnM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciBuZXdTaG93TGFiZWwgPSBvcHRpb25zLnNob3dMYWJlbCA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0dGhpcy5vcHRpb25zLnNob3dMYWJlbCA6XG5cdFx0XHRcdG9wdGlvbnMuc2hvd0xhYmVsLFxuXHRcdFx0bmV3SWNvbiA9IG9wdGlvbnMuaWNvbiA9PT0gdW5kZWZpbmVkID8gdGhpcy5vcHRpb25zLmljb24gOiBvcHRpb25zLmljb247XG5cblx0XHRpZiAoICFuZXdTaG93TGFiZWwgJiYgIW5ld0ljb24gKSB7XG5cdFx0XHRvcHRpb25zLnNob3dMYWJlbCA9IHRydWU7XG5cdFx0fVxuXHRcdHRoaXMuX3N1cGVyKCBvcHRpb25zICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvblwiICkge1xuXHRcdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdFx0dGhpcy5fdXBkYXRlSWNvbigga2V5LCB2YWx1ZSApO1xuXHRcdFx0fSBlbHNlIGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0XHR0aGlzLmljb24ucmVtb3ZlKCk7XG5cdFx0XHRcdGlmICggdGhpcy5pY29uU3BhY2UgKSB7XG5cdFx0XHRcdFx0dGhpcy5pY29uU3BhY2UucmVtb3ZlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJpY29uUG9zaXRpb25cIiApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZUljb24oIGtleSwgdmFsdWUgKTtcblx0XHR9XG5cblx0XHQvLyBNYWtlIHN1cmUgd2UgY2FuJ3QgZW5kIHVwIHdpdGggYSBidXR0b24gdGhhdCBoYXMgbmVpdGhlciB0ZXh0IG5vciBpY29uXG5cdFx0aWYgKCBrZXkgPT09IFwic2hvd0xhYmVsXCIgKSB7XG5cdFx0XHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBcInVpLWJ1dHRvbi1pY29uLW9ubHlcIiwgbnVsbCwgIXZhbHVlICk7XG5cdFx0XHRcdHRoaXMuX3VwZGF0ZVRvb2x0aXAoKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJsYWJlbFwiICkge1xuXHRcdFx0aWYgKCB0aGlzLmlzSW5wdXQgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC52YWwoIHZhbHVlICk7XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIElmIHRoZXJlIGlzIGFuIGljb24sIGFwcGVuZCBpdCwgZWxzZSBub3RoaW5nIHRoZW4gYXBwZW5kIHRoZSB2YWx1ZVxuXHRcdFx0XHQvLyB0aGlzIGF2b2lkcyByZW1vdmFsIG9mIHRoZSBpY29uIHdoZW4gc2V0dGluZyBsYWJlbCB0ZXh0XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5odG1sKCB2YWx1ZSApO1xuXHRcdFx0XHRpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdFx0XHR0aGlzLl9hdHRhY2hJY29uKCB0aGlzLm9wdGlvbnMuaWNvblBvc2l0aW9uICk7XG5cdFx0XHRcdFx0dGhpcy5fYXR0YWNoSWNvblNwYWNlKCB0aGlzLm9wdGlvbnMuaWNvblBvc2l0aW9uICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiApIHtcblx0XHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZCA9IHZhbHVlO1xuXHRcdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LmJsdXIoKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBNYWtlIHN1cmUgdG8gb25seSBjaGVjayBkaXNhYmxlZCBpZiBpdHMgYW4gZWxlbWVudCB0aGF0IHN1cHBvcnRzIHRoaXMgb3RoZXJ3aXNlXG5cdFx0Ly8gY2hlY2sgZm9yIHRoZSBkaXNhYmxlZCBjbGFzcyB0byBkZXRlcm1pbmUgc3RhdGVcblx0XHR2YXIgaXNEaXNhYmxlZCA9IHRoaXMuZWxlbWVudC5pcyggXCJpbnB1dCwgYnV0dG9uXCIgKSA/XG5cdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZCA6IHRoaXMuZWxlbWVudC5oYXNDbGFzcyggXCJ1aS1idXR0b24tZGlzYWJsZWRcIiApO1xuXG5cdFx0aWYgKCBpc0Rpc2FibGVkICE9PSB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb25zKCB7IGRpc2FibGVkOiBpc0Rpc2FibGVkIH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl91cGRhdGVUb29sdGlwKCk7XG5cdH1cbn0gKTtcblxuLy8gREVQUkVDQVRFRFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gVGV4dCBhbmQgSWNvbnMgb3B0aW9uc1xuXHQkLndpZGdldCggXCJ1aS5idXR0b25cIiwgJC51aS5idXR0b24sIHtcblx0XHRvcHRpb25zOiB7XG5cdFx0XHR0ZXh0OiB0cnVlLFxuXHRcdFx0aWNvbnM6IHtcblx0XHRcdFx0cHJpbWFyeTogbnVsbCxcblx0XHRcdFx0c2Vjb25kYXJ5OiBudWxsXG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuc2hvd0xhYmVsICYmICF0aGlzLm9wdGlvbnMudGV4dCApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnNob3dMYWJlbCA9IHRoaXMub3B0aW9ucy50ZXh0O1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zLnNob3dMYWJlbCAmJiB0aGlzLm9wdGlvbnMudGV4dCApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnRleHQgPSB0aGlzLm9wdGlvbnMuc2hvd0xhYmVsO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zLmljb24gJiYgKCB0aGlzLm9wdGlvbnMuaWNvbnMucHJpbWFyeSB8fFxuXHRcdFx0XHRcdHRoaXMub3B0aW9ucy5pY29ucy5zZWNvbmRhcnkgKSApIHtcblx0XHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuaWNvbnMucHJpbWFyeSApIHtcblx0XHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvbiA9IHRoaXMub3B0aW9ucy5pY29ucy5wcmltYXJ5O1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMub3B0aW9ucy5pY29uID0gdGhpcy5vcHRpb25zLmljb25zLnNlY29uZGFyeTtcblx0XHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvblBvc2l0aW9uID0gXCJlbmRcIjtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmICggdGhpcy5vcHRpb25zLmljb24gKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5pY29ucy5wcmltYXJ5ID0gdGhpcy5vcHRpb25zLmljb247XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdH0sXG5cblx0XHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdGlmICgga2V5ID09PSBcInRleHRcIiApIHtcblx0XHRcdFx0dGhpcy5fc3VwZXIoIFwic2hvd0xhYmVsXCIsIHZhbHVlICk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICgga2V5ID09PSBcInNob3dMYWJlbFwiICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudGV4dCA9IHZhbHVlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBrZXkgPT09IFwiaWNvblwiICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvbnMucHJpbWFyeSA9IHZhbHVlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBrZXkgPT09IFwiaWNvbnNcIiApIHtcblx0XHRcdFx0aWYgKCB2YWx1ZS5wcmltYXJ5ICkge1xuXHRcdFx0XHRcdHRoaXMuX3N1cGVyKCBcImljb25cIiwgdmFsdWUucHJpbWFyeSApO1xuXHRcdFx0XHRcdHRoaXMuX3N1cGVyKCBcImljb25Qb3NpdGlvblwiLCBcImJlZ2lubmluZ1wiICk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlLnNlY29uZGFyeSApIHtcblx0XHRcdFx0XHR0aGlzLl9zdXBlciggXCJpY29uXCIsIHZhbHVlLnNlY29uZGFyeSApO1xuXHRcdFx0XHRcdHRoaXMuX3N1cGVyKCBcImljb25Qb3NpdGlvblwiLCBcImVuZFwiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuX3N1cGVyQXBwbHkoIGFyZ3VtZW50cyApO1xuXHRcdH1cblx0fSApO1xuXG5cdCQuZm4uYnV0dG9uID0gKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICF0aGlzLmxlbmd0aCB8fCAoIHRoaXMubGVuZ3RoICYmIHRoaXNbIDAgXS50YWdOYW1lICE9PSBcIklOUFVUXCIgKSB8fFxuXHRcdFx0XHRcdCggdGhpcy5sZW5ndGggJiYgdGhpc1sgMCBdLnRhZ05hbWUgPT09IFwiSU5QVVRcIiAmJiAoXG5cdFx0XHRcdFx0XHR0aGlzLmF0dHIoIFwidHlwZVwiICkgIT09IFwiY2hlY2tib3hcIiAmJiB0aGlzLmF0dHIoIFwidHlwZVwiICkgIT09IFwicmFkaW9cIlxuXHRcdFx0XHRcdCkgKSApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhJC51aS5jaGVja2JveHJhZGlvICkge1xuXHRcdFx0XHQkLmVycm9yKCBcIkNoZWNrYm94cmFkaW8gd2lkZ2V0IG1pc3NpbmdcIiApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID09PSAwICkge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jaGVja2JveHJhZGlvKCB7XG5cdFx0XHRcdFx0XCJpY29uXCI6IGZhbHNlXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB0aGlzLmNoZWNrYm94cmFkaW8uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH07XG5cdH0gKSggJC5mbi5idXR0b24gKTtcblxuXHQkLmZuLmJ1dHRvbnNldCA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggISQudWkuY29udHJvbGdyb3VwICkge1xuXHRcdFx0JC5lcnJvciggXCJDb250cm9sZ3JvdXAgd2lkZ2V0IG1pc3NpbmdcIiApO1xuXHRcdH1cblx0XHRpZiAoIGFyZ3VtZW50c1sgMCBdID09PSBcIm9wdGlvblwiICYmIGFyZ3VtZW50c1sgMSBdID09PSBcIml0ZW1zXCIgJiYgYXJndW1lbnRzWyAyIF0gKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jb250cm9sZ3JvdXAuYXBwbHkoIHRoaXMsXG5cdFx0XHRcdFsgYXJndW1lbnRzWyAwIF0sIFwiaXRlbXMuYnV0dG9uXCIsIGFyZ3VtZW50c1sgMiBdIF0gKTtcblx0XHR9XG5cdFx0aWYgKCBhcmd1bWVudHNbIDAgXSA9PT0gXCJvcHRpb25cIiAmJiBhcmd1bWVudHNbIDEgXSA9PT0gXCJpdGVtc1wiICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuY29udHJvbGdyb3VwLmFwcGx5KCB0aGlzLCBbIGFyZ3VtZW50c1sgMCBdLCBcIml0ZW1zLmJ1dHRvblwiIF0gKTtcblx0XHR9XG5cdFx0aWYgKCB0eXBlb2YgYXJndW1lbnRzWyAwIF0gPT09IFwib2JqZWN0XCIgJiYgYXJndW1lbnRzWyAwIF0uaXRlbXMgKSB7XG5cdFx0XHRhcmd1bWVudHNbIDAgXS5pdGVtcyA9IHtcblx0XHRcdFx0YnV0dG9uOiBhcmd1bWVudHNbIDAgXS5pdGVtc1xuXHRcdFx0fTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuY29udHJvbGdyb3VwLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0fTtcbn1cblxudmFyIHdpZGdldHNCdXR0b24gPSAkLnVpLmJ1dHRvbjtcblxuXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8qIGpzY3M6ZGlzYWJsZSByZXF1aXJlQ2FtZWxDYXNlT3JVcHBlckNhc2VJZGVudGlmaWVycyAqL1xuLyohXG4gKiBqUXVlcnkgVUkgRGF0ZXBpY2tlciAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRGF0ZXBpY2tlclxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGEgY2FsZW5kYXIgZnJvbSBhbiBpbnB1dCBvciBpbmxpbmUgZm9yIHNlbGVjdGluZyBkYXRlcy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kYXRlcGlja2VyL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2RhdGVwaWNrZXIvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9kYXRlcGlja2VyLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLmV4dGVuZCggJC51aSwgeyBkYXRlcGlja2VyOiB7IHZlcnNpb246IFwiMS4xMi4xXCIgfSB9ICk7XG5cbnZhciBkYXRlcGlja2VyX2luc3RBY3RpdmU7XG5cbmZ1bmN0aW9uIGRhdGVwaWNrZXJfZ2V0WmluZGV4KCBlbGVtICkge1xuXHR2YXIgcG9zaXRpb24sIHZhbHVlO1xuXHR3aGlsZSAoIGVsZW0ubGVuZ3RoICYmIGVsZW1bIDAgXSAhPT0gZG9jdW1lbnQgKSB7XG5cblx0XHQvLyBJZ25vcmUgei1pbmRleCBpZiBwb3NpdGlvbiBpcyBzZXQgdG8gYSB2YWx1ZSB3aGVyZSB6LWluZGV4IGlzIGlnbm9yZWQgYnkgdGhlIGJyb3dzZXJcblx0XHQvLyBUaGlzIG1ha2VzIGJlaGF2aW9yIG9mIHRoaXMgZnVuY3Rpb24gY29uc2lzdGVudCBhY3Jvc3MgYnJvd3NlcnNcblx0XHQvLyBXZWJLaXQgYWx3YXlzIHJldHVybnMgYXV0byBpZiB0aGUgZWxlbWVudCBpcyBwb3NpdGlvbmVkXG5cdFx0cG9zaXRpb24gPSBlbGVtLmNzcyggXCJwb3NpdGlvblwiICk7XG5cdFx0aWYgKCBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiIHx8IHBvc2l0aW9uID09PSBcInJlbGF0aXZlXCIgfHwgcG9zaXRpb24gPT09IFwiZml4ZWRcIiApIHtcblxuXHRcdFx0Ly8gSUUgcmV0dXJucyAwIHdoZW4gekluZGV4IGlzIG5vdCBzcGVjaWZpZWRcblx0XHRcdC8vIG90aGVyIGJyb3dzZXJzIHJldHVybiBhIHN0cmluZ1xuXHRcdFx0Ly8gd2UgaWdub3JlIHRoZSBjYXNlIG9mIG5lc3RlZCBlbGVtZW50cyB3aXRoIGFuIGV4cGxpY2l0IHZhbHVlIG9mIDBcblx0XHRcdC8vIDxkaXYgc3R5bGU9XCJ6LWluZGV4OiAtMTA7XCI+PGRpdiBzdHlsZT1cInotaW5kZXg6IDA7XCI+PC9kaXY+PC9kaXY+XG5cdFx0XHR2YWx1ZSA9IHBhcnNlSW50KCBlbGVtLmNzcyggXCJ6SW5kZXhcIiApLCAxMCApO1xuXHRcdFx0aWYgKCAhaXNOYU4oIHZhbHVlICkgJiYgdmFsdWUgIT09IDAgKSB7XG5cdFx0XHRcdHJldHVybiB2YWx1ZTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZWxlbSA9IGVsZW0ucGFyZW50KCk7XG5cdH1cblxuXHRyZXR1cm4gMDtcbn1cbi8qIERhdGUgcGlja2VyIG1hbmFnZXIuXG4gICBVc2UgdGhlIHNpbmdsZXRvbiBpbnN0YW5jZSBvZiB0aGlzIGNsYXNzLCAkLmRhdGVwaWNrZXIsIHRvIGludGVyYWN0IHdpdGggdGhlIGRhdGUgcGlja2VyLlxuICAgU2V0dGluZ3MgZm9yIChncm91cHMgb2YpIGRhdGUgcGlja2VycyBhcmUgbWFpbnRhaW5lZCBpbiBhbiBpbnN0YW5jZSBvYmplY3QsXG4gICBhbGxvd2luZyBtdWx0aXBsZSBkaWZmZXJlbnQgc2V0dGluZ3Mgb24gdGhlIHNhbWUgcGFnZS4gKi9cblxuZnVuY3Rpb24gRGF0ZXBpY2tlcigpIHtcblx0dGhpcy5fY3VySW5zdCA9IG51bGw7IC8vIFRoZSBjdXJyZW50IGluc3RhbmNlIGluIHVzZVxuXHR0aGlzLl9rZXlFdmVudCA9IGZhbHNlOyAvLyBJZiB0aGUgbGFzdCBldmVudCB3YXMgYSBrZXkgZXZlbnRcblx0dGhpcy5fZGlzYWJsZWRJbnB1dHMgPSBbXTsgLy8gTGlzdCBvZiBkYXRlIHBpY2tlciBpbnB1dHMgdGhhdCBoYXZlIGJlZW4gZGlzYWJsZWRcblx0dGhpcy5fZGF0ZXBpY2tlclNob3dpbmcgPSBmYWxzZTsgLy8gVHJ1ZSBpZiB0aGUgcG9wdXAgcGlja2VyIGlzIHNob3dpbmcgLCBmYWxzZSBpZiBub3Rcblx0dGhpcy5faW5EaWFsb2cgPSBmYWxzZTsgLy8gVHJ1ZSBpZiBzaG93aW5nIHdpdGhpbiBhIFwiZGlhbG9nXCIsIGZhbHNlIGlmIG5vdFxuXHR0aGlzLl9tYWluRGl2SWQgPSBcInVpLWRhdGVwaWNrZXItZGl2XCI7IC8vIFRoZSBJRCBvZiB0aGUgbWFpbiBkYXRlcGlja2VyIGRpdmlzaW9uXG5cdHRoaXMuX2lubGluZUNsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWlubGluZVwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgaW5saW5lIG1hcmtlciBjbGFzc1xuXHR0aGlzLl9hcHBlbmRDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1hcHBlbmRcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGFwcGVuZCBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fdHJpZ2dlckNsYXNzID0gXCJ1aS1kYXRlcGlja2VyLXRyaWdnZXJcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIHRyaWdnZXIgbWFya2VyIGNsYXNzXG5cdHRoaXMuX2RpYWxvZ0NsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWRpYWxvZ1wiOyAvLyBUaGUgbmFtZSBvZiB0aGUgZGlhbG9nIG1hcmtlciBjbGFzc1xuXHR0aGlzLl9kaXNhYmxlQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItZGlzYWJsZWRcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGRpc2FibGVkIGNvdmVyaW5nIG1hcmtlciBjbGFzc1xuXHR0aGlzLl91bnNlbGVjdGFibGVDbGFzcyA9IFwidWktZGF0ZXBpY2tlci11bnNlbGVjdGFibGVcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIHVuc2VsZWN0YWJsZSBjZWxsIG1hcmtlciBjbGFzc1xuXHR0aGlzLl9jdXJyZW50Q2xhc3MgPSBcInVpLWRhdGVwaWNrZXItY3VycmVudC1kYXlcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGN1cnJlbnQgZGF5IG1hcmtlciBjbGFzc1xuXHR0aGlzLl9kYXlPdmVyQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItZGF5cy1jZWxsLW92ZXJcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGRheSBob3ZlciBtYXJrZXIgY2xhc3Ncblx0dGhpcy5yZWdpb25hbCA9IFtdOyAvLyBBdmFpbGFibGUgcmVnaW9uYWwgc2V0dGluZ3MsIGluZGV4ZWQgYnkgbGFuZ3VhZ2UgY29kZVxuXHR0aGlzLnJlZ2lvbmFsWyBcIlwiIF0gPSB7IC8vIERlZmF1bHQgcmVnaW9uYWwgc2V0dGluZ3Ncblx0XHRjbG9zZVRleHQ6IFwiRG9uZVwiLCAvLyBEaXNwbGF5IHRleHQgZm9yIGNsb3NlIGxpbmtcblx0XHRwcmV2VGV4dDogXCJQcmV2XCIsIC8vIERpc3BsYXkgdGV4dCBmb3IgcHJldmlvdXMgbW9udGggbGlua1xuXHRcdG5leHRUZXh0OiBcIk5leHRcIiwgLy8gRGlzcGxheSB0ZXh0IGZvciBuZXh0IG1vbnRoIGxpbmtcblx0XHRjdXJyZW50VGV4dDogXCJUb2RheVwiLCAvLyBEaXNwbGF5IHRleHQgZm9yIGN1cnJlbnQgbW9udGggbGlua1xuXHRcdG1vbnRoTmFtZXM6IFsgXCJKYW51YXJ5XCIsXCJGZWJydWFyeVwiLFwiTWFyY2hcIixcIkFwcmlsXCIsXCJNYXlcIixcIkp1bmVcIixcblx0XHRcdFwiSnVseVwiLFwiQXVndXN0XCIsXCJTZXB0ZW1iZXJcIixcIk9jdG9iZXJcIixcIk5vdmVtYmVyXCIsXCJEZWNlbWJlclwiIF0sIC8vIE5hbWVzIG9mIG1vbnRocyBmb3IgZHJvcC1kb3duIGFuZCBmb3JtYXR0aW5nXG5cdFx0bW9udGhOYW1lc1Nob3J0OiBbIFwiSmFuXCIsIFwiRmViXCIsIFwiTWFyXCIsIFwiQXByXCIsIFwiTWF5XCIsIFwiSnVuXCIsIFwiSnVsXCIsIFwiQXVnXCIsIFwiU2VwXCIsIFwiT2N0XCIsIFwiTm92XCIsIFwiRGVjXCIgXSwgLy8gRm9yIGZvcm1hdHRpbmdcblx0XHRkYXlOYW1lczogWyBcIlN1bmRheVwiLCBcIk1vbmRheVwiLCBcIlR1ZXNkYXlcIiwgXCJXZWRuZXNkYXlcIiwgXCJUaHVyc2RheVwiLCBcIkZyaWRheVwiLCBcIlNhdHVyZGF5XCIgXSwgLy8gRm9yIGZvcm1hdHRpbmdcblx0XHRkYXlOYW1lc1Nob3J0OiBbIFwiU3VuXCIsIFwiTW9uXCIsIFwiVHVlXCIsIFwiV2VkXCIsIFwiVGh1XCIsIFwiRnJpXCIsIFwiU2F0XCIgXSwgLy8gRm9yIGZvcm1hdHRpbmdcblx0XHRkYXlOYW1lc01pbjogWyBcIlN1XCIsXCJNb1wiLFwiVHVcIixcIldlXCIsXCJUaFwiLFwiRnJcIixcIlNhXCIgXSwgLy8gQ29sdW1uIGhlYWRpbmdzIGZvciBkYXlzIHN0YXJ0aW5nIGF0IFN1bmRheVxuXHRcdHdlZWtIZWFkZXI6IFwiV2tcIiwgLy8gQ29sdW1uIGhlYWRlciBmb3Igd2VlayBvZiB0aGUgeWVhclxuXHRcdGRhdGVGb3JtYXQ6IFwibW0vZGQveXlcIiwgLy8gU2VlIGZvcm1hdCBvcHRpb25zIG9uIHBhcnNlRGF0ZVxuXHRcdGZpcnN0RGF5OiAwLCAvLyBUaGUgZmlyc3QgZGF5IG9mIHRoZSB3ZWVrLCBTdW4gPSAwLCBNb24gPSAxLCAuLi5cblx0XHRpc1JUTDogZmFsc2UsIC8vIFRydWUgaWYgcmlnaHQtdG8tbGVmdCBsYW5ndWFnZSwgZmFsc2UgaWYgbGVmdC10by1yaWdodFxuXHRcdHNob3dNb250aEFmdGVyWWVhcjogZmFsc2UsIC8vIFRydWUgaWYgdGhlIHllYXIgc2VsZWN0IHByZWNlZGVzIG1vbnRoLCBmYWxzZSBmb3IgbW9udGggdGhlbiB5ZWFyXG5cdFx0eWVhclN1ZmZpeDogXCJcIiAvLyBBZGRpdGlvbmFsIHRleHQgdG8gYXBwZW5kIHRvIHRoZSB5ZWFyIGluIHRoZSBtb250aCBoZWFkZXJzXG5cdH07XG5cdHRoaXMuX2RlZmF1bHRzID0geyAvLyBHbG9iYWwgZGVmYXVsdHMgZm9yIGFsbCB0aGUgZGF0ZSBwaWNrZXIgaW5zdGFuY2VzXG5cdFx0c2hvd09uOiBcImZvY3VzXCIsIC8vIFwiZm9jdXNcIiBmb3IgcG9wdXAgb24gZm9jdXMsXG5cdFx0XHQvLyBcImJ1dHRvblwiIGZvciB0cmlnZ2VyIGJ1dHRvbiwgb3IgXCJib3RoXCIgZm9yIGVpdGhlclxuXHRcdHNob3dBbmltOiBcImZhZGVJblwiLCAvLyBOYW1lIG9mIGpRdWVyeSBhbmltYXRpb24gZm9yIHBvcHVwXG5cdFx0c2hvd09wdGlvbnM6IHt9LCAvLyBPcHRpb25zIGZvciBlbmhhbmNlZCBhbmltYXRpb25zXG5cdFx0ZGVmYXVsdERhdGU6IG51bGwsIC8vIFVzZWQgd2hlbiBmaWVsZCBpcyBibGFuazogYWN0dWFsIGRhdGUsXG5cdFx0XHQvLyArLy1udW1iZXIgZm9yIG9mZnNldCBmcm9tIHRvZGF5LCBudWxsIGZvciB0b2RheVxuXHRcdGFwcGVuZFRleHQ6IFwiXCIsIC8vIERpc3BsYXkgdGV4dCBmb2xsb3dpbmcgdGhlIGlucHV0IGJveCwgZS5nLiBzaG93aW5nIHRoZSBmb3JtYXRcblx0XHRidXR0b25UZXh0OiBcIi4uLlwiLCAvLyBUZXh0IGZvciB0cmlnZ2VyIGJ1dHRvblxuXHRcdGJ1dHRvbkltYWdlOiBcIlwiLCAvLyBVUkwgZm9yIHRyaWdnZXIgYnV0dG9uIGltYWdlXG5cdFx0YnV0dG9uSW1hZ2VPbmx5OiBmYWxzZSwgLy8gVHJ1ZSBpZiB0aGUgaW1hZ2UgYXBwZWFycyBhbG9uZSwgZmFsc2UgaWYgaXQgYXBwZWFycyBvbiBhIGJ1dHRvblxuXHRcdGhpZGVJZk5vUHJldk5leHQ6IGZhbHNlLCAvLyBUcnVlIHRvIGhpZGUgbmV4dC9wcmV2aW91cyBtb250aCBsaW5rc1xuXHRcdFx0Ly8gaWYgbm90IGFwcGxpY2FibGUsIGZhbHNlIHRvIGp1c3QgZGlzYWJsZSB0aGVtXG5cdFx0bmF2aWdhdGlvbkFzRGF0ZUZvcm1hdDogZmFsc2UsIC8vIFRydWUgaWYgZGF0ZSBmb3JtYXR0aW5nIGFwcGxpZWQgdG8gcHJldi90b2RheS9uZXh0IGxpbmtzXG5cdFx0Z290b0N1cnJlbnQ6IGZhbHNlLCAvLyBUcnVlIGlmIHRvZGF5IGxpbmsgZ29lcyBiYWNrIHRvIGN1cnJlbnQgc2VsZWN0aW9uIGluc3RlYWRcblx0XHRjaGFuZ2VNb250aDogZmFsc2UsIC8vIFRydWUgaWYgbW9udGggY2FuIGJlIHNlbGVjdGVkIGRpcmVjdGx5LCBmYWxzZSBpZiBvbmx5IHByZXYvbmV4dFxuXHRcdGNoYW5nZVllYXI6IGZhbHNlLCAvLyBUcnVlIGlmIHllYXIgY2FuIGJlIHNlbGVjdGVkIGRpcmVjdGx5LCBmYWxzZSBpZiBvbmx5IHByZXYvbmV4dFxuXHRcdHllYXJSYW5nZTogXCJjLTEwOmMrMTBcIiwgLy8gUmFuZ2Ugb2YgeWVhcnMgdG8gZGlzcGxheSBpbiBkcm9wLWRvd24sXG5cdFx0XHQvLyBlaXRoZXIgcmVsYXRpdmUgdG8gdG9kYXkncyB5ZWFyICgtbm46K25uKSwgcmVsYXRpdmUgdG8gY3VycmVudGx5IGRpc3BsYXllZCB5ZWFyXG5cdFx0XHQvLyAoYy1ubjpjK25uKSwgYWJzb2x1dGUgKG5ubm46bm5ubiksIG9yIGEgY29tYmluYXRpb24gb2YgdGhlIGFib3ZlIChubm5uOi1uKVxuXHRcdHNob3dPdGhlck1vbnRoczogZmFsc2UsIC8vIFRydWUgdG8gc2hvdyBkYXRlcyBpbiBvdGhlciBtb250aHMsIGZhbHNlIHRvIGxlYXZlIGJsYW5rXG5cdFx0c2VsZWN0T3RoZXJNb250aHM6IGZhbHNlLCAvLyBUcnVlIHRvIGFsbG93IHNlbGVjdGlvbiBvZiBkYXRlcyBpbiBvdGhlciBtb250aHMsIGZhbHNlIGZvciB1bnNlbGVjdGFibGVcblx0XHRzaG93V2VlazogZmFsc2UsIC8vIFRydWUgdG8gc2hvdyB3ZWVrIG9mIHRoZSB5ZWFyLCBmYWxzZSB0byBub3Qgc2hvdyBpdFxuXHRcdGNhbGN1bGF0ZVdlZWs6IHRoaXMuaXNvODYwMVdlZWssIC8vIEhvdyB0byBjYWxjdWxhdGUgdGhlIHdlZWsgb2YgdGhlIHllYXIsXG5cdFx0XHQvLyB0YWtlcyBhIERhdGUgYW5kIHJldHVybnMgdGhlIG51bWJlciBvZiB0aGUgd2VlayBmb3IgaXRcblx0XHRzaG9ydFllYXJDdXRvZmY6IFwiKzEwXCIsIC8vIFNob3J0IHllYXIgdmFsdWVzIDwgdGhpcyBhcmUgaW4gdGhlIGN1cnJlbnQgY2VudHVyeSxcblx0XHRcdC8vID4gdGhpcyBhcmUgaW4gdGhlIHByZXZpb3VzIGNlbnR1cnksXG5cdFx0XHQvLyBzdHJpbmcgdmFsdWUgc3RhcnRpbmcgd2l0aCBcIitcIiBmb3IgY3VycmVudCB5ZWFyICsgdmFsdWVcblx0XHRtaW5EYXRlOiBudWxsLCAvLyBUaGUgZWFybGllc3Qgc2VsZWN0YWJsZSBkYXRlLCBvciBudWxsIGZvciBubyBsaW1pdFxuXHRcdG1heERhdGU6IG51bGwsIC8vIFRoZSBsYXRlc3Qgc2VsZWN0YWJsZSBkYXRlLCBvciBudWxsIGZvciBubyBsaW1pdFxuXHRcdGR1cmF0aW9uOiBcImZhc3RcIiwgLy8gRHVyYXRpb24gb2YgZGlzcGxheS9jbG9zdXJlXG5cdFx0YmVmb3JlU2hvd0RheTogbnVsbCwgLy8gRnVuY3Rpb24gdGhhdCB0YWtlcyBhIGRhdGUgYW5kIHJldHVybnMgYW4gYXJyYXkgd2l0aFxuXHRcdFx0Ly8gWzBdID0gdHJ1ZSBpZiBzZWxlY3RhYmxlLCBmYWxzZSBpZiBub3QsIFsxXSA9IGN1c3RvbSBDU1MgY2xhc3MgbmFtZShzKSBvciBcIlwiLFxuXHRcdFx0Ly8gWzJdID0gY2VsbCB0aXRsZSAob3B0aW9uYWwpLCBlLmcuICQuZGF0ZXBpY2tlci5ub1dlZWtlbmRzXG5cdFx0YmVmb3JlU2hvdzogbnVsbCwgLy8gRnVuY3Rpb24gdGhhdCB0YWtlcyBhbiBpbnB1dCBmaWVsZCBhbmRcblx0XHRcdC8vIHJldHVybnMgYSBzZXQgb2YgY3VzdG9tIHNldHRpbmdzIGZvciB0aGUgZGF0ZSBwaWNrZXJcblx0XHRvblNlbGVjdDogbnVsbCwgLy8gRGVmaW5lIGEgY2FsbGJhY2sgZnVuY3Rpb24gd2hlbiBhIGRhdGUgaXMgc2VsZWN0ZWRcblx0XHRvbkNoYW5nZU1vbnRoWWVhcjogbnVsbCwgLy8gRGVmaW5lIGEgY2FsbGJhY2sgZnVuY3Rpb24gd2hlbiB0aGUgbW9udGggb3IgeWVhciBpcyBjaGFuZ2VkXG5cdFx0b25DbG9zZTogbnVsbCwgLy8gRGVmaW5lIGEgY2FsbGJhY2sgZnVuY3Rpb24gd2hlbiB0aGUgZGF0ZXBpY2tlciBpcyBjbG9zZWRcblx0XHRudW1iZXJPZk1vbnRoczogMSwgLy8gTnVtYmVyIG9mIG1vbnRocyB0byBzaG93IGF0IGEgdGltZVxuXHRcdHNob3dDdXJyZW50QXRQb3M6IDAsIC8vIFRoZSBwb3NpdGlvbiBpbiBtdWx0aXBlIG1vbnRocyBhdCB3aGljaCB0byBzaG93IHRoZSBjdXJyZW50IG1vbnRoIChzdGFydGluZyBhdCAwKVxuXHRcdHN0ZXBNb250aHM6IDEsIC8vIE51bWJlciBvZiBtb250aHMgdG8gc3RlcCBiYWNrL2ZvcndhcmRcblx0XHRzdGVwQmlnTW9udGhzOiAxMiwgLy8gTnVtYmVyIG9mIG1vbnRocyB0byBzdGVwIGJhY2svZm9yd2FyZCBmb3IgdGhlIGJpZyBsaW5rc1xuXHRcdGFsdEZpZWxkOiBcIlwiLCAvLyBTZWxlY3RvciBmb3IgYW4gYWx0ZXJuYXRlIGZpZWxkIHRvIHN0b3JlIHNlbGVjdGVkIGRhdGVzIGludG9cblx0XHRhbHRGb3JtYXQ6IFwiXCIsIC8vIFRoZSBkYXRlIGZvcm1hdCB0byB1c2UgZm9yIHRoZSBhbHRlcm5hdGUgZmllbGRcblx0XHRjb25zdHJhaW5JbnB1dDogdHJ1ZSwgLy8gVGhlIGlucHV0IGlzIGNvbnN0cmFpbmVkIGJ5IHRoZSBjdXJyZW50IGRhdGUgZm9ybWF0XG5cdFx0c2hvd0J1dHRvblBhbmVsOiBmYWxzZSwgLy8gVHJ1ZSB0byBzaG93IGJ1dHRvbiBwYW5lbCwgZmFsc2UgdG8gbm90IHNob3cgaXRcblx0XHRhdXRvU2l6ZTogZmFsc2UsIC8vIFRydWUgdG8gc2l6ZSB0aGUgaW5wdXQgZm9yIHRoZSBkYXRlIGZvcm1hdCwgZmFsc2UgdG8gbGVhdmUgYXMgaXNcblx0XHRkaXNhYmxlZDogZmFsc2UgLy8gVGhlIGluaXRpYWwgZGlzYWJsZWQgc3RhdGVcblx0fTtcblx0JC5leHRlbmQoIHRoaXMuX2RlZmF1bHRzLCB0aGlzLnJlZ2lvbmFsWyBcIlwiIF0gKTtcblx0dGhpcy5yZWdpb25hbC5lbiA9ICQuZXh0ZW5kKCB0cnVlLCB7fSwgdGhpcy5yZWdpb25hbFsgXCJcIiBdICk7XG5cdHRoaXMucmVnaW9uYWxbIFwiZW4tVVNcIiBdID0gJC5leHRlbmQoIHRydWUsIHt9LCB0aGlzLnJlZ2lvbmFsLmVuICk7XG5cdHRoaXMuZHBEaXYgPSBkYXRlcGlja2VyX2JpbmRIb3ZlciggJCggXCI8ZGl2IGlkPSdcIiArIHRoaXMuX21haW5EaXZJZCArIFwiJyBjbGFzcz0ndWktZGF0ZXBpY2tlciB1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnQgdWktaGVscGVyLWNsZWFyZml4IHVpLWNvcm5lci1hbGwnPjwvZGl2PlwiICkgKTtcbn1cblxuJC5leHRlbmQoIERhdGVwaWNrZXIucHJvdG90eXBlLCB7XG5cdC8qIENsYXNzIG5hbWUgYWRkZWQgdG8gZWxlbWVudHMgdG8gaW5kaWNhdGUgYWxyZWFkeSBjb25maWd1cmVkIHdpdGggYSBkYXRlIHBpY2tlci4gKi9cblx0bWFya2VyQ2xhc3NOYW1lOiBcImhhc0RhdGVwaWNrZXJcIixcblxuXHQvL0tlZXAgdHJhY2sgb2YgdGhlIG1heGltdW0gbnVtYmVyIG9mIHJvd3MgZGlzcGxheWVkIChzZWUgIzcwNDMpXG5cdG1heFJvd3M6IDQsXG5cblx0Ly8gVE9ETyByZW5hbWUgdG8gXCJ3aWRnZXRcIiB3aGVuIHN3aXRjaGluZyB0byB3aWRnZXQgZmFjdG9yeVxuXHRfd2lkZ2V0RGF0ZXBpY2tlcjogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZHBEaXY7XG5cdH0sXG5cblx0LyogT3ZlcnJpZGUgdGhlIGRlZmF1bHQgc2V0dGluZ3MgZm9yIGFsbCBpbnN0YW5jZXMgb2YgdGhlIGRhdGUgcGlja2VyLlxuXHQgKiBAcGFyYW0gIHNldHRpbmdzICBvYmplY3QgLSB0aGUgbmV3IHNldHRpbmdzIHRvIHVzZSBhcyBkZWZhdWx0cyAoYW5vbnltb3VzIG9iamVjdClcblx0ICogQHJldHVybiB0aGUgbWFuYWdlciBvYmplY3Rcblx0ICovXG5cdHNldERlZmF1bHRzOiBmdW5jdGlvbiggc2V0dGluZ3MgKSB7XG5cdFx0ZGF0ZXBpY2tlcl9leHRlbmRSZW1vdmUoIHRoaXMuX2RlZmF1bHRzLCBzZXR0aW5ncyB8fCB7fSApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8qIEF0dGFjaCB0aGUgZGF0ZSBwaWNrZXIgdG8gYSBqUXVlcnkgc2VsZWN0aW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldFx0ZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcGFyYW0gIHNldHRpbmdzICBvYmplY3QgLSB0aGUgbmV3IHNldHRpbmdzIHRvIHVzZSBmb3IgdGhpcyBkYXRlIHBpY2tlciBpbnN0YW5jZSAoYW5vbnltb3VzKVxuXHQgKi9cblx0X2F0dGFjaERhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIHNldHRpbmdzICkge1xuXHRcdHZhciBub2RlTmFtZSwgaW5saW5lLCBpbnN0O1xuXHRcdG5vZGVOYW1lID0gdGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0aW5saW5lID0gKCBub2RlTmFtZSA9PT0gXCJkaXZcIiB8fCBub2RlTmFtZSA9PT0gXCJzcGFuXCIgKTtcblx0XHRpZiAoICF0YXJnZXQuaWQgKSB7XG5cdFx0XHR0aGlzLnV1aWQgKz0gMTtcblx0XHRcdHRhcmdldC5pZCA9IFwiZHBcIiArIHRoaXMudXVpZDtcblx0XHR9XG5cdFx0aW5zdCA9IHRoaXMuX25ld0luc3QoICQoIHRhcmdldCApLCBpbmxpbmUgKTtcblx0XHRpbnN0LnNldHRpbmdzID0gJC5leHRlbmQoIHt9LCBzZXR0aW5ncyB8fCB7fSApO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiApIHtcblx0XHRcdHRoaXMuX2Nvbm5lY3REYXRlcGlja2VyKCB0YXJnZXQsIGluc3QgKTtcblx0XHR9IGVsc2UgaWYgKCBpbmxpbmUgKSB7XG5cdFx0XHR0aGlzLl9pbmxpbmVEYXRlcGlja2VyKCB0YXJnZXQsIGluc3QgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogQ3JlYXRlIGEgbmV3IGluc3RhbmNlIG9iamVjdC4gKi9cblx0X25ld0luc3Q6IGZ1bmN0aW9uKCB0YXJnZXQsIGlubGluZSApIHtcblx0XHR2YXIgaWQgPSB0YXJnZXRbIDAgXS5pZC5yZXBsYWNlKCAvKFteQS1aYS16MC05X1xcLV0pL2csIFwiXFxcXFxcXFwkMVwiICk7IC8vIGVzY2FwZSBqUXVlcnkgbWV0YSBjaGFyc1xuXHRcdHJldHVybiB7IGlkOiBpZCwgaW5wdXQ6IHRhcmdldCwgLy8gYXNzb2NpYXRlZCB0YXJnZXRcblx0XHRcdHNlbGVjdGVkRGF5OiAwLCBzZWxlY3RlZE1vbnRoOiAwLCBzZWxlY3RlZFllYXI6IDAsIC8vIGN1cnJlbnQgc2VsZWN0aW9uXG5cdFx0XHRkcmF3TW9udGg6IDAsIGRyYXdZZWFyOiAwLCAvLyBtb250aCBiZWluZyBkcmF3blxuXHRcdFx0aW5saW5lOiBpbmxpbmUsIC8vIGlzIGRhdGVwaWNrZXIgaW5saW5lIG9yIG5vdFxuXHRcdFx0ZHBEaXY6ICggIWlubGluZSA/IHRoaXMuZHBEaXYgOiAvLyBwcmVzZW50YXRpb24gZGl2XG5cdFx0XHRkYXRlcGlja2VyX2JpbmRIb3ZlciggJCggXCI8ZGl2IGNsYXNzPSdcIiArIHRoaXMuX2lubGluZUNsYXNzICsgXCIgdWktZGF0ZXBpY2tlciB1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnQgdWktaGVscGVyLWNsZWFyZml4IHVpLWNvcm5lci1hbGwnPjwvZGl2PlwiICkgKSApIH07XG5cdH0sXG5cblx0LyogQXR0YWNoIHRoZSBkYXRlIHBpY2tlciB0byBhbiBpbnB1dCBmaWVsZC4gKi9cblx0X2Nvbm5lY3REYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBpbnN0ICkge1xuXHRcdHZhciBpbnB1dCA9ICQoIHRhcmdldCApO1xuXHRcdGluc3QuYXBwZW5kID0gJCggW10gKTtcblx0XHRpbnN0LnRyaWdnZXIgPSAkKCBbXSApO1xuXHRcdGlmICggaW5wdXQuaGFzQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuX2F0dGFjaG1lbnRzKCBpbnB1dCwgaW5zdCApO1xuXHRcdGlucHV0LmFkZENsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApLm9uKCBcImtleWRvd25cIiwgdGhpcy5fZG9LZXlEb3duICkuXG5cdFx0XHRvbiggXCJrZXlwcmVzc1wiLCB0aGlzLl9kb0tleVByZXNzICkub24oIFwia2V5dXBcIiwgdGhpcy5fZG9LZXlVcCApO1xuXHRcdHRoaXMuX2F1dG9TaXplKCBpbnN0ICk7XG5cdFx0JC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiLCBpbnN0ICk7XG5cblx0XHQvL0lmIGRpc2FibGVkIG9wdGlvbiBpcyB0cnVlLCBkaXNhYmxlIHRoZSBkYXRlcGlja2VyIG9uY2UgaXQgaGFzIGJlZW4gYXR0YWNoZWQgdG8gdGhlIGlucHV0IChzZWUgdGlja2V0ICM1NjY1KVxuXHRcdGlmICggaW5zdC5zZXR0aW5ncy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX2Rpc2FibGVEYXRlcGlja2VyKCB0YXJnZXQgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogTWFrZSBhdHRhY2htZW50cyBiYXNlZCBvbiBzZXR0aW5ncy4gKi9cblx0X2F0dGFjaG1lbnRzOiBmdW5jdGlvbiggaW5wdXQsIGluc3QgKSB7XG5cdFx0dmFyIHNob3dPbiwgYnV0dG9uVGV4dCwgYnV0dG9uSW1hZ2UsXG5cdFx0XHRhcHBlbmRUZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImFwcGVuZFRleHRcIiApLFxuXHRcdFx0aXNSVEwgPSB0aGlzLl9nZXQoIGluc3QsIFwiaXNSVExcIiApO1xuXG5cdFx0aWYgKCBpbnN0LmFwcGVuZCApIHtcblx0XHRcdGluc3QuYXBwZW5kLnJlbW92ZSgpO1xuXHRcdH1cblx0XHRpZiAoIGFwcGVuZFRleHQgKSB7XG5cdFx0XHRpbnN0LmFwcGVuZCA9ICQoIFwiPHNwYW4gY2xhc3M9J1wiICsgdGhpcy5fYXBwZW5kQ2xhc3MgKyBcIic+XCIgKyBhcHBlbmRUZXh0ICsgXCI8L3NwYW4+XCIgKTtcblx0XHRcdGlucHV0WyBpc1JUTCA/IFwiYmVmb3JlXCIgOiBcImFmdGVyXCIgXSggaW5zdC5hcHBlbmQgKTtcblx0XHR9XG5cblx0XHRpbnB1dC5vZmYoIFwiZm9jdXNcIiwgdGhpcy5fc2hvd0RhdGVwaWNrZXIgKTtcblxuXHRcdGlmICggaW5zdC50cmlnZ2VyICkge1xuXHRcdFx0aW5zdC50cmlnZ2VyLnJlbW92ZSgpO1xuXHRcdH1cblxuXHRcdHNob3dPbiA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93T25cIiApO1xuXHRcdGlmICggc2hvd09uID09PSBcImZvY3VzXCIgfHwgc2hvd09uID09PSBcImJvdGhcIiApIHsgLy8gcG9wLXVwIGRhdGUgcGlja2VyIHdoZW4gaW4gdGhlIG1hcmtlZCBmaWVsZFxuXHRcdFx0aW5wdXQub24oIFwiZm9jdXNcIiwgdGhpcy5fc2hvd0RhdGVwaWNrZXIgKTtcblx0XHR9XG5cdFx0aWYgKCBzaG93T24gPT09IFwiYnV0dG9uXCIgfHwgc2hvd09uID09PSBcImJvdGhcIiApIHsgLy8gcG9wLXVwIGRhdGUgcGlja2VyIHdoZW4gYnV0dG9uIGNsaWNrZWRcblx0XHRcdGJ1dHRvblRleHQgPSB0aGlzLl9nZXQoIGluc3QsIFwiYnV0dG9uVGV4dFwiICk7XG5cdFx0XHRidXR0b25JbWFnZSA9IHRoaXMuX2dldCggaW5zdCwgXCJidXR0b25JbWFnZVwiICk7XG5cdFx0XHRpbnN0LnRyaWdnZXIgPSAkKCB0aGlzLl9nZXQoIGluc3QsIFwiYnV0dG9uSW1hZ2VPbmx5XCIgKSA/XG5cdFx0XHRcdCQoIFwiPGltZy8+XCIgKS5hZGRDbGFzcyggdGhpcy5fdHJpZ2dlckNsYXNzICkuXG5cdFx0XHRcdFx0YXR0ciggeyBzcmM6IGJ1dHRvbkltYWdlLCBhbHQ6IGJ1dHRvblRleHQsIHRpdGxlOiBidXR0b25UZXh0IH0gKSA6XG5cdFx0XHRcdCQoIFwiPGJ1dHRvbiB0eXBlPSdidXR0b24nPjwvYnV0dG9uPlwiICkuYWRkQ2xhc3MoIHRoaXMuX3RyaWdnZXJDbGFzcyApLlxuXHRcdFx0XHRcdGh0bWwoICFidXR0b25JbWFnZSA/IGJ1dHRvblRleHQgOiAkKCBcIjxpbWcvPlwiICkuYXR0cihcblx0XHRcdFx0XHR7IHNyYzpidXR0b25JbWFnZSwgYWx0OmJ1dHRvblRleHQsIHRpdGxlOmJ1dHRvblRleHQgfSApICkgKTtcblx0XHRcdGlucHV0WyBpc1JUTCA/IFwiYmVmb3JlXCIgOiBcImFmdGVyXCIgXSggaW5zdC50cmlnZ2VyICk7XG5cdFx0XHRpbnN0LnRyaWdnZXIub24oIFwiY2xpY2tcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggJC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyAmJiAkLmRhdGVwaWNrZXIuX2xhc3RJbnB1dCA9PT0gaW5wdXRbIDAgXSApIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoICQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgJiYgJC5kYXRlcGlja2VyLl9sYXN0SW5wdXQgIT09IGlucHV0WyAwIF0gKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2hvd0RhdGVwaWNrZXIoIGlucHV0WyAwIF0gKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3Nob3dEYXRlcGlja2VyKCBpbnB1dFsgMCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBBcHBseSB0aGUgbWF4aW11bSBsZW5ndGggZm9yIHRoZSBkYXRlIGZvcm1hdC4gKi9cblx0X2F1dG9TaXplOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHRpZiAoIHRoaXMuX2dldCggaW5zdCwgXCJhdXRvU2l6ZVwiICkgJiYgIWluc3QuaW5saW5lICkge1xuXHRcdFx0dmFyIGZpbmRNYXgsIG1heCwgbWF4SSwgaSxcblx0XHRcdFx0ZGF0ZSA9IG5ldyBEYXRlKCAyMDA5LCAxMiAtIDEsIDIwICksIC8vIEVuc3VyZSBkb3VibGUgZGlnaXRzXG5cdFx0XHRcdGRhdGVGb3JtYXQgPSB0aGlzLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICk7XG5cblx0XHRcdGlmICggZGF0ZUZvcm1hdC5tYXRjaCggL1tETV0vICkgKSB7XG5cdFx0XHRcdGZpbmRNYXggPSBmdW5jdGlvbiggbmFtZXMgKSB7XG5cdFx0XHRcdFx0bWF4ID0gMDtcblx0XHRcdFx0XHRtYXhJID0gMDtcblx0XHRcdFx0XHRmb3IgKCBpID0gMDsgaSA8IG5hbWVzLmxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRcdFx0aWYgKCBuYW1lc1sgaSBdLmxlbmd0aCA+IG1heCApIHtcblx0XHRcdFx0XHRcdFx0bWF4ID0gbmFtZXNbIGkgXS5sZW5ndGg7XG5cdFx0XHRcdFx0XHRcdG1heEkgPSBpO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gbWF4STtcblx0XHRcdFx0fTtcblx0XHRcdFx0ZGF0ZS5zZXRNb250aCggZmluZE1heCggdGhpcy5fZ2V0KCBpbnN0LCAoIGRhdGVGb3JtYXQubWF0Y2goIC9NTS8gKSA/XG5cdFx0XHRcdFx0XCJtb250aE5hbWVzXCIgOiBcIm1vbnRoTmFtZXNTaG9ydFwiICkgKSApICk7XG5cdFx0XHRcdGRhdGUuc2V0RGF0ZSggZmluZE1heCggdGhpcy5fZ2V0KCBpbnN0LCAoIGRhdGVGb3JtYXQubWF0Y2goIC9ERC8gKSA/XG5cdFx0XHRcdFx0XCJkYXlOYW1lc1wiIDogXCJkYXlOYW1lc1Nob3J0XCIgKSApICkgKyAyMCAtIGRhdGUuZ2V0RGF5KCkgKTtcblx0XHRcdH1cblx0XHRcdGluc3QuaW5wdXQuYXR0ciggXCJzaXplXCIsIHRoaXMuX2Zvcm1hdERhdGUoIGluc3QsIGRhdGUgKS5sZW5ndGggKTtcblx0XHR9XG5cdH0sXG5cblx0LyogQXR0YWNoIGFuIGlubGluZSBkYXRlIHBpY2tlciB0byBhIGRpdi4gKi9cblx0X2lubGluZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIGluc3QgKSB7XG5cdFx0dmFyIGRpdlNwYW4gPSAkKCB0YXJnZXQgKTtcblx0XHRpZiAoIGRpdlNwYW4uaGFzQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGRpdlNwYW4uYWRkQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkuYXBwZW5kKCBpbnN0LmRwRGl2ICk7XG5cdFx0JC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiLCBpbnN0ICk7XG5cdFx0dGhpcy5fc2V0RGF0ZSggaW5zdCwgdGhpcy5fZ2V0RGVmYXVsdERhdGUoIGluc3QgKSwgdHJ1ZSApO1xuXHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHR0aGlzLl91cGRhdGVBbHRlcm5hdGUoIGluc3QgKTtcblxuXHRcdC8vSWYgZGlzYWJsZWQgb3B0aW9uIGlzIHRydWUsIGRpc2FibGUgdGhlIGRhdGVwaWNrZXIgYmVmb3JlIHNob3dpbmcgaXQgKHNlZSB0aWNrZXQgIzU2NjUpXG5cdFx0aWYgKCBpbnN0LnNldHRpbmdzLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fZGlzYWJsZURhdGVwaWNrZXIoIHRhcmdldCApO1xuXHRcdH1cblxuXHRcdC8vIFNldCBkaXNwbGF5OmJsb2NrIGluIHBsYWNlIG9mIGluc3QuZHBEaXYuc2hvdygpIHdoaWNoIHdvbid0IHdvcmsgb24gZGlzY29ubmVjdGVkIGVsZW1lbnRzXG5cdFx0Ly8gaHR0cDovL2J1Z3MuanF1ZXJ5dWkuY29tL3RpY2tldC83NTUyIC0gQSBEYXRlcGlja2VyIGNyZWF0ZWQgb24gYSBkZXRhY2hlZCBkaXYgaGFzIHplcm8gaGVpZ2h0XG5cdFx0aW5zdC5kcERpdi5jc3MoIFwiZGlzcGxheVwiLCBcImJsb2NrXCIgKTtcblx0fSxcblxuXHQvKiBQb3AtdXAgdGhlIGRhdGUgcGlja2VyIGluIGEgXCJkaWFsb2dcIiBib3guXG5cdCAqIEBwYXJhbSAgaW5wdXQgZWxlbWVudCAtIGlnbm9yZWRcblx0ICogQHBhcmFtICBkYXRlXHRzdHJpbmcgb3IgRGF0ZSAtIHRoZSBpbml0aWFsIGRhdGUgdG8gZGlzcGxheVxuXHQgKiBAcGFyYW0gIG9uU2VsZWN0ICBmdW5jdGlvbiAtIHRoZSBmdW5jdGlvbiB0byBjYWxsIHdoZW4gYSBkYXRlIGlzIHNlbGVjdGVkXG5cdCAqIEBwYXJhbSAgc2V0dGluZ3MgIG9iamVjdCAtIHVwZGF0ZSB0aGUgZGlhbG9nIGRhdGUgcGlja2VyIGluc3RhbmNlJ3Mgc2V0dGluZ3MgKGFub255bW91cyBvYmplY3QpXG5cdCAqIEBwYXJhbSAgcG9zIGludFsyXSAtIGNvb3JkaW5hdGVzIGZvciB0aGUgZGlhbG9nJ3MgcG9zaXRpb24gd2l0aGluIHRoZSBzY3JlZW4gb3Jcblx0ICpcdFx0XHRcdFx0ZXZlbnQgLSB3aXRoIHgveSBjb29yZGluYXRlcyBvclxuXHQgKlx0XHRcdFx0XHRsZWF2ZSBlbXB0eSBmb3IgZGVmYXVsdCAoc2NyZWVuIGNlbnRyZSlcblx0ICogQHJldHVybiB0aGUgbWFuYWdlciBvYmplY3Rcblx0ICovXG5cdF9kaWFsb2dEYXRlcGlja2VyOiBmdW5jdGlvbiggaW5wdXQsIGRhdGUsIG9uU2VsZWN0LCBzZXR0aW5ncywgcG9zICkge1xuXHRcdHZhciBpZCwgYnJvd3NlcldpZHRoLCBicm93c2VySGVpZ2h0LCBzY3JvbGxYLCBzY3JvbGxZLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2RpYWxvZ0luc3Q7IC8vIGludGVybmFsIGluc3RhbmNlXG5cblx0XHRpZiAoICFpbnN0ICkge1xuXHRcdFx0dGhpcy51dWlkICs9IDE7XG5cdFx0XHRpZCA9IFwiZHBcIiArIHRoaXMudXVpZDtcblx0XHRcdHRoaXMuX2RpYWxvZ0lucHV0ID0gJCggXCI8aW5wdXQgdHlwZT0ndGV4dCcgaWQ9J1wiICsgaWQgK1xuXHRcdFx0XHRcIicgc3R5bGU9J3Bvc2l0aW9uOiBhYnNvbHV0ZTsgdG9wOiAtMTAwcHg7IHdpZHRoOiAwcHg7Jy8+XCIgKTtcblx0XHRcdHRoaXMuX2RpYWxvZ0lucHV0Lm9uKCBcImtleWRvd25cIiwgdGhpcy5fZG9LZXlEb3duICk7XG5cdFx0XHQkKCBcImJvZHlcIiApLmFwcGVuZCggdGhpcy5fZGlhbG9nSW5wdXQgKTtcblx0XHRcdGluc3QgPSB0aGlzLl9kaWFsb2dJbnN0ID0gdGhpcy5fbmV3SW5zdCggdGhpcy5fZGlhbG9nSW5wdXQsIGZhbHNlICk7XG5cdFx0XHRpbnN0LnNldHRpbmdzID0ge307XG5cdFx0XHQkLmRhdGEoIHRoaXMuX2RpYWxvZ0lucHV0WyAwIF0sIFwiZGF0ZXBpY2tlclwiLCBpbnN0ICk7XG5cdFx0fVxuXHRcdGRhdGVwaWNrZXJfZXh0ZW5kUmVtb3ZlKCBpbnN0LnNldHRpbmdzLCBzZXR0aW5ncyB8fCB7fSApO1xuXHRcdGRhdGUgPSAoIGRhdGUgJiYgZGF0ZS5jb25zdHJ1Y3RvciA9PT0gRGF0ZSA/IHRoaXMuX2Zvcm1hdERhdGUoIGluc3QsIGRhdGUgKSA6IGRhdGUgKTtcblx0XHR0aGlzLl9kaWFsb2dJbnB1dC52YWwoIGRhdGUgKTtcblxuXHRcdHRoaXMuX3BvcyA9ICggcG9zID8gKCBwb3MubGVuZ3RoID8gcG9zIDogWyBwb3MucGFnZVgsIHBvcy5wYWdlWSBdICkgOiBudWxsICk7XG5cdFx0aWYgKCAhdGhpcy5fcG9zICkge1xuXHRcdFx0YnJvd3NlcldpZHRoID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoO1xuXHRcdFx0YnJvd3NlckhlaWdodCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQ7XG5cdFx0XHRzY3JvbGxYID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbExlZnQgfHwgZG9jdW1lbnQuYm9keS5zY3JvbGxMZWZ0O1xuXHRcdFx0c2Nyb2xsWSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3AgfHwgZG9jdW1lbnQuYm9keS5zY3JvbGxUb3A7XG5cdFx0XHR0aGlzLl9wb3MgPSAvLyBzaG91bGQgdXNlIGFjdHVhbCB3aWR0aC9oZWlnaHQgYmVsb3dcblx0XHRcdFx0WyAoIGJyb3dzZXJXaWR0aCAvIDIgKSAtIDEwMCArIHNjcm9sbFgsICggYnJvd3NlckhlaWdodCAvIDIgKSAtIDE1MCArIHNjcm9sbFkgXTtcblx0XHR9XG5cblx0XHQvLyBNb3ZlIGlucHV0IG9uIHNjcmVlbiBmb3IgZm9jdXMsIGJ1dCBoaWRkZW4gYmVoaW5kIGRpYWxvZ1xuXHRcdHRoaXMuX2RpYWxvZ0lucHV0LmNzcyggXCJsZWZ0XCIsICggdGhpcy5fcG9zWyAwIF0gKyAyMCApICsgXCJweFwiICkuY3NzKCBcInRvcFwiLCB0aGlzLl9wb3NbIDEgXSArIFwicHhcIiApO1xuXHRcdGluc3Quc2V0dGluZ3Mub25TZWxlY3QgPSBvblNlbGVjdDtcblx0XHR0aGlzLl9pbkRpYWxvZyA9IHRydWU7XG5cdFx0dGhpcy5kcERpdi5hZGRDbGFzcyggdGhpcy5fZGlhbG9nQ2xhc3MgKTtcblx0XHR0aGlzLl9zaG93RGF0ZXBpY2tlciggdGhpcy5fZGlhbG9nSW5wdXRbIDAgXSApO1xuXHRcdGlmICggJC5ibG9ja1VJICkge1xuXHRcdFx0JC5ibG9ja1VJKCB0aGlzLmRwRGl2ICk7XG5cdFx0fVxuXHRcdCQuZGF0YSggdGhpcy5fZGlhbG9nSW5wdXRbIDAgXSwgXCJkYXRlcGlja2VyXCIsIGluc3QgKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvKiBEZXRhY2ggYSBkYXRlcGlja2VyIGZyb20gaXRzIGNvbnRyb2wuXG5cdCAqIEBwYXJhbSAgdGFyZ2V0XHRlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqL1xuXHRfZGVzdHJveURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIG5vZGVOYW1lLFxuXHRcdFx0JHRhcmdldCA9ICQoIHRhcmdldCApLFxuXHRcdFx0aW5zdCA9ICQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiApO1xuXG5cdFx0aWYgKCAhJHRhcmdldC5oYXNDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRub2RlTmFtZSA9IHRhcmdldC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdCQucmVtb3ZlRGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiApO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiApIHtcblx0XHRcdGluc3QuYXBwZW5kLnJlbW92ZSgpO1xuXHRcdFx0aW5zdC50cmlnZ2VyLnJlbW92ZSgpO1xuXHRcdFx0JHRhcmdldC5yZW1vdmVDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKS5cblx0XHRcdFx0b2ZmKCBcImZvY3VzXCIsIHRoaXMuX3Nob3dEYXRlcGlja2VyICkuXG5cdFx0XHRcdG9mZiggXCJrZXlkb3duXCIsIHRoaXMuX2RvS2V5RG93biApLlxuXHRcdFx0XHRvZmYoIFwia2V5cHJlc3NcIiwgdGhpcy5fZG9LZXlQcmVzcyApLlxuXHRcdFx0XHRvZmYoIFwia2V5dXBcIiwgdGhpcy5fZG9LZXlVcCApO1xuXHRcdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcImRpdlwiIHx8IG5vZGVOYW1lID09PSBcInNwYW5cIiApIHtcblx0XHRcdCR0YXJnZXQucmVtb3ZlQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkuZW1wdHkoKTtcblx0XHR9XG5cblx0XHRpZiAoIGRhdGVwaWNrZXJfaW5zdEFjdGl2ZSA9PT0gaW5zdCApIHtcblx0XHRcdGRhdGVwaWNrZXJfaW5zdEFjdGl2ZSA9IG51bGw7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEVuYWJsZSB0aGUgZGF0ZSBwaWNrZXIgdG8gYSBqUXVlcnkgc2VsZWN0aW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldFx0ZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKi9cblx0X2VuYWJsZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIG5vZGVOYW1lLCBpbmxpbmUsXG5cdFx0XHQkdGFyZ2V0ID0gJCggdGFyZ2V0ICksXG5cdFx0XHRpbnN0ID0gJC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiICk7XG5cblx0XHRpZiAoICEkdGFyZ2V0Lmhhc0NsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdG5vZGVOYW1lID0gdGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICkge1xuXHRcdFx0dGFyZ2V0LmRpc2FibGVkID0gZmFsc2U7XG5cdFx0XHRpbnN0LnRyaWdnZXIuZmlsdGVyKCBcImJ1dHRvblwiICkuXG5cdFx0XHRcdGVhY2goIGZ1bmN0aW9uKCkgeyB0aGlzLmRpc2FibGVkID0gZmFsc2U7IH0gKS5lbmQoKS5cblx0XHRcdFx0ZmlsdGVyKCBcImltZ1wiICkuY3NzKCB7IG9wYWNpdHk6IFwiMS4wXCIsIGN1cnNvcjogXCJcIiB9ICk7XG5cdFx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiZGl2XCIgfHwgbm9kZU5hbWUgPT09IFwic3BhblwiICkge1xuXHRcdFx0aW5saW5lID0gJHRhcmdldC5jaGlsZHJlbiggXCIuXCIgKyB0aGlzLl9pbmxpbmVDbGFzcyApO1xuXHRcdFx0aW5saW5lLmNoaWxkcmVuKCkucmVtb3ZlQ2xhc3MoIFwidWktc3RhdGUtZGlzYWJsZWRcIiApO1xuXHRcdFx0aW5saW5lLmZpbmQoIFwic2VsZWN0LnVpLWRhdGVwaWNrZXItbW9udGgsIHNlbGVjdC51aS1kYXRlcGlja2VyLXllYXJcIiApLlxuXHRcdFx0XHRwcm9wKCBcImRpc2FibGVkXCIsIGZhbHNlICk7XG5cdFx0fVxuXHRcdHRoaXMuX2Rpc2FibGVkSW5wdXRzID0gJC5tYXAoIHRoaXMuX2Rpc2FibGVkSW5wdXRzLFxuXHRcdFx0ZnVuY3Rpb24oIHZhbHVlICkgeyByZXR1cm4gKCB2YWx1ZSA9PT0gdGFyZ2V0ID8gbnVsbCA6IHZhbHVlICk7IH0gKTsgLy8gZGVsZXRlIGVudHJ5XG5cdH0sXG5cblx0LyogRGlzYWJsZSB0aGUgZGF0ZSBwaWNrZXIgdG8gYSBqUXVlcnkgc2VsZWN0aW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldFx0ZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKi9cblx0X2Rpc2FibGVEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBub2RlTmFtZSwgaW5saW5lLFxuXHRcdFx0JHRhcmdldCA9ICQoIHRhcmdldCApLFxuXHRcdFx0aW5zdCA9ICQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiApO1xuXG5cdFx0aWYgKCAhJHRhcmdldC5oYXNDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRub2RlTmFtZSA9IHRhcmdldC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiApIHtcblx0XHRcdHRhcmdldC5kaXNhYmxlZCA9IHRydWU7XG5cdFx0XHRpbnN0LnRyaWdnZXIuZmlsdGVyKCBcImJ1dHRvblwiICkuXG5cdFx0XHRcdGVhY2goIGZ1bmN0aW9uKCkgeyB0aGlzLmRpc2FibGVkID0gdHJ1ZTsgfSApLmVuZCgpLlxuXHRcdFx0XHRmaWx0ZXIoIFwiaW1nXCIgKS5jc3MoIHsgb3BhY2l0eTogXCIwLjVcIiwgY3Vyc29yOiBcImRlZmF1bHRcIiB9ICk7XG5cdFx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiZGl2XCIgfHwgbm9kZU5hbWUgPT09IFwic3BhblwiICkge1xuXHRcdFx0aW5saW5lID0gJHRhcmdldC5jaGlsZHJlbiggXCIuXCIgKyB0aGlzLl9pbmxpbmVDbGFzcyApO1xuXHRcdFx0aW5saW5lLmNoaWxkcmVuKCkuYWRkQ2xhc3MoIFwidWktc3RhdGUtZGlzYWJsZWRcIiApO1xuXHRcdFx0aW5saW5lLmZpbmQoIFwic2VsZWN0LnVpLWRhdGVwaWNrZXItbW9udGgsIHNlbGVjdC51aS1kYXRlcGlja2VyLXllYXJcIiApLlxuXHRcdFx0XHRwcm9wKCBcImRpc2FibGVkXCIsIHRydWUgKTtcblx0XHR9XG5cdFx0dGhpcy5fZGlzYWJsZWRJbnB1dHMgPSAkLm1hcCggdGhpcy5fZGlzYWJsZWRJbnB1dHMsXG5cdFx0XHRmdW5jdGlvbiggdmFsdWUgKSB7IHJldHVybiAoIHZhbHVlID09PSB0YXJnZXQgPyBudWxsIDogdmFsdWUgKTsgfSApOyAvLyBkZWxldGUgZW50cnlcblx0XHR0aGlzLl9kaXNhYmxlZElucHV0c1sgdGhpcy5fZGlzYWJsZWRJbnB1dHMubGVuZ3RoIF0gPSB0YXJnZXQ7XG5cdH0sXG5cblx0LyogSXMgdGhlIGZpcnN0IGZpZWxkIGluIGEgalF1ZXJ5IGNvbGxlY3Rpb24gZGlzYWJsZWQgYXMgYSBkYXRlcGlja2VyP1xuXHQgKiBAcGFyYW0gIHRhcmdldFx0ZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcmV0dXJuIGJvb2xlYW4gLSB0cnVlIGlmIGRpc2FibGVkLCBmYWxzZSBpZiBlbmFibGVkXG5cdCAqL1xuXHRfaXNEaXNhYmxlZERhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0aWYgKCAhdGFyZ2V0ICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHRmb3IgKCB2YXIgaSA9IDA7IGkgPCB0aGlzLl9kaXNhYmxlZElucHV0cy5sZW5ndGg7IGkrKyApIHtcblx0XHRcdGlmICggdGhpcy5fZGlzYWJsZWRJbnB1dHNbIGkgXSA9PT0gdGFyZ2V0ICkge1xuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdC8qIFJldHJpZXZlIHRoZSBpbnN0YW5jZSBkYXRhIGZvciB0aGUgdGFyZ2V0IGNvbnRyb2wuXG5cdCAqIEBwYXJhbSAgdGFyZ2V0ICBlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEByZXR1cm4gIG9iamVjdCAtIHRoZSBhc3NvY2lhdGVkIGluc3RhbmNlIGRhdGFcblx0ICogQHRocm93cyAgZXJyb3IgaWYgYSBqUXVlcnkgcHJvYmxlbSBnZXR0aW5nIGRhdGFcblx0ICovXG5cdF9nZXRJbnN0OiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHRyeSB7XG5cdFx0XHRyZXR1cm4gJC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiICk7XG5cdFx0fVxuXHRcdGNhdGNoICggZXJyICkge1xuXHRcdFx0dGhyb3cgXCJNaXNzaW5nIGluc3RhbmNlIGRhdGEgZm9yIHRoaXMgZGF0ZXBpY2tlclwiO1xuXHRcdH1cblx0fSxcblxuXHQvKiBVcGRhdGUgb3IgcmV0cmlldmUgdGhlIHNldHRpbmdzIGZvciBhIGRhdGUgcGlja2VyIGF0dGFjaGVkIHRvIGFuIGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldCAgZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcGFyYW0gIG5hbWVcdG9iamVjdCAtIHRoZSBuZXcgc2V0dGluZ3MgdG8gdXBkYXRlIG9yXG5cdCAqXHRcdFx0XHRzdHJpbmcgLSB0aGUgbmFtZSBvZiB0aGUgc2V0dGluZyB0byBjaGFuZ2Ugb3IgcmV0cmlldmUsXG5cdCAqXHRcdFx0XHR3aGVuIHJldHJpZXZpbmcgYWxzbyBcImFsbFwiIGZvciBhbGwgaW5zdGFuY2Ugc2V0dGluZ3Mgb3Jcblx0ICpcdFx0XHRcdFwiZGVmYXVsdHNcIiBmb3IgYWxsIGdsb2JhbCBkZWZhdWx0c1xuXHQgKiBAcGFyYW0gIHZhbHVlICAgYW55IC0gdGhlIG5ldyB2YWx1ZSBmb3IgdGhlIHNldHRpbmdcblx0ICpcdFx0XHRcdChvbWl0IGlmIGFib3ZlIGlzIGFuIG9iamVjdCBvciB0byByZXRyaWV2ZSBhIHZhbHVlKVxuXHQgKi9cblx0X29wdGlvbkRhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIG5hbWUsIHZhbHVlICkge1xuXHRcdHZhciBzZXR0aW5ncywgZGF0ZSwgbWluRGF0ZSwgbWF4RGF0ZSxcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXQgKTtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA9PT0gMiAmJiB0eXBlb2YgbmFtZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiAoIG5hbWUgPT09IFwiZGVmYXVsdHNcIiA/ICQuZXh0ZW5kKCB7fSwgJC5kYXRlcGlja2VyLl9kZWZhdWx0cyApIDpcblx0XHRcdFx0KCBpbnN0ID8gKCBuYW1lID09PSBcImFsbFwiID8gJC5leHRlbmQoIHt9LCBpbnN0LnNldHRpbmdzICkgOlxuXHRcdFx0XHR0aGlzLl9nZXQoIGluc3QsIG5hbWUgKSApIDogbnVsbCApICk7XG5cdFx0fVxuXG5cdFx0c2V0dGluZ3MgPSBuYW1lIHx8IHt9O1xuXHRcdGlmICggdHlwZW9mIG5hbWUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRzZXR0aW5ncyA9IHt9O1xuXHRcdFx0c2V0dGluZ3NbIG5hbWUgXSA9IHZhbHVlO1xuXHRcdH1cblxuXHRcdGlmICggaW5zdCApIHtcblx0XHRcdGlmICggdGhpcy5fY3VySW5zdCA9PT0gaW5zdCApIHtcblx0XHRcdFx0dGhpcy5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdH1cblxuXHRcdFx0ZGF0ZSA9IHRoaXMuX2dldERhdGVEYXRlcGlja2VyKCB0YXJnZXQsIHRydWUgKTtcblx0XHRcdG1pbkRhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1pblwiICk7XG5cdFx0XHRtYXhEYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtYXhcIiApO1xuXHRcdFx0ZGF0ZXBpY2tlcl9leHRlbmRSZW1vdmUoIGluc3Quc2V0dGluZ3MsIHNldHRpbmdzICk7XG5cblx0XHRcdC8vIHJlZm9ybWF0IHRoZSBvbGQgbWluRGF0ZS9tYXhEYXRlIHZhbHVlcyBpZiBkYXRlRm9ybWF0IGNoYW5nZXMgYW5kIGEgbmV3IG1pbkRhdGUvbWF4RGF0ZSBpc24ndCBwcm92aWRlZFxuXHRcdFx0aWYgKCBtaW5EYXRlICE9PSBudWxsICYmIHNldHRpbmdzLmRhdGVGb3JtYXQgIT09IHVuZGVmaW5lZCAmJiBzZXR0aW5ncy5taW5EYXRlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGluc3Quc2V0dGluZ3MubWluRGF0ZSA9IHRoaXMuX2Zvcm1hdERhdGUoIGluc3QsIG1pbkRhdGUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggbWF4RGF0ZSAhPT0gbnVsbCAmJiBzZXR0aW5ncy5kYXRlRm9ybWF0ICE9PSB1bmRlZmluZWQgJiYgc2V0dGluZ3MubWF4RGF0ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRpbnN0LnNldHRpbmdzLm1heERhdGUgPSB0aGlzLl9mb3JtYXREYXRlKCBpbnN0LCBtYXhEYXRlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIFwiZGlzYWJsZWRcIiBpbiBzZXR0aW5ncyApIHtcblx0XHRcdFx0aWYgKCBzZXR0aW5ncy5kaXNhYmxlZCApIHtcblx0XHRcdFx0XHR0aGlzLl9kaXNhYmxlRGF0ZXBpY2tlciggdGFyZ2V0ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fZW5hYmxlRGF0ZXBpY2tlciggdGFyZ2V0ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuX2F0dGFjaG1lbnRzKCAkKCB0YXJnZXQgKSwgaW5zdCApO1xuXHRcdFx0dGhpcy5fYXV0b1NpemUoIGluc3QgKTtcblx0XHRcdHRoaXMuX3NldERhdGUoIGluc3QsIGRhdGUgKTtcblx0XHRcdHRoaXMuX3VwZGF0ZUFsdGVybmF0ZSggaW5zdCApO1xuXHRcdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdH1cblx0fSxcblxuXHQvLyBDaGFuZ2UgbWV0aG9kIGRlcHJlY2F0ZWRcblx0X2NoYW5nZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIG5hbWUsIHZhbHVlICkge1xuXHRcdHRoaXMuX29wdGlvbkRhdGVwaWNrZXIoIHRhcmdldCwgbmFtZSwgdmFsdWUgKTtcblx0fSxcblxuXHQvKiBSZWRyYXcgdGhlIGRhdGUgcGlja2VyIGF0dGFjaGVkIHRvIGFuIGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldCAgZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKi9cblx0X3JlZnJlc2hEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0ICk7XG5cdFx0aWYgKCBpbnN0ICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBTZXQgdGhlIGRhdGVzIGZvciBhIGpRdWVyeSBzZWxlY3Rpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0IGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHBhcmFtICBkYXRlXHREYXRlIC0gdGhlIG5ldyBkYXRlXG5cdCAqL1xuXHRfc2V0RGF0ZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIGRhdGUgKSB7XG5cdFx0dmFyIGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXQgKTtcblx0XHRpZiAoIGluc3QgKSB7XG5cdFx0XHR0aGlzLl9zZXREYXRlKCBpbnN0LCBkYXRlICk7XG5cdFx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0XHR0aGlzLl91cGRhdGVBbHRlcm5hdGUoIGluc3QgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogR2V0IHRoZSBkYXRlKHMpIGZvciB0aGUgZmlyc3QgZW50cnkgaW4gYSBqUXVlcnkgc2VsZWN0aW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldCBlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEBwYXJhbSAgbm9EZWZhdWx0IGJvb2xlYW4gLSB0cnVlIGlmIG5vIGRlZmF1bHQgZGF0ZSBpcyB0byBiZSB1c2VkXG5cdCAqIEByZXR1cm4gRGF0ZSAtIHRoZSBjdXJyZW50IGRhdGVcblx0ICovXG5cdF9nZXREYXRlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgbm9EZWZhdWx0ICkge1xuXHRcdHZhciBpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0ICk7XG5cdFx0aWYgKCBpbnN0ICYmICFpbnN0LmlubGluZSApIHtcblx0XHRcdHRoaXMuX3NldERhdGVGcm9tRmllbGQoIGluc3QsIG5vRGVmYXVsdCApO1xuXHRcdH1cblx0XHRyZXR1cm4gKCBpbnN0ID8gdGhpcy5fZ2V0RGF0ZSggaW5zdCApIDogbnVsbCApO1xuXHR9LFxuXG5cdC8qIEhhbmRsZSBrZXlzdHJva2VzLiAqL1xuXHRfZG9LZXlEb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG9uU2VsZWN0LCBkYXRlU3RyLCBzZWwsXG5cdFx0XHRpbnN0ID0gJC5kYXRlcGlja2VyLl9nZXRJbnN0KCBldmVudC50YXJnZXQgKSxcblx0XHRcdGhhbmRsZWQgPSB0cnVlLFxuXHRcdFx0aXNSVEwgPSBpbnN0LmRwRGl2LmlzKCBcIi51aS1kYXRlcGlja2VyLXJ0bFwiICk7XG5cblx0XHRpbnN0Ll9rZXlFdmVudCA9IHRydWU7XG5cdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICkge1xuXHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdFx0Y2FzZSA5OiAkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gaGlkZSBvbiB0YWIgb3V0XG5cdFx0XHRcdGNhc2UgMTM6IHNlbCA9ICQoIFwidGQuXCIgKyAkLmRhdGVwaWNrZXIuX2RheU92ZXJDbGFzcyArIFwiOm5vdCguXCIgK1xuXHRcdFx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9jdXJyZW50Q2xhc3MgKyBcIilcIiwgaW5zdC5kcERpdiApO1xuXHRcdFx0XHRcdFx0aWYgKCBzZWxbIDAgXSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zZWxlY3REYXkoIGV2ZW50LnRhcmdldCwgaW5zdC5zZWxlY3RlZE1vbnRoLCBpbnN0LnNlbGVjdGVkWWVhciwgc2VsWyAwIF0gKTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0b25TZWxlY3QgPSAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJvblNlbGVjdFwiICk7XG5cdFx0XHRcdFx0XHRpZiAoIG9uU2VsZWN0ICkge1xuXHRcdFx0XHRcdFx0XHRkYXRlU3RyID0gJC5kYXRlcGlja2VyLl9mb3JtYXREYXRlKCBpbnN0ICk7XG5cblx0XHRcdFx0XHRcdFx0Ly8gVHJpZ2dlciBjdXN0b20gY2FsbGJhY2tcblx0XHRcdFx0XHRcdFx0b25TZWxlY3QuYXBwbHkoICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXRbIDAgXSA6IG51bGwgKSwgWyBkYXRlU3RyLCBpbnN0IF0gKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlOyAvLyBkb24ndCBzdWJtaXQgdGhlIGZvcm1cblx0XHRcdFx0Y2FzZSAyNzogJC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIGhpZGUgb24gZXNjYXBlXG5cdFx0XHRcdGNhc2UgMzM6ICQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGV2ZW50LmN0cmxLZXkgP1xuXHRcdFx0XHRcdFx0XHQtJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcEJpZ01vbnRoc1wiICkgOlxuXHRcdFx0XHRcdFx0XHQtJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICkgKSwgXCJNXCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBwcmV2aW91cyBtb250aC95ZWFyIG9uIHBhZ2UgdXAvKyBjdHJsXG5cdFx0XHRcdGNhc2UgMzQ6ICQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGV2ZW50LmN0cmxLZXkgP1xuXHRcdFx0XHRcdFx0XHQrJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcEJpZ01vbnRoc1wiICkgOlxuXHRcdFx0XHRcdFx0XHQrJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICkgKSwgXCJNXCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBuZXh0IG1vbnRoL3llYXIgb24gcGFnZSBkb3duLysgY3RybFxuXHRcdFx0XHRjYXNlIDM1OiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9jbGVhckRhdGUoIGV2ZW50LnRhcmdldCApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBjbGVhciBvbiBjdHJsIG9yIGNvbW1hbmQgK2VuZFxuXHRcdFx0XHRjYXNlIDM2OiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9nb3RvVG9kYXkoIGV2ZW50LnRhcmdldCApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBjdXJyZW50IG9uIGN0cmwgb3IgY29tbWFuZCAraG9tZVxuXHRcdFx0XHRjYXNlIDM3OiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggaXNSVEwgPyArMSA6IC0xICksIFwiRFwiICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXG5cdFx0XHRcdFx0XHQvLyAtMSBkYXkgb24gY3RybCBvciBjb21tYW5kICtsZWZ0XG5cdFx0XHRcdFx0XHRpZiAoIGV2ZW50Lm9yaWdpbmFsRXZlbnQuYWx0S2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBldmVudC5jdHJsS2V5ID9cblx0XHRcdFx0XHRcdFx0XHQtJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcEJpZ01vbnRoc1wiICkgOlxuXHRcdFx0XHRcdFx0XHRcdC0kLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSApLCBcIk1cIiApO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBuZXh0IG1vbnRoL3llYXIgb24gYWx0ICtsZWZ0IG9uIE1hY1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgMzg6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgLTcsIFwiRFwiICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIC0xIHdlZWsgb24gY3RybCBvciBjb21tYW5kICt1cFxuXHRcdFx0XHRjYXNlIDM5OiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggaXNSVEwgPyAtMSA6ICsxICksIFwiRFwiICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXG5cdFx0XHRcdFx0XHQvLyArMSBkYXkgb24gY3RybCBvciBjb21tYW5kICtyaWdodFxuXHRcdFx0XHRcdFx0aWYgKCBldmVudC5vcmlnaW5hbEV2ZW50LmFsdEtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggZXZlbnQuY3RybEtleSA/XG5cdFx0XHRcdFx0XHRcdFx0KyQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBCaWdNb250aHNcIiApIDpcblx0XHRcdFx0XHRcdFx0XHQrJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICkgKSwgXCJNXCIgKTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gbmV4dCBtb250aC95ZWFyIG9uIGFsdCArcmlnaHRcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIDQwOiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICs3LCBcIkRcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyArMSB3ZWVrIG9uIGN0cmwgb3IgY29tbWFuZCArZG93blxuXHRcdFx0XHRkZWZhdWx0OiBoYW5kbGVkID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIGlmICggZXZlbnQua2V5Q29kZSA9PT0gMzYgJiYgZXZlbnQuY3RybEtleSApIHsgLy8gZGlzcGxheSB0aGUgZGF0ZSBwaWNrZXIgb24gY3RybCtob21lXG5cdFx0XHQkLmRhdGVwaWNrZXIuX3Nob3dEYXRlcGlja2VyKCB0aGlzICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGhhbmRsZWQgPSBmYWxzZTtcblx0XHR9XG5cblx0XHRpZiAoIGhhbmRsZWQgKSB7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0ZXZlbnQuc3RvcFByb3BhZ2F0aW9uKCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEZpbHRlciBlbnRlcmVkIGNoYXJhY3RlcnMgLSBiYXNlZCBvbiBkYXRlIGZvcm1hdC4gKi9cblx0X2RvS2V5UHJlc3M6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgY2hhcnMsIGNocixcblx0XHRcdGluc3QgPSAkLmRhdGVwaWNrZXIuX2dldEluc3QoIGV2ZW50LnRhcmdldCApO1xuXG5cdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJjb25zdHJhaW5JbnB1dFwiICkgKSB7XG5cdFx0XHRjaGFycyA9ICQuZGF0ZXBpY2tlci5fcG9zc2libGVDaGFycyggJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICkgKTtcblx0XHRcdGNociA9IFN0cmluZy5mcm9tQ2hhckNvZGUoIGV2ZW50LmNoYXJDb2RlID09IG51bGwgPyBldmVudC5rZXlDb2RlIDogZXZlbnQuY2hhckNvZGUgKTtcblx0XHRcdHJldHVybiBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgKCBjaHIgPCBcIiBcIiB8fCAhY2hhcnMgfHwgY2hhcnMuaW5kZXhPZiggY2hyICkgPiAtMSApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBTeW5jaHJvbmlzZSBtYW51YWwgZW50cnkgYW5kIGZpZWxkL2FsdGVybmF0ZSBmaWVsZC4gKi9cblx0X2RvS2V5VXA6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZGF0ZSxcblx0XHRcdGluc3QgPSAkLmRhdGVwaWNrZXIuX2dldEluc3QoIGV2ZW50LnRhcmdldCApO1xuXG5cdFx0aWYgKCBpbnN0LmlucHV0LnZhbCgpICE9PSBpbnN0Lmxhc3RWYWwgKSB7XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRkYXRlID0gJC5kYXRlcGlja2VyLnBhcnNlRGF0ZSggJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICksXG5cdFx0XHRcdFx0KCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dC52YWwoKSA6IG51bGwgKSxcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICk7XG5cblx0XHRcdFx0aWYgKCBkYXRlICkgeyAvLyBvbmx5IGlmIHZhbGlkXG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zZXREYXRlRnJvbUZpZWxkKCBpbnN0ICk7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl91cGRhdGVBbHRlcm5hdGUoIGluc3QgKTtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0Y2F0Y2ggKCBlcnIgKSB7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdC8qIFBvcC11cCB0aGUgZGF0ZSBwaWNrZXIgZm9yIGEgZ2l2ZW4gaW5wdXQgZmllbGQuXG5cdCAqIElmIGZhbHNlIHJldHVybmVkIGZyb20gYmVmb3JlU2hvdyBldmVudCBoYW5kbGVyIGRvIG5vdCBzaG93LlxuXHQgKiBAcGFyYW0gIGlucHV0ICBlbGVtZW50IC0gdGhlIGlucHV0IGZpZWxkIGF0dGFjaGVkIHRvIHRoZSBkYXRlIHBpY2tlciBvclxuXHQgKlx0XHRcdFx0XHRldmVudCAtIGlmIHRyaWdnZXJlZCBieSBmb2N1c1xuXHQgKi9cblx0X3Nob3dEYXRlcGlja2VyOiBmdW5jdGlvbiggaW5wdXQgKSB7XG5cdFx0aW5wdXQgPSBpbnB1dC50YXJnZXQgfHwgaW5wdXQ7XG5cdFx0aWYgKCBpbnB1dC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSBcImlucHV0XCIgKSB7IC8vIGZpbmQgZnJvbSBidXR0b24vaW1hZ2UgdHJpZ2dlclxuXHRcdFx0aW5wdXQgPSAkKCBcImlucHV0XCIsIGlucHV0LnBhcmVudE5vZGUgKVsgMCBdO1xuXHRcdH1cblxuXHRcdGlmICggJC5kYXRlcGlja2VyLl9pc0Rpc2FibGVkRGF0ZXBpY2tlciggaW5wdXQgKSB8fCAkLmRhdGVwaWNrZXIuX2xhc3RJbnB1dCA9PT0gaW5wdXQgKSB7IC8vIGFscmVhZHkgaGVyZVxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBpbnN0LCBiZWZvcmVTaG93LCBiZWZvcmVTaG93U2V0dGluZ3MsIGlzRml4ZWQsXG5cdFx0XHRvZmZzZXQsIHNob3dBbmltLCBkdXJhdGlvbjtcblxuXHRcdGluc3QgPSAkLmRhdGVwaWNrZXIuX2dldEluc3QoIGlucHV0ICk7XG5cdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2N1ckluc3QgJiYgJC5kYXRlcGlja2VyLl9jdXJJbnN0ICE9PSBpbnN0ICkge1xuXHRcdFx0JC5kYXRlcGlja2VyLl9jdXJJbnN0LmRwRGl2LnN0b3AoIHRydWUsIHRydWUgKTtcblx0XHRcdGlmICggaW5zdCAmJiAkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICkge1xuXHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCAkLmRhdGVwaWNrZXIuX2N1ckluc3QuaW5wdXRbIDAgXSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGJlZm9yZVNob3cgPSAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJiZWZvcmVTaG93XCIgKTtcblx0XHRiZWZvcmVTaG93U2V0dGluZ3MgPSBiZWZvcmVTaG93ID8gYmVmb3JlU2hvdy5hcHBseSggaW5wdXQsIFsgaW5wdXQsIGluc3QgXSApIDoge307XG5cdFx0aWYgKCBiZWZvcmVTaG93U2V0dGluZ3MgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRkYXRlcGlja2VyX2V4dGVuZFJlbW92ZSggaW5zdC5zZXR0aW5ncywgYmVmb3JlU2hvd1NldHRpbmdzICk7XG5cblx0XHRpbnN0Lmxhc3RWYWwgPSBudWxsO1xuXHRcdCQuZGF0ZXBpY2tlci5fbGFzdElucHV0ID0gaW5wdXQ7XG5cdFx0JC5kYXRlcGlja2VyLl9zZXREYXRlRnJvbUZpZWxkKCBpbnN0ICk7XG5cblx0XHRpZiAoICQuZGF0ZXBpY2tlci5faW5EaWFsb2cgKSB7IC8vIGhpZGUgY3Vyc29yXG5cdFx0XHRpbnB1dC52YWx1ZSA9IFwiXCI7XG5cdFx0fVxuXHRcdGlmICggISQuZGF0ZXBpY2tlci5fcG9zICkgeyAvLyBwb3NpdGlvbiBiZWxvdyBpbnB1dFxuXHRcdFx0JC5kYXRlcGlja2VyLl9wb3MgPSAkLmRhdGVwaWNrZXIuX2ZpbmRQb3MoIGlucHV0ICk7XG5cdFx0XHQkLmRhdGVwaWNrZXIuX3Bvc1sgMSBdICs9IGlucHV0Lm9mZnNldEhlaWdodDsgLy8gYWRkIHRoZSBoZWlnaHRcblx0XHR9XG5cblx0XHRpc0ZpeGVkID0gZmFsc2U7XG5cdFx0JCggaW5wdXQgKS5wYXJlbnRzKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRpc0ZpeGVkIHw9ICQoIHRoaXMgKS5jc3MoIFwicG9zaXRpb25cIiApID09PSBcImZpeGVkXCI7XG5cdFx0XHRyZXR1cm4gIWlzRml4ZWQ7XG5cdFx0fSApO1xuXG5cdFx0b2Zmc2V0ID0geyBsZWZ0OiAkLmRhdGVwaWNrZXIuX3Bvc1sgMCBdLCB0b3A6ICQuZGF0ZXBpY2tlci5fcG9zWyAxIF0gfTtcblx0XHQkLmRhdGVwaWNrZXIuX3BvcyA9IG51bGw7XG5cblx0XHQvL3RvIGF2b2lkIGZsYXNoZXMgb24gRmlyZWZveFxuXHRcdGluc3QuZHBEaXYuZW1wdHkoKTtcblxuXHRcdC8vIGRldGVybWluZSBzaXppbmcgb2Zmc2NyZWVuXG5cdFx0aW5zdC5kcERpdi5jc3MoIHsgcG9zaXRpb246IFwiYWJzb2x1dGVcIiwgZGlzcGxheTogXCJibG9ja1wiLCB0b3A6IFwiLTEwMDBweFwiIH0gKTtcblx0XHQkLmRhdGVwaWNrZXIuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblxuXHRcdC8vIGZpeCB3aWR0aCBmb3IgZHluYW1pYyBudW1iZXIgb2YgZGF0ZSBwaWNrZXJzXG5cdFx0Ly8gYW5kIGFkanVzdCBwb3NpdGlvbiBiZWZvcmUgc2hvd2luZ1xuXHRcdG9mZnNldCA9ICQuZGF0ZXBpY2tlci5fY2hlY2tPZmZzZXQoIGluc3QsIG9mZnNldCwgaXNGaXhlZCApO1xuXHRcdGluc3QuZHBEaXYuY3NzKCB7IHBvc2l0aW9uOiAoICQuZGF0ZXBpY2tlci5faW5EaWFsb2cgJiYgJC5ibG9ja1VJID9cblx0XHRcdFwic3RhdGljXCIgOiAoIGlzRml4ZWQgPyBcImZpeGVkXCIgOiBcImFic29sdXRlXCIgKSApLCBkaXNwbGF5OiBcIm5vbmVcIixcblx0XHRcdGxlZnQ6IG9mZnNldC5sZWZ0ICsgXCJweFwiLCB0b3A6IG9mZnNldC50b3AgKyBcInB4XCIgfSApO1xuXG5cdFx0aWYgKCAhaW5zdC5pbmxpbmUgKSB7XG5cdFx0XHRzaG93QW5pbSA9ICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInNob3dBbmltXCIgKTtcblx0XHRcdGR1cmF0aW9uID0gJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiZHVyYXRpb25cIiApO1xuXHRcdFx0aW5zdC5kcERpdi5jc3MoIFwiei1pbmRleFwiLCBkYXRlcGlja2VyX2dldFppbmRleCggJCggaW5wdXQgKSApICsgMSApO1xuXHRcdFx0JC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyA9IHRydWU7XG5cblx0XHRcdGlmICggJC5lZmZlY3RzICYmICQuZWZmZWN0cy5lZmZlY3RbIHNob3dBbmltIF0gKSB7XG5cdFx0XHRcdGluc3QuZHBEaXYuc2hvdyggc2hvd0FuaW0sICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInNob3dPcHRpb25zXCIgKSwgZHVyYXRpb24gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGluc3QuZHBEaXZbIHNob3dBbmltIHx8IFwic2hvd1wiIF0oIHNob3dBbmltID8gZHVyYXRpb24gOiBudWxsICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggJC5kYXRlcGlja2VyLl9zaG91bGRGb2N1c0lucHV0KCBpbnN0ICkgKSB7XG5cdFx0XHRcdGluc3QuaW5wdXQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHR9XG5cblx0XHRcdCQuZGF0ZXBpY2tlci5fY3VySW5zdCA9IGluc3Q7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEdlbmVyYXRlIHRoZSBkYXRlIHBpY2tlciBjb250ZW50LiAqL1xuXHRfdXBkYXRlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dGhpcy5tYXhSb3dzID0gNDsgLy9SZXNldCB0aGUgbWF4IG51bWJlciBvZiByb3dzIGJlaW5nIGRpc3BsYXllZCAoc2VlICM3MDQzKVxuXHRcdGRhdGVwaWNrZXJfaW5zdEFjdGl2ZSA9IGluc3Q7IC8vIGZvciBkZWxlZ2F0ZSBob3ZlciBldmVudHNcblx0XHRpbnN0LmRwRGl2LmVtcHR5KCkuYXBwZW5kKCB0aGlzLl9nZW5lcmF0ZUhUTUwoIGluc3QgKSApO1xuXHRcdHRoaXMuX2F0dGFjaEhhbmRsZXJzKCBpbnN0ICk7XG5cblx0XHR2YXIgb3JpZ3llYXJzaHRtbCxcblx0XHRcdG51bU1vbnRocyA9IHRoaXMuX2dldE51bWJlck9mTW9udGhzKCBpbnN0ICksXG5cdFx0XHRjb2xzID0gbnVtTW9udGhzWyAxIF0sXG5cdFx0XHR3aWR0aCA9IDE3LFxuXHRcdFx0YWN0aXZlQ2VsbCA9IGluc3QuZHBEaXYuZmluZCggXCIuXCIgKyB0aGlzLl9kYXlPdmVyQ2xhc3MgKyBcIiBhXCIgKTtcblxuXHRcdGlmICggYWN0aXZlQ2VsbC5sZW5ndGggPiAwICkge1xuXHRcdFx0ZGF0ZXBpY2tlcl9oYW5kbGVNb3VzZW92ZXIuYXBwbHkoIGFjdGl2ZUNlbGwuZ2V0KCAwICkgKTtcblx0XHR9XG5cblx0XHRpbnN0LmRwRGl2LnJlbW92ZUNsYXNzKCBcInVpLWRhdGVwaWNrZXItbXVsdGktMiB1aS1kYXRlcGlja2VyLW11bHRpLTMgdWktZGF0ZXBpY2tlci1tdWx0aS00XCIgKS53aWR0aCggXCJcIiApO1xuXHRcdGlmICggY29scyA+IDEgKSB7XG5cdFx0XHRpbnN0LmRwRGl2LmFkZENsYXNzKCBcInVpLWRhdGVwaWNrZXItbXVsdGktXCIgKyBjb2xzICkuY3NzKCBcIndpZHRoXCIsICggd2lkdGggKiBjb2xzICkgKyBcImVtXCIgKTtcblx0XHR9XG5cdFx0aW5zdC5kcERpdlsgKCBudW1Nb250aHNbIDAgXSAhPT0gMSB8fCBudW1Nb250aHNbIDEgXSAhPT0gMSA/IFwiYWRkXCIgOiBcInJlbW92ZVwiICkgK1xuXHRcdFx0XCJDbGFzc1wiIF0oIFwidWktZGF0ZXBpY2tlci1tdWx0aVwiICk7XG5cdFx0aW5zdC5kcERpdlsgKCB0aGlzLl9nZXQoIGluc3QsIFwiaXNSVExcIiApID8gXCJhZGRcIiA6IFwicmVtb3ZlXCIgKSArXG5cdFx0XHRcIkNsYXNzXCIgXSggXCJ1aS1kYXRlcGlja2VyLXJ0bFwiICk7XG5cblx0XHRpZiAoIGluc3QgPT09ICQuZGF0ZXBpY2tlci5fY3VySW5zdCAmJiAkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICYmICQuZGF0ZXBpY2tlci5fc2hvdWxkRm9jdXNJbnB1dCggaW5zdCApICkge1xuXHRcdFx0aW5zdC5pbnB1dC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHR9XG5cblx0XHQvLyBEZWZmZXJlZCByZW5kZXIgb2YgdGhlIHllYXJzIHNlbGVjdCAodG8gYXZvaWQgZmxhc2hlcyBvbiBGaXJlZm94KVxuXHRcdGlmICggaW5zdC55ZWFyc2h0bWwgKSB7XG5cdFx0XHRvcmlneWVhcnNodG1sID0gaW5zdC55ZWFyc2h0bWw7XG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvL2Fzc3VyZSB0aGF0IGluc3QueWVhcnNodG1sIGRpZG4ndCBjaGFuZ2UuXG5cdFx0XHRcdGlmICggb3JpZ3llYXJzaHRtbCA9PT0gaW5zdC55ZWFyc2h0bWwgJiYgaW5zdC55ZWFyc2h0bWwgKSB7XG5cdFx0XHRcdFx0aW5zdC5kcERpdi5maW5kKCBcInNlbGVjdC51aS1kYXRlcGlja2VyLXllYXI6Zmlyc3RcIiApLnJlcGxhY2VXaXRoKCBpbnN0LnllYXJzaHRtbCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG9yaWd5ZWFyc2h0bWwgPSBpbnN0LnllYXJzaHRtbCA9IG51bGw7XG5cdFx0XHR9LCAwICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vICM2Njk0IC0gZG9uJ3QgZm9jdXMgdGhlIGlucHV0IGlmIGl0J3MgYWxyZWFkeSBmb2N1c2VkXG5cdC8vIHRoaXMgYnJlYWtzIHRoZSBjaGFuZ2UgZXZlbnQgaW4gSUVcblx0Ly8gU3VwcG9ydDogSUUgYW5kIGpRdWVyeSA8MS45XG5cdF9zaG91bGRGb2N1c0lucHV0OiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHRyZXR1cm4gaW5zdC5pbnB1dCAmJiBpbnN0LmlucHV0LmlzKCBcIjp2aXNpYmxlXCIgKSAmJiAhaW5zdC5pbnB1dC5pcyggXCI6ZGlzYWJsZWRcIiApICYmICFpbnN0LmlucHV0LmlzKCBcIjpmb2N1c1wiICk7XG5cdH0sXG5cblx0LyogQ2hlY2sgcG9zaXRpb25pbmcgdG8gcmVtYWluIG9uIHNjcmVlbi4gKi9cblx0X2NoZWNrT2Zmc2V0OiBmdW5jdGlvbiggaW5zdCwgb2Zmc2V0LCBpc0ZpeGVkICkge1xuXHRcdHZhciBkcFdpZHRoID0gaW5zdC5kcERpdi5vdXRlcldpZHRoKCksXG5cdFx0XHRkcEhlaWdodCA9IGluc3QuZHBEaXYub3V0ZXJIZWlnaHQoKSxcblx0XHRcdGlucHV0V2lkdGggPSBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dC5vdXRlcldpZHRoKCkgOiAwLFxuXHRcdFx0aW5wdXRIZWlnaHQgPSBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dC5vdXRlckhlaWdodCgpIDogMCxcblx0XHRcdHZpZXdXaWR0aCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aCArICggaXNGaXhlZCA/IDAgOiAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSApLFxuXHRcdFx0dmlld0hlaWdodCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHQgKyAoIGlzRml4ZWQgPyAwIDogJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSApO1xuXG5cdFx0b2Zmc2V0LmxlZnQgLT0gKCB0aGlzLl9nZXQoIGluc3QsIFwiaXNSVExcIiApID8gKCBkcFdpZHRoIC0gaW5wdXRXaWR0aCApIDogMCApO1xuXHRcdG9mZnNldC5sZWZ0IC09ICggaXNGaXhlZCAmJiBvZmZzZXQubGVmdCA9PT0gaW5zdC5pbnB1dC5vZmZzZXQoKS5sZWZ0ICkgPyAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSA6IDA7XG5cdFx0b2Zmc2V0LnRvcCAtPSAoIGlzRml4ZWQgJiYgb2Zmc2V0LnRvcCA9PT0gKCBpbnN0LmlucHV0Lm9mZnNldCgpLnRvcCArIGlucHV0SGVpZ2h0ICkgKSA/ICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgOiAwO1xuXG5cdFx0Ly8gTm93IGNoZWNrIGlmIGRhdGVwaWNrZXIgaXMgc2hvd2luZyBvdXRzaWRlIHdpbmRvdyB2aWV3cG9ydCAtIG1vdmUgdG8gYSBiZXR0ZXIgcGxhY2UgaWYgc28uXG5cdFx0b2Zmc2V0LmxlZnQgLT0gTWF0aC5taW4oIG9mZnNldC5sZWZ0LCAoIG9mZnNldC5sZWZ0ICsgZHBXaWR0aCA+IHZpZXdXaWR0aCAmJiB2aWV3V2lkdGggPiBkcFdpZHRoICkgP1xuXHRcdFx0TWF0aC5hYnMoIG9mZnNldC5sZWZ0ICsgZHBXaWR0aCAtIHZpZXdXaWR0aCApIDogMCApO1xuXHRcdG9mZnNldC50b3AgLT0gTWF0aC5taW4oIG9mZnNldC50b3AsICggb2Zmc2V0LnRvcCArIGRwSGVpZ2h0ID4gdmlld0hlaWdodCAmJiB2aWV3SGVpZ2h0ID4gZHBIZWlnaHQgKSA/XG5cdFx0XHRNYXRoLmFicyggZHBIZWlnaHQgKyBpbnB1dEhlaWdodCApIDogMCApO1xuXG5cdFx0cmV0dXJuIG9mZnNldDtcblx0fSxcblxuXHQvKiBGaW5kIGFuIG9iamVjdCdzIHBvc2l0aW9uIG9uIHRoZSBzY3JlZW4uICovXG5cdF9maW5kUG9zOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdHZhciBwb3NpdGlvbixcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCBvYmogKSxcblx0XHRcdGlzUlRMID0gdGhpcy5fZ2V0KCBpbnN0LCBcImlzUlRMXCIgKTtcblxuXHRcdHdoaWxlICggb2JqICYmICggb2JqLnR5cGUgPT09IFwiaGlkZGVuXCIgfHwgb2JqLm5vZGVUeXBlICE9PSAxIHx8ICQuZXhwci5maWx0ZXJzLmhpZGRlbiggb2JqICkgKSApIHtcblx0XHRcdG9iaiA9IG9ialsgaXNSVEwgPyBcInByZXZpb3VzU2libGluZ1wiIDogXCJuZXh0U2libGluZ1wiIF07XG5cdFx0fVxuXG5cdFx0cG9zaXRpb24gPSAkKCBvYmogKS5vZmZzZXQoKTtcblx0XHRyZXR1cm4gWyBwb3NpdGlvbi5sZWZ0LCBwb3NpdGlvbi50b3AgXTtcblx0fSxcblxuXHQvKiBIaWRlIHRoZSBkYXRlIHBpY2tlciBmcm9tIHZpZXcuXG5cdCAqIEBwYXJhbSAgaW5wdXQgIGVsZW1lbnQgLSB0aGUgaW5wdXQgZmllbGQgYXR0YWNoZWQgdG8gdGhlIGRhdGUgcGlja2VyXG5cdCAqL1xuXHRfaGlkZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCBpbnB1dCApIHtcblx0XHR2YXIgc2hvd0FuaW0sIGR1cmF0aW9uLCBwb3N0UHJvY2Vzcywgb25DbG9zZSxcblx0XHRcdGluc3QgPSB0aGlzLl9jdXJJbnN0O1xuXG5cdFx0aWYgKCAhaW5zdCB8fCAoIGlucHV0ICYmIGluc3QgIT09ICQuZGF0YSggaW5wdXQsIFwiZGF0ZXBpY2tlclwiICkgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX2RhdGVwaWNrZXJTaG93aW5nICkge1xuXHRcdFx0c2hvd0FuaW0gPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd0FuaW1cIiApO1xuXHRcdFx0ZHVyYXRpb24gPSB0aGlzLl9nZXQoIGluc3QsIFwiZHVyYXRpb25cIiApO1xuXHRcdFx0cG9zdFByb2Nlc3MgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0JC5kYXRlcGlja2VyLl90aWR5RGlhbG9nKCBpbnN0ICk7XG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBERVBSRUNBVEVEOiBhZnRlciBCQyBmb3IgMS44LnggJC5lZmZlY3RzWyBzaG93QW5pbSBdIGlzIG5vdCBuZWVkZWRcblx0XHRcdGlmICggJC5lZmZlY3RzICYmICggJC5lZmZlY3RzLmVmZmVjdFsgc2hvd0FuaW0gXSB8fCAkLmVmZmVjdHNbIHNob3dBbmltIF0gKSApIHtcblx0XHRcdFx0aW5zdC5kcERpdi5oaWRlKCBzaG93QW5pbSwgJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic2hvd09wdGlvbnNcIiApLCBkdXJhdGlvbiwgcG9zdFByb2Nlc3MgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGluc3QuZHBEaXZbICggc2hvd0FuaW0gPT09IFwic2xpZGVEb3duXCIgPyBcInNsaWRlVXBcIiA6XG5cdFx0XHRcdFx0KCBzaG93QW5pbSA9PT0gXCJmYWRlSW5cIiA/IFwiZmFkZU91dFwiIDogXCJoaWRlXCIgKSApIF0oICggc2hvd0FuaW0gPyBkdXJhdGlvbiA6IG51bGwgKSwgcG9zdFByb2Nlc3MgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhc2hvd0FuaW0gKSB7XG5cdFx0XHRcdHBvc3RQcm9jZXNzKCk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9kYXRlcGlja2VyU2hvd2luZyA9IGZhbHNlO1xuXG5cdFx0XHRvbkNsb3NlID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm9uQ2xvc2VcIiApO1xuXHRcdFx0aWYgKCBvbkNsb3NlICkge1xuXHRcdFx0XHRvbkNsb3NlLmFwcGx5KCAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0WyAwIF0gOiBudWxsICksIFsgKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dC52YWwoKSA6IFwiXCIgKSwgaW5zdCBdICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xhc3RJbnB1dCA9IG51bGw7XG5cdFx0XHRpZiAoIHRoaXMuX2luRGlhbG9nICkge1xuXHRcdFx0XHR0aGlzLl9kaWFsb2dJbnB1dC5jc3MoIHsgcG9zaXRpb246IFwiYWJzb2x1dGVcIiwgbGVmdDogXCIwXCIsIHRvcDogXCItMTAwcHhcIiB9ICk7XG5cdFx0XHRcdGlmICggJC5ibG9ja1VJICkge1xuXHRcdFx0XHRcdCQudW5ibG9ja1VJKCk7XG5cdFx0XHRcdFx0JCggXCJib2R5XCIgKS5hcHBlbmQoIHRoaXMuZHBEaXYgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5faW5EaWFsb2cgPSBmYWxzZTtcblx0XHR9XG5cdH0sXG5cblx0LyogVGlkeSB1cCBhZnRlciBhIGRpYWxvZyBkaXNwbGF5LiAqL1xuXHRfdGlkeURpYWxvZzogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0aW5zdC5kcERpdi5yZW1vdmVDbGFzcyggdGhpcy5fZGlhbG9nQ2xhc3MgKS5vZmYoIFwiLnVpLWRhdGVwaWNrZXItY2FsZW5kYXJcIiApO1xuXHR9LFxuXG5cdC8qIENsb3NlIGRhdGUgcGlja2VyIGlmIGNsaWNrZWQgZWxzZXdoZXJlLiAqL1xuXHRfY2hlY2tFeHRlcm5hbENsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAhJC5kYXRlcGlja2VyLl9jdXJJbnN0ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciAkdGFyZ2V0ID0gJCggZXZlbnQudGFyZ2V0ICksXG5cdFx0XHRpbnN0ID0gJC5kYXRlcGlja2VyLl9nZXRJbnN0KCAkdGFyZ2V0WyAwIF0gKTtcblxuXHRcdGlmICggKCAoICR0YXJnZXRbIDAgXS5pZCAhPT0gJC5kYXRlcGlja2VyLl9tYWluRGl2SWQgJiZcblx0XHRcdFx0JHRhcmdldC5wYXJlbnRzKCBcIiNcIiArICQuZGF0ZXBpY2tlci5fbWFpbkRpdklkICkubGVuZ3RoID09PSAwICYmXG5cdFx0XHRcdCEkdGFyZ2V0Lmhhc0NsYXNzKCAkLmRhdGVwaWNrZXIubWFya2VyQ2xhc3NOYW1lICkgJiZcblx0XHRcdFx0ISR0YXJnZXQuY2xvc2VzdCggXCIuXCIgKyAkLmRhdGVwaWNrZXIuX3RyaWdnZXJDbGFzcyApLmxlbmd0aCAmJlxuXHRcdFx0XHQkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICYmICEoICQuZGF0ZXBpY2tlci5faW5EaWFsb2cgJiYgJC5ibG9ja1VJICkgKSApIHx8XG5cdFx0XHQoICR0YXJnZXQuaGFzQ2xhc3MoICQuZGF0ZXBpY2tlci5tYXJrZXJDbGFzc05hbWUgKSAmJiAkLmRhdGVwaWNrZXIuX2N1ckluc3QgIT09IGluc3QgKSApIHtcblx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdH1cblx0fSxcblxuXHQvKiBBZGp1c3Qgb25lIG9mIHRoZSBkYXRlIHN1Yi1maWVsZHMuICovXG5cdF9hZGp1c3REYXRlOiBmdW5jdGlvbiggaWQsIG9mZnNldCwgcGVyaW9kICkge1xuXHRcdHZhciB0YXJnZXQgPSAkKCBpZCApLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldFsgMCBdICk7XG5cblx0XHRpZiAoIHRoaXMuX2lzRGlzYWJsZWREYXRlcGlja2VyKCB0YXJnZXRbIDAgXSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLl9hZGp1c3RJbnN0RGF0ZSggaW5zdCwgb2Zmc2V0ICtcblx0XHRcdCggcGVyaW9kID09PSBcIk1cIiA/IHRoaXMuX2dldCggaW5zdCwgXCJzaG93Q3VycmVudEF0UG9zXCIgKSA6IDAgKSwgLy8gdW5kbyBwb3NpdGlvbmluZ1xuXHRcdFx0cGVyaW9kICk7XG5cdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHR9LFxuXG5cdC8qIEFjdGlvbiBmb3IgY3VycmVudCBsaW5rLiAqL1xuXHRfZ290b1RvZGF5OiBmdW5jdGlvbiggaWQgKSB7XG5cdFx0dmFyIGRhdGUsXG5cdFx0XHR0YXJnZXQgPSAkKCBpZCApLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldFsgMCBdICk7XG5cblx0XHRpZiAoIHRoaXMuX2dldCggaW5zdCwgXCJnb3RvQ3VycmVudFwiICkgJiYgaW5zdC5jdXJyZW50RGF5ICkge1xuXHRcdFx0aW5zdC5zZWxlY3RlZERheSA9IGluc3QuY3VycmVudERheTtcblx0XHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoID0gaW5zdC5jdXJyZW50TW9udGg7XG5cdFx0XHRpbnN0LmRyYXdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgPSBpbnN0LmN1cnJlbnRZZWFyO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRkYXRlID0gbmV3IERhdGUoKTtcblx0XHRcdGluc3Quc2VsZWN0ZWREYXkgPSBkYXRlLmdldERhdGUoKTtcblx0XHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoID0gZGF0ZS5nZXRNb250aCgpO1xuXHRcdFx0aW5zdC5kcmF3WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdH1cblx0XHR0aGlzLl9ub3RpZnlDaGFuZ2UoIGluc3QgKTtcblx0XHR0aGlzLl9hZGp1c3REYXRlKCB0YXJnZXQgKTtcblx0fSxcblxuXHQvKiBBY3Rpb24gZm9yIHNlbGVjdGluZyBhIG5ldyBtb250aC95ZWFyLiAqL1xuXHRfc2VsZWN0TW9udGhZZWFyOiBmdW5jdGlvbiggaWQsIHNlbGVjdCwgcGVyaW9kICkge1xuXHRcdHZhciB0YXJnZXQgPSAkKCBpZCApLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldFsgMCBdICk7XG5cblx0XHRpbnN0WyBcInNlbGVjdGVkXCIgKyAoIHBlcmlvZCA9PT0gXCJNXCIgPyBcIk1vbnRoXCIgOiBcIlllYXJcIiApIF0gPVxuXHRcdGluc3RbIFwiZHJhd1wiICsgKCBwZXJpb2QgPT09IFwiTVwiID8gXCJNb250aFwiIDogXCJZZWFyXCIgKSBdID1cblx0XHRcdHBhcnNlSW50KCBzZWxlY3Qub3B0aW9uc1sgc2VsZWN0LnNlbGVjdGVkSW5kZXggXS52YWx1ZSwgMTAgKTtcblxuXHRcdHRoaXMuX25vdGlmeUNoYW5nZSggaW5zdCApO1xuXHRcdHRoaXMuX2FkanVzdERhdGUoIHRhcmdldCApO1xuXHR9LFxuXG5cdC8qIEFjdGlvbiBmb3Igc2VsZWN0aW5nIGEgZGF5LiAqL1xuXHRfc2VsZWN0RGF5OiBmdW5jdGlvbiggaWQsIG1vbnRoLCB5ZWFyLCB0ZCApIHtcblx0XHR2YXIgaW5zdCxcblx0XHRcdHRhcmdldCA9ICQoIGlkICk7XG5cblx0XHRpZiAoICQoIHRkICkuaGFzQ2xhc3MoIHRoaXMuX3Vuc2VsZWN0YWJsZUNsYXNzICkgfHwgdGhpcy5faXNEaXNhYmxlZERhdGVwaWNrZXIoIHRhcmdldFsgMCBdICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldFsgMCBdICk7XG5cdFx0aW5zdC5zZWxlY3RlZERheSA9IGluc3QuY3VycmVudERheSA9ICQoIFwiYVwiLCB0ZCApLmh0bWwoKTtcblx0XHRpbnN0LnNlbGVjdGVkTW9udGggPSBpbnN0LmN1cnJlbnRNb250aCA9IG1vbnRoO1xuXHRcdGluc3Quc2VsZWN0ZWRZZWFyID0gaW5zdC5jdXJyZW50WWVhciA9IHllYXI7XG5cdFx0dGhpcy5fc2VsZWN0RGF0ZSggaWQsIHRoaXMuX2Zvcm1hdERhdGUoIGluc3QsXG5cdFx0XHRpbnN0LmN1cnJlbnREYXksIGluc3QuY3VycmVudE1vbnRoLCBpbnN0LmN1cnJlbnRZZWFyICkgKTtcblx0fSxcblxuXHQvKiBFcmFzZSB0aGUgaW5wdXQgZmllbGQgYW5kIGhpZGUgdGhlIGRhdGUgcGlja2VyLiAqL1xuXHRfY2xlYXJEYXRlOiBmdW5jdGlvbiggaWQgKSB7XG5cdFx0dmFyIHRhcmdldCA9ICQoIGlkICk7XG5cdFx0dGhpcy5fc2VsZWN0RGF0ZSggdGFyZ2V0LCBcIlwiICk7XG5cdH0sXG5cblx0LyogVXBkYXRlIHRoZSBpbnB1dCBmaWVsZCB3aXRoIHRoZSBzZWxlY3RlZCBkYXRlLiAqL1xuXHRfc2VsZWN0RGF0ZTogZnVuY3Rpb24oIGlkLCBkYXRlU3RyICkge1xuXHRcdHZhciBvblNlbGVjdCxcblx0XHRcdHRhcmdldCA9ICQoIGlkICksXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0WyAwIF0gKTtcblxuXHRcdGRhdGVTdHIgPSAoIGRhdGVTdHIgIT0gbnVsbCA/IGRhdGVTdHIgOiB0aGlzLl9mb3JtYXREYXRlKCBpbnN0ICkgKTtcblx0XHRpZiAoIGluc3QuaW5wdXQgKSB7XG5cdFx0XHRpbnN0LmlucHV0LnZhbCggZGF0ZVN0ciApO1xuXHRcdH1cblx0XHR0aGlzLl91cGRhdGVBbHRlcm5hdGUoIGluc3QgKTtcblxuXHRcdG9uU2VsZWN0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm9uU2VsZWN0XCIgKTtcblx0XHRpZiAoIG9uU2VsZWN0ICkge1xuXHRcdFx0b25TZWxlY3QuYXBwbHkoICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXRbIDAgXSA6IG51bGwgKSwgWyBkYXRlU3RyLCBpbnN0IF0gKTsgIC8vIHRyaWdnZXIgY3VzdG9tIGNhbGxiYWNrXG5cdFx0fSBlbHNlIGlmICggaW5zdC5pbnB1dCApIHtcblx0XHRcdGluc3QuaW5wdXQudHJpZ2dlciggXCJjaGFuZ2VcIiApOyAvLyBmaXJlIHRoZSBjaGFuZ2UgZXZlbnRcblx0XHR9XG5cblx0XHRpZiAoIGluc3QuaW5saW5lICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0dGhpcy5fbGFzdElucHV0ID0gaW5zdC5pbnB1dFsgMCBdO1xuXHRcdFx0aWYgKCB0eXBlb2YoIGluc3QuaW5wdXRbIDAgXSApICE9PSBcIm9iamVjdFwiICkge1xuXHRcdFx0XHRpbnN0LmlucHV0LnRyaWdnZXIoIFwiZm9jdXNcIiApOyAvLyByZXN0b3JlIGZvY3VzXG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9sYXN0SW5wdXQgPSBudWxsO1xuXHRcdH1cblx0fSxcblxuXHQvKiBVcGRhdGUgYW55IGFsdGVybmF0ZSBmaWVsZCB0byBzeW5jaHJvbmlzZSB3aXRoIHRoZSBtYWluIGZpZWxkLiAqL1xuXHRfdXBkYXRlQWx0ZXJuYXRlOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgYWx0Rm9ybWF0LCBkYXRlLCBkYXRlU3RyLFxuXHRcdFx0YWx0RmllbGQgPSB0aGlzLl9nZXQoIGluc3QsIFwiYWx0RmllbGRcIiApO1xuXG5cdFx0aWYgKCBhbHRGaWVsZCApIHsgLy8gdXBkYXRlIGFsdGVybmF0ZSBmaWVsZCB0b29cblx0XHRcdGFsdEZvcm1hdCA9IHRoaXMuX2dldCggaW5zdCwgXCJhbHRGb3JtYXRcIiApIHx8IHRoaXMuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKTtcblx0XHRcdGRhdGUgPSB0aGlzLl9nZXREYXRlKCBpbnN0ICk7XG5cdFx0XHRkYXRlU3RyID0gdGhpcy5mb3JtYXREYXRlKCBhbHRGb3JtYXQsIGRhdGUsIHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICk7XG5cdFx0XHQkKCBhbHRGaWVsZCApLnZhbCggZGF0ZVN0ciApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBTZXQgYXMgYmVmb3JlU2hvd0RheSBmdW5jdGlvbiB0byBwcmV2ZW50IHNlbGVjdGlvbiBvZiB3ZWVrZW5kcy5cblx0ICogQHBhcmFtICBkYXRlICBEYXRlIC0gdGhlIGRhdGUgdG8gY3VzdG9taXNlXG5cdCAqIEByZXR1cm4gW2Jvb2xlYW4sIHN0cmluZ10gLSBpcyB0aGlzIGRhdGUgc2VsZWN0YWJsZT8sIHdoYXQgaXMgaXRzIENTUyBjbGFzcz9cblx0ICovXG5cdG5vV2Vla2VuZHM6IGZ1bmN0aW9uKCBkYXRlICkge1xuXHRcdHZhciBkYXkgPSBkYXRlLmdldERheSgpO1xuXHRcdHJldHVybiBbICggZGF5ID4gMCAmJiBkYXkgPCA2ICksIFwiXCIgXTtcblx0fSxcblxuXHQvKiBTZXQgYXMgY2FsY3VsYXRlV2VlayB0byBkZXRlcm1pbmUgdGhlIHdlZWsgb2YgdGhlIHllYXIgYmFzZWQgb24gdGhlIElTTyA4NjAxIGRlZmluaXRpb24uXG5cdCAqIEBwYXJhbSAgZGF0ZSAgRGF0ZSAtIHRoZSBkYXRlIHRvIGdldCB0aGUgd2VlayBmb3Jcblx0ICogQHJldHVybiAgbnVtYmVyIC0gdGhlIG51bWJlciBvZiB0aGUgd2VlayB3aXRoaW4gdGhlIHllYXIgdGhhdCBjb250YWlucyB0aGlzIGRhdGVcblx0ICovXG5cdGlzbzg2MDFXZWVrOiBmdW5jdGlvbiggZGF0ZSApIHtcblx0XHR2YXIgdGltZSxcblx0XHRcdGNoZWNrRGF0ZSA9IG5ldyBEYXRlKCBkYXRlLmdldFRpbWUoKSApO1xuXG5cdFx0Ly8gRmluZCBUaHVyc2RheSBvZiB0aGlzIHdlZWsgc3RhcnRpbmcgb24gTW9uZGF5XG5cdFx0Y2hlY2tEYXRlLnNldERhdGUoIGNoZWNrRGF0ZS5nZXREYXRlKCkgKyA0IC0gKCBjaGVja0RhdGUuZ2V0RGF5KCkgfHwgNyApICk7XG5cblx0XHR0aW1lID0gY2hlY2tEYXRlLmdldFRpbWUoKTtcblx0XHRjaGVja0RhdGUuc2V0TW9udGgoIDAgKTsgLy8gQ29tcGFyZSB3aXRoIEphbiAxXG5cdFx0Y2hlY2tEYXRlLnNldERhdGUoIDEgKTtcblx0XHRyZXR1cm4gTWF0aC5mbG9vciggTWF0aC5yb3VuZCggKCB0aW1lIC0gY2hlY2tEYXRlICkgLyA4NjQwMDAwMCApIC8gNyApICsgMTtcblx0fSxcblxuXHQvKiBQYXJzZSBhIHN0cmluZyB2YWx1ZSBpbnRvIGEgZGF0ZSBvYmplY3QuXG5cdCAqIFNlZSBmb3JtYXREYXRlIGJlbG93IGZvciB0aGUgcG9zc2libGUgZm9ybWF0cy5cblx0ICpcblx0ICogQHBhcmFtICBmb3JtYXQgc3RyaW5nIC0gdGhlIGV4cGVjdGVkIGZvcm1hdCBvZiB0aGUgZGF0ZVxuXHQgKiBAcGFyYW0gIHZhbHVlIHN0cmluZyAtIHRoZSBkYXRlIGluIHRoZSBhYm92ZSBmb3JtYXRcblx0ICogQHBhcmFtICBzZXR0aW5ncyBPYmplY3QgLSBhdHRyaWJ1dGVzIGluY2x1ZGU6XG5cdCAqXHRcdFx0XHRcdHNob3J0WWVhckN1dG9mZiAgbnVtYmVyIC0gdGhlIGN1dG9mZiB5ZWFyIGZvciBkZXRlcm1pbmluZyB0aGUgY2VudHVyeSAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdGRheU5hbWVzU2hvcnRcdHN0cmluZ1s3XSAtIGFiYnJldmlhdGVkIG5hbWVzIG9mIHRoZSBkYXlzIGZyb20gU3VuZGF5IChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0ZGF5TmFtZXNcdFx0c3RyaW5nWzddIC0gbmFtZXMgb2YgdGhlIGRheXMgZnJvbSBTdW5kYXkgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRtb250aE5hbWVzU2hvcnQgc3RyaW5nWzEyXSAtIGFiYnJldmlhdGVkIG5hbWVzIG9mIHRoZSBtb250aHMgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRtb250aE5hbWVzXHRcdHN0cmluZ1sxMl0gLSBuYW1lcyBvZiB0aGUgbW9udGhzIChvcHRpb25hbClcblx0ICogQHJldHVybiAgRGF0ZSAtIHRoZSBleHRyYWN0ZWQgZGF0ZSB2YWx1ZSBvciBudWxsIGlmIHZhbHVlIGlzIGJsYW5rXG5cdCAqL1xuXHRwYXJzZURhdGU6IGZ1bmN0aW9uKCBmb3JtYXQsIHZhbHVlLCBzZXR0aW5ncyApIHtcblx0XHRpZiAoIGZvcm1hdCA9PSBudWxsIHx8IHZhbHVlID09IG51bGwgKSB7XG5cdFx0XHR0aHJvdyBcIkludmFsaWQgYXJndW1lbnRzXCI7XG5cdFx0fVxuXG5cdFx0dmFsdWUgPSAoIHR5cGVvZiB2YWx1ZSA9PT0gXCJvYmplY3RcIiA/IHZhbHVlLnRvU3RyaW5nKCkgOiB2YWx1ZSArIFwiXCIgKTtcblx0XHRpZiAoIHZhbHVlID09PSBcIlwiICkge1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXG5cdFx0dmFyIGlGb3JtYXQsIGRpbSwgZXh0cmEsXG5cdFx0XHRpVmFsdWUgPSAwLFxuXHRcdFx0c2hvcnRZZWFyQ3V0b2ZmVGVtcCA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5zaG9ydFllYXJDdXRvZmYgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMuc2hvcnRZZWFyQ3V0b2ZmLFxuXHRcdFx0c2hvcnRZZWFyQ3V0b2ZmID0gKCB0eXBlb2Ygc2hvcnRZZWFyQ3V0b2ZmVGVtcCAhPT0gXCJzdHJpbmdcIiA/IHNob3J0WWVhckN1dG9mZlRlbXAgOlxuXHRcdFx0XHRuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCkgJSAxMDAgKyBwYXJzZUludCggc2hvcnRZZWFyQ3V0b2ZmVGVtcCwgMTAgKSApLFxuXHRcdFx0ZGF5TmFtZXNTaG9ydCA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5kYXlOYW1lc1Nob3J0IDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLmRheU5hbWVzU2hvcnQsXG5cdFx0XHRkYXlOYW1lcyA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5kYXlOYW1lcyA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5kYXlOYW1lcyxcblx0XHRcdG1vbnRoTmFtZXNTaG9ydCA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5tb250aE5hbWVzU2hvcnQgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMubW9udGhOYW1lc1Nob3J0LFxuXHRcdFx0bW9udGhOYW1lcyA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5tb250aE5hbWVzIDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLm1vbnRoTmFtZXMsXG5cdFx0XHR5ZWFyID0gLTEsXG5cdFx0XHRtb250aCA9IC0xLFxuXHRcdFx0ZGF5ID0gLTEsXG5cdFx0XHRkb3kgPSAtMSxcblx0XHRcdGxpdGVyYWwgPSBmYWxzZSxcblx0XHRcdGRhdGUsXG5cblx0XHRcdC8vIENoZWNrIHdoZXRoZXIgYSBmb3JtYXQgY2hhcmFjdGVyIGlzIGRvdWJsZWRcblx0XHRcdGxvb2tBaGVhZCA9IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdFx0dmFyIG1hdGNoZXMgPSAoIGlGb3JtYXQgKyAxIDwgZm9ybWF0Lmxlbmd0aCAmJiBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICsgMSApID09PSBtYXRjaCApO1xuXHRcdFx0XHRpZiAoIG1hdGNoZXMgKSB7XG5cdFx0XHRcdFx0aUZvcm1hdCsrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBtYXRjaGVzO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRXh0cmFjdCBhIG51bWJlciBmcm9tIHRoZSBzdHJpbmcgdmFsdWVcblx0XHRcdGdldE51bWJlciA9IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdFx0dmFyIGlzRG91YmxlZCA9IGxvb2tBaGVhZCggbWF0Y2ggKSxcblx0XHRcdFx0XHRzaXplID0gKCBtYXRjaCA9PT0gXCJAXCIgPyAxNCA6ICggbWF0Y2ggPT09IFwiIVwiID8gMjAgOlxuXHRcdFx0XHRcdCggbWF0Y2ggPT09IFwieVwiICYmIGlzRG91YmxlZCA/IDQgOiAoIG1hdGNoID09PSBcIm9cIiA/IDMgOiAyICkgKSApICksXG5cdFx0XHRcdFx0bWluU2l6ZSA9ICggbWF0Y2ggPT09IFwieVwiID8gc2l6ZSA6IDEgKSxcblx0XHRcdFx0XHRkaWdpdHMgPSBuZXcgUmVnRXhwKCBcIl5cXFxcZHtcIiArIG1pblNpemUgKyBcIixcIiArIHNpemUgKyBcIn1cIiApLFxuXHRcdFx0XHRcdG51bSA9IHZhbHVlLnN1YnN0cmluZyggaVZhbHVlICkubWF0Y2goIGRpZ2l0cyApO1xuXHRcdFx0XHRpZiAoICFudW0gKSB7XG5cdFx0XHRcdFx0dGhyb3cgXCJNaXNzaW5nIG51bWJlciBhdCBwb3NpdGlvbiBcIiArIGlWYWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpVmFsdWUgKz0gbnVtWyAwIF0ubGVuZ3RoO1xuXHRcdFx0XHRyZXR1cm4gcGFyc2VJbnQoIG51bVsgMCBdLCAxMCApO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRXh0cmFjdCBhIG5hbWUgZnJvbSB0aGUgc3RyaW5nIHZhbHVlIGFuZCBjb252ZXJ0IHRvIGFuIGluZGV4XG5cdFx0XHRnZXROYW1lID0gZnVuY3Rpb24oIG1hdGNoLCBzaG9ydE5hbWVzLCBsb25nTmFtZXMgKSB7XG5cdFx0XHRcdHZhciBpbmRleCA9IC0xLFxuXHRcdFx0XHRcdG5hbWVzID0gJC5tYXAoIGxvb2tBaGVhZCggbWF0Y2ggKSA/IGxvbmdOYW1lcyA6IHNob3J0TmFtZXMsIGZ1bmN0aW9uKCB2LCBrICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIFsgWyBrLCB2IF0gXTtcblx0XHRcdFx0XHR9ICkuc29ydCggZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gLSggYVsgMSBdLmxlbmd0aCAtIGJbIDEgXS5sZW5ndGggKTtcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0JC5lYWNoKCBuYW1lcywgZnVuY3Rpb24oIGksIHBhaXIgKSB7XG5cdFx0XHRcdFx0dmFyIG5hbWUgPSBwYWlyWyAxIF07XG5cdFx0XHRcdFx0aWYgKCB2YWx1ZS5zdWJzdHIoIGlWYWx1ZSwgbmFtZS5sZW5ndGggKS50b0xvd2VyQ2FzZSgpID09PSBuYW1lLnRvTG93ZXJDYXNlKCkgKSB7XG5cdFx0XHRcdFx0XHRpbmRleCA9IHBhaXJbIDAgXTtcblx0XHRcdFx0XHRcdGlWYWx1ZSArPSBuYW1lLmxlbmd0aDtcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0aWYgKCBpbmRleCAhPT0gLTEgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGluZGV4ICsgMTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aHJvdyBcIlVua25vd24gbmFtZSBhdCBwb3NpdGlvbiBcIiArIGlWYWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblxuXHRcdFx0Ly8gQ29uZmlybSB0aGF0IGEgbGl0ZXJhbCBjaGFyYWN0ZXIgbWF0Y2hlcyB0aGUgc3RyaW5nIHZhbHVlXG5cdFx0XHRjaGVja0xpdGVyYWwgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCB2YWx1ZS5jaGFyQXQoIGlWYWx1ZSApICE9PSBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgKSB7XG5cdFx0XHRcdFx0dGhyb3cgXCJVbmV4cGVjdGVkIGxpdGVyYWwgYXQgcG9zaXRpb24gXCIgKyBpVmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0aVZhbHVlKys7XG5cdFx0XHR9O1xuXG5cdFx0Zm9yICggaUZvcm1hdCA9IDA7IGlGb3JtYXQgPCBmb3JtYXQubGVuZ3RoOyBpRm9ybWF0KysgKSB7XG5cdFx0XHRpZiAoIGxpdGVyYWwgKSB7XG5cdFx0XHRcdGlmICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApID09PSBcIidcIiAmJiAhbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdGxpdGVyYWwgPSBmYWxzZTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjaGVja0xpdGVyYWwoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c3dpdGNoICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApICkge1xuXHRcdFx0XHRcdGNhc2UgXCJkXCI6XG5cdFx0XHRcdFx0XHRkYXkgPSBnZXROdW1iZXIoIFwiZFwiICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiRFwiOlxuXHRcdFx0XHRcdFx0Z2V0TmFtZSggXCJEXCIsIGRheU5hbWVzU2hvcnQsIGRheU5hbWVzICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwib1wiOlxuXHRcdFx0XHRcdFx0ZG95ID0gZ2V0TnVtYmVyKCBcIm9cIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIm1cIjpcblx0XHRcdFx0XHRcdG1vbnRoID0gZ2V0TnVtYmVyKCBcIm1cIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIk1cIjpcblx0XHRcdFx0XHRcdG1vbnRoID0gZ2V0TmFtZSggXCJNXCIsIG1vbnRoTmFtZXNTaG9ydCwgbW9udGhOYW1lcyApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcInlcIjpcblx0XHRcdFx0XHRcdHllYXIgPSBnZXROdW1iZXIoIFwieVwiICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiQFwiOlxuXHRcdFx0XHRcdFx0ZGF0ZSA9IG5ldyBEYXRlKCBnZXROdW1iZXIoIFwiQFwiICkgKTtcblx0XHRcdFx0XHRcdHllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0XHRcdFx0XHRtb250aCA9IGRhdGUuZ2V0TW9udGgoKSArIDE7XG5cdFx0XHRcdFx0XHRkYXkgPSBkYXRlLmdldERhdGUoKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCIhXCI6XG5cdFx0XHRcdFx0XHRkYXRlID0gbmV3IERhdGUoICggZ2V0TnVtYmVyKCBcIiFcIiApIC0gdGhpcy5fdGlja3NUbzE5NzAgKSAvIDEwMDAwICk7XG5cdFx0XHRcdFx0XHR5ZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdFx0XHRcdFx0bW9udGggPSBkYXRlLmdldE1vbnRoKCkgKyAxO1xuXHRcdFx0XHRcdFx0ZGF5ID0gZGF0ZS5nZXREYXRlKCk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiJ1wiOlxuXHRcdFx0XHRcdFx0aWYgKCBsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0XHRcdGNoZWNrTGl0ZXJhbCgpO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0bGl0ZXJhbCA9IHRydWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0Y2hlY2tMaXRlcmFsKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGlWYWx1ZSA8IHZhbHVlLmxlbmd0aCApIHtcblx0XHRcdGV4dHJhID0gdmFsdWUuc3Vic3RyKCBpVmFsdWUgKTtcblx0XHRcdGlmICggIS9eXFxzKy8udGVzdCggZXh0cmEgKSApIHtcblx0XHRcdFx0dGhyb3cgXCJFeHRyYS91bnBhcnNlZCBjaGFyYWN0ZXJzIGZvdW5kIGluIGRhdGU6IFwiICsgZXh0cmE7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCB5ZWFyID09PSAtMSApIHtcblx0XHRcdHllYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XG5cdFx0fSBlbHNlIGlmICggeWVhciA8IDEwMCApIHtcblx0XHRcdHllYXIgKz0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpIC0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpICUgMTAwICtcblx0XHRcdFx0KCB5ZWFyIDw9IHNob3J0WWVhckN1dG9mZiA/IDAgOiAtMTAwICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBkb3kgPiAtMSApIHtcblx0XHRcdG1vbnRoID0gMTtcblx0XHRcdGRheSA9IGRveTtcblx0XHRcdGRvIHtcblx0XHRcdFx0ZGltID0gdGhpcy5fZ2V0RGF5c0luTW9udGgoIHllYXIsIG1vbnRoIC0gMSApO1xuXHRcdFx0XHRpZiAoIGRheSA8PSBkaW0gKSB7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdFx0bW9udGgrKztcblx0XHRcdFx0ZGF5IC09IGRpbTtcblx0XHRcdH0gd2hpbGUgKCB0cnVlICk7XG5cdFx0fVxuXG5cdFx0ZGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggeWVhciwgbW9udGggLSAxLCBkYXkgKSApO1xuXHRcdGlmICggZGF0ZS5nZXRGdWxsWWVhcigpICE9PSB5ZWFyIHx8IGRhdGUuZ2V0TW9udGgoKSArIDEgIT09IG1vbnRoIHx8IGRhdGUuZ2V0RGF0ZSgpICE9PSBkYXkgKSB7XG5cdFx0XHR0aHJvdyBcIkludmFsaWQgZGF0ZVwiOyAvLyBFLmcuIDMxLzAyLzAwXG5cdFx0fVxuXHRcdHJldHVybiBkYXRlO1xuXHR9LFxuXG5cdC8qIFN0YW5kYXJkIGRhdGUgZm9ybWF0cy4gKi9cblx0QVRPTTogXCJ5eS1tbS1kZFwiLCAvLyBSRkMgMzMzOSAoSVNPIDg2MDEpXG5cdENPT0tJRTogXCJELCBkZCBNIHl5XCIsXG5cdElTT184NjAxOiBcInl5LW1tLWRkXCIsXG5cdFJGQ184MjI6IFwiRCwgZCBNIHlcIixcblx0UkZDXzg1MDogXCJERCwgZGQtTS15XCIsXG5cdFJGQ18xMDM2OiBcIkQsIGQgTSB5XCIsXG5cdFJGQ18xMTIzOiBcIkQsIGQgTSB5eVwiLFxuXHRSRkNfMjgyMjogXCJELCBkIE0geXlcIixcblx0UlNTOiBcIkQsIGQgTSB5XCIsIC8vIFJGQyA4MjJcblx0VElDS1M6IFwiIVwiLFxuXHRUSU1FU1RBTVA6IFwiQFwiLFxuXHRXM0M6IFwieXktbW0tZGRcIiwgLy8gSVNPIDg2MDFcblxuXHRfdGlja3NUbzE5NzA6ICggKCAoIDE5NzAgLSAxICkgKiAzNjUgKyBNYXRoLmZsb29yKCAxOTcwIC8gNCApIC0gTWF0aC5mbG9vciggMTk3MCAvIDEwMCApICtcblx0XHRNYXRoLmZsb29yKCAxOTcwIC8gNDAwICkgKSAqIDI0ICogNjAgKiA2MCAqIDEwMDAwMDAwICksXG5cblx0LyogRm9ybWF0IGEgZGF0ZSBvYmplY3QgaW50byBhIHN0cmluZyB2YWx1ZS5cblx0ICogVGhlIGZvcm1hdCBjYW4gYmUgY29tYmluYXRpb25zIG9mIHRoZSBmb2xsb3dpbmc6XG5cdCAqIGQgIC0gZGF5IG9mIG1vbnRoIChubyBsZWFkaW5nIHplcm8pXG5cdCAqIGRkIC0gZGF5IG9mIG1vbnRoICh0d28gZGlnaXQpXG5cdCAqIG8gIC0gZGF5IG9mIHllYXIgKG5vIGxlYWRpbmcgemVyb3MpXG5cdCAqIG9vIC0gZGF5IG9mIHllYXIgKHRocmVlIGRpZ2l0KVxuXHQgKiBEICAtIGRheSBuYW1lIHNob3J0XG5cdCAqIEREIC0gZGF5IG5hbWUgbG9uZ1xuXHQgKiBtICAtIG1vbnRoIG9mIHllYXIgKG5vIGxlYWRpbmcgemVybylcblx0ICogbW0gLSBtb250aCBvZiB5ZWFyICh0d28gZGlnaXQpXG5cdCAqIE0gIC0gbW9udGggbmFtZSBzaG9ydFxuXHQgKiBNTSAtIG1vbnRoIG5hbWUgbG9uZ1xuXHQgKiB5ICAtIHllYXIgKHR3byBkaWdpdClcblx0ICogeXkgLSB5ZWFyIChmb3VyIGRpZ2l0KVxuXHQgKiBAIC0gVW5peCB0aW1lc3RhbXAgKG1zIHNpbmNlIDAxLzAxLzE5NzApXG5cdCAqICEgLSBXaW5kb3dzIHRpY2tzICgxMDBucyBzaW5jZSAwMS8wMS8wMDAxKVxuXHQgKiBcIi4uLlwiIC0gbGl0ZXJhbCB0ZXh0XG5cdCAqICcnIC0gc2luZ2xlIHF1b3RlXG5cdCAqXG5cdCAqIEBwYXJhbSAgZm9ybWF0IHN0cmluZyAtIHRoZSBkZXNpcmVkIGZvcm1hdCBvZiB0aGUgZGF0ZVxuXHQgKiBAcGFyYW0gIGRhdGUgRGF0ZSAtIHRoZSBkYXRlIHZhbHVlIHRvIGZvcm1hdFxuXHQgKiBAcGFyYW0gIHNldHRpbmdzIE9iamVjdCAtIGF0dHJpYnV0ZXMgaW5jbHVkZTpcblx0ICpcdFx0XHRcdFx0ZGF5TmFtZXNTaG9ydFx0c3RyaW5nWzddIC0gYWJicmV2aWF0ZWQgbmFtZXMgb2YgdGhlIGRheXMgZnJvbSBTdW5kYXkgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRkYXlOYW1lc1x0XHRzdHJpbmdbN10gLSBuYW1lcyBvZiB0aGUgZGF5cyBmcm9tIFN1bmRheSAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdG1vbnRoTmFtZXNTaG9ydCBzdHJpbmdbMTJdIC0gYWJicmV2aWF0ZWQgbmFtZXMgb2YgdGhlIG1vbnRocyAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdG1vbnRoTmFtZXNcdFx0c3RyaW5nWzEyXSAtIG5hbWVzIG9mIHRoZSBtb250aHMgKG9wdGlvbmFsKVxuXHQgKiBAcmV0dXJuICBzdHJpbmcgLSB0aGUgZGF0ZSBpbiB0aGUgYWJvdmUgZm9ybWF0XG5cdCAqL1xuXHRmb3JtYXREYXRlOiBmdW5jdGlvbiggZm9ybWF0LCBkYXRlLCBzZXR0aW5ncyApIHtcblx0XHRpZiAoICFkYXRlICkge1xuXHRcdFx0cmV0dXJuIFwiXCI7XG5cdFx0fVxuXG5cdFx0dmFyIGlGb3JtYXQsXG5cdFx0XHRkYXlOYW1lc1Nob3J0ID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLmRheU5hbWVzU2hvcnQgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMuZGF5TmFtZXNTaG9ydCxcblx0XHRcdGRheU5hbWVzID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLmRheU5hbWVzIDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLmRheU5hbWVzLFxuXHRcdFx0bW9udGhOYW1lc1Nob3J0ID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLm1vbnRoTmFtZXNTaG9ydCA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5tb250aE5hbWVzU2hvcnQsXG5cdFx0XHRtb250aE5hbWVzID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLm1vbnRoTmFtZXMgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMubW9udGhOYW1lcyxcblxuXHRcdFx0Ly8gQ2hlY2sgd2hldGhlciBhIGZvcm1hdCBjaGFyYWN0ZXIgaXMgZG91YmxlZFxuXHRcdFx0bG9va0FoZWFkID0gZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0XHR2YXIgbWF0Y2hlcyA9ICggaUZvcm1hdCArIDEgPCBmb3JtYXQubGVuZ3RoICYmIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKyAxICkgPT09IG1hdGNoICk7XG5cdFx0XHRcdGlmICggbWF0Y2hlcyApIHtcblx0XHRcdFx0XHRpRm9ybWF0Kys7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG1hdGNoZXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBGb3JtYXQgYSBudW1iZXIsIHdpdGggbGVhZGluZyB6ZXJvIGlmIG5lY2Vzc2FyeVxuXHRcdFx0Zm9ybWF0TnVtYmVyID0gZnVuY3Rpb24oIG1hdGNoLCB2YWx1ZSwgbGVuICkge1xuXHRcdFx0XHR2YXIgbnVtID0gXCJcIiArIHZhbHVlO1xuXHRcdFx0XHRpZiAoIGxvb2tBaGVhZCggbWF0Y2ggKSApIHtcblx0XHRcdFx0XHR3aGlsZSAoIG51bS5sZW5ndGggPCBsZW4gKSB7XG5cdFx0XHRcdFx0XHRudW0gPSBcIjBcIiArIG51bTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG51bTtcblx0XHRcdH0sXG5cblx0XHRcdC8vIEZvcm1hdCBhIG5hbWUsIHNob3J0IG9yIGxvbmcgYXMgcmVxdWVzdGVkXG5cdFx0XHRmb3JtYXROYW1lID0gZnVuY3Rpb24oIG1hdGNoLCB2YWx1ZSwgc2hvcnROYW1lcywgbG9uZ05hbWVzICkge1xuXHRcdFx0XHRyZXR1cm4gKCBsb29rQWhlYWQoIG1hdGNoICkgPyBsb25nTmFtZXNbIHZhbHVlIF0gOiBzaG9ydE5hbWVzWyB2YWx1ZSBdICk7XG5cdFx0XHR9LFxuXHRcdFx0b3V0cHV0ID0gXCJcIixcblx0XHRcdGxpdGVyYWwgPSBmYWxzZTtcblxuXHRcdGlmICggZGF0ZSApIHtcblx0XHRcdGZvciAoIGlGb3JtYXQgPSAwOyBpRm9ybWF0IDwgZm9ybWF0Lmxlbmd0aDsgaUZvcm1hdCsrICkge1xuXHRcdFx0XHRpZiAoIGxpdGVyYWwgKSB7XG5cdFx0XHRcdFx0aWYgKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgPT09IFwiJ1wiICYmICFsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0XHRsaXRlcmFsID0gZmFsc2U7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHN3aXRjaCAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSApIHtcblx0XHRcdFx0XHRcdGNhc2UgXCJkXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXROdW1iZXIoIFwiZFwiLCBkYXRlLmdldERhdGUoKSwgMiApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJEXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXROYW1lKCBcIkRcIiwgZGF0ZS5nZXREYXkoKSwgZGF5TmFtZXNTaG9ydCwgZGF5TmFtZXMgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwib1wiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0TnVtYmVyKCBcIm9cIixcblx0XHRcdFx0XHRcdFx0XHRNYXRoLnJvdW5kKCAoIG5ldyBEYXRlKCBkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSwgZGF0ZS5nZXREYXRlKCkgKS5nZXRUaW1lKCkgLSBuZXcgRGF0ZSggZGF0ZS5nZXRGdWxsWWVhcigpLCAwLCAwICkuZ2V0VGltZSgpICkgLyA4NjQwMDAwMCApLCAzICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIm1cIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdE51bWJlciggXCJtXCIsIGRhdGUuZ2V0TW9udGgoKSArIDEsIDIgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwiTVwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0TmFtZSggXCJNXCIsIGRhdGUuZ2V0TW9udGgoKSwgbW9udGhOYW1lc1Nob3J0LCBtb250aE5hbWVzICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcInlcIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9ICggbG9va0FoZWFkKCBcInlcIiApID8gZGF0ZS5nZXRGdWxsWWVhcigpIDpcblx0XHRcdFx0XHRcdFx0XHQoIGRhdGUuZ2V0RnVsbFllYXIoKSAlIDEwMCA8IDEwID8gXCIwXCIgOiBcIlwiICkgKyBkYXRlLmdldEZ1bGxZZWFyKCkgJSAxMDAgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwiQFwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZGF0ZS5nZXRUaW1lKCk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIiFcIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGRhdGUuZ2V0VGltZSgpICogMTAwMDAgKyB0aGlzLl90aWNrc1RvMTk3MDtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwiJ1wiOlxuXHRcdFx0XHRcdFx0XHRpZiAoIGxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gXCInXCI7XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdFx0bGl0ZXJhbCA9IHRydWU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gb3V0cHV0O1xuXHR9LFxuXG5cdC8qIEV4dHJhY3QgYWxsIHBvc3NpYmxlIGNoYXJhY3RlcnMgZnJvbSB0aGUgZGF0ZSBmb3JtYXQuICovXG5cdF9wb3NzaWJsZUNoYXJzOiBmdW5jdGlvbiggZm9ybWF0ICkge1xuXHRcdHZhciBpRm9ybWF0LFxuXHRcdFx0Y2hhcnMgPSBcIlwiLFxuXHRcdFx0bGl0ZXJhbCA9IGZhbHNlLFxuXG5cdFx0XHQvLyBDaGVjayB3aGV0aGVyIGEgZm9ybWF0IGNoYXJhY3RlciBpcyBkb3VibGVkXG5cdFx0XHRsb29rQWhlYWQgPSBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHRcdHZhciBtYXRjaGVzID0gKCBpRm9ybWF0ICsgMSA8IGZvcm1hdC5sZW5ndGggJiYgZm9ybWF0LmNoYXJBdCggaUZvcm1hdCArIDEgKSA9PT0gbWF0Y2ggKTtcblx0XHRcdFx0aWYgKCBtYXRjaGVzICkge1xuXHRcdFx0XHRcdGlGb3JtYXQrKztcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbWF0Y2hlcztcblx0XHRcdH07XG5cblx0XHRmb3IgKCBpRm9ybWF0ID0gMDsgaUZvcm1hdCA8IGZvcm1hdC5sZW5ndGg7IGlGb3JtYXQrKyApIHtcblx0XHRcdGlmICggbGl0ZXJhbCApIHtcblx0XHRcdFx0aWYgKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgPT09IFwiJ1wiICYmICFsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0bGl0ZXJhbCA9IGZhbHNlO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGNoYXJzICs9IGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c3dpdGNoICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApICkge1xuXHRcdFx0XHRcdGNhc2UgXCJkXCI6IGNhc2UgXCJtXCI6IGNhc2UgXCJ5XCI6IGNhc2UgXCJAXCI6XG5cdFx0XHRcdFx0XHRjaGFycyArPSBcIjAxMjM0NTY3ODlcIjtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJEXCI6IGNhc2UgXCJNXCI6XG5cdFx0XHRcdFx0XHRyZXR1cm4gbnVsbDsgLy8gQWNjZXB0IGFueXRoaW5nXG5cdFx0XHRcdFx0Y2FzZSBcIidcIjpcblx0XHRcdFx0XHRcdGlmICggbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdFx0XHRjaGFycyArPSBcIidcIjtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGxpdGVyYWwgPSB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdGNoYXJzICs9IGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gY2hhcnM7XG5cdH0sXG5cblx0LyogR2V0IGEgc2V0dGluZyB2YWx1ZSwgZGVmYXVsdGluZyBpZiBuZWNlc3NhcnkuICovXG5cdF9nZXQ6IGZ1bmN0aW9uKCBpbnN0LCBuYW1lICkge1xuXHRcdHJldHVybiBpbnN0LnNldHRpbmdzWyBuYW1lIF0gIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRpbnN0LnNldHRpbmdzWyBuYW1lIF0gOiB0aGlzLl9kZWZhdWx0c1sgbmFtZSBdO1xuXHR9LFxuXG5cdC8qIFBhcnNlIGV4aXN0aW5nIGRhdGUgYW5kIGluaXRpYWxpc2UgZGF0ZSBwaWNrZXIuICovXG5cdF9zZXREYXRlRnJvbUZpZWxkOiBmdW5jdGlvbiggaW5zdCwgbm9EZWZhdWx0ICkge1xuXHRcdGlmICggaW5zdC5pbnB1dC52YWwoKSA9PT0gaW5zdC5sYXN0VmFsICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBkYXRlRm9ybWF0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApLFxuXHRcdFx0ZGF0ZXMgPSBpbnN0Lmxhc3RWYWwgPSBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dC52YWwoKSA6IG51bGwsXG5cdFx0XHRkZWZhdWx0RGF0ZSA9IHRoaXMuX2dldERlZmF1bHREYXRlKCBpbnN0ICksXG5cdFx0XHRkYXRlID0gZGVmYXVsdERhdGUsXG5cdFx0XHRzZXR0aW5ncyA9IHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApO1xuXG5cdFx0dHJ5IHtcblx0XHRcdGRhdGUgPSB0aGlzLnBhcnNlRGF0ZSggZGF0ZUZvcm1hdCwgZGF0ZXMsIHNldHRpbmdzICkgfHwgZGVmYXVsdERhdGU7XG5cdFx0fSBjYXRjaCAoIGV2ZW50ICkge1xuXHRcdFx0ZGF0ZXMgPSAoIG5vRGVmYXVsdCA/IFwiXCIgOiBkYXRlcyApO1xuXHRcdH1cblx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gZGF0ZS5nZXREYXRlKCk7XG5cdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggPSBkYXRlLmdldE1vbnRoKCk7XG5cdFx0aW5zdC5kcmF3WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdGluc3QuY3VycmVudERheSA9ICggZGF0ZXMgPyBkYXRlLmdldERhdGUoKSA6IDAgKTtcblx0XHRpbnN0LmN1cnJlbnRNb250aCA9ICggZGF0ZXMgPyBkYXRlLmdldE1vbnRoKCkgOiAwICk7XG5cdFx0aW5zdC5jdXJyZW50WWVhciA9ICggZGF0ZXMgPyBkYXRlLmdldEZ1bGxZZWFyKCkgOiAwICk7XG5cdFx0dGhpcy5fYWRqdXN0SW5zdERhdGUoIGluc3QgKTtcblx0fSxcblxuXHQvKiBSZXRyaWV2ZSB0aGUgZGVmYXVsdCBkYXRlIHNob3duIG9uIG9wZW5pbmcuICovXG5cdF9nZXREZWZhdWx0RGF0ZTogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3Jlc3RyaWN0TWluTWF4KCBpbnN0LFxuXHRcdFx0dGhpcy5fZGV0ZXJtaW5lRGF0ZSggaW5zdCwgdGhpcy5fZ2V0KCBpbnN0LCBcImRlZmF1bHREYXRlXCIgKSwgbmV3IERhdGUoKSApICk7XG5cdH0sXG5cblx0LyogQSBkYXRlIG1heSBiZSBzcGVjaWZpZWQgYXMgYW4gZXhhY3QgdmFsdWUgb3IgYSByZWxhdGl2ZSBvbmUuICovXG5cdF9kZXRlcm1pbmVEYXRlOiBmdW5jdGlvbiggaW5zdCwgZGF0ZSwgZGVmYXVsdERhdGUgKSB7XG5cdFx0dmFyIG9mZnNldE51bWVyaWMgPSBmdW5jdGlvbiggb2Zmc2V0ICkge1xuXHRcdFx0XHR2YXIgZGF0ZSA9IG5ldyBEYXRlKCk7XG5cdFx0XHRcdGRhdGUuc2V0RGF0ZSggZGF0ZS5nZXREYXRlKCkgKyBvZmZzZXQgKTtcblx0XHRcdFx0cmV0dXJuIGRhdGU7XG5cdFx0XHR9LFxuXHRcdFx0b2Zmc2V0U3RyaW5nID0gZnVuY3Rpb24oIG9mZnNldCApIHtcblx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRyZXR1cm4gJC5kYXRlcGlja2VyLnBhcnNlRGF0ZSggJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICksXG5cdFx0XHRcdFx0XHRvZmZzZXQsICQuZGF0ZXBpY2tlci5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0XHQvLyBJZ25vcmVcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHZhciBkYXRlID0gKCBvZmZzZXQudG9Mb3dlckNhc2UoKS5tYXRjaCggL15jLyApID9cblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2dldERhdGUoIGluc3QgKSA6IG51bGwgKSB8fCBuZXcgRGF0ZSgpLFxuXHRcdFx0XHRcdHllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCksXG5cdFx0XHRcdFx0bW9udGggPSBkYXRlLmdldE1vbnRoKCksXG5cdFx0XHRcdFx0ZGF5ID0gZGF0ZS5nZXREYXRlKCksXG5cdFx0XHRcdFx0cGF0dGVybiA9IC8oWytcXC1dP1swLTldKylcXHMqKGR8RHx3fFd8bXxNfHl8WSk/L2csXG5cdFx0XHRcdFx0bWF0Y2hlcyA9IHBhdHRlcm4uZXhlYyggb2Zmc2V0ICk7XG5cblx0XHRcdFx0d2hpbGUgKCBtYXRjaGVzICkge1xuXHRcdFx0XHRcdHN3aXRjaCAoIG1hdGNoZXNbIDIgXSB8fCBcImRcIiApIHtcblx0XHRcdFx0XHRcdGNhc2UgXCJkXCIgOiBjYXNlIFwiRFwiIDpcblx0XHRcdFx0XHRcdFx0ZGF5ICs9IHBhcnNlSW50KCBtYXRjaGVzWyAxIF0sIDEwICk7IGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIndcIiA6IGNhc2UgXCJXXCIgOlxuXHRcdFx0XHRcdFx0XHRkYXkgKz0gcGFyc2VJbnQoIG1hdGNoZXNbIDEgXSwgMTAgKSAqIDc7IGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIm1cIiA6IGNhc2UgXCJNXCIgOlxuXHRcdFx0XHRcdFx0XHRtb250aCArPSBwYXJzZUludCggbWF0Y2hlc1sgMSBdLCAxMCApO1xuXHRcdFx0XHRcdFx0XHRkYXkgPSBNYXRoLm1pbiggZGF5LCAkLmRhdGVwaWNrZXIuX2dldERheXNJbk1vbnRoKCB5ZWFyLCBtb250aCApICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcInlcIjogY2FzZSBcIllcIiA6XG5cdFx0XHRcdFx0XHRcdHllYXIgKz0gcGFyc2VJbnQoIG1hdGNoZXNbIDEgXSwgMTAgKTtcblx0XHRcdFx0XHRcdFx0ZGF5ID0gTWF0aC5taW4oIGRheSwgJC5kYXRlcGlja2VyLl9nZXREYXlzSW5Nb250aCggeWVhciwgbW9udGggKSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bWF0Y2hlcyA9IHBhdHRlcm4uZXhlYyggb2Zmc2V0ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG5ldyBEYXRlKCB5ZWFyLCBtb250aCwgZGF5ICk7XG5cdFx0XHR9LFxuXHRcdFx0bmV3RGF0ZSA9ICggZGF0ZSA9PSBudWxsIHx8IGRhdGUgPT09IFwiXCIgPyBkZWZhdWx0RGF0ZSA6ICggdHlwZW9mIGRhdGUgPT09IFwic3RyaW5nXCIgPyBvZmZzZXRTdHJpbmcoIGRhdGUgKSA6XG5cdFx0XHRcdCggdHlwZW9mIGRhdGUgPT09IFwibnVtYmVyXCIgPyAoIGlzTmFOKCBkYXRlICkgPyBkZWZhdWx0RGF0ZSA6IG9mZnNldE51bWVyaWMoIGRhdGUgKSApIDogbmV3IERhdGUoIGRhdGUuZ2V0VGltZSgpICkgKSApICk7XG5cblx0XHRuZXdEYXRlID0gKCBuZXdEYXRlICYmIG5ld0RhdGUudG9TdHJpbmcoKSA9PT0gXCJJbnZhbGlkIERhdGVcIiA/IGRlZmF1bHREYXRlIDogbmV3RGF0ZSApO1xuXHRcdGlmICggbmV3RGF0ZSApIHtcblx0XHRcdG5ld0RhdGUuc2V0SG91cnMoIDAgKTtcblx0XHRcdG5ld0RhdGUuc2V0TWludXRlcyggMCApO1xuXHRcdFx0bmV3RGF0ZS5zZXRTZWNvbmRzKCAwICk7XG5cdFx0XHRuZXdEYXRlLnNldE1pbGxpc2Vjb25kcyggMCApO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ld0RhdGUgKTtcblx0fSxcblxuXHQvKiBIYW5kbGUgc3dpdGNoIHRvL2Zyb20gZGF5bGlnaHQgc2F2aW5nLlxuXHQgKiBIb3VycyBtYXkgYmUgbm9uLXplcm8gb24gZGF5bGlnaHQgc2F2aW5nIGN1dC1vdmVyOlxuXHQgKiA+IDEyIHdoZW4gbWlkbmlnaHQgY2hhbmdlb3ZlciwgYnV0IHRoZW4gY2Fubm90IGdlbmVyYXRlXG5cdCAqIG1pZG5pZ2h0IGRhdGV0aW1lLCBzbyBqdW1wIHRvIDFBTSwgb3RoZXJ3aXNlIHJlc2V0LlxuXHQgKiBAcGFyYW0gIGRhdGUgIChEYXRlKSB0aGUgZGF0ZSB0byBjaGVja1xuXHQgKiBAcmV0dXJuICAoRGF0ZSkgdGhlIGNvcnJlY3RlZCBkYXRlXG5cdCAqL1xuXHRfZGF5bGlnaHRTYXZpbmdBZGp1c3Q6IGZ1bmN0aW9uKCBkYXRlICkge1xuXHRcdGlmICggIWRhdGUgKSB7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cdFx0ZGF0ZS5zZXRIb3VycyggZGF0ZS5nZXRIb3VycygpID4gMTIgPyBkYXRlLmdldEhvdXJzKCkgKyAyIDogMCApO1xuXHRcdHJldHVybiBkYXRlO1xuXHR9LFxuXG5cdC8qIFNldCB0aGUgZGF0ZShzKSBkaXJlY3RseS4gKi9cblx0X3NldERhdGU6IGZ1bmN0aW9uKCBpbnN0LCBkYXRlLCBub0NoYW5nZSApIHtcblx0XHR2YXIgY2xlYXIgPSAhZGF0ZSxcblx0XHRcdG9yaWdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCxcblx0XHRcdG9yaWdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIsXG5cdFx0XHRuZXdEYXRlID0gdGhpcy5fcmVzdHJpY3RNaW5NYXgoIGluc3QsIHRoaXMuX2RldGVybWluZURhdGUoIGluc3QsIGRhdGUsIG5ldyBEYXRlKCkgKSApO1xuXG5cdFx0aW5zdC5zZWxlY3RlZERheSA9IGluc3QuY3VycmVudERheSA9IG5ld0RhdGUuZ2V0RGF0ZSgpO1xuXHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoID0gaW5zdC5jdXJyZW50TW9udGggPSBuZXdEYXRlLmdldE1vbnRoKCk7XG5cdFx0aW5zdC5kcmF3WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyID0gaW5zdC5jdXJyZW50WWVhciA9IG5ld0RhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHRpZiAoICggb3JpZ01vbnRoICE9PSBpbnN0LnNlbGVjdGVkTW9udGggfHwgb3JpZ1llYXIgIT09IGluc3Quc2VsZWN0ZWRZZWFyICkgJiYgIW5vQ2hhbmdlICkge1xuXHRcdFx0dGhpcy5fbm90aWZ5Q2hhbmdlKCBpbnN0ICk7XG5cdFx0fVxuXHRcdHRoaXMuX2FkanVzdEluc3REYXRlKCBpbnN0ICk7XG5cdFx0aWYgKCBpbnN0LmlucHV0ICkge1xuXHRcdFx0aW5zdC5pbnB1dC52YWwoIGNsZWFyID8gXCJcIiA6IHRoaXMuX2Zvcm1hdERhdGUoIGluc3QgKSApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBSZXRyaWV2ZSB0aGUgZGF0ZShzKSBkaXJlY3RseS4gKi9cblx0X2dldERhdGU6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBzdGFydERhdGUgPSAoICFpbnN0LmN1cnJlbnRZZWFyIHx8ICggaW5zdC5pbnB1dCAmJiBpbnN0LmlucHV0LnZhbCgpID09PSBcIlwiICkgPyBudWxsIDpcblx0XHRcdHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZShcblx0XHRcdGluc3QuY3VycmVudFllYXIsIGluc3QuY3VycmVudE1vbnRoLCBpbnN0LmN1cnJlbnREYXkgKSApICk7XG5cdFx0XHRyZXR1cm4gc3RhcnREYXRlO1xuXHR9LFxuXG5cdC8qIEF0dGFjaCB0aGUgb254eHggaGFuZGxlcnMuICBUaGVzZSBhcmUgZGVjbGFyZWQgc3RhdGljYWxseSBzb1xuXHQgKiB0aGV5IHdvcmsgd2l0aCBzdGF0aWMgY29kZSB0cmFuc2Zvcm1lcnMgbGlrZSBDYWphLlxuXHQgKi9cblx0X2F0dGFjaEhhbmRsZXJzOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgc3RlcE1vbnRocyA9IHRoaXMuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSxcblx0XHRcdGlkID0gXCIjXCIgKyBpbnN0LmlkLnJlcGxhY2UoIC9cXFxcXFxcXC9nLCBcIlxcXFxcIiApO1xuXHRcdGluc3QuZHBEaXYuZmluZCggXCJbZGF0YS1oYW5kbGVyXVwiICkubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBoYW5kbGVyID0ge1xuXHRcdFx0XHRwcmV2OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGlkLCAtc3RlcE1vbnRocywgXCJNXCIgKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0bmV4dDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBpZCwgK3N0ZXBNb250aHMsIFwiTVwiICk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdGhpZGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0dG9kYXk6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fZ290b1RvZGF5KCBpZCApO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRzZWxlY3REYXk6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2VsZWN0RGF5KCBpZCwgK3RoaXMuZ2V0QXR0cmlidXRlKCBcImRhdGEtbW9udGhcIiApLCArdGhpcy5nZXRBdHRyaWJ1dGUoIFwiZGF0YS15ZWFyXCIgKSwgdGhpcyApO1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fSxcblx0XHRcdFx0c2VsZWN0TW9udGg6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2VsZWN0TW9udGhZZWFyKCBpZCwgdGhpcywgXCJNXCIgKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHNlbGVjdFllYXI6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2VsZWN0TW9udGhZZWFyKCBpZCwgdGhpcywgXCJZXCIgKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0XHQkKCB0aGlzICkub24oIHRoaXMuZ2V0QXR0cmlidXRlKCBcImRhdGEtZXZlbnRcIiApLCBoYW5kbGVyWyB0aGlzLmdldEF0dHJpYnV0ZSggXCJkYXRhLWhhbmRsZXJcIiApIF0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0LyogR2VuZXJhdGUgdGhlIEhUTUwgZm9yIHRoZSBjdXJyZW50IHN0YXRlIG9mIHRoZSBkYXRlIHBpY2tlci4gKi9cblx0X2dlbmVyYXRlSFRNTDogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIG1heERyYXcsIHByZXZUZXh0LCBwcmV2LCBuZXh0VGV4dCwgbmV4dCwgY3VycmVudFRleHQsIGdvdG9EYXRlLFxuXHRcdFx0Y29udHJvbHMsIGJ1dHRvblBhbmVsLCBmaXJzdERheSwgc2hvd1dlZWssIGRheU5hbWVzLCBkYXlOYW1lc01pbixcblx0XHRcdG1vbnRoTmFtZXMsIG1vbnRoTmFtZXNTaG9ydCwgYmVmb3JlU2hvd0RheSwgc2hvd090aGVyTW9udGhzLFxuXHRcdFx0c2VsZWN0T3RoZXJNb250aHMsIGRlZmF1bHREYXRlLCBodG1sLCBkb3csIHJvdywgZ3JvdXAsIGNvbCwgc2VsZWN0ZWREYXRlLFxuXHRcdFx0Y29ybmVyQ2xhc3MsIGNhbGVuZGVyLCB0aGVhZCwgZGF5LCBkYXlzSW5Nb250aCwgbGVhZERheXMsIGN1clJvd3MsIG51bVJvd3MsXG5cdFx0XHRwcmludERhdGUsIGRSb3csIHRib2R5LCBkYXlTZXR0aW5ncywgb3RoZXJNb250aCwgdW5zZWxlY3RhYmxlLFxuXHRcdFx0dGVtcERhdGUgPSBuZXcgRGF0ZSgpLFxuXHRcdFx0dG9kYXkgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdChcblx0XHRcdFx0bmV3IERhdGUoIHRlbXBEYXRlLmdldEZ1bGxZZWFyKCksIHRlbXBEYXRlLmdldE1vbnRoKCksIHRlbXBEYXRlLmdldERhdGUoKSApICksIC8vIGNsZWFyIHRpbWVcblx0XHRcdGlzUlRMID0gdGhpcy5fZ2V0KCBpbnN0LCBcImlzUlRMXCIgKSxcblx0XHRcdHNob3dCdXR0b25QYW5lbCA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93QnV0dG9uUGFuZWxcIiApLFxuXHRcdFx0aGlkZUlmTm9QcmV2TmV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJoaWRlSWZOb1ByZXZOZXh0XCIgKSxcblx0XHRcdG5hdmlnYXRpb25Bc0RhdGVGb3JtYXQgPSB0aGlzLl9nZXQoIGluc3QsIFwibmF2aWdhdGlvbkFzRGF0ZUZvcm1hdFwiICksXG5cdFx0XHRudW1Nb250aHMgPSB0aGlzLl9nZXROdW1iZXJPZk1vbnRocyggaW5zdCApLFxuXHRcdFx0c2hvd0N1cnJlbnRBdFBvcyA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93Q3VycmVudEF0UG9zXCIgKSxcblx0XHRcdHN0ZXBNb250aHMgPSB0aGlzLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICksXG5cdFx0XHRpc011bHRpTW9udGggPSAoIG51bU1vbnRoc1sgMCBdICE9PSAxIHx8IG51bU1vbnRoc1sgMSBdICE9PSAxICksXG5cdFx0XHRjdXJyZW50RGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCAoICFpbnN0LmN1cnJlbnREYXkgPyBuZXcgRGF0ZSggOTk5OSwgOSwgOSApIDpcblx0XHRcdFx0bmV3IERhdGUoIGluc3QuY3VycmVudFllYXIsIGluc3QuY3VycmVudE1vbnRoLCBpbnN0LmN1cnJlbnREYXkgKSApICksXG5cdFx0XHRtaW5EYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtaW5cIiApLFxuXHRcdFx0bWF4RGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWF4XCIgKSxcblx0XHRcdGRyYXdNb250aCA9IGluc3QuZHJhd01vbnRoIC0gc2hvd0N1cnJlbnRBdFBvcyxcblx0XHRcdGRyYXdZZWFyID0gaW5zdC5kcmF3WWVhcjtcblxuXHRcdGlmICggZHJhd01vbnRoIDwgMCApIHtcblx0XHRcdGRyYXdNb250aCArPSAxMjtcblx0XHRcdGRyYXdZZWFyLS07XG5cdFx0fVxuXHRcdGlmICggbWF4RGF0ZSApIHtcblx0XHRcdG1heERyYXcgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIG1heERhdGUuZ2V0RnVsbFllYXIoKSxcblx0XHRcdFx0bWF4RGF0ZS5nZXRNb250aCgpIC0gKCBudW1Nb250aHNbIDAgXSAqIG51bU1vbnRoc1sgMSBdICkgKyAxLCBtYXhEYXRlLmdldERhdGUoKSApICk7XG5cdFx0XHRtYXhEcmF3ID0gKCBtaW5EYXRlICYmIG1heERyYXcgPCBtaW5EYXRlID8gbWluRGF0ZSA6IG1heERyYXcgKTtcblx0XHRcdHdoaWxlICggdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBkcmF3WWVhciwgZHJhd01vbnRoLCAxICkgKSA+IG1heERyYXcgKSB7XG5cdFx0XHRcdGRyYXdNb250aC0tO1xuXHRcdFx0XHRpZiAoIGRyYXdNb250aCA8IDAgKSB7XG5cdFx0XHRcdFx0ZHJhd01vbnRoID0gMTE7XG5cdFx0XHRcdFx0ZHJhd1llYXItLTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRpbnN0LmRyYXdNb250aCA9IGRyYXdNb250aDtcblx0XHRpbnN0LmRyYXdZZWFyID0gZHJhd1llYXI7XG5cblx0XHRwcmV2VGV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJwcmV2VGV4dFwiICk7XG5cdFx0cHJldlRleHQgPSAoICFuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0ID8gcHJldlRleHQgOiB0aGlzLmZvcm1hdERhdGUoIHByZXZUZXh0LFxuXHRcdFx0dGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBkcmF3WWVhciwgZHJhd01vbnRoIC0gc3RlcE1vbnRocywgMSApICksXG5cdFx0XHR0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApICk7XG5cblx0XHRwcmV2ID0gKCB0aGlzLl9jYW5BZGp1c3RNb250aCggaW5zdCwgLTEsIGRyYXdZZWFyLCBkcmF3TW9udGggKSA/XG5cdFx0XHRcIjxhIGNsYXNzPSd1aS1kYXRlcGlja2VyLXByZXYgdWktY29ybmVyLWFsbCcgZGF0YS1oYW5kbGVyPSdwcmV2JyBkYXRhLWV2ZW50PSdjbGljaydcIiArXG5cdFx0XHRcIiB0aXRsZT0nXCIgKyBwcmV2VGV4dCArIFwiJz48c3BhbiBjbGFzcz0ndWktaWNvbiB1aS1pY29uLWNpcmNsZS10cmlhbmdsZS1cIiArICggaXNSVEwgPyBcImVcIiA6IFwid1wiICkgKyBcIic+XCIgKyBwcmV2VGV4dCArIFwiPC9zcGFuPjwvYT5cIiA6XG5cdFx0XHQoIGhpZGVJZk5vUHJldk5leHQgPyBcIlwiIDogXCI8YSBjbGFzcz0ndWktZGF0ZXBpY2tlci1wcmV2IHVpLWNvcm5lci1hbGwgdWktc3RhdGUtZGlzYWJsZWQnIHRpdGxlPSdcIiArIHByZXZUZXh0ICsgXCInPjxzcGFuIGNsYXNzPSd1aS1pY29uIHVpLWljb24tY2lyY2xlLXRyaWFuZ2xlLVwiICsgKCBpc1JUTCA/IFwiZVwiIDogXCJ3XCIgKSArIFwiJz5cIiArIHByZXZUZXh0ICsgXCI8L3NwYW4+PC9hPlwiICkgKTtcblxuXHRcdG5leHRUZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm5leHRUZXh0XCIgKTtcblx0XHRuZXh0VGV4dCA9ICggIW5hdmlnYXRpb25Bc0RhdGVGb3JtYXQgPyBuZXh0VGV4dCA6IHRoaXMuZm9ybWF0RGF0ZSggbmV4dFRleHQsXG5cdFx0XHR0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGRyYXdZZWFyLCBkcmF3TW9udGggKyBzdGVwTW9udGhzLCAxICkgKSxcblx0XHRcdHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICkgKTtcblxuXHRcdG5leHQgPSAoIHRoaXMuX2NhbkFkanVzdE1vbnRoKCBpbnN0LCArMSwgZHJhd1llYXIsIGRyYXdNb250aCApID9cblx0XHRcdFwiPGEgY2xhc3M9J3VpLWRhdGVwaWNrZXItbmV4dCB1aS1jb3JuZXItYWxsJyBkYXRhLWhhbmRsZXI9J25leHQnIGRhdGEtZXZlbnQ9J2NsaWNrJ1wiICtcblx0XHRcdFwiIHRpdGxlPSdcIiArIG5leHRUZXh0ICsgXCInPjxzcGFuIGNsYXNzPSd1aS1pY29uIHVpLWljb24tY2lyY2xlLXRyaWFuZ2xlLVwiICsgKCBpc1JUTCA/IFwid1wiIDogXCJlXCIgKSArIFwiJz5cIiArIG5leHRUZXh0ICsgXCI8L3NwYW4+PC9hPlwiIDpcblx0XHRcdCggaGlkZUlmTm9QcmV2TmV4dCA/IFwiXCIgOiBcIjxhIGNsYXNzPSd1aS1kYXRlcGlja2VyLW5leHQgdWktY29ybmVyLWFsbCB1aS1zdGF0ZS1kaXNhYmxlZCcgdGl0bGU9J1wiICsgbmV4dFRleHQgKyBcIic+PHNwYW4gY2xhc3M9J3VpLWljb24gdWktaWNvbi1jaXJjbGUtdHJpYW5nbGUtXCIgKyAoIGlzUlRMID8gXCJ3XCIgOiBcImVcIiApICsgXCInPlwiICsgbmV4dFRleHQgKyBcIjwvc3Bhbj48L2E+XCIgKSApO1xuXG5cdFx0Y3VycmVudFRleHQgPSB0aGlzLl9nZXQoIGluc3QsIFwiY3VycmVudFRleHRcIiApO1xuXHRcdGdvdG9EYXRlID0gKCB0aGlzLl9nZXQoIGluc3QsIFwiZ290b0N1cnJlbnRcIiApICYmIGluc3QuY3VycmVudERheSA/IGN1cnJlbnREYXRlIDogdG9kYXkgKTtcblx0XHRjdXJyZW50VGV4dCA9ICggIW5hdmlnYXRpb25Bc0RhdGVGb3JtYXQgPyBjdXJyZW50VGV4dCA6XG5cdFx0XHR0aGlzLmZvcm1hdERhdGUoIGN1cnJlbnRUZXh0LCBnb3RvRGF0ZSwgdGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKSApO1xuXG5cdFx0Y29udHJvbHMgPSAoICFpbnN0LmlubGluZSA/IFwiPGJ1dHRvbiB0eXBlPSdidXR0b24nIGNsYXNzPSd1aS1kYXRlcGlja2VyLWNsb3NlIHVpLXN0YXRlLWRlZmF1bHQgdWktcHJpb3JpdHktcHJpbWFyeSB1aS1jb3JuZXItYWxsJyBkYXRhLWhhbmRsZXI9J2hpZGUnIGRhdGEtZXZlbnQ9J2NsaWNrJz5cIiArXG5cdFx0XHR0aGlzLl9nZXQoIGluc3QsIFwiY2xvc2VUZXh0XCIgKSArIFwiPC9idXR0b24+XCIgOiBcIlwiICk7XG5cblx0XHRidXR0b25QYW5lbCA9ICggc2hvd0J1dHRvblBhbmVsICkgPyBcIjxkaXYgY2xhc3M9J3VpLWRhdGVwaWNrZXItYnV0dG9ucGFuZSB1aS13aWRnZXQtY29udGVudCc+XCIgKyAoIGlzUlRMID8gY29udHJvbHMgOiBcIlwiICkgK1xuXHRcdFx0KCB0aGlzLl9pc0luUmFuZ2UoIGluc3QsIGdvdG9EYXRlICkgPyBcIjxidXR0b24gdHlwZT0nYnV0dG9uJyBjbGFzcz0ndWktZGF0ZXBpY2tlci1jdXJyZW50IHVpLXN0YXRlLWRlZmF1bHQgdWktcHJpb3JpdHktc2Vjb25kYXJ5IHVpLWNvcm5lci1hbGwnIGRhdGEtaGFuZGxlcj0ndG9kYXknIGRhdGEtZXZlbnQ9J2NsaWNrJ1wiICtcblx0XHRcdFwiPlwiICsgY3VycmVudFRleHQgKyBcIjwvYnV0dG9uPlwiIDogXCJcIiApICsgKCBpc1JUTCA/IFwiXCIgOiBjb250cm9scyApICsgXCI8L2Rpdj5cIiA6IFwiXCI7XG5cblx0XHRmaXJzdERheSA9IHBhcnNlSW50KCB0aGlzLl9nZXQoIGluc3QsIFwiZmlyc3REYXlcIiApLCAxMCApO1xuXHRcdGZpcnN0RGF5ID0gKCBpc05hTiggZmlyc3REYXkgKSA/IDAgOiBmaXJzdERheSApO1xuXG5cdFx0c2hvd1dlZWsgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd1dlZWtcIiApO1xuXHRcdGRheU5hbWVzID0gdGhpcy5fZ2V0KCBpbnN0LCBcImRheU5hbWVzXCIgKTtcblx0XHRkYXlOYW1lc01pbiA9IHRoaXMuX2dldCggaW5zdCwgXCJkYXlOYW1lc01pblwiICk7XG5cdFx0bW9udGhOYW1lcyA9IHRoaXMuX2dldCggaW5zdCwgXCJtb250aE5hbWVzXCIgKTtcblx0XHRtb250aE5hbWVzU2hvcnQgPSB0aGlzLl9nZXQoIGluc3QsIFwibW9udGhOYW1lc1Nob3J0XCIgKTtcblx0XHRiZWZvcmVTaG93RGF5ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImJlZm9yZVNob3dEYXlcIiApO1xuXHRcdHNob3dPdGhlck1vbnRocyA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93T3RoZXJNb250aHNcIiApO1xuXHRcdHNlbGVjdE90aGVyTW9udGhzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNlbGVjdE90aGVyTW9udGhzXCIgKTtcblx0XHRkZWZhdWx0RGF0ZSA9IHRoaXMuX2dldERlZmF1bHREYXRlKCBpbnN0ICk7XG5cdFx0aHRtbCA9IFwiXCI7XG5cblx0XHRmb3IgKCByb3cgPSAwOyByb3cgPCBudW1Nb250aHNbIDAgXTsgcm93KysgKSB7XG5cdFx0XHRncm91cCA9IFwiXCI7XG5cdFx0XHR0aGlzLm1heFJvd3MgPSA0O1xuXHRcdFx0Zm9yICggY29sID0gMDsgY29sIDwgbnVtTW9udGhzWyAxIF07IGNvbCsrICkge1xuXHRcdFx0XHRzZWxlY3RlZERhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGRyYXdZZWFyLCBkcmF3TW9udGgsIGluc3Quc2VsZWN0ZWREYXkgKSApO1xuXHRcdFx0XHRjb3JuZXJDbGFzcyA9IFwiIHVpLWNvcm5lci1hbGxcIjtcblx0XHRcdFx0Y2FsZW5kZXIgPSBcIlwiO1xuXHRcdFx0XHRpZiAoIGlzTXVsdGlNb250aCApIHtcblx0XHRcdFx0XHRjYWxlbmRlciArPSBcIjxkaXYgY2xhc3M9J3VpLWRhdGVwaWNrZXItZ3JvdXBcIjtcblx0XHRcdFx0XHRpZiAoIG51bU1vbnRoc1sgMSBdID4gMSApIHtcblx0XHRcdFx0XHRcdHN3aXRjaCAoIGNvbCApIHtcblx0XHRcdFx0XHRcdFx0Y2FzZSAwOiBjYWxlbmRlciArPSBcIiB1aS1kYXRlcGlja2VyLWdyb3VwLWZpcnN0XCI7XG5cdFx0XHRcdFx0XHRcdFx0Y29ybmVyQ2xhc3MgPSBcIiB1aS1jb3JuZXItXCIgKyAoIGlzUlRMID8gXCJyaWdodFwiIDogXCJsZWZ0XCIgKTsgYnJlYWs7XG5cdFx0XHRcdFx0XHRcdGNhc2UgbnVtTW9udGhzWyAxIF0gLSAxOiBjYWxlbmRlciArPSBcIiB1aS1kYXRlcGlja2VyLWdyb3VwLWxhc3RcIjtcblx0XHRcdFx0XHRcdFx0XHRjb3JuZXJDbGFzcyA9IFwiIHVpLWNvcm5lci1cIiArICggaXNSVEwgPyBcImxlZnRcIiA6IFwicmlnaHRcIiApOyBicmVhaztcblx0XHRcdFx0XHRcdFx0ZGVmYXVsdDogY2FsZW5kZXIgKz0gXCIgdWktZGF0ZXBpY2tlci1ncm91cC1taWRkbGVcIjsgY29ybmVyQ2xhc3MgPSBcIlwiOyBicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Y2FsZW5kZXIgKz0gXCInPlwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNhbGVuZGVyICs9IFwiPGRpdiBjbGFzcz0ndWktZGF0ZXBpY2tlci1oZWFkZXIgdWktd2lkZ2V0LWhlYWRlciB1aS1oZWxwZXItY2xlYXJmaXhcIiArIGNvcm5lckNsYXNzICsgXCInPlwiICtcblx0XHRcdFx0XHQoIC9hbGx8bGVmdC8udGVzdCggY29ybmVyQ2xhc3MgKSAmJiByb3cgPT09IDAgPyAoIGlzUlRMID8gbmV4dCA6IHByZXYgKSA6IFwiXCIgKSArXG5cdFx0XHRcdFx0KCAvYWxsfHJpZ2h0Ly50ZXN0KCBjb3JuZXJDbGFzcyApICYmIHJvdyA9PT0gMCA/ICggaXNSVEwgPyBwcmV2IDogbmV4dCApIDogXCJcIiApICtcblx0XHRcdFx0XHR0aGlzLl9nZW5lcmF0ZU1vbnRoWWVhckhlYWRlciggaW5zdCwgZHJhd01vbnRoLCBkcmF3WWVhciwgbWluRGF0ZSwgbWF4RGF0ZSxcblx0XHRcdFx0XHRyb3cgPiAwIHx8IGNvbCA+IDAsIG1vbnRoTmFtZXMsIG1vbnRoTmFtZXNTaG9ydCApICsgLy8gZHJhdyBtb250aCBoZWFkZXJzXG5cdFx0XHRcdFx0XCI8L2Rpdj48dGFibGUgY2xhc3M9J3VpLWRhdGVwaWNrZXItY2FsZW5kYXInPjx0aGVhZD5cIiArXG5cdFx0XHRcdFx0XCI8dHI+XCI7XG5cdFx0XHRcdHRoZWFkID0gKCBzaG93V2VlayA/IFwiPHRoIGNsYXNzPSd1aS1kYXRlcGlja2VyLXdlZWstY29sJz5cIiArIHRoaXMuX2dldCggaW5zdCwgXCJ3ZWVrSGVhZGVyXCIgKSArIFwiPC90aD5cIiA6IFwiXCIgKTtcblx0XHRcdFx0Zm9yICggZG93ID0gMDsgZG93IDwgNzsgZG93KysgKSB7IC8vIGRheXMgb2YgdGhlIHdlZWtcblx0XHRcdFx0XHRkYXkgPSAoIGRvdyArIGZpcnN0RGF5ICkgJSA3O1xuXHRcdFx0XHRcdHRoZWFkICs9IFwiPHRoIHNjb3BlPSdjb2wnXCIgKyAoICggZG93ICsgZmlyc3REYXkgKyA2ICkgJSA3ID49IDUgPyBcIiBjbGFzcz0ndWktZGF0ZXBpY2tlci13ZWVrLWVuZCdcIiA6IFwiXCIgKSArIFwiPlwiICtcblx0XHRcdFx0XHRcdFwiPHNwYW4gdGl0bGU9J1wiICsgZGF5TmFtZXNbIGRheSBdICsgXCInPlwiICsgZGF5TmFtZXNNaW5bIGRheSBdICsgXCI8L3NwYW4+PC90aD5cIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRjYWxlbmRlciArPSB0aGVhZCArIFwiPC90cj48L3RoZWFkPjx0Ym9keT5cIjtcblx0XHRcdFx0ZGF5c0luTW9udGggPSB0aGlzLl9nZXREYXlzSW5Nb250aCggZHJhd1llYXIsIGRyYXdNb250aCApO1xuXHRcdFx0XHRpZiAoIGRyYXdZZWFyID09PSBpbnN0LnNlbGVjdGVkWWVhciAmJiBkcmF3TW9udGggPT09IGluc3Quc2VsZWN0ZWRNb250aCApIHtcblx0XHRcdFx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gTWF0aC5taW4oIGluc3Quc2VsZWN0ZWREYXksIGRheXNJbk1vbnRoICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0bGVhZERheXMgPSAoIHRoaXMuX2dldEZpcnN0RGF5T2ZNb250aCggZHJhd1llYXIsIGRyYXdNb250aCApIC0gZmlyc3REYXkgKyA3ICkgJSA3O1xuXHRcdFx0XHRjdXJSb3dzID0gTWF0aC5jZWlsKCAoIGxlYWREYXlzICsgZGF5c0luTW9udGggKSAvIDcgKTsgLy8gY2FsY3VsYXRlIHRoZSBudW1iZXIgb2Ygcm93cyB0byBnZW5lcmF0ZVxuXHRcdFx0XHRudW1Sb3dzID0gKCBpc011bHRpTW9udGggPyB0aGlzLm1heFJvd3MgPiBjdXJSb3dzID8gdGhpcy5tYXhSb3dzIDogY3VyUm93cyA6IGN1clJvd3MgKTsgLy9JZiBtdWx0aXBsZSBtb250aHMsIHVzZSB0aGUgaGlnaGVyIG51bWJlciBvZiByb3dzIChzZWUgIzcwNDMpXG5cdFx0XHRcdHRoaXMubWF4Um93cyA9IG51bVJvd3M7XG5cdFx0XHRcdHByaW50RGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggZHJhd1llYXIsIGRyYXdNb250aCwgMSAtIGxlYWREYXlzICkgKTtcblx0XHRcdFx0Zm9yICggZFJvdyA9IDA7IGRSb3cgPCBudW1Sb3dzOyBkUm93KysgKSB7IC8vIGNyZWF0ZSBkYXRlIHBpY2tlciByb3dzXG5cdFx0XHRcdFx0Y2FsZW5kZXIgKz0gXCI8dHI+XCI7XG5cdFx0XHRcdFx0dGJvZHkgPSAoICFzaG93V2VlayA/IFwiXCIgOiBcIjx0ZCBjbGFzcz0ndWktZGF0ZXBpY2tlci13ZWVrLWNvbCc+XCIgK1xuXHRcdFx0XHRcdFx0dGhpcy5fZ2V0KCBpbnN0LCBcImNhbGN1bGF0ZVdlZWtcIiApKCBwcmludERhdGUgKSArIFwiPC90ZD5cIiApO1xuXHRcdFx0XHRcdGZvciAoIGRvdyA9IDA7IGRvdyA8IDc7IGRvdysrICkgeyAvLyBjcmVhdGUgZGF0ZSBwaWNrZXIgZGF5c1xuXHRcdFx0XHRcdFx0ZGF5U2V0dGluZ3MgPSAoIGJlZm9yZVNob3dEYXkgP1xuXHRcdFx0XHRcdFx0XHRiZWZvcmVTaG93RGF5LmFwcGx5KCAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0WyAwIF0gOiBudWxsICksIFsgcHJpbnREYXRlIF0gKSA6IFsgdHJ1ZSwgXCJcIiBdICk7XG5cdFx0XHRcdFx0XHRvdGhlck1vbnRoID0gKCBwcmludERhdGUuZ2V0TW9udGgoKSAhPT0gZHJhd01vbnRoICk7XG5cdFx0XHRcdFx0XHR1bnNlbGVjdGFibGUgPSAoIG90aGVyTW9udGggJiYgIXNlbGVjdE90aGVyTW9udGhzICkgfHwgIWRheVNldHRpbmdzWyAwIF0gfHxcblx0XHRcdFx0XHRcdFx0KCBtaW5EYXRlICYmIHByaW50RGF0ZSA8IG1pbkRhdGUgKSB8fCAoIG1heERhdGUgJiYgcHJpbnREYXRlID4gbWF4RGF0ZSApO1xuXHRcdFx0XHRcdFx0dGJvZHkgKz0gXCI8dGQgY2xhc3M9J1wiICtcblx0XHRcdFx0XHRcdFx0KCAoIGRvdyArIGZpcnN0RGF5ICsgNiApICUgNyA+PSA1ID8gXCIgdWktZGF0ZXBpY2tlci13ZWVrLWVuZFwiIDogXCJcIiApICsgLy8gaGlnaGxpZ2h0IHdlZWtlbmRzXG5cdFx0XHRcdFx0XHRcdCggb3RoZXJNb250aCA/IFwiIHVpLWRhdGVwaWNrZXItb3RoZXItbW9udGhcIiA6IFwiXCIgKSArIC8vIGhpZ2hsaWdodCBkYXlzIGZyb20gb3RoZXIgbW9udGhzXG5cdFx0XHRcdFx0XHRcdCggKCBwcmludERhdGUuZ2V0VGltZSgpID09PSBzZWxlY3RlZERhdGUuZ2V0VGltZSgpICYmIGRyYXdNb250aCA9PT0gaW5zdC5zZWxlY3RlZE1vbnRoICYmIGluc3QuX2tleUV2ZW50ICkgfHwgLy8gdXNlciBwcmVzc2VkIGtleVxuXHRcdFx0XHRcdFx0XHQoIGRlZmF1bHREYXRlLmdldFRpbWUoKSA9PT0gcHJpbnREYXRlLmdldFRpbWUoKSAmJiBkZWZhdWx0RGF0ZS5nZXRUaW1lKCkgPT09IHNlbGVjdGVkRGF0ZS5nZXRUaW1lKCkgKSA/XG5cblx0XHRcdFx0XHRcdFx0Ly8gb3IgZGVmYXVsdERhdGUgaXMgY3VycmVudCBwcmludGVkRGF0ZSBhbmQgZGVmYXVsdERhdGUgaXMgc2VsZWN0ZWREYXRlXG5cdFx0XHRcdFx0XHRcdFwiIFwiICsgdGhpcy5fZGF5T3ZlckNsYXNzIDogXCJcIiApICsgLy8gaGlnaGxpZ2h0IHNlbGVjdGVkIGRheVxuXHRcdFx0XHRcdFx0XHQoIHVuc2VsZWN0YWJsZSA/IFwiIFwiICsgdGhpcy5fdW5zZWxlY3RhYmxlQ2xhc3MgKyBcIiB1aS1zdGF0ZS1kaXNhYmxlZFwiIDogXCJcIiApICsgIC8vIGhpZ2hsaWdodCB1bnNlbGVjdGFibGUgZGF5c1xuXHRcdFx0XHRcdFx0XHQoIG90aGVyTW9udGggJiYgIXNob3dPdGhlck1vbnRocyA/IFwiXCIgOiBcIiBcIiArIGRheVNldHRpbmdzWyAxIF0gKyAvLyBoaWdobGlnaHQgY3VzdG9tIGRhdGVzXG5cdFx0XHRcdFx0XHRcdCggcHJpbnREYXRlLmdldFRpbWUoKSA9PT0gY3VycmVudERhdGUuZ2V0VGltZSgpID8gXCIgXCIgKyB0aGlzLl9jdXJyZW50Q2xhc3MgOiBcIlwiICkgKyAvLyBoaWdobGlnaHQgc2VsZWN0ZWQgZGF5XG5cdFx0XHRcdFx0XHRcdCggcHJpbnREYXRlLmdldFRpbWUoKSA9PT0gdG9kYXkuZ2V0VGltZSgpID8gXCIgdWktZGF0ZXBpY2tlci10b2RheVwiIDogXCJcIiApICkgKyBcIidcIiArIC8vIGhpZ2hsaWdodCB0b2RheSAoaWYgZGlmZmVyZW50KVxuXHRcdFx0XHRcdFx0XHQoICggIW90aGVyTW9udGggfHwgc2hvd090aGVyTW9udGhzICkgJiYgZGF5U2V0dGluZ3NbIDIgXSA/IFwiIHRpdGxlPSdcIiArIGRheVNldHRpbmdzWyAyIF0ucmVwbGFjZSggLycvZywgXCImIzM5O1wiICkgKyBcIidcIiA6IFwiXCIgKSArIC8vIGNlbGwgdGl0bGVcblx0XHRcdFx0XHRcdFx0KCB1bnNlbGVjdGFibGUgPyBcIlwiIDogXCIgZGF0YS1oYW5kbGVyPSdzZWxlY3REYXknIGRhdGEtZXZlbnQ9J2NsaWNrJyBkYXRhLW1vbnRoPSdcIiArIHByaW50RGF0ZS5nZXRNb250aCgpICsgXCInIGRhdGEteWVhcj0nXCIgKyBwcmludERhdGUuZ2V0RnVsbFllYXIoKSArIFwiJ1wiICkgKyBcIj5cIiArIC8vIGFjdGlvbnNcblx0XHRcdFx0XHRcdFx0KCBvdGhlck1vbnRoICYmICFzaG93T3RoZXJNb250aHMgPyBcIiYjeGEwO1wiIDogLy8gZGlzcGxheSBmb3Igb3RoZXIgbW9udGhzXG5cdFx0XHRcdFx0XHRcdCggdW5zZWxlY3RhYmxlID8gXCI8c3BhbiBjbGFzcz0ndWktc3RhdGUtZGVmYXVsdCc+XCIgKyBwcmludERhdGUuZ2V0RGF0ZSgpICsgXCI8L3NwYW4+XCIgOiBcIjxhIGNsYXNzPSd1aS1zdGF0ZS1kZWZhdWx0XCIgK1xuXHRcdFx0XHRcdFx0XHQoIHByaW50RGF0ZS5nZXRUaW1lKCkgPT09IHRvZGF5LmdldFRpbWUoKSA/IFwiIHVpLXN0YXRlLWhpZ2hsaWdodFwiIDogXCJcIiApICtcblx0XHRcdFx0XHRcdFx0KCBwcmludERhdGUuZ2V0VGltZSgpID09PSBjdXJyZW50RGF0ZS5nZXRUaW1lKCkgPyBcIiB1aS1zdGF0ZS1hY3RpdmVcIiA6IFwiXCIgKSArIC8vIGhpZ2hsaWdodCBzZWxlY3RlZCBkYXlcblx0XHRcdFx0XHRcdFx0KCBvdGhlck1vbnRoID8gXCIgdWktcHJpb3JpdHktc2Vjb25kYXJ5XCIgOiBcIlwiICkgKyAvLyBkaXN0aW5ndWlzaCBkYXRlcyBmcm9tIG90aGVyIG1vbnRoc1xuXHRcdFx0XHRcdFx0XHRcIicgaHJlZj0nIyc+XCIgKyBwcmludERhdGUuZ2V0RGF0ZSgpICsgXCI8L2E+XCIgKSApICsgXCI8L3RkPlwiOyAvLyBkaXNwbGF5IHNlbGVjdGFibGUgZGF0ZVxuXHRcdFx0XHRcdFx0cHJpbnREYXRlLnNldERhdGUoIHByaW50RGF0ZS5nZXREYXRlKCkgKyAxICk7XG5cdFx0XHRcdFx0XHRwcmludERhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggcHJpbnREYXRlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGNhbGVuZGVyICs9IHRib2R5ICsgXCI8L3RyPlwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRyYXdNb250aCsrO1xuXHRcdFx0XHRpZiAoIGRyYXdNb250aCA+IDExICkge1xuXHRcdFx0XHRcdGRyYXdNb250aCA9IDA7XG5cdFx0XHRcdFx0ZHJhd1llYXIrKztcblx0XHRcdFx0fVxuXHRcdFx0XHRjYWxlbmRlciArPSBcIjwvdGJvZHk+PC90YWJsZT5cIiArICggaXNNdWx0aU1vbnRoID8gXCI8L2Rpdj5cIiArXG5cdFx0XHRcdFx0XHRcdCggKCBudW1Nb250aHNbIDAgXSA+IDAgJiYgY29sID09PSBudW1Nb250aHNbIDEgXSAtIDEgKSA/IFwiPGRpdiBjbGFzcz0ndWktZGF0ZXBpY2tlci1yb3ctYnJlYWsnPjwvZGl2PlwiIDogXCJcIiApIDogXCJcIiApO1xuXHRcdFx0XHRncm91cCArPSBjYWxlbmRlcjtcblx0XHRcdH1cblx0XHRcdGh0bWwgKz0gZ3JvdXA7XG5cdFx0fVxuXHRcdGh0bWwgKz0gYnV0dG9uUGFuZWw7XG5cdFx0aW5zdC5fa2V5RXZlbnQgPSBmYWxzZTtcblx0XHRyZXR1cm4gaHRtbDtcblx0fSxcblxuXHQvKiBHZW5lcmF0ZSB0aGUgbW9udGggYW5kIHllYXIgaGVhZGVyLiAqL1xuXHRfZ2VuZXJhdGVNb250aFllYXJIZWFkZXI6IGZ1bmN0aW9uKCBpbnN0LCBkcmF3TW9udGgsIGRyYXdZZWFyLCBtaW5EYXRlLCBtYXhEYXRlLFxuXHRcdFx0c2Vjb25kYXJ5LCBtb250aE5hbWVzLCBtb250aE5hbWVzU2hvcnQgKSB7XG5cblx0XHR2YXIgaW5NaW5ZZWFyLCBpbk1heFllYXIsIG1vbnRoLCB5ZWFycywgdGhpc1llYXIsIGRldGVybWluZVllYXIsIHllYXIsIGVuZFllYXIsXG5cdFx0XHRjaGFuZ2VNb250aCA9IHRoaXMuX2dldCggaW5zdCwgXCJjaGFuZ2VNb250aFwiICksXG5cdFx0XHRjaGFuZ2VZZWFyID0gdGhpcy5fZ2V0KCBpbnN0LCBcImNoYW5nZVllYXJcIiApLFxuXHRcdFx0c2hvd01vbnRoQWZ0ZXJZZWFyID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dNb250aEFmdGVyWWVhclwiICksXG5cdFx0XHRodG1sID0gXCI8ZGl2IGNsYXNzPSd1aS1kYXRlcGlja2VyLXRpdGxlJz5cIixcblx0XHRcdG1vbnRoSHRtbCA9IFwiXCI7XG5cblx0XHQvLyBNb250aCBzZWxlY3Rpb25cblx0XHRpZiAoIHNlY29uZGFyeSB8fCAhY2hhbmdlTW9udGggKSB7XG5cdFx0XHRtb250aEh0bWwgKz0gXCI8c3BhbiBjbGFzcz0ndWktZGF0ZXBpY2tlci1tb250aCc+XCIgKyBtb250aE5hbWVzWyBkcmF3TW9udGggXSArIFwiPC9zcGFuPlwiO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpbk1pblllYXIgPSAoIG1pbkRhdGUgJiYgbWluRGF0ZS5nZXRGdWxsWWVhcigpID09PSBkcmF3WWVhciApO1xuXHRcdFx0aW5NYXhZZWFyID0gKCBtYXhEYXRlICYmIG1heERhdGUuZ2V0RnVsbFllYXIoKSA9PT0gZHJhd1llYXIgKTtcblx0XHRcdG1vbnRoSHRtbCArPSBcIjxzZWxlY3QgY2xhc3M9J3VpLWRhdGVwaWNrZXItbW9udGgnIGRhdGEtaGFuZGxlcj0nc2VsZWN0TW9udGgnIGRhdGEtZXZlbnQ9J2NoYW5nZSc+XCI7XG5cdFx0XHRmb3IgKCBtb250aCA9IDA7IG1vbnRoIDwgMTI7IG1vbnRoKysgKSB7XG5cdFx0XHRcdGlmICggKCAhaW5NaW5ZZWFyIHx8IG1vbnRoID49IG1pbkRhdGUuZ2V0TW9udGgoKSApICYmICggIWluTWF4WWVhciB8fCBtb250aCA8PSBtYXhEYXRlLmdldE1vbnRoKCkgKSApIHtcblx0XHRcdFx0XHRtb250aEh0bWwgKz0gXCI8b3B0aW9uIHZhbHVlPSdcIiArIG1vbnRoICsgXCInXCIgK1xuXHRcdFx0XHRcdFx0KCBtb250aCA9PT0gZHJhd01vbnRoID8gXCIgc2VsZWN0ZWQ9J3NlbGVjdGVkJ1wiIDogXCJcIiApICtcblx0XHRcdFx0XHRcdFwiPlwiICsgbW9udGhOYW1lc1Nob3J0WyBtb250aCBdICsgXCI8L29wdGlvbj5cIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bW9udGhIdG1sICs9IFwiPC9zZWxlY3Q+XCI7XG5cdFx0fVxuXG5cdFx0aWYgKCAhc2hvd01vbnRoQWZ0ZXJZZWFyICkge1xuXHRcdFx0aHRtbCArPSBtb250aEh0bWwgKyAoIHNlY29uZGFyeSB8fCAhKCBjaGFuZ2VNb250aCAmJiBjaGFuZ2VZZWFyICkgPyBcIiYjeGEwO1wiIDogXCJcIiApO1xuXHRcdH1cblxuXHRcdC8vIFllYXIgc2VsZWN0aW9uXG5cdFx0aWYgKCAhaW5zdC55ZWFyc2h0bWwgKSB7XG5cdFx0XHRpbnN0LnllYXJzaHRtbCA9IFwiXCI7XG5cdFx0XHRpZiAoIHNlY29uZGFyeSB8fCAhY2hhbmdlWWVhciApIHtcblx0XHRcdFx0aHRtbCArPSBcIjxzcGFuIGNsYXNzPSd1aS1kYXRlcGlja2VyLXllYXInPlwiICsgZHJhd1llYXIgKyBcIjwvc3Bhbj5cIjtcblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gZGV0ZXJtaW5lIHJhbmdlIG9mIHllYXJzIHRvIGRpc3BsYXlcblx0XHRcdFx0eWVhcnMgPSB0aGlzLl9nZXQoIGluc3QsIFwieWVhclJhbmdlXCIgKS5zcGxpdCggXCI6XCIgKTtcblx0XHRcdFx0dGhpc1llYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XG5cdFx0XHRcdGRldGVybWluZVllYXIgPSBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHRcdFx0dmFyIHllYXIgPSAoIHZhbHVlLm1hdGNoKCAvY1srXFwtXS4qLyApID8gZHJhd1llYXIgKyBwYXJzZUludCggdmFsdWUuc3Vic3RyaW5nKCAxICksIDEwICkgOlxuXHRcdFx0XHRcdFx0KCB2YWx1ZS5tYXRjaCggL1srXFwtXS4qLyApID8gdGhpc1llYXIgKyBwYXJzZUludCggdmFsdWUsIDEwICkgOlxuXHRcdFx0XHRcdFx0cGFyc2VJbnQoIHZhbHVlLCAxMCApICkgKTtcblx0XHRcdFx0XHRyZXR1cm4gKCBpc05hTiggeWVhciApID8gdGhpc1llYXIgOiB5ZWFyICk7XG5cdFx0XHRcdH07XG5cdFx0XHRcdHllYXIgPSBkZXRlcm1pbmVZZWFyKCB5ZWFyc1sgMCBdICk7XG5cdFx0XHRcdGVuZFllYXIgPSBNYXRoLm1heCggeWVhciwgZGV0ZXJtaW5lWWVhciggeWVhcnNbIDEgXSB8fCBcIlwiICkgKTtcblx0XHRcdFx0eWVhciA9ICggbWluRGF0ZSA/IE1hdGgubWF4KCB5ZWFyLCBtaW5EYXRlLmdldEZ1bGxZZWFyKCkgKSA6IHllYXIgKTtcblx0XHRcdFx0ZW5kWWVhciA9ICggbWF4RGF0ZSA/IE1hdGgubWluKCBlbmRZZWFyLCBtYXhEYXRlLmdldEZ1bGxZZWFyKCkgKSA6IGVuZFllYXIgKTtcblx0XHRcdFx0aW5zdC55ZWFyc2h0bWwgKz0gXCI8c2VsZWN0IGNsYXNzPSd1aS1kYXRlcGlja2VyLXllYXInIGRhdGEtaGFuZGxlcj0nc2VsZWN0WWVhcicgZGF0YS1ldmVudD0nY2hhbmdlJz5cIjtcblx0XHRcdFx0Zm9yICggOyB5ZWFyIDw9IGVuZFllYXI7IHllYXIrKyApIHtcblx0XHRcdFx0XHRpbnN0LnllYXJzaHRtbCArPSBcIjxvcHRpb24gdmFsdWU9J1wiICsgeWVhciArIFwiJ1wiICtcblx0XHRcdFx0XHRcdCggeWVhciA9PT0gZHJhd1llYXIgPyBcIiBzZWxlY3RlZD0nc2VsZWN0ZWQnXCIgOiBcIlwiICkgK1xuXHRcdFx0XHRcdFx0XCI+XCIgKyB5ZWFyICsgXCI8L29wdGlvbj5cIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpbnN0LnllYXJzaHRtbCArPSBcIjwvc2VsZWN0PlwiO1xuXG5cdFx0XHRcdGh0bWwgKz0gaW5zdC55ZWFyc2h0bWw7XG5cdFx0XHRcdGluc3QueWVhcnNodG1sID0gbnVsbDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRodG1sICs9IHRoaXMuX2dldCggaW5zdCwgXCJ5ZWFyU3VmZml4XCIgKTtcblx0XHRpZiAoIHNob3dNb250aEFmdGVyWWVhciApIHtcblx0XHRcdGh0bWwgKz0gKCBzZWNvbmRhcnkgfHwgISggY2hhbmdlTW9udGggJiYgY2hhbmdlWWVhciApID8gXCImI3hhMDtcIiA6IFwiXCIgKSArIG1vbnRoSHRtbDtcblx0XHR9XG5cdFx0aHRtbCArPSBcIjwvZGl2PlwiOyAvLyBDbG9zZSBkYXRlcGlja2VyX2hlYWRlclxuXHRcdHJldHVybiBodG1sO1xuXHR9LFxuXG5cdC8qIEFkanVzdCBvbmUgb2YgdGhlIGRhdGUgc3ViLWZpZWxkcy4gKi9cblx0X2FkanVzdEluc3REYXRlOiBmdW5jdGlvbiggaW5zdCwgb2Zmc2V0LCBwZXJpb2QgKSB7XG5cdFx0dmFyIHllYXIgPSBpbnN0LnNlbGVjdGVkWWVhciArICggcGVyaW9kID09PSBcIllcIiA/IG9mZnNldCA6IDAgKSxcblx0XHRcdG1vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoICsgKCBwZXJpb2QgPT09IFwiTVwiID8gb2Zmc2V0IDogMCApLFxuXHRcdFx0ZGF5ID0gTWF0aC5taW4oIGluc3Quc2VsZWN0ZWREYXksIHRoaXMuX2dldERheXNJbk1vbnRoKCB5ZWFyLCBtb250aCApICkgKyAoIHBlcmlvZCA9PT0gXCJEXCIgPyBvZmZzZXQgOiAwICksXG5cdFx0XHRkYXRlID0gdGhpcy5fcmVzdHJpY3RNaW5NYXgoIGluc3QsIHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggeWVhciwgbW9udGgsIGRheSApICkgKTtcblxuXHRcdGluc3Quc2VsZWN0ZWREYXkgPSBkYXRlLmdldERhdGUoKTtcblx0XHRpbnN0LmRyYXdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCA9IGRhdGUuZ2V0TW9udGgoKTtcblx0XHRpbnN0LmRyYXdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0aWYgKCBwZXJpb2QgPT09IFwiTVwiIHx8IHBlcmlvZCA9PT0gXCJZXCIgKSB7XG5cdFx0XHR0aGlzLl9ub3RpZnlDaGFuZ2UoIGluc3QgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogRW5zdXJlIGEgZGF0ZSBpcyB3aXRoaW4gYW55IG1pbi9tYXggYm91bmRzLiAqL1xuXHRfcmVzdHJpY3RNaW5NYXg6IGZ1bmN0aW9uKCBpbnN0LCBkYXRlICkge1xuXHRcdHZhciBtaW5EYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtaW5cIiApLFxuXHRcdFx0bWF4RGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWF4XCIgKSxcblx0XHRcdG5ld0RhdGUgPSAoIG1pbkRhdGUgJiYgZGF0ZSA8IG1pbkRhdGUgPyBtaW5EYXRlIDogZGF0ZSApO1xuXHRcdHJldHVybiAoIG1heERhdGUgJiYgbmV3RGF0ZSA+IG1heERhdGUgPyBtYXhEYXRlIDogbmV3RGF0ZSApO1xuXHR9LFxuXG5cdC8qIE5vdGlmeSBjaGFuZ2Ugb2YgbW9udGgveWVhci4gKi9cblx0X25vdGlmeUNoYW5nZTogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIG9uQ2hhbmdlID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm9uQ2hhbmdlTW9udGhZZWFyXCIgKTtcblx0XHRpZiAoIG9uQ2hhbmdlICkge1xuXHRcdFx0b25DaGFuZ2UuYXBwbHkoICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXRbIDAgXSA6IG51bGwgKSxcblx0XHRcdFx0WyBpbnN0LnNlbGVjdGVkWWVhciwgaW5zdC5zZWxlY3RlZE1vbnRoICsgMSwgaW5zdCBdICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIERldGVybWluZSB0aGUgbnVtYmVyIG9mIG1vbnRocyB0byBzaG93LiAqL1xuXHRfZ2V0TnVtYmVyT2ZNb250aHM6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBudW1Nb250aHMgPSB0aGlzLl9nZXQoIGluc3QsIFwibnVtYmVyT2ZNb250aHNcIiApO1xuXHRcdHJldHVybiAoIG51bU1vbnRocyA9PSBudWxsID8gWyAxLCAxIF0gOiAoIHR5cGVvZiBudW1Nb250aHMgPT09IFwibnVtYmVyXCIgPyBbIDEsIG51bU1vbnRocyBdIDogbnVtTW9udGhzICkgKTtcblx0fSxcblxuXHQvKiBEZXRlcm1pbmUgdGhlIGN1cnJlbnQgbWF4aW11bSBkYXRlIC0gZW5zdXJlIG5vIHRpbWUgY29tcG9uZW50cyBhcmUgc2V0LiAqL1xuXHRfZ2V0TWluTWF4RGF0ZTogZnVuY3Rpb24oIGluc3QsIG1pbk1heCApIHtcblx0XHRyZXR1cm4gdGhpcy5fZGV0ZXJtaW5lRGF0ZSggaW5zdCwgdGhpcy5fZ2V0KCBpbnN0LCBtaW5NYXggKyBcIkRhdGVcIiApLCBudWxsICk7XG5cdH0sXG5cblx0LyogRmluZCB0aGUgbnVtYmVyIG9mIGRheXMgaW4gYSBnaXZlbiBtb250aC4gKi9cblx0X2dldERheXNJbk1vbnRoOiBmdW5jdGlvbiggeWVhciwgbW9udGggKSB7XG5cdFx0cmV0dXJuIDMyIC0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCB5ZWFyLCBtb250aCwgMzIgKSApLmdldERhdGUoKTtcblx0fSxcblxuXHQvKiBGaW5kIHRoZSBkYXkgb2YgdGhlIHdlZWsgb2YgdGhlIGZpcnN0IG9mIGEgbW9udGguICovXG5cdF9nZXRGaXJzdERheU9mTW9udGg6IGZ1bmN0aW9uKCB5ZWFyLCBtb250aCApIHtcblx0XHRyZXR1cm4gbmV3IERhdGUoIHllYXIsIG1vbnRoLCAxICkuZ2V0RGF5KCk7XG5cdH0sXG5cblx0LyogRGV0ZXJtaW5lcyBpZiB3ZSBzaG91bGQgYWxsb3cgYSBcIm5leHQvcHJldlwiIG1vbnRoIGRpc3BsYXkgY2hhbmdlLiAqL1xuXHRfY2FuQWRqdXN0TW9udGg6IGZ1bmN0aW9uKCBpbnN0LCBvZmZzZXQsIGN1clllYXIsIGN1ck1vbnRoICkge1xuXHRcdHZhciBudW1Nb250aHMgPSB0aGlzLl9nZXROdW1iZXJPZk1vbnRocyggaW5zdCApLFxuXHRcdFx0ZGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggY3VyWWVhcixcblx0XHRcdGN1ck1vbnRoICsgKCBvZmZzZXQgPCAwID8gb2Zmc2V0IDogbnVtTW9udGhzWyAwIF0gKiBudW1Nb250aHNbIDEgXSApLCAxICkgKTtcblxuXHRcdGlmICggb2Zmc2V0IDwgMCApIHtcblx0XHRcdGRhdGUuc2V0RGF0ZSggdGhpcy5fZ2V0RGF5c0luTW9udGgoIGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpICkgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuX2lzSW5SYW5nZSggaW5zdCwgZGF0ZSApO1xuXHR9LFxuXG5cdC8qIElzIHRoZSBnaXZlbiBkYXRlIGluIHRoZSBhY2NlcHRlZCByYW5nZT8gKi9cblx0X2lzSW5SYW5nZTogZnVuY3Rpb24oIGluc3QsIGRhdGUgKSB7XG5cdFx0dmFyIHllYXJTcGxpdCwgY3VycmVudFllYXIsXG5cdFx0XHRtaW5EYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtaW5cIiApLFxuXHRcdFx0bWF4RGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWF4XCIgKSxcblx0XHRcdG1pblllYXIgPSBudWxsLFxuXHRcdFx0bWF4WWVhciA9IG51bGwsXG5cdFx0XHR5ZWFycyA9IHRoaXMuX2dldCggaW5zdCwgXCJ5ZWFyUmFuZ2VcIiApO1xuXHRcdFx0aWYgKCB5ZWFycyApIHtcblx0XHRcdFx0eWVhclNwbGl0ID0geWVhcnMuc3BsaXQoIFwiOlwiICk7XG5cdFx0XHRcdGN1cnJlbnRZZWFyID0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpO1xuXHRcdFx0XHRtaW5ZZWFyID0gcGFyc2VJbnQoIHllYXJTcGxpdFsgMCBdLCAxMCApO1xuXHRcdFx0XHRtYXhZZWFyID0gcGFyc2VJbnQoIHllYXJTcGxpdFsgMSBdLCAxMCApO1xuXHRcdFx0XHRpZiAoIHllYXJTcGxpdFsgMCBdLm1hdGNoKCAvWytcXC1dLiovICkgKSB7XG5cdFx0XHRcdFx0bWluWWVhciArPSBjdXJyZW50WWVhcjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHllYXJTcGxpdFsgMSBdLm1hdGNoKCAvWytcXC1dLiovICkgKSB7XG5cdFx0XHRcdFx0bWF4WWVhciArPSBjdXJyZW50WWVhcjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0cmV0dXJuICggKCAhbWluRGF0ZSB8fCBkYXRlLmdldFRpbWUoKSA+PSBtaW5EYXRlLmdldFRpbWUoKSApICYmXG5cdFx0XHQoICFtYXhEYXRlIHx8IGRhdGUuZ2V0VGltZSgpIDw9IG1heERhdGUuZ2V0VGltZSgpICkgJiZcblx0XHRcdCggIW1pblllYXIgfHwgZGF0ZS5nZXRGdWxsWWVhcigpID49IG1pblllYXIgKSAmJlxuXHRcdFx0KCAhbWF4WWVhciB8fCBkYXRlLmdldEZ1bGxZZWFyKCkgPD0gbWF4WWVhciApICk7XG5cdH0sXG5cblx0LyogUHJvdmlkZSB0aGUgY29uZmlndXJhdGlvbiBzZXR0aW5ncyBmb3IgZm9ybWF0dGluZy9wYXJzaW5nLiAqL1xuXHRfZ2V0Rm9ybWF0Q29uZmlnOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgc2hvcnRZZWFyQ3V0b2ZmID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3J0WWVhckN1dG9mZlwiICk7XG5cdFx0c2hvcnRZZWFyQ3V0b2ZmID0gKCB0eXBlb2Ygc2hvcnRZZWFyQ3V0b2ZmICE9PSBcInN0cmluZ1wiID8gc2hvcnRZZWFyQ3V0b2ZmIDpcblx0XHRcdG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSAlIDEwMCArIHBhcnNlSW50KCBzaG9ydFllYXJDdXRvZmYsIDEwICkgKTtcblx0XHRyZXR1cm4geyBzaG9ydFllYXJDdXRvZmY6IHNob3J0WWVhckN1dG9mZixcblx0XHRcdGRheU5hbWVzU2hvcnQ6IHRoaXMuX2dldCggaW5zdCwgXCJkYXlOYW1lc1Nob3J0XCIgKSwgZGF5TmFtZXM6IHRoaXMuX2dldCggaW5zdCwgXCJkYXlOYW1lc1wiICksXG5cdFx0XHRtb250aE5hbWVzU2hvcnQ6IHRoaXMuX2dldCggaW5zdCwgXCJtb250aE5hbWVzU2hvcnRcIiApLCBtb250aE5hbWVzOiB0aGlzLl9nZXQoIGluc3QsIFwibW9udGhOYW1lc1wiICkgfTtcblx0fSxcblxuXHQvKiBGb3JtYXQgdGhlIGdpdmVuIGRhdGUgZm9yIGRpc3BsYXkuICovXG5cdF9mb3JtYXREYXRlOiBmdW5jdGlvbiggaW5zdCwgZGF5LCBtb250aCwgeWVhciApIHtcblx0XHRpZiAoICFkYXkgKSB7XG5cdFx0XHRpbnN0LmN1cnJlbnREYXkgPSBpbnN0LnNlbGVjdGVkRGF5O1xuXHRcdFx0aW5zdC5jdXJyZW50TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGg7XG5cdFx0XHRpbnN0LmN1cnJlbnRZZWFyID0gaW5zdC5zZWxlY3RlZFllYXI7XG5cdFx0fVxuXHRcdHZhciBkYXRlID0gKCBkYXkgPyAoIHR5cGVvZiBkYXkgPT09IFwib2JqZWN0XCIgPyBkYXkgOlxuXHRcdFx0dGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCB5ZWFyLCBtb250aCwgZGF5ICkgKSApIDpcblx0XHRcdHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggaW5zdC5jdXJyZW50WWVhciwgaW5zdC5jdXJyZW50TW9udGgsIGluc3QuY3VycmVudERheSApICkgKTtcblx0XHRyZXR1cm4gdGhpcy5mb3JtYXREYXRlKCB0aGlzLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICksIGRhdGUsIHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICk7XG5cdH1cbn0gKTtcblxuLypcbiAqIEJpbmQgaG92ZXIgZXZlbnRzIGZvciBkYXRlcGlja2VyIGVsZW1lbnRzLlxuICogRG9uZSB2aWEgZGVsZWdhdGUgc28gdGhlIGJpbmRpbmcgb25seSBvY2N1cnMgb25jZSBpbiB0aGUgbGlmZXRpbWUgb2YgdGhlIHBhcmVudCBkaXYuXG4gKiBHbG9iYWwgZGF0ZXBpY2tlcl9pbnN0QWN0aXZlLCBzZXQgYnkgX3VwZGF0ZURhdGVwaWNrZXIgYWxsb3dzIHRoZSBoYW5kbGVycyB0byBmaW5kIHRoZWlyIHdheSBiYWNrIHRvIHRoZSBhY3RpdmUgcGlja2VyLlxuICovXG5mdW5jdGlvbiBkYXRlcGlja2VyX2JpbmRIb3ZlciggZHBEaXYgKSB7XG5cdHZhciBzZWxlY3RvciA9IFwiYnV0dG9uLCAudWktZGF0ZXBpY2tlci1wcmV2LCAudWktZGF0ZXBpY2tlci1uZXh0LCAudWktZGF0ZXBpY2tlci1jYWxlbmRhciB0ZCBhXCI7XG5cdHJldHVybiBkcERpdi5vbiggXCJtb3VzZW91dFwiLCBzZWxlY3RvciwgZnVuY3Rpb24oKSB7XG5cdFx0XHQkKCB0aGlzICkucmVtb3ZlQ2xhc3MoIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdFx0aWYgKCB0aGlzLmNsYXNzTmFtZS5pbmRleE9mKCBcInVpLWRhdGVwaWNrZXItcHJldlwiICkgIT09IC0xICkge1xuXHRcdFx0XHQkKCB0aGlzICkucmVtb3ZlQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1wcmV2LWhvdmVyXCIgKTtcblx0XHRcdH1cblx0XHRcdGlmICggdGhpcy5jbGFzc05hbWUuaW5kZXhPZiggXCJ1aS1kYXRlcGlja2VyLW5leHRcIiApICE9PSAtMSApIHtcblx0XHRcdFx0JCggdGhpcyApLnJlbW92ZUNsYXNzKCBcInVpLWRhdGVwaWNrZXItbmV4dC1ob3ZlclwiICk7XG5cdFx0XHR9XG5cdFx0fSApXG5cdFx0Lm9uKCBcIm1vdXNlb3ZlclwiLCBzZWxlY3RvciwgZGF0ZXBpY2tlcl9oYW5kbGVNb3VzZW92ZXIgKTtcbn1cblxuZnVuY3Rpb24gZGF0ZXBpY2tlcl9oYW5kbGVNb3VzZW92ZXIoKSB7XG5cdGlmICggISQuZGF0ZXBpY2tlci5faXNEaXNhYmxlZERhdGVwaWNrZXIoIGRhdGVwaWNrZXJfaW5zdEFjdGl2ZS5pbmxpbmUgPyBkYXRlcGlja2VyX2luc3RBY3RpdmUuZHBEaXYucGFyZW50KClbIDAgXSA6IGRhdGVwaWNrZXJfaW5zdEFjdGl2ZS5pbnB1dFsgMCBdICkgKSB7XG5cdFx0JCggdGhpcyApLnBhcmVudHMoIFwiLnVpLWRhdGVwaWNrZXItY2FsZW5kYXJcIiApLmZpbmQoIFwiYVwiICkucmVtb3ZlQ2xhc3MoIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdCQoIHRoaXMgKS5hZGRDbGFzcyggXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0aWYgKCB0aGlzLmNsYXNzTmFtZS5pbmRleE9mKCBcInVpLWRhdGVwaWNrZXItcHJldlwiICkgIT09IC0xICkge1xuXHRcdFx0JCggdGhpcyApLmFkZENsYXNzKCBcInVpLWRhdGVwaWNrZXItcHJldi1ob3ZlclwiICk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5jbGFzc05hbWUuaW5kZXhPZiggXCJ1aS1kYXRlcGlja2VyLW5leHRcIiApICE9PSAtMSApIHtcblx0XHRcdCQoIHRoaXMgKS5hZGRDbGFzcyggXCJ1aS1kYXRlcGlja2VyLW5leHQtaG92ZXJcIiApO1xuXHRcdH1cblx0fVxufVxuXG4vKiBqUXVlcnkgZXh0ZW5kIG5vdyBpZ25vcmVzIG51bGxzISAqL1xuZnVuY3Rpb24gZGF0ZXBpY2tlcl9leHRlbmRSZW1vdmUoIHRhcmdldCwgcHJvcHMgKSB7XG5cdCQuZXh0ZW5kKCB0YXJnZXQsIHByb3BzICk7XG5cdGZvciAoIHZhciBuYW1lIGluIHByb3BzICkge1xuXHRcdGlmICggcHJvcHNbIG5hbWUgXSA9PSBudWxsICkge1xuXHRcdFx0dGFyZ2V0WyBuYW1lIF0gPSBwcm9wc1sgbmFtZSBdO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gdGFyZ2V0O1xufVxuXG4vKiBJbnZva2UgdGhlIGRhdGVwaWNrZXIgZnVuY3Rpb25hbGl0eS5cbiAgIEBwYXJhbSAgb3B0aW9ucyAgc3RyaW5nIC0gYSBjb21tYW5kLCBvcHRpb25hbGx5IGZvbGxvd2VkIGJ5IGFkZGl0aW9uYWwgcGFyYW1ldGVycyBvclxuXHRcdFx0XHRcdE9iamVjdCAtIHNldHRpbmdzIGZvciBhdHRhY2hpbmcgbmV3IGRhdGVwaWNrZXIgZnVuY3Rpb25hbGl0eVxuICAgQHJldHVybiAgalF1ZXJ5IG9iamVjdCAqL1xuJC5mbi5kYXRlcGlja2VyID0gZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cblx0LyogVmVyaWZ5IGFuIGVtcHR5IGNvbGxlY3Rpb24gd2Fzbid0IHBhc3NlZCAtIEZpeGVzICM2OTc2ICovXG5cdGlmICggIXRoaXMubGVuZ3RoICkge1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyogSW5pdGlhbGlzZSB0aGUgZGF0ZSBwaWNrZXIuICovXG5cdGlmICggISQuZGF0ZXBpY2tlci5pbml0aWFsaXplZCApIHtcblx0XHQkKCBkb2N1bWVudCApLm9uKCBcIm1vdXNlZG93blwiLCAkLmRhdGVwaWNrZXIuX2NoZWNrRXh0ZXJuYWxDbGljayApO1xuXHRcdCQuZGF0ZXBpY2tlci5pbml0aWFsaXplZCA9IHRydWU7XG5cdH1cblxuXHQvKiBBcHBlbmQgZGF0ZXBpY2tlciBtYWluIGNvbnRhaW5lciB0byBib2R5IGlmIG5vdCBleGlzdC4gKi9cblx0aWYgKCAkKCBcIiNcIiArICQuZGF0ZXBpY2tlci5fbWFpbkRpdklkICkubGVuZ3RoID09PSAwICkge1xuXHRcdCQoIFwiYm9keVwiICkuYXBwZW5kKCAkLmRhdGVwaWNrZXIuZHBEaXYgKTtcblx0fVxuXG5cdHZhciBvdGhlckFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggYXJndW1lbnRzLCAxICk7XG5cdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgJiYgKCBvcHRpb25zID09PSBcImlzRGlzYWJsZWRcIiB8fCBvcHRpb25zID09PSBcImdldERhdGVcIiB8fCBvcHRpb25zID09PSBcIndpZGdldFwiICkgKSB7XG5cdFx0cmV0dXJuICQuZGF0ZXBpY2tlclsgXCJfXCIgKyBvcHRpb25zICsgXCJEYXRlcGlja2VyXCIgXS5cblx0XHRcdGFwcGx5KCAkLmRhdGVwaWNrZXIsIFsgdGhpc1sgMCBdIF0uY29uY2F0KCBvdGhlckFyZ3MgKSApO1xuXHR9XG5cdGlmICggb3B0aW9ucyA9PT0gXCJvcHRpb25cIiAmJiBhcmd1bWVudHMubGVuZ3RoID09PSAyICYmIHR5cGVvZiBhcmd1bWVudHNbIDEgXSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRyZXR1cm4gJC5kYXRlcGlja2VyWyBcIl9cIiArIG9wdGlvbnMgKyBcIkRhdGVwaWNrZXJcIiBdLlxuXHRcdFx0YXBwbHkoICQuZGF0ZXBpY2tlciwgWyB0aGlzWyAwIF0gXS5jb25jYXQoIG90aGVyQXJncyApICk7XG5cdH1cblx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0dHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgP1xuXHRcdFx0JC5kYXRlcGlja2VyWyBcIl9cIiArIG9wdGlvbnMgKyBcIkRhdGVwaWNrZXJcIiBdLlxuXHRcdFx0XHRhcHBseSggJC5kYXRlcGlja2VyLCBbIHRoaXMgXS5jb25jYXQoIG90aGVyQXJncyApICkgOlxuXHRcdFx0JC5kYXRlcGlja2VyLl9hdHRhY2hEYXRlcGlja2VyKCB0aGlzLCBvcHRpb25zICk7XG5cdH0gKTtcbn07XG5cbiQuZGF0ZXBpY2tlciA9IG5ldyBEYXRlcGlja2VyKCk7IC8vIHNpbmdsZXRvbiBpbnN0YW5jZVxuJC5kYXRlcGlja2VyLmluaXRpYWxpemVkID0gZmFsc2U7XG4kLmRhdGVwaWNrZXIudXVpZCA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuJC5kYXRlcGlja2VyLnZlcnNpb24gPSBcIjEuMTIuMVwiO1xuXG52YXIgd2lkZ2V0c0RhdGVwaWNrZXIgPSAkLmRhdGVwaWNrZXI7XG5cblxuXG5cbi8vIFRoaXMgZmlsZSBpcyBkZXByZWNhdGVkXG52YXIgaWUgPSAkLnVpLmllID0gISEvbXNpZSBbXFx3Ll0rLy5leGVjKCBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCkgKTtcblxuLyohXG4gKiBqUXVlcnkgVUkgTW91c2UgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IE1vdXNlXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogQWJzdHJhY3RzIG1vdXNlLWJhc2VkIGludGVyYWN0aW9ucyB0byBhc3Npc3QgaW4gY3JlYXRpbmcgY2VydGFpbiB3aWRnZXRzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL21vdXNlL1xuXG5cblxudmFyIG1vdXNlSGFuZGxlZCA9IGZhbHNlO1xuJCggZG9jdW1lbnQgKS5vbiggXCJtb3VzZXVwXCIsIGZ1bmN0aW9uKCkge1xuXHRtb3VzZUhhbmRsZWQgPSBmYWxzZTtcbn0gKTtcblxudmFyIHdpZGdldHNNb3VzZSA9ICQud2lkZ2V0KCBcInVpLm1vdXNlXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGNhbmNlbDogXCJpbnB1dCwgdGV4dGFyZWEsIGJ1dHRvbiwgc2VsZWN0LCBvcHRpb25cIixcblx0XHRkaXN0YW5jZTogMSxcblx0XHRkZWxheTogMFxuXHR9LFxuXHRfbW91c2VJbml0OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5vbiggXCJtb3VzZWRvd24uXCIgKyB0aGlzLndpZGdldE5hbWUsIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0cmV0dXJuIHRoYXQuX21vdXNlRG93biggZXZlbnQgKTtcblx0XHRcdH0gKVxuXHRcdFx0Lm9uKCBcImNsaWNrLlwiICsgdGhpcy53aWRnZXROYW1lLCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdHJ1ZSA9PT0gJC5kYXRhKCBldmVudC50YXJnZXQsIHRoYXQud2lkZ2V0TmFtZSArIFwiLnByZXZlbnRDbGlja0V2ZW50XCIgKSApIHtcblx0XHRcdFx0XHQkLnJlbW92ZURhdGEoIGV2ZW50LnRhcmdldCwgdGhhdC53aWRnZXROYW1lICsgXCIucHJldmVudENsaWNrRXZlbnRcIiApO1xuXHRcdFx0XHRcdGV2ZW50LnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXG5cdFx0dGhpcy5zdGFydGVkID0gZmFsc2U7XG5cdH0sXG5cblx0Ly8gVE9ETzogbWFrZSBzdXJlIGRlc3Ryb3lpbmcgb25lIGluc3RhbmNlIG9mIG1vdXNlIGRvZXNuJ3QgbWVzcyB3aXRoXG5cdC8vIG90aGVyIGluc3RhbmNlcyBvZiBtb3VzZVxuXHRfbW91c2VEZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnQub2ZmKCBcIi5cIiArIHRoaXMud2lkZ2V0TmFtZSApO1xuXHRcdGlmICggdGhpcy5fbW91c2VNb3ZlRGVsZWdhdGUgKSB7XG5cdFx0XHR0aGlzLmRvY3VtZW50XG5cdFx0XHRcdC5vZmYoIFwibW91c2Vtb3ZlLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZU1vdmVEZWxlZ2F0ZSApXG5cdFx0XHRcdC5vZmYoIFwibW91c2V1cC5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VVcERlbGVnYXRlICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9tb3VzZURvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdC8vIGRvbid0IGxldCBtb3JlIHRoYW4gb25lIHdpZGdldCBoYW5kbGUgbW91c2VTdGFydFxuXHRcdGlmICggbW91c2VIYW5kbGVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX21vdXNlTW92ZWQgPSBmYWxzZTtcblxuXHRcdC8vIFdlIG1heSBoYXZlIG1pc3NlZCBtb3VzZXVwIChvdXQgb2Ygd2luZG93KVxuXHRcdCggdGhpcy5fbW91c2VTdGFydGVkICYmIHRoaXMuX21vdXNlVXAoIGV2ZW50ICkgKTtcblxuXHRcdHRoaXMuX21vdXNlRG93bkV2ZW50ID0gZXZlbnQ7XG5cblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRidG5Jc0xlZnQgPSAoIGV2ZW50LndoaWNoID09PSAxICksXG5cblx0XHRcdC8vIGV2ZW50LnRhcmdldC5ub2RlTmFtZSB3b3JrcyBhcm91bmQgYSBidWcgaW4gSUUgOCB3aXRoXG5cdFx0XHQvLyBkaXNhYmxlZCBpbnB1dHMgKCM3NjIwKVxuXHRcdFx0ZWxJc0NhbmNlbCA9ICggdHlwZW9mIHRoaXMub3B0aW9ucy5jYW5jZWwgPT09IFwic3RyaW5nXCIgJiYgZXZlbnQudGFyZ2V0Lm5vZGVOYW1lID9cblx0XHRcdFx0JCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggdGhpcy5vcHRpb25zLmNhbmNlbCApLmxlbmd0aCA6IGZhbHNlICk7XG5cdFx0aWYgKCAhYnRuSXNMZWZ0IHx8IGVsSXNDYW5jZWwgfHwgIXRoaXMuX21vdXNlQ2FwdHVyZSggZXZlbnQgKSApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdHRoaXMubW91c2VEZWxheU1ldCA9ICF0aGlzLm9wdGlvbnMuZGVsYXk7XG5cdFx0aWYgKCAhdGhpcy5tb3VzZURlbGF5TWV0ICkge1xuXHRcdFx0dGhpcy5fbW91c2VEZWxheVRpbWVyID0gc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoYXQubW91c2VEZWxheU1ldCA9IHRydWU7XG5cdFx0XHR9LCB0aGlzLm9wdGlvbnMuZGVsYXkgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX21vdXNlRGlzdGFuY2VNZXQoIGV2ZW50ICkgJiYgdGhpcy5fbW91c2VEZWxheU1ldCggZXZlbnQgKSApIHtcblx0XHRcdHRoaXMuX21vdXNlU3RhcnRlZCA9ICggdGhpcy5fbW91c2VTdGFydCggZXZlbnQgKSAhPT0gZmFsc2UgKTtcblx0XHRcdGlmICggIXRoaXMuX21vdXNlU3RhcnRlZCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQ2xpY2sgZXZlbnQgbWF5IG5ldmVyIGhhdmUgZmlyZWQgKEdlY2tvICYgT3BlcmEpXG5cdFx0aWYgKCB0cnVlID09PSAkLmRhdGEoIGV2ZW50LnRhcmdldCwgdGhpcy53aWRnZXROYW1lICsgXCIucHJldmVudENsaWNrRXZlbnRcIiApICkge1xuXHRcdFx0JC5yZW1vdmVEYXRhKCBldmVudC50YXJnZXQsIHRoaXMud2lkZ2V0TmFtZSArIFwiLnByZXZlbnRDbGlja0V2ZW50XCIgKTtcblx0XHR9XG5cblx0XHQvLyBUaGVzZSBkZWxlZ2F0ZXMgYXJlIHJlcXVpcmVkIHRvIGtlZXAgY29udGV4dFxuXHRcdHRoaXMuX21vdXNlTW92ZURlbGVnYXRlID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0cmV0dXJuIHRoYXQuX21vdXNlTW92ZSggZXZlbnQgKTtcblx0XHR9O1xuXHRcdHRoaXMuX21vdXNlVXBEZWxlZ2F0ZSA9IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHJldHVybiB0aGF0Ll9tb3VzZVVwKCBldmVudCApO1xuXHRcdH07XG5cblx0XHR0aGlzLmRvY3VtZW50XG5cdFx0XHQub24oIFwibW91c2Vtb3ZlLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZU1vdmVEZWxlZ2F0ZSApXG5cdFx0XHQub24oIFwibW91c2V1cC5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VVcERlbGVnYXRlICk7XG5cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0bW91c2VIYW5kbGVkID0gdHJ1ZTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfbW91c2VNb3ZlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvLyBPbmx5IGNoZWNrIGZvciBtb3VzZXVwcyBvdXRzaWRlIHRoZSBkb2N1bWVudCBpZiB5b3UndmUgbW92ZWQgaW5zaWRlIHRoZSBkb2N1bWVudFxuXHRcdC8vIGF0IGxlYXN0IG9uY2UuIFRoaXMgcHJldmVudHMgdGhlIGZpcmluZyBvZiBtb3VzZXVwIGluIHRoZSBjYXNlIG9mIElFPDksIHdoaWNoIHdpbGxcblx0XHQvLyBmaXJlIGEgbW91c2Vtb3ZlIGV2ZW50IGlmIGNvbnRlbnQgaXMgcGxhY2VkIHVuZGVyIHRoZSBjdXJzb3IuIFNlZSAjNzc3OFxuXHRcdC8vIFN1cHBvcnQ6IElFIDw5XG5cdFx0aWYgKCB0aGlzLl9tb3VzZU1vdmVkICkge1xuXG5cdFx0XHQvLyBJRSBtb3VzZXVwIGNoZWNrIC0gbW91c2V1cCBoYXBwZW5lZCB3aGVuIG1vdXNlIHdhcyBvdXQgb2Ygd2luZG93XG5cdFx0XHRpZiAoICQudWkuaWUgJiYgKCAhZG9jdW1lbnQuZG9jdW1lbnRNb2RlIHx8IGRvY3VtZW50LmRvY3VtZW50TW9kZSA8IDkgKSAmJlxuXHRcdFx0XHRcdCFldmVudC5idXR0b24gKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLl9tb3VzZVVwKCBldmVudCApO1xuXG5cdFx0XHQvLyBJZnJhbWUgbW91c2V1cCBjaGVjayAtIG1vdXNldXAgb2NjdXJyZWQgaW4gYW5vdGhlciBkb2N1bWVudFxuXHRcdFx0fSBlbHNlIGlmICggIWV2ZW50LndoaWNoICkge1xuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA8PTggLSA5XG5cdFx0XHRcdC8vIFNhZmFyaSBzZXRzIHdoaWNoIHRvIDAgaWYgeW91IHByZXNzIGFueSBvZiB0aGUgZm9sbG93aW5nIGtleXNcblx0XHRcdFx0Ly8gZHVyaW5nIGEgZHJhZyAoIzE0NDYxKVxuXHRcdFx0XHRpZiAoIGV2ZW50Lm9yaWdpbmFsRXZlbnQuYWx0S2V5IHx8IGV2ZW50Lm9yaWdpbmFsRXZlbnQuY3RybEtleSB8fFxuXHRcdFx0XHRcdFx0ZXZlbnQub3JpZ2luYWxFdmVudC5tZXRhS2V5IHx8IGV2ZW50Lm9yaWdpbmFsRXZlbnQuc2hpZnRLZXkgKSB7XG5cdFx0XHRcdFx0dGhpcy5pZ25vcmVNaXNzaW5nV2hpY2ggPSB0cnVlO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAhdGhpcy5pZ25vcmVNaXNzaW5nV2hpY2ggKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuX21vdXNlVXAoIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGV2ZW50LndoaWNoIHx8IGV2ZW50LmJ1dHRvbiApIHtcblx0XHRcdHRoaXMuX21vdXNlTW92ZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbW91c2VTdGFydGVkICkge1xuXHRcdFx0dGhpcy5fbW91c2VEcmFnKCBldmVudCApO1xuXHRcdFx0cmV0dXJuIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9tb3VzZURpc3RhbmNlTWV0KCBldmVudCApICYmIHRoaXMuX21vdXNlRGVsYXlNZXQoIGV2ZW50ICkgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZVN0YXJ0ZWQgPVxuXHRcdFx0XHQoIHRoaXMuX21vdXNlU3RhcnQoIHRoaXMuX21vdXNlRG93bkV2ZW50LCBldmVudCApICE9PSBmYWxzZSApO1xuXHRcdFx0KCB0aGlzLl9tb3VzZVN0YXJ0ZWQgPyB0aGlzLl9tb3VzZURyYWcoIGV2ZW50ICkgOiB0aGlzLl9tb3VzZVVwKCBldmVudCApICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuICF0aGlzLl9tb3VzZVN0YXJ0ZWQ7XG5cdH0sXG5cblx0X21vdXNlVXA6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLmRvY3VtZW50XG5cdFx0XHQub2ZmKCBcIm1vdXNlbW92ZS5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VNb3ZlRGVsZWdhdGUgKVxuXHRcdFx0Lm9mZiggXCJtb3VzZXVwLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZVVwRGVsZWdhdGUgKTtcblxuXHRcdGlmICggdGhpcy5fbW91c2VTdGFydGVkICkge1xuXHRcdFx0dGhpcy5fbW91c2VTdGFydGVkID0gZmFsc2U7XG5cblx0XHRcdGlmICggZXZlbnQudGFyZ2V0ID09PSB0aGlzLl9tb3VzZURvd25FdmVudC50YXJnZXQgKSB7XG5cdFx0XHRcdCQuZGF0YSggZXZlbnQudGFyZ2V0LCB0aGlzLndpZGdldE5hbWUgKyBcIi5wcmV2ZW50Q2xpY2tFdmVudFwiLCB0cnVlICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX21vdXNlU3RvcCggZXZlbnQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX21vdXNlRGVsYXlUaW1lciApIHtcblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5fbW91c2VEZWxheVRpbWVyICk7XG5cdFx0XHRkZWxldGUgdGhpcy5fbW91c2VEZWxheVRpbWVyO1xuXHRcdH1cblxuXHRcdHRoaXMuaWdub3JlTWlzc2luZ1doaWNoID0gZmFsc2U7XG5cdFx0bW91c2VIYW5kbGVkID0gZmFsc2U7XG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0fSxcblxuXHRfbW91c2VEaXN0YW5jZU1ldDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHJldHVybiAoIE1hdGgubWF4KFxuXHRcdFx0XHRNYXRoLmFicyggdGhpcy5fbW91c2VEb3duRXZlbnQucGFnZVggLSBldmVudC5wYWdlWCApLFxuXHRcdFx0XHRNYXRoLmFicyggdGhpcy5fbW91c2VEb3duRXZlbnQucGFnZVkgLSBldmVudC5wYWdlWSApXG5cdFx0XHQpID49IHRoaXMub3B0aW9ucy5kaXN0YW5jZVxuXHRcdCk7XG5cdH0sXG5cblx0X21vdXNlRGVsYXlNZXQ6IGZ1bmN0aW9uKCAvKiBldmVudCAqLyApIHtcblx0XHRyZXR1cm4gdGhpcy5tb3VzZURlbGF5TWV0O1xuXHR9LFxuXG5cdC8vIFRoZXNlIGFyZSBwbGFjZWhvbGRlciBtZXRob2RzLCB0byBiZSBvdmVycmlkZW4gYnkgZXh0ZW5kaW5nIHBsdWdpblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oIC8qIGV2ZW50ICovICkge30sXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCAvKiBldmVudCAqLyApIHt9LFxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggLyogZXZlbnQgKi8gKSB7fSxcblx0X21vdXNlQ2FwdHVyZTogZnVuY3Rpb24oIC8qIGV2ZW50ICovICkgeyByZXR1cm4gdHJ1ZTsgfVxufSApO1xuXG5cblxuXG4vLyAkLnVpLnBsdWdpbiBpcyBkZXByZWNhdGVkLiBVc2UgJC53aWRnZXQoKSBleHRlbnNpb25zIGluc3RlYWQuXG52YXIgcGx1Z2luID0gJC51aS5wbHVnaW4gPSB7XG5cdGFkZDogZnVuY3Rpb24oIG1vZHVsZSwgb3B0aW9uLCBzZXQgKSB7XG5cdFx0dmFyIGksXG5cdFx0XHRwcm90byA9ICQudWlbIG1vZHVsZSBdLnByb3RvdHlwZTtcblx0XHRmb3IgKCBpIGluIHNldCApIHtcblx0XHRcdHByb3RvLnBsdWdpbnNbIGkgXSA9IHByb3RvLnBsdWdpbnNbIGkgXSB8fCBbXTtcblx0XHRcdHByb3RvLnBsdWdpbnNbIGkgXS5wdXNoKCBbIG9wdGlvbiwgc2V0WyBpIF0gXSApO1xuXHRcdH1cblx0fSxcblx0Y2FsbDogZnVuY3Rpb24oIGluc3RhbmNlLCBuYW1lLCBhcmdzLCBhbGxvd0Rpc2Nvbm5lY3RlZCApIHtcblx0XHR2YXIgaSxcblx0XHRcdHNldCA9IGluc3RhbmNlLnBsdWdpbnNbIG5hbWUgXTtcblxuXHRcdGlmICggIXNldCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoICFhbGxvd0Rpc2Nvbm5lY3RlZCAmJiAoICFpbnN0YW5jZS5lbGVtZW50WyAwIF0ucGFyZW50Tm9kZSB8fFxuXHRcdFx0XHRpbnN0YW5jZS5lbGVtZW50WyAwIF0ucGFyZW50Tm9kZS5ub2RlVHlwZSA9PT0gMTEgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRmb3IgKCBpID0gMDsgaSA8IHNldC5sZW5ndGg7IGkrKyApIHtcblx0XHRcdGlmICggaW5zdGFuY2Uub3B0aW9uc1sgc2V0WyBpIF1bIDAgXSBdICkge1xuXHRcdFx0XHRzZXRbIGkgXVsgMSBdLmFwcGx5KCBpbnN0YW5jZS5lbGVtZW50LCBhcmdzICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG5cblxudmFyIHNhZmVCbHVyID0gJC51aS5zYWZlQmx1ciA9IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXG5cdC8vIFN1cHBvcnQ6IElFOSAtIDEwIG9ubHlcblx0Ly8gSWYgdGhlIDxib2R5PiBpcyBibHVycmVkLCBJRSB3aWxsIHN3aXRjaCB3aW5kb3dzLCBzZWUgIzk0MjBcblx0aWYgKCBlbGVtZW50ICYmIGVsZW1lbnQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJib2R5XCIgKSB7XG5cdFx0JCggZWxlbWVudCApLnRyaWdnZXIoIFwiYmx1clwiICk7XG5cdH1cbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRHJhZ2dhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBEcmFnZ2FibGVcbi8vPj5ncm91cDogSW50ZXJhY3Rpb25zXG4vLz4+ZGVzY3JpcHRpb246IEVuYWJsZXMgZHJhZ2dpbmcgZnVuY3Rpb25hbGl0eSBmb3IgYW55IGVsZW1lbnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZHJhZ2dhYmxlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2RyYWdnYWJsZS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9kcmFnZ2FibGUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5kcmFnZ2FibGVcIiwgJC51aS5tb3VzZSwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJkcmFnXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhZGRDbGFzc2VzOiB0cnVlLFxuXHRcdGFwcGVuZFRvOiBcInBhcmVudFwiLFxuXHRcdGF4aXM6IGZhbHNlLFxuXHRcdGNvbm5lY3RUb1NvcnRhYmxlOiBmYWxzZSxcblx0XHRjb250YWlubWVudDogZmFsc2UsXG5cdFx0Y3Vyc29yOiBcImF1dG9cIixcblx0XHRjdXJzb3JBdDogZmFsc2UsXG5cdFx0Z3JpZDogZmFsc2UsXG5cdFx0aGFuZGxlOiBmYWxzZSxcblx0XHRoZWxwZXI6IFwib3JpZ2luYWxcIixcblx0XHRpZnJhbWVGaXg6IGZhbHNlLFxuXHRcdG9wYWNpdHk6IGZhbHNlLFxuXHRcdHJlZnJlc2hQb3NpdGlvbnM6IGZhbHNlLFxuXHRcdHJldmVydDogZmFsc2UsXG5cdFx0cmV2ZXJ0RHVyYXRpb246IDUwMCxcblx0XHRzY29wZTogXCJkZWZhdWx0XCIsXG5cdFx0c2Nyb2xsOiB0cnVlLFxuXHRcdHNjcm9sbFNlbnNpdGl2aXR5OiAyMCxcblx0XHRzY3JvbGxTcGVlZDogMjAsXG5cdFx0c25hcDogZmFsc2UsXG5cdFx0c25hcE1vZGU6IFwiYm90aFwiLFxuXHRcdHNuYXBUb2xlcmFuY2U6IDIwLFxuXHRcdHN0YWNrOiBmYWxzZSxcblx0XHR6SW5kZXg6IGZhbHNlLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0ZHJhZzogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsXG5cdH0sXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGVscGVyID09PSBcIm9yaWdpbmFsXCIgKSB7XG5cdFx0XHR0aGlzLl9zZXRQb3NpdGlvblJlbGF0aXZlKCk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5vcHRpb25zLmFkZENsYXNzZXMgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1kcmFnZ2FibGVcIiApO1xuXHRcdH1cblx0XHR0aGlzLl9zZXRIYW5kbGVDbGFzc05hbWUoKTtcblxuXHRcdHRoaXMuX21vdXNlSW5pdCgpO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdFx0aWYgKCBrZXkgPT09IFwiaGFuZGxlXCIgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVIYW5kbGVDbGFzc05hbWUoKTtcblx0XHRcdHRoaXMuX3NldEhhbmRsZUNsYXNzTmFtZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAoIHRoaXMuaGVscGVyIHx8IHRoaXMuZWxlbWVudCApLmlzKCBcIi51aS1kcmFnZ2FibGUtZHJhZ2dpbmdcIiApICkge1xuXHRcdFx0dGhpcy5kZXN0cm95T25DbGVhciA9IHRydWU7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuX3JlbW92ZUhhbmRsZUNsYXNzTmFtZSgpO1xuXHRcdHRoaXMuX21vdXNlRGVzdHJveSgpO1xuXHR9LFxuXG5cdF9tb3VzZUNhcHR1cmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgbyA9IHRoaXMub3B0aW9ucztcblxuXHRcdC8vIEFtb25nIG90aGVycywgcHJldmVudCBhIGRyYWcgb24gYSByZXNpemFibGUtaGFuZGxlXG5cdFx0aWYgKCB0aGlzLmhlbHBlciB8fCBvLmRpc2FibGVkIHx8XG5cdFx0XHRcdCQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLXJlc2l6YWJsZS1oYW5kbGVcIiApLmxlbmd0aCA+IDAgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly9RdWl0IGlmIHdlJ3JlIG5vdCBvbiBhIHZhbGlkIGhhbmRsZVxuXHRcdHRoaXMuaGFuZGxlID0gdGhpcy5fZ2V0SGFuZGxlKCBldmVudCApO1xuXHRcdGlmICggIXRoaXMuaGFuZGxlICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHRoaXMuX2JsdXJBY3RpdmVFbGVtZW50KCBldmVudCApO1xuXG5cdFx0dGhpcy5fYmxvY2tGcmFtZXMoIG8uaWZyYW1lRml4ID09PSB0cnVlID8gXCJpZnJhbWVcIiA6IG8uaWZyYW1lRml4ICk7XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9LFxuXG5cdF9ibG9ja0ZyYW1lczogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHRoaXMuaWZyYW1lQmxvY2tzID0gdGhpcy5kb2N1bWVudC5maW5kKCBzZWxlY3RvciApLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaWZyYW1lID0gJCggdGhpcyApO1xuXG5cdFx0XHRyZXR1cm4gJCggXCI8ZGl2PlwiIClcblx0XHRcdFx0LmNzcyggXCJwb3NpdGlvblwiLCBcImFic29sdXRlXCIgKVxuXHRcdFx0XHQuYXBwZW5kVG8oIGlmcmFtZS5wYXJlbnQoKSApXG5cdFx0XHRcdC5vdXRlcldpZHRoKCBpZnJhbWUub3V0ZXJXaWR0aCgpIClcblx0XHRcdFx0Lm91dGVySGVpZ2h0KCBpZnJhbWUub3V0ZXJIZWlnaHQoKSApXG5cdFx0XHRcdC5vZmZzZXQoIGlmcmFtZS5vZmZzZXQoKSApWyAwIF07XG5cdFx0fSApO1xuXHR9LFxuXG5cdF91bmJsb2NrRnJhbWVzOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIHRoaXMuaWZyYW1lQmxvY2tzICkge1xuXHRcdFx0dGhpcy5pZnJhbWVCbG9ja3MucmVtb3ZlKCk7XG5cdFx0XHRkZWxldGUgdGhpcy5pZnJhbWVCbG9ja3M7XG5cdFx0fVxuXHR9LFxuXG5cdF9ibHVyQWN0aXZlRWxlbWVudDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBhY3RpdmVFbGVtZW50ID0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICksXG5cdFx0XHR0YXJnZXQgPSAkKCBldmVudC50YXJnZXQgKTtcblxuXHRcdC8vIERvbid0IGJsdXIgaWYgdGhlIGV2ZW50IG9jY3VycmVkIG9uIGFuIGVsZW1lbnQgdGhhdCBpcyB3aXRoaW5cblx0XHQvLyB0aGUgY3VycmVudGx5IGZvY3VzZWQgZWxlbWVudFxuXHRcdC8vIFNlZSAjMTA1MjcsICMxMjQ3MlxuXHRcdGlmICggdGFyZ2V0LmNsb3Nlc3QoIGFjdGl2ZUVsZW1lbnQgKS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gQmx1ciBhbnkgZWxlbWVudCB0aGF0IGN1cnJlbnRseSBoYXMgZm9jdXMsIHNlZSAjNDI2MVxuXHRcdCQudWkuc2FmZUJsdXIoIGFjdGl2ZUVsZW1lbnQgKTtcblx0fSxcblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIG8gPSB0aGlzLm9wdGlvbnM7XG5cblx0XHQvL0NyZWF0ZSBhbmQgYXBwZW5kIHRoZSB2aXNpYmxlIGhlbHBlclxuXHRcdHRoaXMuaGVscGVyID0gdGhpcy5fY3JlYXRlSGVscGVyKCBldmVudCApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGVscGVyLCBcInVpLWRyYWdnYWJsZS1kcmFnZ2luZ1wiICk7XG5cblx0XHQvL0NhY2hlIHRoZSBoZWxwZXIgc2l6ZVxuXHRcdHRoaXMuX2NhY2hlSGVscGVyUHJvcG9ydGlvbnMoKTtcblxuXHRcdC8vSWYgZGRtYW5hZ2VyIGlzIHVzZWQgZm9yIGRyb3BwYWJsZXMsIHNldCB0aGUgZ2xvYmFsIGRyYWdnYWJsZVxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5jdXJyZW50ID0gdGhpcztcblx0XHR9XG5cblx0XHQvKlxuXHRcdCAqIC0gUG9zaXRpb24gZ2VuZXJhdGlvbiAtXG5cdFx0ICogVGhpcyBibG9jayBnZW5lcmF0ZXMgZXZlcnl0aGluZyBwb3NpdGlvbiByZWxhdGVkIC0gaXQncyB0aGUgY29yZSBvZiBkcmFnZ2FibGVzLlxuXHRcdCAqL1xuXG5cdFx0Ly9DYWNoZSB0aGUgbWFyZ2lucyBvZiB0aGUgb3JpZ2luYWwgZWxlbWVudFxuXHRcdHRoaXMuX2NhY2hlTWFyZ2lucygpO1xuXG5cdFx0Ly9TdG9yZSB0aGUgaGVscGVyJ3MgY3NzIHBvc2l0aW9uXG5cdFx0dGhpcy5jc3NQb3NpdGlvbiA9IHRoaXMuaGVscGVyLmNzcyggXCJwb3NpdGlvblwiICk7XG5cdFx0dGhpcy5zY3JvbGxQYXJlbnQgPSB0aGlzLmhlbHBlci5zY3JvbGxQYXJlbnQoIHRydWUgKTtcblx0XHR0aGlzLm9mZnNldFBhcmVudCA9IHRoaXMuaGVscGVyLm9mZnNldFBhcmVudCgpO1xuXHRcdHRoaXMuaGFzRml4ZWRBbmNlc3RvciA9IHRoaXMuaGVscGVyLnBhcmVudHMoKS5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gJCggdGhpcyApLmNzcyggXCJwb3NpdGlvblwiICkgPT09IFwiZml4ZWRcIjtcblx0XHRcdH0gKS5sZW5ndGggPiAwO1xuXG5cdFx0Ly9UaGUgZWxlbWVudCdzIGFic29sdXRlIHBvc2l0aW9uIG9uIHRoZSBwYWdlIG1pbnVzIG1hcmdpbnNcblx0XHR0aGlzLnBvc2l0aW9uQWJzID0gdGhpcy5lbGVtZW50Lm9mZnNldCgpO1xuXHRcdHRoaXMuX3JlZnJlc2hPZmZzZXRzKCBldmVudCApO1xuXG5cdFx0Ly9HZW5lcmF0ZSB0aGUgb3JpZ2luYWwgcG9zaXRpb25cblx0XHR0aGlzLm9yaWdpbmFsUG9zaXRpb24gPSB0aGlzLnBvc2l0aW9uID0gdGhpcy5fZ2VuZXJhdGVQb3NpdGlvbiggZXZlbnQsIGZhbHNlICk7XG5cdFx0dGhpcy5vcmlnaW5hbFBhZ2VYID0gZXZlbnQucGFnZVg7XG5cdFx0dGhpcy5vcmlnaW5hbFBhZ2VZID0gZXZlbnQucGFnZVk7XG5cblx0XHQvL0FkanVzdCB0aGUgbW91c2Ugb2Zmc2V0IHJlbGF0aXZlIHRvIHRoZSBoZWxwZXIgaWYgXCJjdXJzb3JBdFwiIGlzIHN1cHBsaWVkXG5cdFx0KCBvLmN1cnNvckF0ICYmIHRoaXMuX2FkanVzdE9mZnNldEZyb21IZWxwZXIoIG8uY3Vyc29yQXQgKSApO1xuXG5cdFx0Ly9TZXQgYSBjb250YWlubWVudCBpZiBnaXZlbiBpbiB0aGUgb3B0aW9uc1xuXHRcdHRoaXMuX3NldENvbnRhaW5tZW50KCk7XG5cblx0XHQvL1RyaWdnZXIgZXZlbnQgKyBjYWxsYmFja3Ncblx0XHRpZiAoIHRoaXMuX3RyaWdnZXIoIFwic3RhcnRcIiwgZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLl9jbGVhcigpO1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vUmVjYWNoZSB0aGUgaGVscGVyIHNpemVcblx0XHR0aGlzLl9jYWNoZUhlbHBlclByb3BvcnRpb25zKCk7XG5cblx0XHQvL1ByZXBhcmUgdGhlIGRyb3BwYWJsZSBvZmZzZXRzXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciAmJiAhby5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly8gRXhlY3V0ZSB0aGUgZHJhZyBvbmNlIC0gdGhpcyBjYXVzZXMgdGhlIGhlbHBlciBub3QgdG8gYmUgdmlzaWJsZSBiZWZvcmUgZ2V0dGluZyBpdHNcblx0XHQvLyBjb3JyZWN0IHBvc2l0aW9uXG5cdFx0dGhpcy5fbW91c2VEcmFnKCBldmVudCwgdHJ1ZSApO1xuXG5cdFx0Ly8gSWYgdGhlIGRkbWFuYWdlciBpcyB1c2VkIGZvciBkcm9wcGFibGVzLCBpbmZvcm0gdGhlIG1hbmFnZXIgdGhhdCBkcmFnZ2luZyBoYXMgc3RhcnRlZFxuXHRcdC8vIChzZWUgIzUwMDMpXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmRyYWdTdGFydCggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfcmVmcmVzaE9mZnNldHM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLm9mZnNldCA9IHtcblx0XHRcdHRvcDogdGhpcy5wb3NpdGlvbkFicy50b3AgLSB0aGlzLm1hcmdpbnMudG9wLFxuXHRcdFx0bGVmdDogdGhpcy5wb3NpdGlvbkFicy5sZWZ0IC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRzY3JvbGw6IGZhbHNlLFxuXHRcdFx0cGFyZW50OiB0aGlzLl9nZXRQYXJlbnRPZmZzZXQoKSxcblx0XHRcdHJlbGF0aXZlOiB0aGlzLl9nZXRSZWxhdGl2ZU9mZnNldCgpXG5cdFx0fTtcblxuXHRcdHRoaXMub2Zmc2V0LmNsaWNrID0ge1xuXHRcdFx0bGVmdDogZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5sZWZ0LFxuXHRcdFx0dG9wOiBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LnRvcFxuXHRcdH07XG5cdH0sXG5cblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIGV2ZW50LCBub1Byb3BhZ2F0aW9uICkge1xuXG5cdFx0Ly8gcmVzZXQgYW55IG5lY2Vzc2FyeSBjYWNoZWQgcHJvcGVydGllcyAoc2VlICM1MDA5KVxuXHRcdGlmICggdGhpcy5oYXNGaXhlZEFuY2VzdG9yICkge1xuXHRcdFx0dGhpcy5vZmZzZXQucGFyZW50ID0gdGhpcy5fZ2V0UGFyZW50T2Zmc2V0KCk7XG5cdFx0fVxuXG5cdFx0Ly9Db21wdXRlIHRoZSBoZWxwZXJzIHBvc2l0aW9uXG5cdFx0dGhpcy5wb3NpdGlvbiA9IHRoaXMuX2dlbmVyYXRlUG9zaXRpb24oIGV2ZW50LCB0cnVlICk7XG5cdFx0dGhpcy5wb3NpdGlvbkFicyA9IHRoaXMuX2NvbnZlcnRQb3NpdGlvblRvKCBcImFic29sdXRlXCIgKTtcblxuXHRcdC8vQ2FsbCBwbHVnaW5zIGFuZCBjYWxsYmFja3MgYW5kIHVzZSB0aGUgcmVzdWx0aW5nIHBvc2l0aW9uIGlmIHNvbWV0aGluZyBpcyByZXR1cm5lZFxuXHRcdGlmICggIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHR2YXIgdWkgPSB0aGlzLl91aUhhc2goKTtcblx0XHRcdGlmICggdGhpcy5fdHJpZ2dlciggXCJkcmFnXCIsIGV2ZW50LCB1aSApID09PSBmYWxzZSApIHtcblx0XHRcdFx0dGhpcy5fbW91c2VVcCggbmV3ICQuRXZlbnQoIFwibW91c2V1cFwiLCBldmVudCApICk7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHRoaXMucG9zaXRpb24gPSB1aS5wb3NpdGlvbjtcblx0XHR9XG5cblx0XHR0aGlzLmhlbHBlclsgMCBdLnN0eWxlLmxlZnQgPSB0aGlzLnBvc2l0aW9uLmxlZnQgKyBcInB4XCI7XG5cdFx0dGhpcy5oZWxwZXJbIDAgXS5zdHlsZS50b3AgPSB0aGlzLnBvc2l0aW9uLnRvcCArIFwicHhcIjtcblxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5kcmFnKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvL0lmIHdlIGFyZSB1c2luZyBkcm9wcGFibGVzLCBpbmZvcm0gdGhlIG1hbmFnZXIgYWJvdXQgdGhlIGRyb3Bcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRkcm9wcGVkID0gZmFsc2U7XG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciAmJiAhdGhpcy5vcHRpb25zLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHRkcm9wcGVkID0gJC51aS5kZG1hbmFnZXIuZHJvcCggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHQvL2lmIGEgZHJvcCBjb21lcyBmcm9tIG91dHNpZGUgKGEgc29ydGFibGUpXG5cdFx0aWYgKCB0aGlzLmRyb3BwZWQgKSB7XG5cdFx0XHRkcm9wcGVkID0gdGhpcy5kcm9wcGVkO1xuXHRcdFx0dGhpcy5kcm9wcGVkID0gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCAoIHRoaXMub3B0aW9ucy5yZXZlcnQgPT09IFwiaW52YWxpZFwiICYmICFkcm9wcGVkICkgfHxcblx0XHRcdFx0KCB0aGlzLm9wdGlvbnMucmV2ZXJ0ID09PSBcInZhbGlkXCIgJiYgZHJvcHBlZCApIHx8XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5yZXZlcnQgPT09IHRydWUgfHwgKCAkLmlzRnVuY3Rpb24oIHRoaXMub3B0aW9ucy5yZXZlcnQgKSAmJlxuXHRcdFx0XHR0aGlzLm9wdGlvbnMucmV2ZXJ0LmNhbGwoIHRoaXMuZWxlbWVudCwgZHJvcHBlZCApIClcblx0XHQpIHtcblx0XHRcdCQoIHRoaXMuaGVscGVyICkuYW5pbWF0ZShcblx0XHRcdFx0dGhpcy5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0XHRwYXJzZUludCggdGhpcy5vcHRpb25zLnJldmVydER1cmF0aW9uLCAxMCApLFxuXHRcdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIHRoYXQuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCApICE9PSBmYWxzZSApIHtcblx0XHRcdFx0XHRcdHRoYXQuX2NsZWFyKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIHRoaXMuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCApICE9PSBmYWxzZSApIHtcblx0XHRcdFx0dGhpcy5fY2xlYXIoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X21vdXNlVXA6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLl91bmJsb2NrRnJhbWVzKCk7XG5cblx0XHQvLyBJZiB0aGUgZGRtYW5hZ2VyIGlzIHVzZWQgZm9yIGRyb3BwYWJsZXMsIGluZm9ybSB0aGUgbWFuYWdlciB0aGF0IGRyYWdnaW5nIGhhcyBzdG9wcGVkXG5cdFx0Ly8gKHNlZSAjNTAwMylcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuZHJhZ1N0b3AoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly8gT25seSBuZWVkIHRvIGZvY3VzIGlmIHRoZSBldmVudCBvY2N1cnJlZCBvbiB0aGUgZHJhZ2dhYmxlIGl0c2VsZiwgc2VlICMxMDUyN1xuXHRcdGlmICggdGhpcy5oYW5kbGVFbGVtZW50LmlzKCBldmVudC50YXJnZXQgKSApIHtcblxuXHRcdFx0Ly8gVGhlIGludGVyYWN0aW9uIGlzIG92ZXI7IHdoZXRoZXIgb3Igbm90IHRoZSBjbGljayByZXN1bHRlZCBpbiBhIGRyYWcsXG5cdFx0XHQvLyBmb2N1cyB0aGUgZWxlbWVudFxuXHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdH1cblxuXHRcdHJldHVybiAkLnVpLm1vdXNlLnByb3RvdHlwZS5fbW91c2VVcC5jYWxsKCB0aGlzLCBldmVudCApO1xuXHR9LFxuXG5cdGNhbmNlbDogZnVuY3Rpb24oKSB7XG5cblx0XHRpZiAoIHRoaXMuaGVscGVyLmlzKCBcIi51aS1kcmFnZ2FibGUtZHJhZ2dpbmdcIiApICkge1xuXHRcdFx0dGhpcy5fbW91c2VVcCggbmV3ICQuRXZlbnQoIFwibW91c2V1cFwiLCB7IHRhcmdldDogdGhpcy5lbGVtZW50WyAwIF0gfSApICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2NsZWFyKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRfZ2V0SGFuZGxlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5oYW5kbGUgP1xuXHRcdFx0ISEkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCB0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLmhhbmRsZSApICkubGVuZ3RoIDpcblx0XHRcdHRydWU7XG5cdH0sXG5cblx0X3NldEhhbmRsZUNsYXNzTmFtZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5oYW5kbGVFbGVtZW50ID0gdGhpcy5vcHRpb25zLmhhbmRsZSA/XG5cdFx0XHR0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLmhhbmRsZSApIDogdGhpcy5lbGVtZW50O1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhhbmRsZUVsZW1lbnQsIFwidWktZHJhZ2dhYmxlLWhhbmRsZVwiICk7XG5cdH0sXG5cblx0X3JlbW92ZUhhbmRsZUNsYXNzTmFtZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaGFuZGxlRWxlbWVudCwgXCJ1aS1kcmFnZ2FibGUtaGFuZGxlXCIgKTtcblx0fSxcblxuXHRfY3JlYXRlSGVscGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgbyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGhlbHBlcklzRnVuY3Rpb24gPSAkLmlzRnVuY3Rpb24oIG8uaGVscGVyICksXG5cdFx0XHRoZWxwZXIgPSBoZWxwZXJJc0Z1bmN0aW9uID9cblx0XHRcdFx0JCggby5oZWxwZXIuYXBwbHkoIHRoaXMuZWxlbWVudFsgMCBdLCBbIGV2ZW50IF0gKSApIDpcblx0XHRcdFx0KCBvLmhlbHBlciA9PT0gXCJjbG9uZVwiID9cblx0XHRcdFx0XHR0aGlzLmVsZW1lbnQuY2xvbmUoKS5yZW1vdmVBdHRyKCBcImlkXCIgKSA6XG5cdFx0XHRcdFx0dGhpcy5lbGVtZW50ICk7XG5cblx0XHRpZiAoICFoZWxwZXIucGFyZW50cyggXCJib2R5XCIgKS5sZW5ndGggKSB7XG5cdFx0XHRoZWxwZXIuYXBwZW5kVG8oICggby5hcHBlbmRUbyA9PT0gXCJwYXJlbnRcIiA/XG5cdFx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLnBhcmVudE5vZGUgOlxuXHRcdFx0XHRvLmFwcGVuZFRvICkgKTtcblx0XHR9XG5cblx0XHQvLyBIdHRwOi8vYnVncy5qcXVlcnl1aS5jb20vdGlja2V0Lzk0NDZcblx0XHQvLyBhIGhlbHBlciBmdW5jdGlvbiBjYW4gcmV0dXJuIHRoZSBvcmlnaW5hbCBlbGVtZW50XG5cdFx0Ly8gd2hpY2ggd291bGRuJ3QgaGF2ZSBiZWVuIHNldCB0byByZWxhdGl2ZSBpbiBfY3JlYXRlXG5cdFx0aWYgKCBoZWxwZXJJc0Z1bmN0aW9uICYmIGhlbHBlclsgMCBdID09PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdHRoaXMuX3NldFBvc2l0aW9uUmVsYXRpdmUoKTtcblx0XHR9XG5cblx0XHRpZiAoIGhlbHBlclsgMCBdICE9PSB0aGlzLmVsZW1lbnRbIDAgXSAmJlxuXHRcdFx0XHQhKCAvKGZpeGVkfGFic29sdXRlKS8gKS50ZXN0KCBoZWxwZXIuY3NzKCBcInBvc2l0aW9uXCIgKSApICkge1xuXHRcdFx0aGVscGVyLmNzcyggXCJwb3NpdGlvblwiLCBcImFic29sdXRlXCIgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaGVscGVyO1xuXG5cdH0sXG5cblx0X3NldFBvc2l0aW9uUmVsYXRpdmU6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggISggL14oPzpyfGF8ZikvICkudGVzdCggdGhpcy5lbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICkgKSApIHtcblx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLnBvc2l0aW9uID0gXCJyZWxhdGl2ZVwiO1xuXHRcdH1cblx0fSxcblxuXHRfYWRqdXN0T2Zmc2V0RnJvbUhlbHBlcjogZnVuY3Rpb24oIG9iaiApIHtcblx0XHRpZiAoIHR5cGVvZiBvYmogPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRvYmogPSBvYmouc3BsaXQoIFwiIFwiICk7XG5cdFx0fVxuXHRcdGlmICggJC5pc0FycmF5KCBvYmogKSApIHtcblx0XHRcdG9iaiA9IHsgbGVmdDogK29ialsgMCBdLCB0b3A6ICtvYmpbIDEgXSB8fCAwIH07XG5cdFx0fVxuXHRcdGlmICggXCJsZWZ0XCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCA9IG9iai5sZWZ0ICsgdGhpcy5tYXJnaW5zLmxlZnQ7XG5cdFx0fVxuXHRcdGlmICggXCJyaWdodFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPSB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gb2JqLnJpZ2h0ICsgdGhpcy5tYXJnaW5zLmxlZnQ7XG5cdFx0fVxuXHRcdGlmICggXCJ0b3BcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgPSBvYmoudG9wICsgdGhpcy5tYXJnaW5zLnRvcDtcblx0XHR9XG5cdFx0aWYgKCBcImJvdHRvbVwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA9IHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gb2JqLmJvdHRvbSArIHRoaXMubWFyZ2lucy50b3A7XG5cdFx0fVxuXHR9LFxuXG5cdF9pc1Jvb3ROb2RlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRyZXR1cm4gKCAvKGh0bWx8Ym9keSkvaSApLnRlc3QoIGVsZW1lbnQudGFnTmFtZSApIHx8IGVsZW1lbnQgPT09IHRoaXMuZG9jdW1lbnRbIDAgXTtcblx0fSxcblxuXHRfZ2V0UGFyZW50T2Zmc2V0OiBmdW5jdGlvbigpIHtcblxuXHRcdC8vR2V0IHRoZSBvZmZzZXRQYXJlbnQgYW5kIGNhY2hlIGl0cyBwb3NpdGlvblxuXHRcdHZhciBwbyA9IHRoaXMub2Zmc2V0UGFyZW50Lm9mZnNldCgpLFxuXHRcdFx0ZG9jdW1lbnQgPSB0aGlzLmRvY3VtZW50WyAwIF07XG5cblx0XHQvLyBUaGlzIGlzIGEgc3BlY2lhbCBjYXNlIHdoZXJlIHdlIG5lZWQgdG8gbW9kaWZ5IGEgb2Zmc2V0IGNhbGN1bGF0ZWQgb24gc3RhcnQsIHNpbmNlIHRoZVxuXHRcdC8vIGZvbGxvd2luZyBoYXBwZW5lZDpcblx0XHQvLyAxLiBUaGUgcG9zaXRpb24gb2YgdGhlIGhlbHBlciBpcyBhYnNvbHV0ZSwgc28gaXQncyBwb3NpdGlvbiBpcyBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZVxuXHRcdC8vIG5leHQgcG9zaXRpb25lZCBwYXJlbnRcblx0XHQvLyAyLiBUaGUgYWN0dWFsIG9mZnNldCBwYXJlbnQgaXMgYSBjaGlsZCBvZiB0aGUgc2Nyb2xsIHBhcmVudCwgYW5kIHRoZSBzY3JvbGwgcGFyZW50IGlzbid0XG5cdFx0Ly8gdGhlIGRvY3VtZW50LCB3aGljaCBtZWFucyB0aGF0IHRoZSBzY3JvbGwgaXMgaW5jbHVkZWQgaW4gdGhlIGluaXRpYWwgY2FsY3VsYXRpb24gb2YgdGhlXG5cdFx0Ly8gb2Zmc2V0IG9mIHRoZSBwYXJlbnQsIGFuZCBuZXZlciByZWNhbGN1bGF0ZWQgdXBvbiBkcmFnXG5cdFx0aWYgKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImFic29sdXRlXCIgJiYgdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gZG9jdW1lbnQgJiZcblx0XHRcdFx0JC5jb250YWlucyggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSwgdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkge1xuXHRcdFx0cG8ubGVmdCArPSB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KCk7XG5cdFx0XHRwby50b3AgKz0gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9pc1Jvb3ROb2RlKCB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSB7XG5cdFx0XHRwbyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogcG8udG9wICsgKCBwYXJzZUludCggdGhpcy5vZmZzZXRQYXJlbnQuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHRsZWZ0OiBwby5sZWZ0ICsgKCBwYXJzZUludCggdGhpcy5vZmZzZXRQYXJlbnQuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiICksIDEwICkgfHwgMCApXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9nZXRSZWxhdGl2ZU9mZnNldDogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCB0aGlzLmNzc1Bvc2l0aW9uICE9PSBcInJlbGF0aXZlXCIgKSB7XG5cdFx0XHRyZXR1cm4geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblx0XHR9XG5cblx0XHR2YXIgcCA9IHRoaXMuZWxlbWVudC5wb3NpdGlvbigpLFxuXHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA9IHRoaXMuX2lzUm9vdE5vZGUoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gKTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IHAudG9wIC0gKCBwYXJzZUludCggdGhpcy5oZWxwZXIuY3NzKCBcInRvcFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0KCAhc2Nyb2xsSXNSb290Tm9kZSA/IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpIDogMCApLFxuXHRcdFx0bGVmdDogcC5sZWZ0IC0gKCBwYXJzZUludCggdGhpcy5oZWxwZXIuY3NzKCBcImxlZnRcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdCggIXNjcm9sbElzUm9vdE5vZGUgPyB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KCkgOiAwIClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2NhY2hlTWFyZ2luczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5tYXJnaW5zID0ge1xuXHRcdFx0bGVmdDogKCBwYXJzZUludCggdGhpcy5lbGVtZW50LmNzcyggXCJtYXJnaW5MZWZ0XCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHR0b3A6ICggcGFyc2VJbnQoIHRoaXMuZWxlbWVudC5jc3MoIFwibWFyZ2luVG9wXCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHRyaWdodDogKCBwYXJzZUludCggdGhpcy5lbGVtZW50LmNzcyggXCJtYXJnaW5SaWdodFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0Ym90dG9tOiAoIHBhcnNlSW50KCB0aGlzLmVsZW1lbnQuY3NzKCBcIm1hcmdpbkJvdHRvbVwiICksIDEwICkgfHwgMCApXG5cdFx0fTtcblx0fSxcblxuXHRfY2FjaGVIZWxwZXJQcm9wb3J0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucyA9IHtcblx0XHRcdHdpZHRoOiB0aGlzLmhlbHBlci5vdXRlcldpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IHRoaXMuaGVscGVyLm91dGVySGVpZ2h0KClcblx0XHR9O1xuXHR9LFxuXG5cdF9zZXRDb250YWlubWVudDogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgaXNVc2VyU2Nyb2xsYWJsZSwgYywgY2UsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0ZG9jdW1lbnQgPSB0aGlzLmRvY3VtZW50WyAwIF07XG5cblx0XHR0aGlzLnJlbGF0aXZlQ29udGFpbmVyID0gbnVsbDtcblxuXHRcdGlmICggIW8uY29udGFpbm1lbnQgKSB7XG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gbnVsbDtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIG8uY29udGFpbm1lbnQgPT09IFwid2luZG93XCIgKSB7XG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gW1xuXHRcdFx0XHQkKCB3aW5kb3cgKS5zY3JvbGxMZWZ0KCkgLSB0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0IC0gdGhpcy5vZmZzZXQucGFyZW50LmxlZnQsXG5cdFx0XHRcdCQoIHdpbmRvdyApLnNjcm9sbFRvcCgpIC0gdGhpcy5vZmZzZXQucmVsYXRpdmUudG9wIC0gdGhpcy5vZmZzZXQucGFyZW50LnRvcCxcblx0XHRcdFx0JCggd2luZG93ICkuc2Nyb2xsTGVmdCgpICsgJCggd2luZG93ICkud2lkdGgoKSAtXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0XHQkKCB3aW5kb3cgKS5zY3JvbGxUb3AoKSArXG5cdFx0XHRcdFx0KCAkKCB3aW5kb3cgKS5oZWlnaHQoKSB8fCBkb2N1bWVudC5ib2R5LnBhcmVudE5vZGUuc2Nyb2xsSGVpZ2h0ICkgLVxuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gdGhpcy5tYXJnaW5zLnRvcFxuXHRcdFx0XTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIG8uY29udGFpbm1lbnQgPT09IFwiZG9jdW1lbnRcIiApIHtcblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBbXG5cdFx0XHRcdDAsXG5cdFx0XHRcdDAsXG5cdFx0XHRcdCQoIGRvY3VtZW50ICkud2lkdGgoKSAtIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdFx0KCAkKCBkb2N1bWVudCApLmhlaWdodCgpIHx8IGRvY3VtZW50LmJvZHkucGFyZW50Tm9kZS5zY3JvbGxIZWlnaHQgKSAtXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSB0aGlzLm1hcmdpbnMudG9wXG5cdFx0XHRdO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggby5jb250YWlubWVudC5jb25zdHJ1Y3RvciA9PT0gQXJyYXkgKSB7XG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gby5jb250YWlubWVudDtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIG8uY29udGFpbm1lbnQgPT09IFwicGFyZW50XCIgKSB7XG5cdFx0XHRvLmNvbnRhaW5tZW50ID0gdGhpcy5oZWxwZXJbIDAgXS5wYXJlbnROb2RlO1xuXHRcdH1cblxuXHRcdGMgPSAkKCBvLmNvbnRhaW5tZW50ICk7XG5cdFx0Y2UgPSBjWyAwIF07XG5cblx0XHRpZiAoICFjZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpc1VzZXJTY3JvbGxhYmxlID0gLyhzY3JvbGx8YXV0bykvLnRlc3QoIGMuY3NzKCBcIm92ZXJmbG93XCIgKSApO1xuXG5cdFx0dGhpcy5jb250YWlubWVudCA9IFtcblx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwicGFkZGluZ0xlZnRcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJwYWRkaW5nVG9wXCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHQoIGlzVXNlclNjcm9sbGFibGUgPyBNYXRoLm1heCggY2Uuc2Nyb2xsV2lkdGgsIGNlLm9mZnNldFdpZHRoICkgOiBjZS5vZmZzZXRXaWR0aCApIC1cblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwiYm9yZGVyUmlnaHRXaWR0aFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwicGFkZGluZ1JpZ2h0XCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC1cblx0XHRcdFx0dGhpcy5tYXJnaW5zLmxlZnQgLVxuXHRcdFx0XHR0aGlzLm1hcmdpbnMucmlnaHQsXG5cdFx0XHQoIGlzVXNlclNjcm9sbGFibGUgPyBNYXRoLm1heCggY2Uuc2Nyb2xsSGVpZ2h0LCBjZS5vZmZzZXRIZWlnaHQgKSA6IGNlLm9mZnNldEhlaWdodCApIC1cblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwiYm9yZGVyQm90dG9tV2lkdGhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcInBhZGRpbmdCb3R0b21cIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC1cblx0XHRcdFx0dGhpcy5tYXJnaW5zLnRvcCAtXG5cdFx0XHRcdHRoaXMubWFyZ2lucy5ib3R0b21cblx0XHRdO1xuXHRcdHRoaXMucmVsYXRpdmVDb250YWluZXIgPSBjO1xuXHR9LFxuXG5cdF9jb252ZXJ0UG9zaXRpb25UbzogZnVuY3Rpb24oIGQsIHBvcyApIHtcblxuXHRcdGlmICggIXBvcyApIHtcblx0XHRcdHBvcyA9IHRoaXMucG9zaXRpb247XG5cdFx0fVxuXG5cdFx0dmFyIG1vZCA9IGQgPT09IFwiYWJzb2x1dGVcIiA/IDEgOiAtMSxcblx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPSB0aGlzLl9pc1Jvb3ROb2RlKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBvcy50b3BcdCtcblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUudG9wICogbW9kICtcblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQudG9wICogbW9kIC1cblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMub2Zmc2V0LnNjcm9sbC50b3AgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiB0aGlzLm9mZnNldC5zY3JvbGwudG9wICkgKSAqIG1vZCApXG5cdFx0XHQpLFxuXHRcdFx0bGVmdDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwb3MubGVmdCArXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgKiBtb2QgK1xuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0ICogbW9kXHQtXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLm9mZnNldC5zY3JvbGwubGVmdCA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHRoaXMub2Zmc2V0LnNjcm9sbC5sZWZ0ICkgKSAqIG1vZCApXG5cdFx0XHQpXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9nZW5lcmF0ZVBvc2l0aW9uOiBmdW5jdGlvbiggZXZlbnQsIGNvbnN0cmFpblBvc2l0aW9uICkge1xuXG5cdFx0dmFyIGNvbnRhaW5tZW50LCBjbywgdG9wLCBsZWZ0LFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPSB0aGlzLl9pc1Jvb3ROb2RlKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICksXG5cdFx0XHRwYWdlWCA9IGV2ZW50LnBhZ2VYLFxuXHRcdFx0cGFnZVkgPSBldmVudC5wYWdlWTtcblxuXHRcdC8vIENhY2hlIHRoZSBzY3JvbGxcblx0XHRpZiAoICFzY3JvbGxJc1Jvb3ROb2RlIHx8ICF0aGlzLm9mZnNldC5zY3JvbGwgKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5zY3JvbGwgPSB7XG5cdFx0XHRcdHRvcDogdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCksXG5cdFx0XHRcdGxlZnQ6IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKVxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHQvKlxuXHRcdCAqIC0gUG9zaXRpb24gY29uc3RyYWluaW5nIC1cblx0XHQgKiBDb25zdHJhaW4gdGhlIHBvc2l0aW9uIHRvIGEgbWl4IG9mIGdyaWQsIGNvbnRhaW5tZW50LlxuXHRcdCAqL1xuXG5cdFx0Ly8gSWYgd2UgYXJlIG5vdCBkcmFnZ2luZyB5ZXQsIHdlIHdvbid0IGNoZWNrIGZvciBvcHRpb25zXG5cdFx0aWYgKCBjb25zdHJhaW5Qb3NpdGlvbiApIHtcblx0XHRcdGlmICggdGhpcy5jb250YWlubWVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLnJlbGF0aXZlQ29udGFpbmVyICkge1xuXHRcdFx0XHRcdGNvID0gdGhpcy5yZWxhdGl2ZUNvbnRhaW5lci5vZmZzZXQoKTtcblx0XHRcdFx0XHRjb250YWlubWVudCA9IFtcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbm1lbnRbIDAgXSArIGNvLmxlZnQsXG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5tZW50WyAxIF0gKyBjby50b3AsXG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5tZW50WyAyIF0gKyBjby5sZWZ0LFxuXHRcdFx0XHRcdFx0dGhpcy5jb250YWlubWVudFsgMyBdICsgY28udG9wXG5cdFx0XHRcdFx0XTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjb250YWlubWVudCA9IHRoaXMuY29udGFpbm1lbnQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA8IGNvbnRhaW5tZW50WyAwIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVggPSBjb250YWlubWVudFsgMCBdICsgdGhpcy5vZmZzZXQuY2xpY2subGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wIDwgY29udGFpbm1lbnRbIDEgXSApIHtcblx0XHRcdFx0XHRwYWdlWSA9IGNvbnRhaW5tZW50WyAxIF0gKyB0aGlzLm9mZnNldC5jbGljay50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPiBjb250YWlubWVudFsgMiBdICkge1xuXHRcdFx0XHRcdHBhZ2VYID0gY29udGFpbm1lbnRbIDIgXSArIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+IGNvbnRhaW5tZW50WyAzIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVkgPSBjb250YWlubWVudFsgMyBdICsgdGhpcy5vZmZzZXQuY2xpY2sudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggby5ncmlkICkge1xuXG5cdFx0XHRcdC8vQ2hlY2sgZm9yIGdyaWQgZWxlbWVudHMgc2V0IHRvIDAgdG8gcHJldmVudCBkaXZpZGUgYnkgMCBlcnJvciBjYXVzaW5nIGludmFsaWRcblx0XHRcdFx0Ly8gYXJndW1lbnQgZXJyb3JzIGluIElFIChzZWUgdGlja2V0ICM2OTUwKVxuXHRcdFx0XHR0b3AgPSBvLmdyaWRbIDEgXSA/IHRoaXMub3JpZ2luYWxQYWdlWSArIE1hdGgucm91bmQoICggcGFnZVkgLVxuXHRcdFx0XHRcdHRoaXMub3JpZ2luYWxQYWdlWSApIC8gby5ncmlkWyAxIF0gKSAqIG8uZ3JpZFsgMSBdIDogdGhpcy5vcmlnaW5hbFBhZ2VZO1xuXHRcdFx0XHRwYWdlWSA9IGNvbnRhaW5tZW50ID8gKCAoIHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+PSBjb250YWlubWVudFsgMSBdIHx8XG5cdFx0XHRcdFx0dG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID4gY29udGFpbm1lbnRbIDMgXSApID9cblx0XHRcdFx0XHRcdHRvcCA6XG5cdFx0XHRcdFx0XHQoICggdG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID49IGNvbnRhaW5tZW50WyAxIF0gKSA/XG5cdFx0XHRcdFx0XHRcdHRvcCAtIG8uZ3JpZFsgMSBdIDogdG9wICsgby5ncmlkWyAxIF0gKSApIDogdG9wO1xuXG5cdFx0XHRcdGxlZnQgPSBvLmdyaWRbIDAgXSA/IHRoaXMub3JpZ2luYWxQYWdlWCArXG5cdFx0XHRcdFx0TWF0aC5yb3VuZCggKCBwYWdlWCAtIHRoaXMub3JpZ2luYWxQYWdlWCApIC8gby5ncmlkWyAwIF0gKSAqIG8uZ3JpZFsgMCBdIDpcblx0XHRcdFx0XHR0aGlzLm9yaWdpbmFsUGFnZVg7XG5cdFx0XHRcdHBhZ2VYID0gY29udGFpbm1lbnQgPyAoICggbGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPj0gY29udGFpbm1lbnRbIDAgXSB8fFxuXHRcdFx0XHRcdGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID4gY29udGFpbm1lbnRbIDIgXSApID9cblx0XHRcdFx0XHRcdGxlZnQgOlxuXHRcdFx0XHRcdFx0KCAoIGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID49IGNvbnRhaW5tZW50WyAwIF0gKSA/XG5cdFx0XHRcdFx0XHRcdGxlZnQgLSBvLmdyaWRbIDAgXSA6IGxlZnQgKyBvLmdyaWRbIDAgXSApICkgOiBsZWZ0O1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG8uYXhpcyA9PT0gXCJ5XCIgKSB7XG5cdFx0XHRcdHBhZ2VYID0gdGhpcy5vcmlnaW5hbFBhZ2VYO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG8uYXhpcyA9PT0gXCJ4XCIgKSB7XG5cdFx0XHRcdHBhZ2VZID0gdGhpcy5vcmlnaW5hbFBhZ2VZO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cGFnZVkgLVxuXG5cdFx0XHRcdC8vIENsaWNrIG9mZnNldCAocmVsYXRpdmUgdG8gdGhlIGVsZW1lbnQpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCAtXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAtXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LnRvcCArXG5cdFx0XHRcdCggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5vZmZzZXQuc2Nyb2xsLnRvcCA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHRoaXMub2Zmc2V0LnNjcm9sbC50b3AgKSApXG5cdFx0XHQpLFxuXHRcdFx0bGVmdDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwYWdlWCAtXG5cblx0XHRcdFx0Ly8gQ2xpY2sgb2Zmc2V0IChyZWxhdGl2ZSB0byB0aGUgZWxlbWVudClcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCAtXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgLVxuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0ICtcblx0XHRcdFx0KCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLm9mZnNldC5zY3JvbGwubGVmdCA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHRoaXMub2Zmc2V0LnNjcm9sbC5sZWZ0ICkgKVxuXHRcdFx0KVxuXHRcdH07XG5cblx0fSxcblxuXHRfY2xlYXI6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmhlbHBlciwgXCJ1aS1kcmFnZ2FibGUtZHJhZ2dpbmdcIiApO1xuXHRcdGlmICggdGhpcy5oZWxwZXJbIDAgXSAhPT0gdGhpcy5lbGVtZW50WyAwIF0gJiYgIXRoaXMuY2FuY2VsSGVscGVyUmVtb3ZhbCApIHtcblx0XHRcdHRoaXMuaGVscGVyLnJlbW92ZSgpO1xuXHRcdH1cblx0XHR0aGlzLmhlbHBlciA9IG51bGw7XG5cdFx0dGhpcy5jYW5jZWxIZWxwZXJSZW1vdmFsID0gZmFsc2U7XG5cdFx0aWYgKCB0aGlzLmRlc3Ryb3lPbkNsZWFyICkge1xuXHRcdFx0dGhpcy5kZXN0cm95KCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIEZyb20gbm93IG9uIGJ1bGsgc3R1ZmYgLSBtYWlubHkgaGVscGVyc1xuXG5cdF90cmlnZ2VyOiBmdW5jdGlvbiggdHlwZSwgZXZlbnQsIHVpICkge1xuXHRcdHVpID0gdWkgfHwgdGhpcy5fdWlIYXNoKCk7XG5cdFx0JC51aS5wbHVnaW4uY2FsbCggdGhpcywgdHlwZSwgWyBldmVudCwgdWksIHRoaXMgXSwgdHJ1ZSApO1xuXG5cdFx0Ly8gQWJzb2x1dGUgcG9zaXRpb24gYW5kIG9mZnNldCAoc2VlICM2ODg0ICkgaGF2ZSB0byBiZSByZWNhbGN1bGF0ZWQgYWZ0ZXIgcGx1Z2luc1xuXHRcdGlmICggL14oZHJhZ3xzdGFydHxzdG9wKS8udGVzdCggdHlwZSApICkge1xuXHRcdFx0dGhpcy5wb3NpdGlvbkFicyA9IHRoaXMuX2NvbnZlcnRQb3NpdGlvblRvKCBcImFic29sdXRlXCIgKTtcblx0XHRcdHVpLm9mZnNldCA9IHRoaXMucG9zaXRpb25BYnM7XG5cdFx0fVxuXHRcdHJldHVybiAkLldpZGdldC5wcm90b3R5cGUuX3RyaWdnZXIuY2FsbCggdGhpcywgdHlwZSwgZXZlbnQsIHVpICk7XG5cdH0sXG5cblx0cGx1Z2luczoge30sXG5cblx0X3VpSGFzaDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGhlbHBlcjogdGhpcy5oZWxwZXIsXG5cdFx0XHRwb3NpdGlvbjogdGhpcy5wb3NpdGlvbixcblx0XHRcdG9yaWdpbmFsUG9zaXRpb246IHRoaXMub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdG9mZnNldDogdGhpcy5wb3NpdGlvbkFic1xuXHRcdH07XG5cdH1cblxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwiY29ubmVjdFRvU29ydGFibGVcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgZHJhZ2dhYmxlICkge1xuXHRcdHZhciB1aVNvcnRhYmxlID0gJC5leHRlbmQoIHt9LCB1aSwge1xuXHRcdFx0aXRlbTogZHJhZ2dhYmxlLmVsZW1lbnRcblx0XHR9ICk7XG5cblx0XHRkcmFnZ2FibGUuc29ydGFibGVzID0gW107XG5cdFx0JCggZHJhZ2dhYmxlLm9wdGlvbnMuY29ubmVjdFRvU29ydGFibGUgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzb3J0YWJsZSA9ICQoIHRoaXMgKS5zb3J0YWJsZSggXCJpbnN0YW5jZVwiICk7XG5cblx0XHRcdGlmICggc29ydGFibGUgJiYgIXNvcnRhYmxlLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRcdGRyYWdnYWJsZS5zb3J0YWJsZXMucHVzaCggc29ydGFibGUgKTtcblxuXHRcdFx0XHQvLyBSZWZyZXNoUG9zaXRpb25zIGlzIGNhbGxlZCBhdCBkcmFnIHN0YXJ0IHRvIHJlZnJlc2ggdGhlIGNvbnRhaW5lckNhY2hlXG5cdFx0XHRcdC8vIHdoaWNoIGlzIHVzZWQgaW4gZHJhZy4gVGhpcyBlbnN1cmVzIGl0J3MgaW5pdGlhbGl6ZWQgYW5kIHN5bmNocm9uaXplZFxuXHRcdFx0XHQvLyB3aXRoIGFueSBjaGFuZ2VzIHRoYXQgbWlnaHQgaGF2ZSBoYXBwZW5lZCBvbiB0aGUgcGFnZSBzaW5jZSBpbml0aWFsaXphdGlvbi5cblx0XHRcdFx0c29ydGFibGUucmVmcmVzaFBvc2l0aW9ucygpO1xuXHRcdFx0XHRzb3J0YWJsZS5fdHJpZ2dlciggXCJhY3RpdmF0ZVwiLCBldmVudCwgdWlTb3J0YWJsZSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgZHJhZ2dhYmxlICkge1xuXHRcdHZhciB1aVNvcnRhYmxlID0gJC5leHRlbmQoIHt9LCB1aSwge1xuXHRcdFx0aXRlbTogZHJhZ2dhYmxlLmVsZW1lbnRcblx0XHR9ICk7XG5cblx0XHRkcmFnZ2FibGUuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IGZhbHNlO1xuXG5cdFx0JC5lYWNoKCBkcmFnZ2FibGUuc29ydGFibGVzLCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzb3J0YWJsZSA9IHRoaXM7XG5cblx0XHRcdGlmICggc29ydGFibGUuaXNPdmVyICkge1xuXHRcdFx0XHRzb3J0YWJsZS5pc092ZXIgPSAwO1xuXG5cdFx0XHRcdC8vIEFsbG93IHRoaXMgc29ydGFibGUgdG8gaGFuZGxlIHJlbW92aW5nIHRoZSBoZWxwZXJcblx0XHRcdFx0ZHJhZ2dhYmxlLmNhbmNlbEhlbHBlclJlbW92YWwgPSB0cnVlO1xuXHRcdFx0XHRzb3J0YWJsZS5jYW5jZWxIZWxwZXJSZW1vdmFsID0gZmFsc2U7XG5cblx0XHRcdFx0Ly8gVXNlIF9zdG9yZWRDU1MgVG8gcmVzdG9yZSBwcm9wZXJ0aWVzIGluIHRoZSBzb3J0YWJsZSxcblx0XHRcdFx0Ly8gYXMgdGhpcyBhbHNvIGhhbmRsZXMgcmV2ZXJ0ICgjOTY3NSkgc2luY2UgdGhlIGRyYWdnYWJsZVxuXHRcdFx0XHQvLyBtYXkgaGF2ZSBtb2RpZmllZCB0aGVtIGluIHVuZXhwZWN0ZWQgd2F5cyAoIzg4MDkpXG5cdFx0XHRcdHNvcnRhYmxlLl9zdG9yZWRDU1MgPSB7XG5cdFx0XHRcdFx0cG9zaXRpb246IHNvcnRhYmxlLnBsYWNlaG9sZGVyLmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRcdFx0dG9wOiBzb3J0YWJsZS5wbGFjZWhvbGRlci5jc3MoIFwidG9wXCIgKSxcblx0XHRcdFx0XHRsZWZ0OiBzb3J0YWJsZS5wbGFjZWhvbGRlci5jc3MoIFwibGVmdFwiIClcblx0XHRcdFx0fTtcblxuXHRcdFx0XHRzb3J0YWJsZS5fbW91c2VTdG9wKCBldmVudCApO1xuXG5cdFx0XHRcdC8vIE9uY2UgZHJhZyBoYXMgZW5kZWQsIHRoZSBzb3J0YWJsZSBzaG91bGQgcmV0dXJuIHRvIHVzaW5nXG5cdFx0XHRcdC8vIGl0cyBvcmlnaW5hbCBoZWxwZXIsIG5vdCB0aGUgc2hhcmVkIGhlbHBlciBmcm9tIGRyYWdnYWJsZVxuXHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLmhlbHBlciA9IHNvcnRhYmxlLm9wdGlvbnMuX2hlbHBlcjtcblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gUHJldmVudCB0aGlzIFNvcnRhYmxlIGZyb20gcmVtb3ZpbmcgdGhlIGhlbHBlci5cblx0XHRcdFx0Ly8gSG93ZXZlciwgZG9uJ3Qgc2V0IHRoZSBkcmFnZ2FibGUgdG8gcmVtb3ZlIHRoZSBoZWxwZXJcblx0XHRcdFx0Ly8gZWl0aGVyIGFzIGFub3RoZXIgY29ubmVjdGVkIFNvcnRhYmxlIG1heSB5ZXQgaGFuZGxlIHRoZSByZW1vdmFsLlxuXHRcdFx0XHRzb3J0YWJsZS5jYW5jZWxIZWxwZXJSZW1vdmFsID0gdHJ1ZTtcblxuXHRcdFx0XHRzb3J0YWJsZS5fdHJpZ2dlciggXCJkZWFjdGl2YXRlXCIsIGV2ZW50LCB1aVNvcnRhYmxlICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXHRkcmFnOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBkcmFnZ2FibGUgKSB7XG5cdFx0JC5lYWNoKCBkcmFnZ2FibGUuc29ydGFibGVzLCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpbm5lcm1vc3RJbnRlcnNlY3RpbmcgPSBmYWxzZSxcblx0XHRcdFx0c29ydGFibGUgPSB0aGlzO1xuXG5cdFx0XHQvLyBDb3B5IG92ZXIgdmFyaWFibGVzIHRoYXQgc29ydGFibGUncyBfaW50ZXJzZWN0c1dpdGggdXNlc1xuXHRcdFx0c29ydGFibGUucG9zaXRpb25BYnMgPSBkcmFnZ2FibGUucG9zaXRpb25BYnM7XG5cdFx0XHRzb3J0YWJsZS5oZWxwZXJQcm9wb3J0aW9ucyA9IGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucztcblx0XHRcdHNvcnRhYmxlLm9mZnNldC5jbGljayA9IGRyYWdnYWJsZS5vZmZzZXQuY2xpY2s7XG5cblx0XHRcdGlmICggc29ydGFibGUuX2ludGVyc2VjdHNXaXRoKCBzb3J0YWJsZS5jb250YWluZXJDYWNoZSApICkge1xuXHRcdFx0XHRpbm5lcm1vc3RJbnRlcnNlY3RpbmcgPSB0cnVlO1xuXG5cdFx0XHRcdCQuZWFjaCggZHJhZ2dhYmxlLnNvcnRhYmxlcywgZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0XHQvLyBDb3B5IG92ZXIgdmFyaWFibGVzIHRoYXQgc29ydGFibGUncyBfaW50ZXJzZWN0c1dpdGggdXNlc1xuXHRcdFx0XHRcdHRoaXMucG9zaXRpb25BYnMgPSBkcmFnZ2FibGUucG9zaXRpb25BYnM7XG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucyA9IGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucztcblx0XHRcdFx0XHR0aGlzLm9mZnNldC5jbGljayA9IGRyYWdnYWJsZS5vZmZzZXQuY2xpY2s7XG5cblx0XHRcdFx0XHRpZiAoIHRoaXMgIT09IHNvcnRhYmxlICYmXG5cdFx0XHRcdFx0XHRcdHRoaXMuX2ludGVyc2VjdHNXaXRoKCB0aGlzLmNvbnRhaW5lckNhY2hlICkgJiZcblx0XHRcdFx0XHRcdFx0JC5jb250YWlucyggc29ydGFibGUuZWxlbWVudFsgMCBdLCB0aGlzLmVsZW1lbnRbIDAgXSApICkge1xuXHRcdFx0XHRcdFx0aW5uZXJtb3N0SW50ZXJzZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0cmV0dXJuIGlubmVybW9zdEludGVyc2VjdGluZztcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGlubmVybW9zdEludGVyc2VjdGluZyApIHtcblxuXHRcdFx0XHQvLyBJZiBpdCBpbnRlcnNlY3RzLCB3ZSB1c2UgYSBsaXR0bGUgaXNPdmVyIHZhcmlhYmxlIGFuZCBzZXQgaXQgb25jZSxcblx0XHRcdFx0Ly8gc28gdGhhdCB0aGUgbW92ZS1pbiBzdHVmZiBnZXRzIGZpcmVkIG9ubHkgb25jZS5cblx0XHRcdFx0aWYgKCAhc29ydGFibGUuaXNPdmVyICkge1xuXHRcdFx0XHRcdHNvcnRhYmxlLmlzT3ZlciA9IDE7XG5cblx0XHRcdFx0XHQvLyBTdG9yZSBkcmFnZ2FibGUncyBwYXJlbnQgaW4gY2FzZSB3ZSBuZWVkIHRvIHJlYXBwZW5kIHRvIGl0IGxhdGVyLlxuXHRcdFx0XHRcdGRyYWdnYWJsZS5fcGFyZW50ID0gdWkuaGVscGVyLnBhcmVudCgpO1xuXG5cdFx0XHRcdFx0c29ydGFibGUuY3VycmVudEl0ZW0gPSB1aS5oZWxwZXJcblx0XHRcdFx0XHRcdC5hcHBlbmRUbyggc29ydGFibGUuZWxlbWVudCApXG5cdFx0XHRcdFx0XHQuZGF0YSggXCJ1aS1zb3J0YWJsZS1pdGVtXCIsIHRydWUgKTtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGhlbHBlciBvcHRpb24gdG8gbGF0ZXIgcmVzdG9yZSBpdFxuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMuX2hlbHBlciA9IHNvcnRhYmxlLm9wdGlvbnMuaGVscGVyO1xuXG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5oZWxwZXIgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHJldHVybiB1aS5oZWxwZXJbIDAgXTtcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Ly8gRmlyZSB0aGUgc3RhcnQgZXZlbnRzIG9mIHRoZSBzb3J0YWJsZSB3aXRoIG91ciBwYXNzZWQgYnJvd3NlciBldmVudCxcblx0XHRcdFx0XHQvLyBhbmQgb3VyIG93biBoZWxwZXIgKHNvIGl0IGRvZXNuJ3QgY3JlYXRlIGEgbmV3IG9uZSlcblx0XHRcdFx0XHRldmVudC50YXJnZXQgPSBzb3J0YWJsZS5jdXJyZW50SXRlbVsgMCBdO1xuXHRcdFx0XHRcdHNvcnRhYmxlLl9tb3VzZUNhcHR1cmUoIGV2ZW50LCB0cnVlICk7XG5cdFx0XHRcdFx0c29ydGFibGUuX21vdXNlU3RhcnQoIGV2ZW50LCB0cnVlLCB0cnVlICk7XG5cblx0XHRcdFx0XHQvLyBCZWNhdXNlIHRoZSBicm93c2VyIGV2ZW50IGlzIHdheSBvZmYgdGhlIG5ldyBhcHBlbmRlZCBwb3J0bGV0LFxuXHRcdFx0XHRcdC8vIG1vZGlmeSBuZWNlc3NhcnkgdmFyaWFibGVzIHRvIHJlZmxlY3QgdGhlIGNoYW5nZXNcblx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQuY2xpY2sudG9wID0gZHJhZ2dhYmxlLm9mZnNldC5jbGljay50b3A7XG5cdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LmNsaWNrLmxlZnQgPSBkcmFnZ2FibGUub2Zmc2V0LmNsaWNrLmxlZnQ7XG5cdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LnBhcmVudC5sZWZ0IC09IGRyYWdnYWJsZS5vZmZzZXQucGFyZW50LmxlZnQgLVxuXHRcdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LnBhcmVudC5sZWZ0O1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5wYXJlbnQudG9wIC09IGRyYWdnYWJsZS5vZmZzZXQucGFyZW50LnRvcCAtXG5cdFx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQucGFyZW50LnRvcDtcblxuXHRcdFx0XHRcdGRyYWdnYWJsZS5fdHJpZ2dlciggXCJ0b1NvcnRhYmxlXCIsIGV2ZW50ICk7XG5cblx0XHRcdFx0XHQvLyBJbmZvcm0gZHJhZ2dhYmxlIHRoYXQgdGhlIGhlbHBlciBpcyBpbiBhIHZhbGlkIGRyb3Agem9uZSxcblx0XHRcdFx0XHQvLyB1c2VkIHNvbGVseSBpbiB0aGUgcmV2ZXJ0IG9wdGlvbiB0byBoYW5kbGUgXCJ2YWxpZC9pbnZhbGlkXCIuXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLmRyb3BwZWQgPSBzb3J0YWJsZS5lbGVtZW50O1xuXG5cdFx0XHRcdFx0Ly8gTmVlZCB0byByZWZyZXNoUG9zaXRpb25zIG9mIGFsbCBzb3J0YWJsZXMgaW4gdGhlIGNhc2UgdGhhdFxuXHRcdFx0XHRcdC8vIGFkZGluZyB0byBvbmUgc29ydGFibGUgY2hhbmdlcyB0aGUgbG9jYXRpb24gb2YgdGhlIG90aGVyIHNvcnRhYmxlcyAoIzk2NzUpXG5cdFx0XHRcdFx0JC5lYWNoKCBkcmFnZ2FibGUuc29ydGFibGVzLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHRoaXMucmVmcmVzaFBvc2l0aW9ucygpO1xuXHRcdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRcdC8vIEhhY2sgc28gcmVjZWl2ZS91cGRhdGUgY2FsbGJhY2tzIHdvcmsgKG1vc3RseSlcblx0XHRcdFx0XHRkcmFnZ2FibGUuY3VycmVudEl0ZW0gPSBkcmFnZ2FibGUuZWxlbWVudDtcblx0XHRcdFx0XHRzb3J0YWJsZS5mcm9tT3V0c2lkZSA9IGRyYWdnYWJsZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggc29ydGFibGUuY3VycmVudEl0ZW0gKSB7XG5cdFx0XHRcdFx0c29ydGFibGUuX21vdXNlRHJhZyggZXZlbnQgKTtcblxuXHRcdFx0XHRcdC8vIENvcHkgdGhlIHNvcnRhYmxlJ3MgcG9zaXRpb24gYmVjYXVzZSB0aGUgZHJhZ2dhYmxlJ3MgY2FuIHBvdGVudGlhbGx5IHJlZmxlY3Rcblx0XHRcdFx0XHQvLyBhIHJlbGF0aXZlIHBvc2l0aW9uLCB3aGlsZSBzb3J0YWJsZSBpcyBhbHdheXMgYWJzb2x1dGUsIHdoaWNoIHRoZSBkcmFnZ2VkXG5cdFx0XHRcdFx0Ly8gZWxlbWVudCBoYXMgbm93IGJlY29tZS4gKCM4ODA5KVxuXHRcdFx0XHRcdHVpLnBvc2l0aW9uID0gc29ydGFibGUucG9zaXRpb247XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gSWYgaXQgZG9lc24ndCBpbnRlcnNlY3Qgd2l0aCB0aGUgc29ydGFibGUsIGFuZCBpdCBpbnRlcnNlY3RlZCBiZWZvcmUsXG5cdFx0XHRcdC8vIHdlIGZha2UgdGhlIGRyYWcgc3RvcCBvZiB0aGUgc29ydGFibGUsIGJ1dCBtYWtlIHN1cmUgaXQgZG9lc24ndCByZW1vdmVcblx0XHRcdFx0Ly8gdGhlIGhlbHBlciBieSB1c2luZyBjYW5jZWxIZWxwZXJSZW1vdmFsLlxuXHRcdFx0XHRpZiAoIHNvcnRhYmxlLmlzT3ZlciApIHtcblxuXHRcdFx0XHRcdHNvcnRhYmxlLmlzT3ZlciA9IDA7XG5cdFx0XHRcdFx0c29ydGFibGUuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IHRydWU7XG5cblx0XHRcdFx0XHQvLyBDYWxsaW5nIHNvcnRhYmxlJ3MgbW91c2VTdG9wIHdvdWxkIHRyaWdnZXIgYSByZXZlcnQsXG5cdFx0XHRcdFx0Ly8gc28gcmV2ZXJ0IG11c3QgYmUgdGVtcG9yYXJpbHkgZmFsc2UgdW50aWwgYWZ0ZXIgbW91c2VTdG9wIGlzIGNhbGxlZC5cblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLl9yZXZlcnQgPSBzb3J0YWJsZS5vcHRpb25zLnJldmVydDtcblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLnJldmVydCA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0c29ydGFibGUuX3RyaWdnZXIoIFwib3V0XCIsIGV2ZW50LCBzb3J0YWJsZS5fdWlIYXNoKCBzb3J0YWJsZSApICk7XG5cdFx0XHRcdFx0c29ydGFibGUuX21vdXNlU3RvcCggZXZlbnQsIHRydWUgKTtcblxuXHRcdFx0XHRcdC8vIFJlc3RvcmUgc29ydGFibGUgYmVoYXZpb3JzIHRoYXQgd2VyZSBtb2RmaWVkXG5cdFx0XHRcdFx0Ly8gd2hlbiB0aGUgZHJhZ2dhYmxlIGVudGVyZWQgdGhlIHNvcnRhYmxlIGFyZWEgKCM5NDgxKVxuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMucmV2ZXJ0ID0gc29ydGFibGUub3B0aW9ucy5fcmV2ZXJ0O1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMuaGVscGVyID0gc29ydGFibGUub3B0aW9ucy5faGVscGVyO1xuXG5cdFx0XHRcdFx0aWYgKCBzb3J0YWJsZS5wbGFjZWhvbGRlciApIHtcblx0XHRcdFx0XHRcdHNvcnRhYmxlLnBsYWNlaG9sZGVyLnJlbW92ZSgpO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFJlc3RvcmUgYW5kIHJlY2FsY3VsYXRlIHRoZSBkcmFnZ2FibGUncyBvZmZzZXQgY29uc2lkZXJpbmcgdGhlIHNvcnRhYmxlXG5cdFx0XHRcdFx0Ly8gbWF5IGhhdmUgbW9kaWZpZWQgdGhlbSBpbiB1bmV4cGVjdGVkIHdheXMuICgjODgwOSwgIzEwNjY5KVxuXHRcdFx0XHRcdHVpLmhlbHBlci5hcHBlbmRUbyggZHJhZ2dhYmxlLl9wYXJlbnQgKTtcblx0XHRcdFx0XHRkcmFnZ2FibGUuX3JlZnJlc2hPZmZzZXRzKCBldmVudCApO1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uID0gZHJhZ2dhYmxlLl9nZW5lcmF0ZVBvc2l0aW9uKCBldmVudCwgdHJ1ZSApO1xuXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLl90cmlnZ2VyKCBcImZyb21Tb3J0YWJsZVwiLCBldmVudCApO1xuXG5cdFx0XHRcdFx0Ly8gSW5mb3JtIGRyYWdnYWJsZSB0aGF0IHRoZSBoZWxwZXIgaXMgbm8gbG9uZ2VyIGluIGEgdmFsaWQgZHJvcCB6b25lXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLmRyb3BwZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRcdC8vIE5lZWQgdG8gcmVmcmVzaFBvc2l0aW9ucyBvZiBhbGwgc29ydGFibGVzIGp1c3QgaW4gY2FzZSByZW1vdmluZ1xuXHRcdFx0XHRcdC8vIGZyb20gb25lIHNvcnRhYmxlIGNoYW5nZXMgdGhlIGxvY2F0aW9uIG9mIG90aGVyIHNvcnRhYmxlcyAoIzk2NzUpXG5cdFx0XHRcdFx0JC5lYWNoKCBkcmFnZ2FibGUuc29ydGFibGVzLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHRoaXMucmVmcmVzaFBvc2l0aW9ucygpO1xuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwiY3Vyc29yXCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciB0ID0gJCggXCJib2R5XCIgKSxcblx0XHRcdG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXG5cdFx0aWYgKCB0LmNzcyggXCJjdXJzb3JcIiApICkge1xuXHRcdFx0by5fY3Vyc29yID0gdC5jc3MoIFwiY3Vyc29yXCIgKTtcblx0XHR9XG5cdFx0dC5jc3MoIFwiY3Vyc29yXCIsIG8uY3Vyc29yICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciBvID0gaW5zdGFuY2Uub3B0aW9ucztcblx0XHRpZiAoIG8uX2N1cnNvciApIHtcblx0XHRcdCQoIFwiYm9keVwiICkuY3NzKCBcImN1cnNvclwiLCBvLl9jdXJzb3IgKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcIm9wYWNpdHlcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIHQgPSAkKCB1aS5oZWxwZXIgKSxcblx0XHRcdG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXHRcdGlmICggdC5jc3MoIFwib3BhY2l0eVwiICkgKSB7XG5cdFx0XHRvLl9vcGFjaXR5ID0gdC5jc3MoIFwib3BhY2l0eVwiICk7XG5cdFx0fVxuXHRcdHQuY3NzKCBcIm9wYWNpdHlcIiwgby5vcGFjaXR5ICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciBvID0gaW5zdGFuY2Uub3B0aW9ucztcblx0XHRpZiAoIG8uX29wYWNpdHkgKSB7XG5cdFx0XHQkKCB1aS5oZWxwZXIgKS5jc3MoIFwib3BhY2l0eVwiLCBvLl9vcGFjaXR5ICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJzY3JvbGxcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaSApIHtcblx0XHRpZiAoICFpLnNjcm9sbFBhcmVudE5vdEhpZGRlbiApIHtcblx0XHRcdGkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuID0gaS5oZWxwZXIuc2Nyb2xsUGFyZW50KCBmYWxzZSApO1xuXHRcdH1cblxuXHRcdGlmICggaS5zY3JvbGxQYXJlbnROb3RIaWRkZW5bIDAgXSAhPT0gaS5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdGkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuWyAwIF0udGFnTmFtZSAhPT0gXCJIVE1MXCIgKSB7XG5cdFx0XHRpLm92ZXJmbG93T2Zmc2V0ID0gaS5zY3JvbGxQYXJlbnROb3RIaWRkZW4ub2Zmc2V0KCk7XG5cdFx0fVxuXHR9LFxuXHRkcmFnOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpICApIHtcblxuXHRcdHZhciBvID0gaS5vcHRpb25zLFxuXHRcdFx0c2Nyb2xsZWQgPSBmYWxzZSxcblx0XHRcdHNjcm9sbFBhcmVudCA9IGkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuWyAwIF0sXG5cdFx0XHRkb2N1bWVudCA9IGkuZG9jdW1lbnRbIDAgXTtcblxuXHRcdGlmICggc2Nyb2xsUGFyZW50ICE9PSBkb2N1bWVudCAmJiBzY3JvbGxQYXJlbnQudGFnTmFtZSAhPT0gXCJIVE1MXCIgKSB7XG5cdFx0XHRpZiAoICFvLmF4aXMgfHwgby5heGlzICE9PSBcInhcIiApIHtcblx0XHRcdFx0aWYgKCAoIGkub3ZlcmZsb3dPZmZzZXQudG9wICsgc2Nyb2xsUGFyZW50Lm9mZnNldEhlaWdodCApIC0gZXZlbnQucGFnZVkgPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxQYXJlbnQuc2Nyb2xsVG9wID0gc2Nyb2xsZWQgPSBzY3JvbGxQYXJlbnQuc2Nyb2xsVG9wICsgby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fSBlbHNlIGlmICggZXZlbnQucGFnZVkgLSBpLm92ZXJmbG93T2Zmc2V0LnRvcCA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsUGFyZW50LnNjcm9sbFRvcCA9IHNjcm9sbGVkID0gc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCAtIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhby5heGlzIHx8IG8uYXhpcyAhPT0gXCJ5XCIgKSB7XG5cdFx0XHRcdGlmICggKCBpLm92ZXJmbG93T2Zmc2V0LmxlZnQgKyBzY3JvbGxQYXJlbnQub2Zmc2V0V2lkdGggKSAtIGV2ZW50LnBhZ2VYIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsUGFyZW50LnNjcm9sbExlZnQgPSBzY3JvbGxlZCA9IHNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0ICsgby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fSBlbHNlIGlmICggZXZlbnQucGFnZVggLSBpLm92ZXJmbG93T2Zmc2V0LmxlZnQgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0ID0gc2Nyb2xsZWQgPSBzY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCAtIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggIW8uYXhpcyB8fCBvLmF4aXMgIT09IFwieFwiICkge1xuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCggJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSAtIG8uc2Nyb2xsU3BlZWQgKTtcblx0XHRcdFx0fSBlbHNlIGlmICggJCggd2luZG93ICkuaGVpZ2h0KCkgLSAoIGV2ZW50LnBhZ2VZIC0gJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSApIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCggJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSArIG8uc2Nyb2xsU3BlZWQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFvLmF4aXMgfHwgby5heGlzICE9PSBcInlcIiApIHtcblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9ICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdChcblx0XHRcdFx0XHRcdCQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpIC0gby5zY3JvbGxTcGVlZFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoICQoIHdpbmRvdyApLndpZHRoKCkgLSAoIGV2ZW50LnBhZ2VYIC0gJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgKSA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KFxuXHRcdFx0XHRcdFx0JCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgKyBvLnNjcm9sbFNwZWVkXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBzY3JvbGxlZCAhPT0gZmFsc2UgJiYgJC51aS5kZG1hbmFnZXIgJiYgIW8uZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCBpLCBldmVudCApO1xuXHRcdH1cblxuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJzbmFwXCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGkgKSB7XG5cblx0XHR2YXIgbyA9IGkub3B0aW9ucztcblxuXHRcdGkuc25hcEVsZW1lbnRzID0gW107XG5cblx0XHQkKCBvLnNuYXAuY29uc3RydWN0b3IgIT09IFN0cmluZyA/ICggby5zbmFwLml0ZW1zIHx8IFwiOmRhdGEodWktZHJhZ2dhYmxlKVwiICkgOiBvLnNuYXAgKVxuXHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgJHQgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0JG8gPSAkdC5vZmZzZXQoKTtcblx0XHRcdFx0aWYgKCB0aGlzICE9PSBpLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdFx0XHRpLnNuYXBFbGVtZW50cy5wdXNoKCB7XG5cdFx0XHRcdFx0XHRpdGVtOiB0aGlzLFxuXHRcdFx0XHRcdFx0d2lkdGg6ICR0Lm91dGVyV2lkdGgoKSwgaGVpZ2h0OiAkdC5vdXRlckhlaWdodCgpLFxuXHRcdFx0XHRcdFx0dG9wOiAkby50b3AsIGxlZnQ6ICRvLmxlZnRcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHR9LFxuXHRkcmFnOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0ICkge1xuXG5cdFx0dmFyIHRzLCBicywgbHMsIHJzLCBsLCByLCB0LCBiLCBpLCBmaXJzdCxcblx0XHRcdG8gPSBpbnN0Lm9wdGlvbnMsXG5cdFx0XHRkID0gby5zbmFwVG9sZXJhbmNlLFxuXHRcdFx0eDEgPSB1aS5vZmZzZXQubGVmdCwgeDIgPSB4MSArIGluc3QuaGVscGVyUHJvcG9ydGlvbnMud2lkdGgsXG5cdFx0XHR5MSA9IHVpLm9mZnNldC50b3AsIHkyID0geTEgKyBpbnN0LmhlbHBlclByb3BvcnRpb25zLmhlaWdodDtcblxuXHRcdGZvciAoIGkgPSBpbnN0LnNuYXBFbGVtZW50cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblxuXHRcdFx0bCA9IGluc3Quc25hcEVsZW1lbnRzWyBpIF0ubGVmdCAtIGluc3QubWFyZ2lucy5sZWZ0O1xuXHRcdFx0ciA9IGwgKyBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLndpZHRoO1xuXHRcdFx0dCA9IGluc3Quc25hcEVsZW1lbnRzWyBpIF0udG9wIC0gaW5zdC5tYXJnaW5zLnRvcDtcblx0XHRcdGIgPSB0ICsgaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5oZWlnaHQ7XG5cblx0XHRcdGlmICggeDIgPCBsIC0gZCB8fCB4MSA+IHIgKyBkIHx8IHkyIDwgdCAtIGQgfHwgeTEgPiBiICsgZCB8fFxuXHRcdFx0XHRcdCEkLmNvbnRhaW5zKCBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLml0ZW0ub3duZXJEb2N1bWVudCxcblx0XHRcdFx0XHRpbnN0LnNuYXBFbGVtZW50c1sgaSBdLml0ZW0gKSApIHtcblx0XHRcdFx0aWYgKCBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLnNuYXBwaW5nICkge1xuXHRcdFx0XHRcdCggaW5zdC5vcHRpb25zLnNuYXAucmVsZWFzZSAmJlxuXHRcdFx0XHRcdFx0aW5zdC5vcHRpb25zLnNuYXAucmVsZWFzZS5jYWxsKFxuXHRcdFx0XHRcdFx0XHRpbnN0LmVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdGV2ZW50LFxuXHRcdFx0XHRcdFx0XHQkLmV4dGVuZCggaW5zdC5fdWlIYXNoKCksIHsgc25hcEl0ZW06IGluc3Quc25hcEVsZW1lbnRzWyBpIF0uaXRlbSB9IClcblx0XHRcdFx0XHRcdCkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpbnN0LnNuYXBFbGVtZW50c1sgaSBdLnNuYXBwaW5nID0gZmFsc2U7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG8uc25hcE1vZGUgIT09IFwiaW5uZXJcIiApIHtcblx0XHRcdFx0dHMgPSBNYXRoLmFicyggdCAtIHkyICkgPD0gZDtcblx0XHRcdFx0YnMgPSBNYXRoLmFicyggYiAtIHkxICkgPD0gZDtcblx0XHRcdFx0bHMgPSBNYXRoLmFicyggbCAtIHgyICkgPD0gZDtcblx0XHRcdFx0cnMgPSBNYXRoLmFicyggciAtIHgxICkgPD0gZDtcblx0XHRcdFx0aWYgKCB0cyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi50b3AgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IHQgLSBpbnN0LmhlbHBlclByb3BvcnRpb25zLmhlaWdodCxcblx0XHRcdFx0XHRcdGxlZnQ6IDBcblx0XHRcdFx0XHR9ICkudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggYnMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24udG9wID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiBiLFxuXHRcdFx0XHRcdFx0bGVmdDogMFxuXHRcdFx0XHRcdH0gKS50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBscyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi5sZWZ0ID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRcdFx0bGVmdDogbCAtIGluc3QuaGVscGVyUHJvcG9ydGlvbnMud2lkdGhcblx0XHRcdFx0XHR9ICkubGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHJzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLmxlZnQgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0XHRsZWZ0OiByXG5cdFx0XHRcdFx0fSApLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Zmlyc3QgPSAoIHRzIHx8IGJzIHx8IGxzIHx8IHJzICk7XG5cblx0XHRcdGlmICggby5zbmFwTW9kZSAhPT0gXCJvdXRlclwiICkge1xuXHRcdFx0XHR0cyA9IE1hdGguYWJzKCB0IC0geTEgKSA8PSBkO1xuXHRcdFx0XHRicyA9IE1hdGguYWJzKCBiIC0geTIgKSA8PSBkO1xuXHRcdFx0XHRscyA9IE1hdGguYWJzKCBsIC0geDEgKSA8PSBkO1xuXHRcdFx0XHRycyA9IE1hdGguYWJzKCByIC0geDIgKSA8PSBkO1xuXHRcdFx0XHRpZiAoIHRzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLnRvcCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogdCxcblx0XHRcdFx0XHRcdGxlZnQ6IDBcblx0XHRcdFx0XHR9ICkudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggYnMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24udG9wID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiBiIC0gaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQsXG5cdFx0XHRcdFx0XHRsZWZ0OiAwXG5cdFx0XHRcdFx0fSApLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGxzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLmxlZnQgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0XHRsZWZ0OiBsXG5cdFx0XHRcdFx0fSApLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBycyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi5sZWZ0ID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRcdFx0bGVmdDogciAtIGluc3QuaGVscGVyUHJvcG9ydGlvbnMud2lkdGhcblx0XHRcdFx0XHR9ICkubGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFpbnN0LnNuYXBFbGVtZW50c1sgaSBdLnNuYXBwaW5nICYmICggdHMgfHwgYnMgfHwgbHMgfHwgcnMgfHwgZmlyc3QgKSApIHtcblx0XHRcdFx0KCBpbnN0Lm9wdGlvbnMuc25hcC5zbmFwICYmXG5cdFx0XHRcdFx0aW5zdC5vcHRpb25zLnNuYXAuc25hcC5jYWxsKFxuXHRcdFx0XHRcdFx0aW5zdC5lbGVtZW50LFxuXHRcdFx0XHRcdFx0ZXZlbnQsXG5cdFx0XHRcdFx0XHQkLmV4dGVuZCggaW5zdC5fdWlIYXNoKCksIHtcblx0XHRcdFx0XHRcdFx0c25hcEl0ZW06IGluc3Quc25hcEVsZW1lbnRzWyBpIF0uaXRlbVxuXHRcdFx0XHRcdFx0fSApICkgKTtcblx0XHRcdH1cblx0XHRcdGluc3Quc25hcEVsZW1lbnRzWyBpIF0uc25hcHBpbmcgPSAoIHRzIHx8IGJzIHx8IGxzIHx8IHJzIHx8IGZpcnN0ICk7XG5cblx0XHR9XG5cblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwic3RhY2tcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIG1pbixcblx0XHRcdG8gPSBpbnN0YW5jZS5vcHRpb25zLFxuXHRcdFx0Z3JvdXAgPSAkLm1ha2VBcnJheSggJCggby5zdGFjayApICkuc29ydCggZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0XHRcdHJldHVybiAoIHBhcnNlSW50KCAkKCBhICkuY3NzKCBcInpJbmRleFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBiICkuY3NzKCBcInpJbmRleFwiICksIDEwICkgfHwgMCApO1xuXHRcdFx0fSApO1xuXG5cdFx0aWYgKCAhZ3JvdXAubGVuZ3RoICkgeyByZXR1cm47IH1cblxuXHRcdG1pbiA9IHBhcnNlSW50KCAkKCBncm91cFsgMCBdICkuY3NzKCBcInpJbmRleFwiICksIDEwICkgfHwgMDtcblx0XHQkKCBncm91cCApLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0JCggdGhpcyApLmNzcyggXCJ6SW5kZXhcIiwgbWluICsgaSApO1xuXHRcdH0gKTtcblx0XHR0aGlzLmNzcyggXCJ6SW5kZXhcIiwgKCBtaW4gKyBncm91cC5sZW5ndGggKSApO1xuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJ6SW5kZXhcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIHQgPSAkKCB1aS5oZWxwZXIgKSxcblx0XHRcdG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXG5cdFx0aWYgKCB0LmNzcyggXCJ6SW5kZXhcIiApICkge1xuXHRcdFx0by5fekluZGV4ID0gdC5jc3MoIFwiekluZGV4XCIgKTtcblx0XHR9XG5cdFx0dC5jc3MoIFwiekluZGV4XCIsIG8uekluZGV4ICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciBvID0gaW5zdGFuY2Uub3B0aW9ucztcblxuXHRcdGlmICggby5fekluZGV4ICkge1xuXHRcdFx0JCggdWkuaGVscGVyICkuY3NzKCBcInpJbmRleFwiLCBvLl96SW5kZXggKTtcblx0XHR9XG5cdH1cbn0gKTtcblxudmFyIHdpZGdldHNEcmFnZ2FibGUgPSAkLnVpLmRyYWdnYWJsZTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBSZXNpemFibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFJlc2l6YWJsZVxuLy8+Pmdyb3VwOiBJbnRlcmFjdGlvbnNcbi8vPj5kZXNjcmlwdGlvbjogRW5hYmxlcyByZXNpemUgZnVuY3Rpb25hbGl0eSBmb3IgYW55IGVsZW1lbnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcmVzaXphYmxlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3Jlc2l6YWJsZS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3Jlc2l6YWJsZS5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkucmVzaXphYmxlXCIsICQudWkubW91c2UsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwicmVzaXplXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhbHNvUmVzaXplOiBmYWxzZSxcblx0XHRhbmltYXRlOiBmYWxzZSxcblx0XHRhbmltYXRlRHVyYXRpb246IFwic2xvd1wiLFxuXHRcdGFuaW1hdGVFYXNpbmc6IFwic3dpbmdcIixcblx0XHRhc3BlY3RSYXRpbzogZmFsc2UsXG5cdFx0YXV0b0hpZGU6IGZhbHNlLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktcmVzaXphYmxlLXNlXCI6IFwidWktaWNvbiB1aS1pY29uLWdyaXBzbWFsbC1kaWFnb25hbC1zZVwiXG5cdFx0fSxcblx0XHRjb250YWlubWVudDogZmFsc2UsXG5cdFx0Z2hvc3Q6IGZhbHNlLFxuXHRcdGdyaWQ6IGZhbHNlLFxuXHRcdGhhbmRsZXM6IFwiZSxzLHNlXCIsXG5cdFx0aGVscGVyOiBmYWxzZSxcblx0XHRtYXhIZWlnaHQ6IG51bGwsXG5cdFx0bWF4V2lkdGg6IG51bGwsXG5cdFx0bWluSGVpZ2h0OiAxMCxcblx0XHRtaW5XaWR0aDogMTAsXG5cblx0XHQvLyBTZWUgIzc5NjBcblx0XHR6SW5kZXg6IDkwLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0cmVzaXplOiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGxcblx0fSxcblxuXHRfbnVtOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0cmV0dXJuIHBhcnNlRmxvYXQoIHZhbHVlICkgfHwgMDtcblx0fSxcblxuXHRfaXNOdW1iZXI6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gIWlzTmFOKCBwYXJzZUZsb2F0KCB2YWx1ZSApICk7XG5cdH0sXG5cblx0X2hhc1Njcm9sbDogZnVuY3Rpb24oIGVsLCBhICkge1xuXG5cdFx0aWYgKCAkKCBlbCApLmNzcyggXCJvdmVyZmxvd1wiICkgPT09IFwiaGlkZGVuXCIgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dmFyIHNjcm9sbCA9ICggYSAmJiBhID09PSBcImxlZnRcIiApID8gXCJzY3JvbGxMZWZ0XCIgOiBcInNjcm9sbFRvcFwiLFxuXHRcdFx0aGFzID0gZmFsc2U7XG5cblx0XHRpZiAoIGVsWyBzY3JvbGwgXSA+IDAgKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHQvLyBUT0RPOiBkZXRlcm1pbmUgd2hpY2ggY2FzZXMgYWN0dWFsbHkgY2F1c2UgdGhpcyB0byBoYXBwZW5cblx0XHQvLyBpZiB0aGUgZWxlbWVudCBkb2Vzbid0IGhhdmUgdGhlIHNjcm9sbCBzZXQsIHNlZSBpZiBpdCdzIHBvc3NpYmxlIHRvXG5cdFx0Ly8gc2V0IHRoZSBzY3JvbGxcblx0XHRlbFsgc2Nyb2xsIF0gPSAxO1xuXHRcdGhhcyA9ICggZWxbIHNjcm9sbCBdID4gMCApO1xuXHRcdGVsWyBzY3JvbGwgXSA9IDA7XG5cdFx0cmV0dXJuIGhhcztcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBtYXJnaW5zLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHRoYXQgPSB0aGlzO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXJlc2l6YWJsZVwiICk7XG5cblx0XHQkLmV4dGVuZCggdGhpcywge1xuXHRcdFx0X2FzcGVjdFJhdGlvOiAhISggby5hc3BlY3RSYXRpbyApLFxuXHRcdFx0YXNwZWN0UmF0aW86IG8uYXNwZWN0UmF0aW8sXG5cdFx0XHRvcmlnaW5hbEVsZW1lbnQ6IHRoaXMuZWxlbWVudCxcblx0XHRcdF9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzOiBbXSxcblx0XHRcdF9oZWxwZXI6IG8uaGVscGVyIHx8IG8uZ2hvc3QgfHwgby5hbmltYXRlID8gby5oZWxwZXIgfHwgXCJ1aS1yZXNpemFibGUtaGVscGVyXCIgOiBudWxsXG5cdFx0fSApO1xuXG5cdFx0Ly8gV3JhcCB0aGUgZWxlbWVudCBpZiBpdCBjYW5ub3QgaG9sZCBjaGlsZCBub2Rlc1xuXHRcdGlmICggdGhpcy5lbGVtZW50WyAwIF0ubm9kZU5hbWUubWF0Y2goIC9eKGNhbnZhc3x0ZXh0YXJlYXxpbnB1dHxzZWxlY3R8YnV0dG9ufGltZykkL2kgKSApIHtcblxuXHRcdFx0dGhpcy5lbGVtZW50LndyYXAoXG5cdFx0XHRcdCQoIFwiPGRpdiBjbGFzcz0ndWktd3JhcHBlcicgc3R5bGU9J292ZXJmbG93OiBoaWRkZW47Jz48L2Rpdj5cIiApLmNzcygge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiB0aGlzLmVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdFx0XHR3aWR0aDogdGhpcy5lbGVtZW50Lm91dGVyV2lkdGgoKSxcblx0XHRcdFx0XHRoZWlnaHQ6IHRoaXMuZWxlbWVudC5vdXRlckhlaWdodCgpLFxuXHRcdFx0XHRcdHRvcDogdGhpcy5lbGVtZW50LmNzcyggXCJ0b3BcIiApLFxuXHRcdFx0XHRcdGxlZnQ6IHRoaXMuZWxlbWVudC5jc3MoIFwibGVmdFwiIClcblx0XHRcdFx0fSApXG5cdFx0XHQpO1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQgPSB0aGlzLmVsZW1lbnQucGFyZW50KCkuZGF0YShcblx0XHRcdFx0XCJ1aS1yZXNpemFibGVcIiwgdGhpcy5lbGVtZW50LnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiIClcblx0XHRcdCk7XG5cblx0XHRcdHRoaXMuZWxlbWVudElzV3JhcHBlciA9IHRydWU7XG5cblx0XHRcdG1hcmdpbnMgPSB7XG5cdFx0XHRcdG1hcmdpblRvcDogdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcIm1hcmdpblRvcFwiICksXG5cdFx0XHRcdG1hcmdpblJpZ2h0OiB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwibWFyZ2luUmlnaHRcIiApLFxuXHRcdFx0XHRtYXJnaW5Cb3R0b206IHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJtYXJnaW5Cb3R0b21cIiApLFxuXHRcdFx0XHRtYXJnaW5MZWZ0OiB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwibWFyZ2luTGVmdFwiIClcblx0XHRcdH07XG5cblx0XHRcdHRoaXMuZWxlbWVudC5jc3MoIG1hcmdpbnMgKTtcblx0XHRcdHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJtYXJnaW5cIiwgMCApO1xuXG5cdFx0XHQvLyBzdXBwb3J0OiBTYWZhcmlcblx0XHRcdC8vIFByZXZlbnQgU2FmYXJpIHRleHRhcmVhIHJlc2l6ZVxuXHRcdFx0dGhpcy5vcmlnaW5hbFJlc2l6ZVN0eWxlID0gdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcInJlc2l6ZVwiICk7XG5cdFx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwicmVzaXplXCIsIFwibm9uZVwiICk7XG5cblx0XHRcdHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHMucHVzaCggdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCB7XG5cdFx0XHRcdHBvc2l0aW9uOiBcInN0YXRpY1wiLFxuXHRcdFx0XHR6b29tOiAxLFxuXHRcdFx0XHRkaXNwbGF5OiBcImJsb2NrXCJcblx0XHRcdH0gKSApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTlcblx0XHRcdC8vIGF2b2lkIElFIGp1bXAgKGhhcmQgc2V0IHRoZSBtYXJnaW4pXG5cdFx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIG1hcmdpbnMgKTtcblxuXHRcdFx0dGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemUoKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zZXR1cEhhbmRsZXMoKTtcblxuXHRcdGlmICggby5hdXRvSGlkZSApIHtcblx0XHRcdCQoIHRoaXMuZWxlbWVudCApXG5cdFx0XHRcdC5vbiggXCJtb3VzZWVudGVyXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggby5kaXNhYmxlZCApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIFwidWktcmVzaXphYmxlLWF1dG9oaWRlXCIgKTtcblx0XHRcdFx0XHR0aGF0Ll9oYW5kbGVzLnNob3coKTtcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5vbiggXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggby5kaXNhYmxlZCApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCAhdGhhdC5yZXNpemluZyApIHtcblx0XHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBcInVpLXJlc2l6YWJsZS1hdXRvaGlkZVwiICk7XG5cdFx0XHRcdFx0XHR0aGF0Ll9oYW5kbGVzLmhpZGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9tb3VzZUluaXQoKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cblx0XHR0aGlzLl9tb3VzZURlc3Ryb3koKTtcblxuXHRcdHZhciB3cmFwcGVyLFxuXHRcdFx0X2Rlc3Ryb3kgPSBmdW5jdGlvbiggZXhwICkge1xuXHRcdFx0XHQkKCBleHAgKVxuXHRcdFx0XHRcdC5yZW1vdmVEYXRhKCBcInJlc2l6YWJsZVwiIClcblx0XHRcdFx0XHQucmVtb3ZlRGF0YSggXCJ1aS1yZXNpemFibGVcIiApXG5cdFx0XHRcdFx0Lm9mZiggXCIucmVzaXphYmxlXCIgKVxuXHRcdFx0XHRcdC5maW5kKCBcIi51aS1yZXNpemFibGUtaGFuZGxlXCIgKVxuXHRcdFx0XHRcdFx0LnJlbW92ZSgpO1xuXHRcdFx0fTtcblxuXHRcdC8vIFRPRE86IFVud3JhcCBhdCBzYW1lIERPTSBwb3NpdGlvblxuXHRcdGlmICggdGhpcy5lbGVtZW50SXNXcmFwcGVyICkge1xuXHRcdFx0X2Rlc3Ryb3koIHRoaXMuZWxlbWVudCApO1xuXHRcdFx0d3JhcHBlciA9IHRoaXMuZWxlbWVudDtcblx0XHRcdHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcygge1xuXHRcdFx0XHRwb3NpdGlvbjogd3JhcHBlci5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0XHR3aWR0aDogd3JhcHBlci5vdXRlcldpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogd3JhcHBlci5vdXRlckhlaWdodCgpLFxuXHRcdFx0XHR0b3A6IHdyYXBwZXIuY3NzKCBcInRvcFwiICksXG5cdFx0XHRcdGxlZnQ6IHdyYXBwZXIuY3NzKCBcImxlZnRcIiApXG5cdFx0XHR9ICkuaW5zZXJ0QWZ0ZXIoIHdyYXBwZXIgKTtcblx0XHRcdHdyYXBwZXIucmVtb3ZlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcInJlc2l6ZVwiLCB0aGlzLm9yaWdpbmFsUmVzaXplU3R5bGUgKTtcblx0XHRfZGVzdHJveSggdGhpcy5vcmlnaW5hbEVsZW1lbnQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRzd2l0Y2ggKCBrZXkgKSB7XG5cdFx0Y2FzZSBcImhhbmRsZXNcIjpcblx0XHRcdHRoaXMuX3JlbW92ZUhhbmRsZXMoKTtcblx0XHRcdHRoaXMuX3NldHVwSGFuZGxlcygpO1xuXHRcdFx0YnJlYWs7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdGJyZWFrO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0dXBIYW5kbGVzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbyA9IHRoaXMub3B0aW9ucywgaGFuZGxlLCBpLCBuLCBobmFtZSwgYXhpcywgdGhhdCA9IHRoaXM7XG5cdFx0dGhpcy5oYW5kbGVzID0gby5oYW5kbGVzIHx8XG5cdFx0XHQoICEkKCBcIi51aS1yZXNpemFibGUtaGFuZGxlXCIsIHRoaXMuZWxlbWVudCApLmxlbmd0aCA/XG5cdFx0XHRcdFwiZSxzLHNlXCIgOiB7XG5cdFx0XHRcdFx0bjogXCIudWktcmVzaXphYmxlLW5cIixcblx0XHRcdFx0XHRlOiBcIi51aS1yZXNpemFibGUtZVwiLFxuXHRcdFx0XHRcdHM6IFwiLnVpLXJlc2l6YWJsZS1zXCIsXG5cdFx0XHRcdFx0dzogXCIudWktcmVzaXphYmxlLXdcIixcblx0XHRcdFx0XHRzZTogXCIudWktcmVzaXphYmxlLXNlXCIsXG5cdFx0XHRcdFx0c3c6IFwiLnVpLXJlc2l6YWJsZS1zd1wiLFxuXHRcdFx0XHRcdG5lOiBcIi51aS1yZXNpemFibGUtbmVcIixcblx0XHRcdFx0XHRudzogXCIudWktcmVzaXphYmxlLW53XCJcblx0XHRcdFx0fSApO1xuXG5cdFx0dGhpcy5faGFuZGxlcyA9ICQoKTtcblx0XHRpZiAoIHRoaXMuaGFuZGxlcy5jb25zdHJ1Y3RvciA9PT0gU3RyaW5nICkge1xuXG5cdFx0XHRpZiAoIHRoaXMuaGFuZGxlcyA9PT0gXCJhbGxcIiApIHtcblx0XHRcdFx0dGhpcy5oYW5kbGVzID0gXCJuLGUscyx3LHNlLHN3LG5lLG53XCI7XG5cdFx0XHR9XG5cblx0XHRcdG4gPSB0aGlzLmhhbmRsZXMuc3BsaXQoIFwiLFwiICk7XG5cdFx0XHR0aGlzLmhhbmRsZXMgPSB7fTtcblxuXHRcdFx0Zm9yICggaSA9IDA7IGkgPCBuLmxlbmd0aDsgaSsrICkge1xuXG5cdFx0XHRcdGhhbmRsZSA9ICQudHJpbSggblsgaSBdICk7XG5cdFx0XHRcdGhuYW1lID0gXCJ1aS1yZXNpemFibGUtXCIgKyBoYW5kbGU7XG5cdFx0XHRcdGF4aXMgPSAkKCBcIjxkaXY+XCIgKTtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGF4aXMsIFwidWktcmVzaXphYmxlLWhhbmRsZSBcIiArIGhuYW1lICk7XG5cblx0XHRcdFx0YXhpcy5jc3MoIHsgekluZGV4OiBvLnpJbmRleCB9ICk7XG5cblx0XHRcdFx0dGhpcy5oYW5kbGVzWyBoYW5kbGUgXSA9IFwiLnVpLXJlc2l6YWJsZS1cIiArIGhhbmRsZTtcblx0XHRcdFx0dGhpcy5lbGVtZW50LmFwcGVuZCggYXhpcyApO1xuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVuZGVyQXhpcyA9IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cblx0XHRcdHZhciBpLCBheGlzLCBwYWRQb3MsIHBhZFdyYXBwZXI7XG5cblx0XHRcdHRhcmdldCA9IHRhcmdldCB8fCB0aGlzLmVsZW1lbnQ7XG5cblx0XHRcdGZvciAoIGkgaW4gdGhpcy5oYW5kbGVzICkge1xuXG5cdFx0XHRcdGlmICggdGhpcy5oYW5kbGVzWyBpIF0uY29uc3RydWN0b3IgPT09IFN0cmluZyApIHtcblx0XHRcdFx0XHR0aGlzLmhhbmRsZXNbIGkgXSA9IHRoaXMuZWxlbWVudC5jaGlsZHJlbiggdGhpcy5oYW5kbGVzWyBpIF0gKS5maXJzdCgpLnNob3coKTtcblx0XHRcdFx0fSBlbHNlIGlmICggdGhpcy5oYW5kbGVzWyBpIF0uanF1ZXJ5IHx8IHRoaXMuaGFuZGxlc1sgaSBdLm5vZGVUeXBlICkge1xuXHRcdFx0XHRcdHRoaXMuaGFuZGxlc1sgaSBdID0gJCggdGhpcy5oYW5kbGVzWyBpIF0gKTtcblx0XHRcdFx0XHR0aGlzLl9vbiggdGhpcy5oYW5kbGVzWyBpIF0sIHsgXCJtb3VzZWRvd25cIjogdGhhdC5fbW91c2VEb3duIH0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggdGhpcy5lbGVtZW50SXNXcmFwcGVyICYmXG5cdFx0XHRcdFx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudFsgMCBdXG5cdFx0XHRcdFx0XHRcdC5ub2RlTmFtZVxuXHRcdFx0XHRcdFx0XHQubWF0Y2goIC9eKHRleHRhcmVhfGlucHV0fHNlbGVjdHxidXR0b24pJC9pICkgKSB7XG5cdFx0XHRcdFx0YXhpcyA9ICQoIHRoaXMuaGFuZGxlc1sgaSBdLCB0aGlzLmVsZW1lbnQgKTtcblxuXHRcdFx0XHRcdHBhZFdyYXBwZXIgPSAvc3d8bmV8bnd8c2V8bnxzLy50ZXN0KCBpICkgP1xuXHRcdFx0XHRcdFx0YXhpcy5vdXRlckhlaWdodCgpIDpcblx0XHRcdFx0XHRcdGF4aXMub3V0ZXJXaWR0aCgpO1xuXG5cdFx0XHRcdFx0cGFkUG9zID0gWyBcInBhZGRpbmdcIixcblx0XHRcdFx0XHRcdC9uZXxud3xuLy50ZXN0KCBpICkgPyBcIlRvcFwiIDpcblx0XHRcdFx0XHRcdC9zZXxzd3xzLy50ZXN0KCBpICkgPyBcIkJvdHRvbVwiIDpcblx0XHRcdFx0XHRcdC9eZSQvLnRlc3QoIGkgKSA/IFwiUmlnaHRcIiA6IFwiTGVmdFwiIF0uam9pbiggXCJcIiApO1xuXG5cdFx0XHRcdFx0dGFyZ2V0LmNzcyggcGFkUG9zLCBwYWRXcmFwcGVyICk7XG5cblx0XHRcdFx0XHR0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZSgpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5faGFuZGxlcyA9IHRoaXMuX2hhbmRsZXMuYWRkKCB0aGlzLmhhbmRsZXNbIGkgXSApO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvLyBUT0RPOiBtYWtlIHJlbmRlckF4aXMgYSBwcm90b3R5cGUgZnVuY3Rpb25cblx0XHR0aGlzLl9yZW5kZXJBeGlzKCB0aGlzLmVsZW1lbnQgKTtcblxuXHRcdHRoaXMuX2hhbmRsZXMgPSB0aGlzLl9oYW5kbGVzLmFkZCggdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLXJlc2l6YWJsZS1oYW5kbGVcIiApICk7XG5cdFx0dGhpcy5faGFuZGxlcy5kaXNhYmxlU2VsZWN0aW9uKCk7XG5cblx0XHR0aGlzLl9oYW5kbGVzLm9uKCBcIm1vdXNlb3ZlclwiLCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggIXRoYXQucmVzaXppbmcgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5jbGFzc05hbWUgKSB7XG5cdFx0XHRcdFx0YXhpcyA9IHRoaXMuY2xhc3NOYW1lLm1hdGNoKCAvdWktcmVzaXphYmxlLShzZXxzd3xuZXxud3xufGV8c3x3KS9pICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhhdC5heGlzID0gYXhpcyAmJiBheGlzWyAxIF0gPyBheGlzWyAxIF0gOiBcInNlXCI7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0aWYgKCBvLmF1dG9IaWRlICkge1xuXHRcdFx0dGhpcy5faGFuZGxlcy5oaWRlKCk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1yZXNpemFibGUtYXV0b2hpZGVcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfcmVtb3ZlSGFuZGxlczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5faGFuZGxlcy5yZW1vdmUoKTtcblx0fSxcblxuXHRfbW91c2VDYXB0dXJlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGksIGhhbmRsZSxcblx0XHRcdGNhcHR1cmUgPSBmYWxzZTtcblxuXHRcdGZvciAoIGkgaW4gdGhpcy5oYW5kbGVzICkge1xuXHRcdFx0aGFuZGxlID0gJCggdGhpcy5oYW5kbGVzWyBpIF0gKVsgMCBdO1xuXHRcdFx0aWYgKCBoYW5kbGUgPT09IGV2ZW50LnRhcmdldCB8fCAkLmNvbnRhaW5zKCBoYW5kbGUsIGV2ZW50LnRhcmdldCApICkge1xuXHRcdFx0XHRjYXB0dXJlID0gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gIXRoaXMub3B0aW9ucy5kaXNhYmxlZCAmJiBjYXB0dXJlO1xuXHR9LFxuXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgY3VybGVmdCwgY3VydG9wLCBjdXJzb3IsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0ZWwgPSB0aGlzLmVsZW1lbnQ7XG5cblx0XHR0aGlzLnJlc2l6aW5nID0gdHJ1ZTtcblxuXHRcdHRoaXMuX3JlbmRlclByb3h5KCk7XG5cblx0XHRjdXJsZWZ0ID0gdGhpcy5fbnVtKCB0aGlzLmhlbHBlci5jc3MoIFwibGVmdFwiICkgKTtcblx0XHRjdXJ0b3AgPSB0aGlzLl9udW0oIHRoaXMuaGVscGVyLmNzcyggXCJ0b3BcIiApICk7XG5cblx0XHRpZiAoIG8uY29udGFpbm1lbnQgKSB7XG5cdFx0XHRjdXJsZWZ0ICs9ICQoIG8uY29udGFpbm1lbnQgKS5zY3JvbGxMZWZ0KCkgfHwgMDtcblx0XHRcdGN1cnRvcCArPSAkKCBvLmNvbnRhaW5tZW50ICkuc2Nyb2xsVG9wKCkgfHwgMDtcblx0XHR9XG5cblx0XHR0aGlzLm9mZnNldCA9IHRoaXMuaGVscGVyLm9mZnNldCgpO1xuXHRcdHRoaXMucG9zaXRpb24gPSB7IGxlZnQ6IGN1cmxlZnQsIHRvcDogY3VydG9wIH07XG5cblx0XHR0aGlzLnNpemUgPSB0aGlzLl9oZWxwZXIgPyB7XG5cdFx0XHRcdHdpZHRoOiB0aGlzLmhlbHBlci53aWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IHRoaXMuaGVscGVyLmhlaWdodCgpXG5cdFx0XHR9IDoge1xuXHRcdFx0XHR3aWR0aDogZWwud2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiBlbC5oZWlnaHQoKVxuXHRcdFx0fTtcblxuXHRcdHRoaXMub3JpZ2luYWxTaXplID0gdGhpcy5faGVscGVyID8ge1xuXHRcdFx0XHR3aWR0aDogZWwub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IGVsLm91dGVySGVpZ2h0KClcblx0XHRcdH0gOiB7XG5cdFx0XHRcdHdpZHRoOiBlbC53aWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IGVsLmhlaWdodCgpXG5cdFx0XHR9O1xuXG5cdFx0dGhpcy5zaXplRGlmZiA9IHtcblx0XHRcdHdpZHRoOiBlbC5vdXRlcldpZHRoKCkgLSBlbC53aWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiBlbC5vdXRlckhlaWdodCgpIC0gZWwuaGVpZ2h0KClcblx0XHR9O1xuXG5cdFx0dGhpcy5vcmlnaW5hbFBvc2l0aW9uID0geyBsZWZ0OiBjdXJsZWZ0LCB0b3A6IGN1cnRvcCB9O1xuXHRcdHRoaXMub3JpZ2luYWxNb3VzZVBvc2l0aW9uID0geyBsZWZ0OiBldmVudC5wYWdlWCwgdG9wOiBldmVudC5wYWdlWSB9O1xuXG5cdFx0dGhpcy5hc3BlY3RSYXRpbyA9ICggdHlwZW9mIG8uYXNwZWN0UmF0aW8gPT09IFwibnVtYmVyXCIgKSA/XG5cdFx0XHRvLmFzcGVjdFJhdGlvIDpcblx0XHRcdCggKCB0aGlzLm9yaWdpbmFsU2l6ZS53aWR0aCAvIHRoaXMub3JpZ2luYWxTaXplLmhlaWdodCApIHx8IDEgKTtcblxuXHRcdGN1cnNvciA9ICQoIFwiLnVpLXJlc2l6YWJsZS1cIiArIHRoaXMuYXhpcyApLmNzcyggXCJjdXJzb3JcIiApO1xuXHRcdCQoIFwiYm9keVwiICkuY3NzKCBcImN1cnNvclwiLCBjdXJzb3IgPT09IFwiYXV0b1wiID8gdGhpcy5heGlzICsgXCItcmVzaXplXCIgOiBjdXJzb3IgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXJlc2l6YWJsZS1yZXNpemluZ1wiICk7XG5cdFx0dGhpcy5fcHJvcGFnYXRlKCBcInN0YXJ0XCIsIGV2ZW50ICk7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIGRhdGEsIHByb3BzLFxuXHRcdFx0c21wID0gdGhpcy5vcmlnaW5hbE1vdXNlUG9zaXRpb24sXG5cdFx0XHRhID0gdGhpcy5heGlzLFxuXHRcdFx0ZHggPSAoIGV2ZW50LnBhZ2VYIC0gc21wLmxlZnQgKSB8fCAwLFxuXHRcdFx0ZHkgPSAoIGV2ZW50LnBhZ2VZIC0gc21wLnRvcCApIHx8IDAsXG5cdFx0XHR0cmlnZ2VyID0gdGhpcy5fY2hhbmdlWyBhIF07XG5cblx0XHR0aGlzLl91cGRhdGVQcmV2UHJvcGVydGllcygpO1xuXG5cdFx0aWYgKCAhdHJpZ2dlciApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRkYXRhID0gdHJpZ2dlci5hcHBseSggdGhpcywgWyBldmVudCwgZHgsIGR5IF0gKTtcblxuXHRcdHRoaXMuX3VwZGF0ZVZpcnR1YWxCb3VuZGFyaWVzKCBldmVudC5zaGlmdEtleSApO1xuXHRcdGlmICggdGhpcy5fYXNwZWN0UmF0aW8gfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cdFx0XHRkYXRhID0gdGhpcy5fdXBkYXRlUmF0aW8oIGRhdGEsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0ZGF0YSA9IHRoaXMuX3Jlc3BlY3RTaXplKCBkYXRhLCBldmVudCApO1xuXG5cdFx0dGhpcy5fdXBkYXRlQ2FjaGUoIGRhdGEgKTtcblxuXHRcdHRoaXMuX3Byb3BhZ2F0ZSggXCJyZXNpemVcIiwgZXZlbnQgKTtcblxuXHRcdHByb3BzID0gdGhpcy5fYXBwbHlDaGFuZ2VzKCk7XG5cblx0XHRpZiAoICF0aGlzLl9oZWxwZXIgJiYgdGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZSgpO1xuXHRcdH1cblxuXHRcdGlmICggISQuaXNFbXB0eU9iamVjdCggcHJvcHMgKSApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZVByZXZQcm9wZXJ0aWVzKCk7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcInJlc2l6ZVwiLCBldmVudCwgdGhpcy51aSgpICk7XG5cdFx0XHR0aGlzLl9hcHBseUNoYW5nZXMoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dGhpcy5yZXNpemluZyA9IGZhbHNlO1xuXHRcdHZhciBwciwgaXN0YSwgc29mZnNldGgsIHNvZmZzZXR3LCBzLCBsZWZ0LCB0b3AsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLCB0aGF0ID0gdGhpcztcblxuXHRcdGlmICggdGhpcy5faGVscGVyICkge1xuXG5cdFx0XHRwciA9IHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHM7XG5cdFx0XHRpc3RhID0gcHIubGVuZ3RoICYmICggL3RleHRhcmVhL2kgKS50ZXN0KCBwclsgMCBdLm5vZGVOYW1lICk7XG5cdFx0XHRzb2Zmc2V0aCA9IGlzdGEgJiYgdGhpcy5faGFzU2Nyb2xsKCBwclsgMCBdLCBcImxlZnRcIiApID8gMCA6IHRoYXQuc2l6ZURpZmYuaGVpZ2h0O1xuXHRcdFx0c29mZnNldHcgPSBpc3RhID8gMCA6IHRoYXQuc2l6ZURpZmYud2lkdGg7XG5cblx0XHRcdHMgPSB7XG5cdFx0XHRcdHdpZHRoOiAoIHRoYXQuaGVscGVyLndpZHRoKCkgIC0gc29mZnNldHcgKSxcblx0XHRcdFx0aGVpZ2h0OiAoIHRoYXQuaGVscGVyLmhlaWdodCgpIC0gc29mZnNldGggKVxuXHRcdFx0fTtcblx0XHRcdGxlZnQgPSAoIHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwibGVmdFwiICkgKSArXG5cdFx0XHRcdCggdGhhdC5wb3NpdGlvbi5sZWZ0IC0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLmxlZnQgKSApIHx8IG51bGw7XG5cdFx0XHR0b3AgPSAoIHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwidG9wXCIgKSApICtcblx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLnRvcCAtIHRoYXQub3JpZ2luYWxQb3NpdGlvbi50b3AgKSApIHx8IG51bGw7XG5cblx0XHRcdGlmICggIW8uYW5pbWF0ZSApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LmNzcyggJC5leHRlbmQoIHMsIHsgdG9wOiB0b3AsIGxlZnQ6IGxlZnQgfSApICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoYXQuaGVscGVyLmhlaWdodCggdGhhdC5zaXplLmhlaWdodCApO1xuXHRcdFx0dGhhdC5oZWxwZXIud2lkdGgoIHRoYXQuc2l6ZS53aWR0aCApO1xuXG5cdFx0XHRpZiAoIHRoaXMuX2hlbHBlciAmJiAhby5hbmltYXRlICkge1xuXHRcdFx0XHR0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZSgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdCQoIFwiYm9keVwiICkuY3NzKCBcImN1cnNvclwiLCBcImF1dG9cIiApO1xuXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktcmVzaXphYmxlLXJlc2l6aW5nXCIgKTtcblxuXHRcdHRoaXMuX3Byb3BhZ2F0ZSggXCJzdG9wXCIsIGV2ZW50ICk7XG5cblx0XHRpZiAoIHRoaXMuX2hlbHBlciApIHtcblx0XHRcdHRoaXMuaGVscGVyLnJlbW92ZSgpO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9LFxuXG5cdF91cGRhdGVQcmV2UHJvcGVydGllczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5wcmV2UG9zaXRpb24gPSB7XG5cdFx0XHR0b3A6IHRoaXMucG9zaXRpb24udG9wLFxuXHRcdFx0bGVmdDogdGhpcy5wb3NpdGlvbi5sZWZ0XG5cdFx0fTtcblx0XHR0aGlzLnByZXZTaXplID0ge1xuXHRcdFx0d2lkdGg6IHRoaXMuc2l6ZS53aWR0aCxcblx0XHRcdGhlaWdodDogdGhpcy5zaXplLmhlaWdodFxuXHRcdH07XG5cdH0sXG5cblx0X2FwcGx5Q2hhbmdlczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByb3BzID0ge307XG5cblx0XHRpZiAoIHRoaXMucG9zaXRpb24udG9wICE9PSB0aGlzLnByZXZQb3NpdGlvbi50b3AgKSB7XG5cdFx0XHRwcm9wcy50b3AgPSB0aGlzLnBvc2l0aW9uLnRvcCArIFwicHhcIjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLnBvc2l0aW9uLmxlZnQgIT09IHRoaXMucHJldlBvc2l0aW9uLmxlZnQgKSB7XG5cdFx0XHRwcm9wcy5sZWZ0ID0gdGhpcy5wb3NpdGlvbi5sZWZ0ICsgXCJweFwiO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuc2l6ZS53aWR0aCAhPT0gdGhpcy5wcmV2U2l6ZS53aWR0aCApIHtcblx0XHRcdHByb3BzLndpZHRoID0gdGhpcy5zaXplLndpZHRoICsgXCJweFwiO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuc2l6ZS5oZWlnaHQgIT09IHRoaXMucHJldlNpemUuaGVpZ2h0ICkge1xuXHRcdFx0cHJvcHMuaGVpZ2h0ID0gdGhpcy5zaXplLmhlaWdodCArIFwicHhcIjtcblx0XHR9XG5cblx0XHR0aGlzLmhlbHBlci5jc3MoIHByb3BzICk7XG5cblx0XHRyZXR1cm4gcHJvcHM7XG5cdH0sXG5cblx0X3VwZGF0ZVZpcnR1YWxCb3VuZGFyaWVzOiBmdW5jdGlvbiggZm9yY2VBc3BlY3RSYXRpbyApIHtcblx0XHR2YXIgcE1pbldpZHRoLCBwTWF4V2lkdGgsIHBNaW5IZWlnaHQsIHBNYXhIZWlnaHQsIGIsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0YiA9IHtcblx0XHRcdG1pbldpZHRoOiB0aGlzLl9pc051bWJlciggby5taW5XaWR0aCApID8gby5taW5XaWR0aCA6IDAsXG5cdFx0XHRtYXhXaWR0aDogdGhpcy5faXNOdW1iZXIoIG8ubWF4V2lkdGggKSA/IG8ubWF4V2lkdGggOiBJbmZpbml0eSxcblx0XHRcdG1pbkhlaWdodDogdGhpcy5faXNOdW1iZXIoIG8ubWluSGVpZ2h0ICkgPyBvLm1pbkhlaWdodCA6IDAsXG5cdFx0XHRtYXhIZWlnaHQ6IHRoaXMuX2lzTnVtYmVyKCBvLm1heEhlaWdodCApID8gby5tYXhIZWlnaHQgOiBJbmZpbml0eVxuXHRcdH07XG5cblx0XHRpZiAoIHRoaXMuX2FzcGVjdFJhdGlvIHx8IGZvcmNlQXNwZWN0UmF0aW8gKSB7XG5cdFx0XHRwTWluV2lkdGggPSBiLm1pbkhlaWdodCAqIHRoaXMuYXNwZWN0UmF0aW87XG5cdFx0XHRwTWluSGVpZ2h0ID0gYi5taW5XaWR0aCAvIHRoaXMuYXNwZWN0UmF0aW87XG5cdFx0XHRwTWF4V2lkdGggPSBiLm1heEhlaWdodCAqIHRoaXMuYXNwZWN0UmF0aW87XG5cdFx0XHRwTWF4SGVpZ2h0ID0gYi5tYXhXaWR0aCAvIHRoaXMuYXNwZWN0UmF0aW87XG5cblx0XHRcdGlmICggcE1pbldpZHRoID4gYi5taW5XaWR0aCApIHtcblx0XHRcdFx0Yi5taW5XaWR0aCA9IHBNaW5XaWR0aDtcblx0XHRcdH1cblx0XHRcdGlmICggcE1pbkhlaWdodCA+IGIubWluSGVpZ2h0ICkge1xuXHRcdFx0XHRiLm1pbkhlaWdodCA9IHBNaW5IZWlnaHQ7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHBNYXhXaWR0aCA8IGIubWF4V2lkdGggKSB7XG5cdFx0XHRcdGIubWF4V2lkdGggPSBwTWF4V2lkdGg7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHBNYXhIZWlnaHQgPCBiLm1heEhlaWdodCApIHtcblx0XHRcdFx0Yi5tYXhIZWlnaHQgPSBwTWF4SGVpZ2h0O1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLl92Qm91bmRhcmllcyA9IGI7XG5cdH0sXG5cblx0X3VwZGF0ZUNhY2hlOiBmdW5jdGlvbiggZGF0YSApIHtcblx0XHR0aGlzLm9mZnNldCA9IHRoaXMuaGVscGVyLm9mZnNldCgpO1xuXHRcdGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEubGVmdCApICkge1xuXHRcdFx0dGhpcy5wb3NpdGlvbi5sZWZ0ID0gZGF0YS5sZWZ0O1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLnRvcCApICkge1xuXHRcdFx0dGhpcy5wb3NpdGlvbi50b3AgPSBkYXRhLnRvcDtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9pc051bWJlciggZGF0YS5oZWlnaHQgKSApIHtcblx0XHRcdHRoaXMuc2l6ZS5oZWlnaHQgPSBkYXRhLmhlaWdodDtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9pc051bWJlciggZGF0YS53aWR0aCApICkge1xuXHRcdFx0dGhpcy5zaXplLndpZHRoID0gZGF0YS53aWR0aDtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZVJhdGlvOiBmdW5jdGlvbiggZGF0YSApIHtcblxuXHRcdHZhciBjcG9zID0gdGhpcy5wb3NpdGlvbixcblx0XHRcdGNzaXplID0gdGhpcy5zaXplLFxuXHRcdFx0YSA9IHRoaXMuYXhpcztcblxuXHRcdGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEuaGVpZ2h0ICkgKSB7XG5cdFx0XHRkYXRhLndpZHRoID0gKCBkYXRhLmhlaWdodCAqIHRoaXMuYXNwZWN0UmF0aW8gKTtcblx0XHR9IGVsc2UgaWYgKCB0aGlzLl9pc051bWJlciggZGF0YS53aWR0aCApICkge1xuXHRcdFx0ZGF0YS5oZWlnaHQgPSAoIGRhdGEud2lkdGggLyB0aGlzLmFzcGVjdFJhdGlvICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBhID09PSBcInN3XCIgKSB7XG5cdFx0XHRkYXRhLmxlZnQgPSBjcG9zLmxlZnQgKyAoIGNzaXplLndpZHRoIC0gZGF0YS53aWR0aCApO1xuXHRcdFx0ZGF0YS50b3AgPSBudWxsO1xuXHRcdH1cblx0XHRpZiAoIGEgPT09IFwibndcIiApIHtcblx0XHRcdGRhdGEudG9wID0gY3Bvcy50b3AgKyAoIGNzaXplLmhlaWdodCAtIGRhdGEuaGVpZ2h0ICk7XG5cdFx0XHRkYXRhLmxlZnQgPSBjcG9zLmxlZnQgKyAoIGNzaXplLndpZHRoIC0gZGF0YS53aWR0aCApO1xuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXHR9LFxuXG5cdF9yZXNwZWN0U2l6ZTogZnVuY3Rpb24oIGRhdGEgKSB7XG5cblx0XHR2YXIgbyA9IHRoaXMuX3ZCb3VuZGFyaWVzLFxuXHRcdFx0YSA9IHRoaXMuYXhpcyxcblx0XHRcdGlzbWF4dyA9IHRoaXMuX2lzTnVtYmVyKCBkYXRhLndpZHRoICkgJiYgby5tYXhXaWR0aCAmJiAoIG8ubWF4V2lkdGggPCBkYXRhLndpZHRoICksXG5cdFx0XHRpc21heGggPSB0aGlzLl9pc051bWJlciggZGF0YS5oZWlnaHQgKSAmJiBvLm1heEhlaWdodCAmJiAoIG8ubWF4SGVpZ2h0IDwgZGF0YS5oZWlnaHQgKSxcblx0XHRcdGlzbWludyA9IHRoaXMuX2lzTnVtYmVyKCBkYXRhLndpZHRoICkgJiYgby5taW5XaWR0aCAmJiAoIG8ubWluV2lkdGggPiBkYXRhLndpZHRoICksXG5cdFx0XHRpc21pbmggPSB0aGlzLl9pc051bWJlciggZGF0YS5oZWlnaHQgKSAmJiBvLm1pbkhlaWdodCAmJiAoIG8ubWluSGVpZ2h0ID4gZGF0YS5oZWlnaHQgKSxcblx0XHRcdGR3ID0gdGhpcy5vcmlnaW5hbFBvc2l0aW9uLmxlZnQgKyB0aGlzLm9yaWdpbmFsU2l6ZS53aWR0aCxcblx0XHRcdGRoID0gdGhpcy5vcmlnaW5hbFBvc2l0aW9uLnRvcCArIHRoaXMub3JpZ2luYWxTaXplLmhlaWdodCxcblx0XHRcdGN3ID0gL3N3fG53fHcvLnRlc3QoIGEgKSwgY2ggPSAvbnd8bmV8bi8udGVzdCggYSApO1xuXHRcdGlmICggaXNtaW53ICkge1xuXHRcdFx0ZGF0YS53aWR0aCA9IG8ubWluV2lkdGg7XG5cdFx0fVxuXHRcdGlmICggaXNtaW5oICkge1xuXHRcdFx0ZGF0YS5oZWlnaHQgPSBvLm1pbkhlaWdodDtcblx0XHR9XG5cdFx0aWYgKCBpc21heHcgKSB7XG5cdFx0XHRkYXRhLndpZHRoID0gby5tYXhXaWR0aDtcblx0XHR9XG5cdFx0aWYgKCBpc21heGggKSB7XG5cdFx0XHRkYXRhLmhlaWdodCA9IG8ubWF4SGVpZ2h0O1xuXHRcdH1cblxuXHRcdGlmICggaXNtaW53ICYmIGN3ICkge1xuXHRcdFx0ZGF0YS5sZWZ0ID0gZHcgLSBvLm1pbldpZHRoO1xuXHRcdH1cblx0XHRpZiAoIGlzbWF4dyAmJiBjdyApIHtcblx0XHRcdGRhdGEubGVmdCA9IGR3IC0gby5tYXhXaWR0aDtcblx0XHR9XG5cdFx0aWYgKCBpc21pbmggJiYgY2ggKSB7XG5cdFx0XHRkYXRhLnRvcCA9IGRoIC0gby5taW5IZWlnaHQ7XG5cdFx0fVxuXHRcdGlmICggaXNtYXhoICYmIGNoICkge1xuXHRcdFx0ZGF0YS50b3AgPSBkaCAtIG8ubWF4SGVpZ2h0O1xuXHRcdH1cblxuXHRcdC8vIEZpeGluZyBqdW1wIGVycm9yIG9uIHRvcC9sZWZ0IC0gYnVnICMyMzMwXG5cdFx0aWYgKCAhZGF0YS53aWR0aCAmJiAhZGF0YS5oZWlnaHQgJiYgIWRhdGEubGVmdCAmJiBkYXRhLnRvcCApIHtcblx0XHRcdGRhdGEudG9wID0gbnVsbDtcblx0XHR9IGVsc2UgaWYgKCAhZGF0YS53aWR0aCAmJiAhZGF0YS5oZWlnaHQgJiYgIWRhdGEudG9wICYmIGRhdGEubGVmdCApIHtcblx0XHRcdGRhdGEubGVmdCA9IG51bGw7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cdH0sXG5cblx0X2dldFBhZGRpbmdQbHVzQm9yZGVyRGltZW5zaW9uczogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIGkgPSAwLFxuXHRcdFx0d2lkdGhzID0gW10sXG5cdFx0XHRib3JkZXJzID0gW1xuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcImJvcmRlclJpZ2h0V2lkdGhcIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJib3JkZXJCb3R0b21XaWR0aFwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiIClcblx0XHRcdF0sXG5cdFx0XHRwYWRkaW5ncyA9IFtcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwicGFkZGluZ1RvcFwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcInBhZGRpbmdSaWdodFwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcInBhZGRpbmdCb3R0b21cIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJwYWRkaW5nTGVmdFwiIClcblx0XHRcdF07XG5cblx0XHRmb3IgKCA7IGkgPCA0OyBpKysgKSB7XG5cdFx0XHR3aWR0aHNbIGkgXSA9ICggcGFyc2VGbG9hdCggYm9yZGVyc1sgaSBdICkgfHwgMCApO1xuXHRcdFx0d2lkdGhzWyBpIF0gKz0gKCBwYXJzZUZsb2F0KCBwYWRkaW5nc1sgaSBdICkgfHwgMCApO1xuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHRoZWlnaHQ6IHdpZHRoc1sgMCBdICsgd2lkdGhzWyAyIF0sXG5cdFx0XHR3aWR0aDogd2lkdGhzWyAxIF0gKyB3aWR0aHNbIDMgXVxuXHRcdH07XG5cdH0sXG5cblx0X3Byb3BvcnRpb25hbGx5UmVzaXplOiBmdW5jdGlvbigpIHtcblxuXHRcdGlmICggIXRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBwcmVsLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRlbGVtZW50ID0gdGhpcy5oZWxwZXIgfHwgdGhpcy5lbGVtZW50O1xuXG5cdFx0Zm9yICggOyBpIDwgdGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cy5sZW5ndGg7IGkrKyApIHtcblxuXHRcdFx0cHJlbCA9IHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHNbIGkgXTtcblxuXHRcdFx0Ly8gVE9ETzogU2VlbXMgbGlrZSBhIGJ1ZyB0byBjYWNoZSB0aGlzLm91dGVyRGltZW5zaW9uc1xuXHRcdFx0Ly8gY29uc2lkZXJpbmcgdGhhdCB3ZSBhcmUgaW4gYSBsb29wLlxuXHRcdFx0aWYgKCAhdGhpcy5vdXRlckRpbWVuc2lvbnMgKSB7XG5cdFx0XHRcdHRoaXMub3V0ZXJEaW1lbnNpb25zID0gdGhpcy5fZ2V0UGFkZGluZ1BsdXNCb3JkZXJEaW1lbnNpb25zKCBwcmVsICk7XG5cdFx0XHR9XG5cblx0XHRcdHByZWwuY3NzKCB7XG5cdFx0XHRcdGhlaWdodDogKCBlbGVtZW50LmhlaWdodCgpIC0gdGhpcy5vdXRlckRpbWVuc2lvbnMuaGVpZ2h0ICkgfHwgMCxcblx0XHRcdFx0d2lkdGg6ICggZWxlbWVudC53aWR0aCgpIC0gdGhpcy5vdXRlckRpbWVuc2lvbnMud2lkdGggKSB8fCAwXG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0fSxcblxuXHRfcmVuZGVyUHJveHk6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIGVsID0gdGhpcy5lbGVtZW50LCBvID0gdGhpcy5vcHRpb25zO1xuXHRcdHRoaXMuZWxlbWVudE9mZnNldCA9IGVsLm9mZnNldCgpO1xuXG5cdFx0aWYgKCB0aGlzLl9oZWxwZXIgKSB7XG5cblx0XHRcdHRoaXMuaGVscGVyID0gdGhpcy5oZWxwZXIgfHwgJCggXCI8ZGl2IHN0eWxlPSdvdmVyZmxvdzpoaWRkZW47Jz48L2Rpdj5cIiApO1xuXG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oZWxwZXIsIHRoaXMuX2hlbHBlciApO1xuXHRcdFx0dGhpcy5oZWxwZXIuY3NzKCB7XG5cdFx0XHRcdHdpZHRoOiB0aGlzLmVsZW1lbnQub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IHRoaXMuZWxlbWVudC5vdXRlckhlaWdodCgpLFxuXHRcdFx0XHRwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLFxuXHRcdFx0XHRsZWZ0OiB0aGlzLmVsZW1lbnRPZmZzZXQubGVmdCArIFwicHhcIixcblx0XHRcdFx0dG9wOiB0aGlzLmVsZW1lbnRPZmZzZXQudG9wICsgXCJweFwiLFxuXHRcdFx0XHR6SW5kZXg6ICsrby56SW5kZXggLy9UT0RPOiBEb24ndCBtb2RpZnkgb3B0aW9uXG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuaGVscGVyXG5cdFx0XHRcdC5hcHBlbmRUbyggXCJib2R5XCIgKVxuXHRcdFx0XHQuZGlzYWJsZVNlbGVjdGlvbigpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuaGVscGVyID0gdGhpcy5lbGVtZW50O1xuXHRcdH1cblxuXHR9LFxuXG5cdF9jaGFuZ2U6IHtcblx0XHRlOiBmdW5jdGlvbiggZXZlbnQsIGR4ICkge1xuXHRcdFx0cmV0dXJuIHsgd2lkdGg6IHRoaXMub3JpZ2luYWxTaXplLndpZHRoICsgZHggfTtcblx0XHR9LFxuXHRcdHc6IGZ1bmN0aW9uKCBldmVudCwgZHggKSB7XG5cdFx0XHR2YXIgY3MgPSB0aGlzLm9yaWdpbmFsU2l6ZSwgc3AgPSB0aGlzLm9yaWdpbmFsUG9zaXRpb247XG5cdFx0XHRyZXR1cm4geyBsZWZ0OiBzcC5sZWZ0ICsgZHgsIHdpZHRoOiBjcy53aWR0aCAtIGR4IH07XG5cdFx0fSxcblx0XHRuOiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHZhciBjcyA9IHRoaXMub3JpZ2luYWxTaXplLCBzcCA9IHRoaXMub3JpZ2luYWxQb3NpdGlvbjtcblx0XHRcdHJldHVybiB7IHRvcDogc3AudG9wICsgZHksIGhlaWdodDogY3MuaGVpZ2h0IC0gZHkgfTtcblx0XHR9LFxuXHRcdHM6IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0cmV0dXJuIHsgaGVpZ2h0OiB0aGlzLm9yaWdpbmFsU2l6ZS5oZWlnaHQgKyBkeSB9O1xuXHRcdH0sXG5cdFx0c2U6IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0cmV0dXJuICQuZXh0ZW5kKCB0aGlzLl9jaGFuZ2Uucy5hcHBseSggdGhpcywgYXJndW1lbnRzICksXG5cdFx0XHRcdHRoaXMuX2NoYW5nZS5lLmFwcGx5KCB0aGlzLCBbIGV2ZW50LCBkeCwgZHkgXSApICk7XG5cdFx0fSxcblx0XHRzdzogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHRyZXR1cm4gJC5leHRlbmQoIHRoaXMuX2NoYW5nZS5zLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSxcblx0XHRcdFx0dGhpcy5fY2hhbmdlLncuYXBwbHkoIHRoaXMsIFsgZXZlbnQsIGR4LCBkeSBdICkgKTtcblx0XHR9LFxuXHRcdG5lOiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHJldHVybiAkLmV4dGVuZCggdGhpcy5fY2hhbmdlLm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApLFxuXHRcdFx0XHR0aGlzLl9jaGFuZ2UuZS5hcHBseSggdGhpcywgWyBldmVudCwgZHgsIGR5IF0gKSApO1xuXHRcdH0sXG5cdFx0bnc6IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0cmV0dXJuICQuZXh0ZW5kKCB0aGlzLl9jaGFuZ2Uubi5hcHBseSggdGhpcywgYXJndW1lbnRzICksXG5cdFx0XHRcdHRoaXMuX2NoYW5nZS53LmFwcGx5KCB0aGlzLCBbIGV2ZW50LCBkeCwgZHkgXSApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9wcm9wYWdhdGU6IGZ1bmN0aW9uKCBuLCBldmVudCApIHtcblx0XHQkLnVpLnBsdWdpbi5jYWxsKCB0aGlzLCBuLCBbIGV2ZW50LCB0aGlzLnVpKCkgXSApO1xuXHRcdCggbiAhPT0gXCJyZXNpemVcIiAmJiB0aGlzLl90cmlnZ2VyKCBuLCBldmVudCwgdGhpcy51aSgpICkgKTtcblx0fSxcblxuXHRwbHVnaW5zOiB7fSxcblxuXHR1aTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdG9yaWdpbmFsRWxlbWVudDogdGhpcy5vcmlnaW5hbEVsZW1lbnQsXG5cdFx0XHRlbGVtZW50OiB0aGlzLmVsZW1lbnQsXG5cdFx0XHRoZWxwZXI6IHRoaXMuaGVscGVyLFxuXHRcdFx0cG9zaXRpb246IHRoaXMucG9zaXRpb24sXG5cdFx0XHRzaXplOiB0aGlzLnNpemUsXG5cdFx0XHRvcmlnaW5hbFNpemU6IHRoaXMub3JpZ2luYWxTaXplLFxuXHRcdFx0b3JpZ2luYWxQb3NpdGlvbjogdGhpcy5vcmlnaW5hbFBvc2l0aW9uXG5cdFx0fTtcblx0fVxuXG59ICk7XG5cbi8qXG4gKiBSZXNpemFibGUgRXh0ZW5zaW9uc1xuICovXG5cbiQudWkucGx1Z2luLmFkZCggXCJyZXNpemFibGVcIiwgXCJhbmltYXRlXCIsIHtcblxuXHRzdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRwciA9IHRoYXQuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHMsXG5cdFx0XHRpc3RhID0gcHIubGVuZ3RoICYmICggL3RleHRhcmVhL2kgKS50ZXN0KCBwclsgMCBdLm5vZGVOYW1lICksXG5cdFx0XHRzb2Zmc2V0aCA9IGlzdGEgJiYgdGhhdC5faGFzU2Nyb2xsKCBwclsgMCBdLCBcImxlZnRcIiApID8gMCA6IHRoYXQuc2l6ZURpZmYuaGVpZ2h0LFxuXHRcdFx0c29mZnNldHcgPSBpc3RhID8gMCA6IHRoYXQuc2l6ZURpZmYud2lkdGgsXG5cdFx0XHRzdHlsZSA9IHtcblx0XHRcdFx0d2lkdGg6ICggdGhhdC5zaXplLndpZHRoIC0gc29mZnNldHcgKSxcblx0XHRcdFx0aGVpZ2h0OiAoIHRoYXQuc2l6ZS5oZWlnaHQgLSBzb2Zmc2V0aCApXG5cdFx0XHR9LFxuXHRcdFx0bGVmdCA9ICggcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJsZWZ0XCIgKSApICtcblx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLmxlZnQgLSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24ubGVmdCApICkgfHwgbnVsbCxcblx0XHRcdHRvcCA9ICggcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJ0b3BcIiApICkgK1xuXHRcdFx0XHQoIHRoYXQucG9zaXRpb24udG9wIC0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLnRvcCApICkgfHwgbnVsbDtcblxuXHRcdHRoYXQuZWxlbWVudC5hbmltYXRlKFxuXHRcdFx0JC5leHRlbmQoIHN0eWxlLCB0b3AgJiYgbGVmdCA/IHsgdG9wOiB0b3AsIGxlZnQ6IGxlZnQgfSA6IHt9ICksIHtcblx0XHRcdFx0ZHVyYXRpb246IG8uYW5pbWF0ZUR1cmF0aW9uLFxuXHRcdFx0XHRlYXNpbmc6IG8uYW5pbWF0ZUVhc2luZyxcblx0XHRcdFx0c3RlcDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0XHR2YXIgZGF0YSA9IHtcblx0XHRcdFx0XHRcdHdpZHRoOiBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcIndpZHRoXCIgKSApLFxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcImhlaWdodFwiICkgKSxcblx0XHRcdFx0XHRcdHRvcDogcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJ0b3BcIiApICksXG5cdFx0XHRcdFx0XHRsZWZ0OiBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcImxlZnRcIiApIClcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0aWYgKCBwciAmJiBwci5sZW5ndGggKSB7XG5cdFx0XHRcdFx0XHQkKCBwclsgMCBdICkuY3NzKCB7IHdpZHRoOiBkYXRhLndpZHRoLCBoZWlnaHQ6IGRhdGEuaGVpZ2h0IH0gKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBQcm9wYWdhdGluZyByZXNpemUsIGFuZCB1cGRhdGluZyB2YWx1ZXMgZm9yIGVhY2ggYW5pbWF0aW9uIHN0ZXBcblx0XHRcdFx0XHR0aGF0Ll91cGRhdGVDYWNoZSggZGF0YSApO1xuXHRcdFx0XHRcdHRoYXQuX3Byb3BhZ2F0ZSggXCJyZXNpemVcIiwgZXZlbnQgKTtcblxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0KTtcblx0fVxuXG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJyZXNpemFibGVcIiwgXCJjb250YWlubWVudFwiLCB7XG5cblx0c3RhcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlbGVtZW50LCBwLCBjbywgY2gsIGN3LCB3aWR0aCwgaGVpZ2h0LFxuXHRcdFx0dGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdGVsID0gdGhhdC5lbGVtZW50LFxuXHRcdFx0b2MgPSBvLmNvbnRhaW5tZW50LFxuXHRcdFx0Y2UgPSAoIG9jIGluc3RhbmNlb2YgJCApID9cblx0XHRcdFx0b2MuZ2V0KCAwICkgOlxuXHRcdFx0XHQoIC9wYXJlbnQvLnRlc3QoIG9jICkgKSA/IGVsLnBhcmVudCgpLmdldCggMCApIDogb2M7XG5cblx0XHRpZiAoICFjZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGF0LmNvbnRhaW5lckVsZW1lbnQgPSAkKCBjZSApO1xuXG5cdFx0aWYgKCAvZG9jdW1lbnQvLnRlc3QoIG9jICkgfHwgb2MgPT09IGRvY3VtZW50ICkge1xuXHRcdFx0dGhhdC5jb250YWluZXJPZmZzZXQgPSB7XG5cdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdHRvcDogMFxuXHRcdFx0fTtcblx0XHRcdHRoYXQuY29udGFpbmVyUG9zaXRpb24gPSB7XG5cdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdHRvcDogMFxuXHRcdFx0fTtcblxuXHRcdFx0dGhhdC5wYXJlbnREYXRhID0ge1xuXHRcdFx0XHRlbGVtZW50OiAkKCBkb2N1bWVudCApLFxuXHRcdFx0XHRsZWZ0OiAwLFxuXHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdHdpZHRoOiAkKCBkb2N1bWVudCApLndpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogJCggZG9jdW1lbnQgKS5oZWlnaHQoKSB8fCBkb2N1bWVudC5ib2R5LnBhcmVudE5vZGUuc2Nyb2xsSGVpZ2h0XG5cdFx0XHR9O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtZW50ID0gJCggY2UgKTtcblx0XHRcdHAgPSBbXTtcblx0XHRcdCQoIFsgXCJUb3BcIiwgXCJSaWdodFwiLCBcIkxlZnRcIiwgXCJCb3R0b21cIiBdICkuZWFjaCggZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdFx0XHRcdHBbIGkgXSA9IHRoYXQuX251bSggZWxlbWVudC5jc3MoIFwicGFkZGluZ1wiICsgbmFtZSApICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoYXQuY29udGFpbmVyT2Zmc2V0ID0gZWxlbWVudC5vZmZzZXQoKTtcblx0XHRcdHRoYXQuY29udGFpbmVyUG9zaXRpb24gPSBlbGVtZW50LnBvc2l0aW9uKCk7XG5cdFx0XHR0aGF0LmNvbnRhaW5lclNpemUgPSB7XG5cdFx0XHRcdGhlaWdodDogKCBlbGVtZW50LmlubmVySGVpZ2h0KCkgLSBwWyAzIF0gKSxcblx0XHRcdFx0d2lkdGg6ICggZWxlbWVudC5pbm5lcldpZHRoKCkgLSBwWyAxIF0gKVxuXHRcdFx0fTtcblxuXHRcdFx0Y28gPSB0aGF0LmNvbnRhaW5lck9mZnNldDtcblx0XHRcdGNoID0gdGhhdC5jb250YWluZXJTaXplLmhlaWdodDtcblx0XHRcdGN3ID0gdGhhdC5jb250YWluZXJTaXplLndpZHRoO1xuXHRcdFx0d2lkdGggPSAoIHRoYXQuX2hhc1Njcm9sbCAoIGNlLCBcImxlZnRcIiApID8gY2Uuc2Nyb2xsV2lkdGggOiBjdyApO1xuXHRcdFx0aGVpZ2h0ID0gKCB0aGF0Ll9oYXNTY3JvbGwgKCBjZSApID8gY2Uuc2Nyb2xsSGVpZ2h0IDogY2ggKSA7XG5cblx0XHRcdHRoYXQucGFyZW50RGF0YSA9IHtcblx0XHRcdFx0ZWxlbWVudDogY2UsXG5cdFx0XHRcdGxlZnQ6IGNvLmxlZnQsXG5cdFx0XHRcdHRvcDogY28udG9wLFxuXHRcdFx0XHR3aWR0aDogd2lkdGgsXG5cdFx0XHRcdGhlaWdodDogaGVpZ2h0XG5cdFx0XHR9O1xuXHRcdH1cblx0fSxcblxuXHRyZXNpemU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgd29zZXQsIGhvc2V0LCBpc1BhcmVudCwgaXNPZmZzZXRSZWxhdGl2ZSxcblx0XHRcdHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRjbyA9IHRoYXQuY29udGFpbmVyT2Zmc2V0LFxuXHRcdFx0Y3AgPSB0aGF0LnBvc2l0aW9uLFxuXHRcdFx0cFJhdGlvID0gdGhhdC5fYXNwZWN0UmF0aW8gfHwgZXZlbnQuc2hpZnRLZXksXG5cdFx0XHRjb3AgPSB7XG5cdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0bGVmdDogMFxuXHRcdFx0fSxcblx0XHRcdGNlID0gdGhhdC5jb250YWluZXJFbGVtZW50LFxuXHRcdFx0Y29udGludWVSZXNpemUgPSB0cnVlO1xuXG5cdFx0aWYgKCBjZVsgMCBdICE9PSBkb2N1bWVudCAmJiAoIC9zdGF0aWMvICkudGVzdCggY2UuY3NzKCBcInBvc2l0aW9uXCIgKSApICkge1xuXHRcdFx0Y29wID0gY287XG5cdFx0fVxuXG5cdFx0aWYgKCBjcC5sZWZ0IDwgKCB0aGF0Ll9oZWxwZXIgPyBjby5sZWZ0IDogMCApICkge1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gdGhhdC5zaXplLndpZHRoICtcblx0XHRcdFx0KCB0aGF0Ll9oZWxwZXIgP1xuXHRcdFx0XHRcdCggdGhhdC5wb3NpdGlvbi5sZWZ0IC0gY28ubGVmdCApIDpcblx0XHRcdFx0XHQoIHRoYXQucG9zaXRpb24ubGVmdCAtIGNvcC5sZWZ0ICkgKTtcblxuXHRcdFx0aWYgKCBwUmF0aW8gKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSB0aGF0LnNpemUud2lkdGggLyB0aGF0LmFzcGVjdFJhdGlvO1xuXHRcdFx0XHRjb250aW51ZVJlc2l6ZSA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dGhhdC5wb3NpdGlvbi5sZWZ0ID0gby5oZWxwZXIgPyBjby5sZWZ0IDogMDtcblx0XHR9XG5cblx0XHRpZiAoIGNwLnRvcCA8ICggdGhhdC5faGVscGVyID8gY28udG9wIDogMCApICkge1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IHRoYXQuc2l6ZS5oZWlnaHQgK1xuXHRcdFx0XHQoIHRoYXQuX2hlbHBlciA/XG5cdFx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLnRvcCAtIGNvLnRvcCApIDpcblx0XHRcdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCApO1xuXG5cdFx0XHRpZiAoIHBSYXRpbyApIHtcblx0XHRcdFx0dGhhdC5zaXplLndpZHRoID0gdGhhdC5zaXplLmhlaWdodCAqIHRoYXQuYXNwZWN0UmF0aW87XG5cdFx0XHRcdGNvbnRpbnVlUmVzaXplID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCA9IHRoYXQuX2hlbHBlciA/IGNvLnRvcCA6IDA7XG5cdFx0fVxuXG5cdFx0aXNQYXJlbnQgPSB0aGF0LmNvbnRhaW5lckVsZW1lbnQuZ2V0KCAwICkgPT09IHRoYXQuZWxlbWVudC5wYXJlbnQoKS5nZXQoIDAgKTtcblx0XHRpc09mZnNldFJlbGF0aXZlID0gL3JlbGF0aXZlfGFic29sdXRlLy50ZXN0KCB0aGF0LmNvbnRhaW5lckVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSApO1xuXG5cdFx0aWYgKCBpc1BhcmVudCAmJiBpc09mZnNldFJlbGF0aXZlICkge1xuXHRcdFx0dGhhdC5vZmZzZXQubGVmdCA9IHRoYXQucGFyZW50RGF0YS5sZWZ0ICsgdGhhdC5wb3NpdGlvbi5sZWZ0O1xuXHRcdFx0dGhhdC5vZmZzZXQudG9wID0gdGhhdC5wYXJlbnREYXRhLnRvcCArIHRoYXQucG9zaXRpb24udG9wO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGF0Lm9mZnNldC5sZWZ0ID0gdGhhdC5lbGVtZW50Lm9mZnNldCgpLmxlZnQ7XG5cdFx0XHR0aGF0Lm9mZnNldC50b3AgPSB0aGF0LmVsZW1lbnQub2Zmc2V0KCkudG9wO1xuXHRcdH1cblxuXHRcdHdvc2V0ID0gTWF0aC5hYnMoIHRoYXQuc2l6ZURpZmYud2lkdGggK1xuXHRcdFx0KCB0aGF0Ll9oZWxwZXIgP1xuXHRcdFx0XHR0aGF0Lm9mZnNldC5sZWZ0IC0gY29wLmxlZnQgOlxuXHRcdFx0XHQoIHRoYXQub2Zmc2V0LmxlZnQgLSBjby5sZWZ0ICkgKSApO1xuXG5cdFx0aG9zZXQgPSBNYXRoLmFicyggdGhhdC5zaXplRGlmZi5oZWlnaHQgK1xuXHRcdFx0KCB0aGF0Ll9oZWxwZXIgP1xuXHRcdFx0XHR0aGF0Lm9mZnNldC50b3AgLSBjb3AudG9wIDpcblx0XHRcdFx0KCB0aGF0Lm9mZnNldC50b3AgLSBjby50b3AgKSApICk7XG5cblx0XHRpZiAoIHdvc2V0ICsgdGhhdC5zaXplLndpZHRoID49IHRoYXQucGFyZW50RGF0YS53aWR0aCApIHtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IHRoYXQucGFyZW50RGF0YS53aWR0aCAtIHdvc2V0O1xuXHRcdFx0aWYgKCBwUmF0aW8gKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSB0aGF0LnNpemUud2lkdGggLyB0aGF0LmFzcGVjdFJhdGlvO1xuXHRcdFx0XHRjb250aW51ZVJlc2l6ZSA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggaG9zZXQgKyB0aGF0LnNpemUuaGVpZ2h0ID49IHRoYXQucGFyZW50RGF0YS5oZWlnaHQgKSB7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gdGhhdC5wYXJlbnREYXRhLmhlaWdodCAtIGhvc2V0O1xuXHRcdFx0aWYgKCBwUmF0aW8gKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IHRoYXQuc2l6ZS5oZWlnaHQgKiB0aGF0LmFzcGVjdFJhdGlvO1xuXHRcdFx0XHRjb250aW51ZVJlc2l6ZSA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggIWNvbnRpbnVlUmVzaXplICkge1xuXHRcdFx0dGhhdC5wb3NpdGlvbi5sZWZ0ID0gdGhhdC5wcmV2UG9zaXRpb24ubGVmdDtcblx0XHRcdHRoYXQucG9zaXRpb24udG9wID0gdGhhdC5wcmV2UG9zaXRpb24udG9wO1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gdGhhdC5wcmV2U2l6ZS53aWR0aDtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSB0aGF0LnByZXZTaXplLmhlaWdodDtcblx0XHR9XG5cdH0sXG5cblx0c3RvcDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRjbyA9IHRoYXQuY29udGFpbmVyT2Zmc2V0LFxuXHRcdFx0Y29wID0gdGhhdC5jb250YWluZXJQb3NpdGlvbixcblx0XHRcdGNlID0gdGhhdC5jb250YWluZXJFbGVtZW50LFxuXHRcdFx0aGVscGVyID0gJCggdGhhdC5oZWxwZXIgKSxcblx0XHRcdGhvID0gaGVscGVyLm9mZnNldCgpLFxuXHRcdFx0dyA9IGhlbHBlci5vdXRlcldpZHRoKCkgLSB0aGF0LnNpemVEaWZmLndpZHRoLFxuXHRcdFx0aCA9IGhlbHBlci5vdXRlckhlaWdodCgpIC0gdGhhdC5zaXplRGlmZi5oZWlnaHQ7XG5cblx0XHRpZiAoIHRoYXQuX2hlbHBlciAmJiAhby5hbmltYXRlICYmICggL3JlbGF0aXZlLyApLnRlc3QoIGNlLmNzcyggXCJwb3NpdGlvblwiICkgKSApIHtcblx0XHRcdCQoIHRoaXMgKS5jc3MoIHtcblx0XHRcdFx0bGVmdDogaG8ubGVmdCAtIGNvcC5sZWZ0IC0gY28ubGVmdCxcblx0XHRcdFx0d2lkdGg6IHcsXG5cdFx0XHRcdGhlaWdodDogaFxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhhdC5faGVscGVyICYmICFvLmFuaW1hdGUgJiYgKCAvc3RhdGljLyApLnRlc3QoIGNlLmNzcyggXCJwb3NpdGlvblwiICkgKSApIHtcblx0XHRcdCQoIHRoaXMgKS5jc3MoIHtcblx0XHRcdFx0bGVmdDogaG8ubGVmdCAtIGNvcC5sZWZ0IC0gY28ubGVmdCxcblx0XHRcdFx0d2lkdGg6IHcsXG5cdFx0XHRcdGhlaWdodDogaFxuXHRcdFx0fSApO1xuXHRcdH1cblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwicmVzaXphYmxlXCIsIFwiYWxzb1Jlc2l6ZVwiLCB7XG5cblx0c3RhcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zO1xuXG5cdFx0JCggby5hbHNvUmVzaXplICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZWwgPSAkKCB0aGlzICk7XG5cdFx0XHRlbC5kYXRhKCBcInVpLXJlc2l6YWJsZS1hbHNvcmVzaXplXCIsIHtcblx0XHRcdFx0d2lkdGg6IHBhcnNlRmxvYXQoIGVsLndpZHRoKCkgKSwgaGVpZ2h0OiBwYXJzZUZsb2F0KCBlbC5oZWlnaHQoKSApLFxuXHRcdFx0XHRsZWZ0OiBwYXJzZUZsb2F0KCBlbC5jc3MoIFwibGVmdFwiICkgKSwgdG9wOiBwYXJzZUZsb2F0KCBlbC5jc3MoIFwidG9wXCIgKSApXG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdHJlc2l6ZTogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdG9zID0gdGhhdC5vcmlnaW5hbFNpemUsXG5cdFx0XHRvcCA9IHRoYXQub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdGRlbHRhID0ge1xuXHRcdFx0XHRoZWlnaHQ6ICggdGhhdC5zaXplLmhlaWdodCAtIG9zLmhlaWdodCApIHx8IDAsXG5cdFx0XHRcdHdpZHRoOiAoIHRoYXQuc2l6ZS53aWR0aCAtIG9zLndpZHRoICkgfHwgMCxcblx0XHRcdFx0dG9wOiAoIHRoYXQucG9zaXRpb24udG9wIC0gb3AudG9wICkgfHwgMCxcblx0XHRcdFx0bGVmdDogKCB0aGF0LnBvc2l0aW9uLmxlZnQgLSBvcC5sZWZ0ICkgfHwgMFxuXHRcdFx0fTtcblxuXHRcdFx0JCggby5hbHNvUmVzaXplICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbCA9ICQoIHRoaXMgKSwgc3RhcnQgPSAkKCB0aGlzICkuZGF0YSggXCJ1aS1yZXNpemFibGUtYWxzb3Jlc2l6ZVwiICksIHN0eWxlID0ge30sXG5cdFx0XHRcdFx0Y3NzID0gZWwucGFyZW50cyggdWkub3JpZ2luYWxFbGVtZW50WyAwIF0gKS5sZW5ndGggP1xuXHRcdFx0XHRcdFx0XHRbIFwid2lkdGhcIiwgXCJoZWlnaHRcIiBdIDpcblx0XHRcdFx0XHRcdFx0WyBcIndpZHRoXCIsIFwiaGVpZ2h0XCIsIFwidG9wXCIsIFwibGVmdFwiIF07XG5cblx0XHRcdFx0JC5lYWNoKCBjc3MsIGZ1bmN0aW9uKCBpLCBwcm9wICkge1xuXHRcdFx0XHRcdHZhciBzdW0gPSAoIHN0YXJ0WyBwcm9wIF0gfHwgMCApICsgKCBkZWx0YVsgcHJvcCBdIHx8IDAgKTtcblx0XHRcdFx0XHRpZiAoIHN1bSAmJiBzdW0gPj0gMCApIHtcblx0XHRcdFx0XHRcdHN0eWxlWyBwcm9wIF0gPSBzdW0gfHwgbnVsbDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRlbC5jc3MoIHN0eWxlICk7XG5cdFx0XHR9ICk7XG5cdH0sXG5cblx0c3RvcDogZnVuY3Rpb24oKSB7XG5cdFx0JCggdGhpcyApLnJlbW92ZURhdGEoIFwidWktcmVzaXphYmxlLWFsc29yZXNpemVcIiApO1xuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJyZXNpemFibGVcIiwgXCJnaG9zdFwiLCB7XG5cblx0c3RhcnQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSwgY3MgPSB0aGF0LnNpemU7XG5cblx0XHR0aGF0Lmdob3N0ID0gdGhhdC5vcmlnaW5hbEVsZW1lbnQuY2xvbmUoKTtcblx0XHR0aGF0Lmdob3N0LmNzcygge1xuXHRcdFx0b3BhY2l0eTogMC4yNSxcblx0XHRcdGRpc3BsYXk6IFwiYmxvY2tcIixcblx0XHRcdHBvc2l0aW9uOiBcInJlbGF0aXZlXCIsXG5cdFx0XHRoZWlnaHQ6IGNzLmhlaWdodCxcblx0XHRcdHdpZHRoOiBjcy53aWR0aCxcblx0XHRcdG1hcmdpbjogMCxcblx0XHRcdGxlZnQ6IDAsXG5cdFx0XHR0b3A6IDBcblx0XHR9ICk7XG5cblx0XHR0aGF0Ll9hZGRDbGFzcyggdGhhdC5naG9zdCwgXCJ1aS1yZXNpemFibGUtZ2hvc3RcIiApO1xuXG5cdFx0Ly8gREVQUkVDQVRFRFxuXHRcdC8vIFRPRE86IHJlbW92ZSBhZnRlciAxLjEyXG5cdFx0aWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgJiYgdHlwZW9mIHRoYXQub3B0aW9ucy5naG9zdCA9PT0gXCJzdHJpbmdcIiApIHtcblxuXHRcdFx0Ly8gR2hvc3Qgb3B0aW9uXG5cdFx0XHR0aGF0Lmdob3N0LmFkZENsYXNzKCB0aGlzLm9wdGlvbnMuZ2hvc3QgKTtcblx0XHR9XG5cblx0XHR0aGF0Lmdob3N0LmFwcGVuZFRvKCB0aGF0LmhlbHBlciApO1xuXG5cdH0sXG5cblx0cmVzaXplOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApO1xuXHRcdGlmICggdGhhdC5naG9zdCApIHtcblx0XHRcdHRoYXQuZ2hvc3QuY3NzKCB7XG5cdFx0XHRcdHBvc2l0aW9uOiBcInJlbGF0aXZlXCIsXG5cdFx0XHRcdGhlaWdodDogdGhhdC5zaXplLmhlaWdodCxcblx0XHRcdFx0d2lkdGg6IHRoYXQuc2l6ZS53aWR0aFxuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRzdG9wOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApO1xuXHRcdGlmICggdGhhdC5naG9zdCAmJiB0aGF0LmhlbHBlciApIHtcblx0XHRcdHRoYXQuaGVscGVyLmdldCggMCApLnJlbW92ZUNoaWxkKCB0aGF0Lmdob3N0LmdldCggMCApICk7XG5cdFx0fVxuXHR9XG5cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcInJlc2l6YWJsZVwiLCBcImdyaWRcIiwge1xuXG5cdHJlc2l6ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG91dGVyRGltZW5zaW9ucyxcblx0XHRcdHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRjcyA9IHRoYXQuc2l6ZSxcblx0XHRcdG9zID0gdGhhdC5vcmlnaW5hbFNpemUsXG5cdFx0XHRvcCA9IHRoYXQub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdGEgPSB0aGF0LmF4aXMsXG5cdFx0XHRncmlkID0gdHlwZW9mIG8uZ3JpZCA9PT0gXCJudW1iZXJcIiA/IFsgby5ncmlkLCBvLmdyaWQgXSA6IG8uZ3JpZCxcblx0XHRcdGdyaWRYID0gKCBncmlkWyAwIF0gfHwgMSApLFxuXHRcdFx0Z3JpZFkgPSAoIGdyaWRbIDEgXSB8fCAxICksXG5cdFx0XHRveCA9IE1hdGgucm91bmQoICggY3Mud2lkdGggLSBvcy53aWR0aCApIC8gZ3JpZFggKSAqIGdyaWRYLFxuXHRcdFx0b3kgPSBNYXRoLnJvdW5kKCAoIGNzLmhlaWdodCAtIG9zLmhlaWdodCApIC8gZ3JpZFkgKSAqIGdyaWRZLFxuXHRcdFx0bmV3V2lkdGggPSBvcy53aWR0aCArIG94LFxuXHRcdFx0bmV3SGVpZ2h0ID0gb3MuaGVpZ2h0ICsgb3ksXG5cdFx0XHRpc01heFdpZHRoID0gby5tYXhXaWR0aCAmJiAoIG8ubWF4V2lkdGggPCBuZXdXaWR0aCApLFxuXHRcdFx0aXNNYXhIZWlnaHQgPSBvLm1heEhlaWdodCAmJiAoIG8ubWF4SGVpZ2h0IDwgbmV3SGVpZ2h0ICksXG5cdFx0XHRpc01pbldpZHRoID0gby5taW5XaWR0aCAmJiAoIG8ubWluV2lkdGggPiBuZXdXaWR0aCApLFxuXHRcdFx0aXNNaW5IZWlnaHQgPSBvLm1pbkhlaWdodCAmJiAoIG8ubWluSGVpZ2h0ID4gbmV3SGVpZ2h0ICk7XG5cblx0XHRvLmdyaWQgPSBncmlkO1xuXG5cdFx0aWYgKCBpc01pbldpZHRoICkge1xuXHRcdFx0bmV3V2lkdGggKz0gZ3JpZFg7XG5cdFx0fVxuXHRcdGlmICggaXNNaW5IZWlnaHQgKSB7XG5cdFx0XHRuZXdIZWlnaHQgKz0gZ3JpZFk7XG5cdFx0fVxuXHRcdGlmICggaXNNYXhXaWR0aCApIHtcblx0XHRcdG5ld1dpZHRoIC09IGdyaWRYO1xuXHRcdH1cblx0XHRpZiAoIGlzTWF4SGVpZ2h0ICkge1xuXHRcdFx0bmV3SGVpZ2h0IC09IGdyaWRZO1xuXHRcdH1cblxuXHRcdGlmICggL14oc2V8c3xlKSQvLnRlc3QoIGEgKSApIHtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IG5ld1dpZHRoO1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IG5ld0hlaWdodDtcblx0XHR9IGVsc2UgaWYgKCAvXihuZSkkLy50ZXN0KCBhICkgKSB7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSBuZXdXaWR0aDtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSBuZXdIZWlnaHQ7XG5cdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCA9IG9wLnRvcCAtIG95O1xuXHRcdH0gZWxzZSBpZiAoIC9eKHN3KSQvLnRlc3QoIGEgKSApIHtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IG5ld1dpZHRoO1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IG5ld0hlaWdodDtcblx0XHRcdHRoYXQucG9zaXRpb24ubGVmdCA9IG9wLmxlZnQgLSBveDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aWYgKCBuZXdIZWlnaHQgLSBncmlkWSA8PSAwIHx8IG5ld1dpZHRoIC0gZ3JpZFggPD0gMCApIHtcblx0XHRcdFx0b3V0ZXJEaW1lbnNpb25zID0gdGhhdC5fZ2V0UGFkZGluZ1BsdXNCb3JkZXJEaW1lbnNpb25zKCB0aGlzICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggbmV3SGVpZ2h0IC0gZ3JpZFkgPiAwICkge1xuXHRcdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gbmV3SGVpZ2h0O1xuXHRcdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCA9IG9wLnRvcCAtIG95O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0bmV3SGVpZ2h0ID0gZ3JpZFkgLSBvdXRlckRpbWVuc2lvbnMuaGVpZ2h0O1xuXHRcdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gbmV3SGVpZ2h0O1xuXHRcdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCA9IG9wLnRvcCArIG9zLmhlaWdodCAtIG5ld0hlaWdodDtcblx0XHRcdH1cblx0XHRcdGlmICggbmV3V2lkdGggLSBncmlkWCA+IDAgKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IG5ld1dpZHRoO1xuXHRcdFx0XHR0aGF0LnBvc2l0aW9uLmxlZnQgPSBvcC5sZWZ0IC0gb3g7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRuZXdXaWR0aCA9IGdyaWRYIC0gb3V0ZXJEaW1lbnNpb25zLndpZHRoO1xuXHRcdFx0XHR0aGF0LnNpemUud2lkdGggPSBuZXdXaWR0aDtcblx0XHRcdFx0dGhhdC5wb3NpdGlvbi5sZWZ0ID0gb3AubGVmdCArIG9zLndpZHRoIC0gbmV3V2lkdGg7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cbn0gKTtcblxudmFyIHdpZGdldHNSZXNpemFibGUgPSAkLnVpLnJlc2l6YWJsZTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBEaWFsb2cgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IERpYWxvZ1xuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGN1c3RvbWl6YWJsZSBkaWFsb2cgd2luZG93cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kaWFsb2cvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZGlhbG9nL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvZGlhbG9nLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5kaWFsb2dcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YXBwZW5kVG86IFwiYm9keVwiLFxuXHRcdGF1dG9PcGVuOiB0cnVlLFxuXHRcdGJ1dHRvbnM6IFtdLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktZGlhbG9nXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1kaWFsb2ctdGl0bGViYXJcIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHR9LFxuXHRcdGNsb3NlT25Fc2NhcGU6IHRydWUsXG5cdFx0Y2xvc2VUZXh0OiBcIkNsb3NlXCIsXG5cdFx0ZHJhZ2dhYmxlOiB0cnVlLFxuXHRcdGhpZGU6IG51bGwsXG5cdFx0aGVpZ2h0OiBcImF1dG9cIixcblx0XHRtYXhIZWlnaHQ6IG51bGwsXG5cdFx0bWF4V2lkdGg6IG51bGwsXG5cdFx0bWluSGVpZ2h0OiAxNTAsXG5cdFx0bWluV2lkdGg6IDE1MCxcblx0XHRtb2RhbDogZmFsc2UsXG5cdFx0cG9zaXRpb246IHtcblx0XHRcdG15OiBcImNlbnRlclwiLFxuXHRcdFx0YXQ6IFwiY2VudGVyXCIsXG5cdFx0XHRvZjogd2luZG93LFxuXHRcdFx0Y29sbGlzaW9uOiBcImZpdFwiLFxuXG5cdFx0XHQvLyBFbnN1cmUgdGhlIHRpdGxlYmFyIGlzIGFsd2F5cyB2aXNpYmxlXG5cdFx0XHR1c2luZzogZnVuY3Rpb24oIHBvcyApIHtcblx0XHRcdFx0dmFyIHRvcE9mZnNldCA9ICQoIHRoaXMgKS5jc3MoIHBvcyApLm9mZnNldCgpLnRvcDtcblx0XHRcdFx0aWYgKCB0b3BPZmZzZXQgPCAwICkge1xuXHRcdFx0XHRcdCQoIHRoaXMgKS5jc3MoIFwidG9wXCIsIHBvcy50b3AgLSB0b3BPZmZzZXQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cdFx0cmVzaXphYmxlOiB0cnVlLFxuXHRcdHNob3c6IG51bGwsXG5cdFx0dGl0bGU6IG51bGwsXG5cdFx0d2lkdGg6IDMwMCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGJlZm9yZUNsb3NlOiBudWxsLFxuXHRcdGNsb3NlOiBudWxsLFxuXHRcdGRyYWc6IG51bGwsXG5cdFx0ZHJhZ1N0YXJ0OiBudWxsLFxuXHRcdGRyYWdTdG9wOiBudWxsLFxuXHRcdGZvY3VzOiBudWxsLFxuXHRcdG9wZW46IG51bGwsXG5cdFx0cmVzaXplOiBudWxsLFxuXHRcdHJlc2l6ZVN0YXJ0OiBudWxsLFxuXHRcdHJlc2l6ZVN0b3A6IG51bGxcblx0fSxcblxuXHRzaXplUmVsYXRlZE9wdGlvbnM6IHtcblx0XHRidXR0b25zOiB0cnVlLFxuXHRcdGhlaWdodDogdHJ1ZSxcblx0XHRtYXhIZWlnaHQ6IHRydWUsXG5cdFx0bWF4V2lkdGg6IHRydWUsXG5cdFx0bWluSGVpZ2h0OiB0cnVlLFxuXHRcdG1pbldpZHRoOiB0cnVlLFxuXHRcdHdpZHRoOiB0cnVlXG5cdH0sXG5cblx0cmVzaXphYmxlUmVsYXRlZE9wdGlvbnM6IHtcblx0XHRtYXhIZWlnaHQ6IHRydWUsXG5cdFx0bWF4V2lkdGg6IHRydWUsXG5cdFx0bWluSGVpZ2h0OiB0cnVlLFxuXHRcdG1pbldpZHRoOiB0cnVlXG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5vcmlnaW5hbENzcyA9IHtcblx0XHRcdGRpc3BsYXk6IHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLmRpc3BsYXksXG5cdFx0XHR3aWR0aDogdGhpcy5lbGVtZW50WyAwIF0uc3R5bGUud2lkdGgsXG5cdFx0XHRtaW5IZWlnaHQ6IHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLm1pbkhlaWdodCxcblx0XHRcdG1heEhlaWdodDogdGhpcy5lbGVtZW50WyAwIF0uc3R5bGUubWF4SGVpZ2h0LFxuXHRcdFx0aGVpZ2h0OiB0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS5oZWlnaHRcblx0XHR9O1xuXHRcdHRoaXMub3JpZ2luYWxQb3NpdGlvbiA9IHtcblx0XHRcdHBhcmVudDogdGhpcy5lbGVtZW50LnBhcmVudCgpLFxuXHRcdFx0aW5kZXg6IHRoaXMuZWxlbWVudC5wYXJlbnQoKS5jaGlsZHJlbigpLmluZGV4KCB0aGlzLmVsZW1lbnQgKVxuXHRcdH07XG5cdFx0dGhpcy5vcmlnaW5hbFRpdGxlID0gdGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLnRpdGxlID09IG51bGwgJiYgdGhpcy5vcmlnaW5hbFRpdGxlICE9IG51bGwgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMudGl0bGUgPSB0aGlzLm9yaWdpbmFsVGl0bGU7XG5cdFx0fVxuXG5cdFx0Ly8gRGlhbG9ncyBjYW4ndCBiZSBkaXNhYmxlZFxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLmRpc2FibGVkID0gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dGhpcy5fY3JlYXRlV3JhcHBlcigpO1xuXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQuc2hvdygpXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJ0aXRsZVwiIClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy51aURpYWxvZyApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktZGlhbG9nLWNvbnRlbnRcIiwgXCJ1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHR0aGlzLl9jcmVhdGVUaXRsZWJhcigpO1xuXHRcdHRoaXMuX2NyZWF0ZUJ1dHRvblBhbmUoKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRyYWdnYWJsZSAmJiAkLmZuLmRyYWdnYWJsZSApIHtcblx0XHRcdHRoaXMuX21ha2VEcmFnZ2FibGUoKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMucmVzaXphYmxlICYmICQuZm4ucmVzaXphYmxlICkge1xuXHRcdFx0dGhpcy5fbWFrZVJlc2l6YWJsZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2lzT3BlbiA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fdHJhY2tGb2N1cygpO1xuXHR9LFxuXG5cdF9pbml0OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5hdXRvT3BlbiApIHtcblx0XHRcdHRoaXMub3BlbigpO1xuXHRcdH1cblx0fSxcblxuXHRfYXBwZW5kVG86IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlbGVtZW50ID0gdGhpcy5vcHRpb25zLmFwcGVuZFRvO1xuXHRcdGlmICggZWxlbWVudCAmJiAoIGVsZW1lbnQuanF1ZXJ5IHx8IGVsZW1lbnQubm9kZVR5cGUgKSApIHtcblx0XHRcdHJldHVybiAkKCBlbGVtZW50ICk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmRvY3VtZW50LmZpbmQoIGVsZW1lbnQgfHwgXCJib2R5XCIgKS5lcSggMCApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbmV4dCxcblx0XHRcdG9yaWdpbmFsUG9zaXRpb24gPSB0aGlzLm9yaWdpbmFsUG9zaXRpb247XG5cblx0XHR0aGlzLl91bnRyYWNrSW5zdGFuY2UoKTtcblx0XHR0aGlzLl9kZXN0cm95T3ZlcmxheSgpO1xuXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQucmVtb3ZlVW5pcXVlSWQoKVxuXHRcdFx0LmNzcyggdGhpcy5vcmlnaW5hbENzcyApXG5cblx0XHRcdC8vIFdpdGhvdXQgZGV0YWNoaW5nIGZpcnN0LCB0aGUgZm9sbG93aW5nIGJlY29tZXMgcmVhbGx5IHNsb3dcblx0XHRcdC5kZXRhY2goKTtcblxuXHRcdHRoaXMudWlEaWFsb2cucmVtb3ZlKCk7XG5cblx0XHRpZiAoIHRoaXMub3JpZ2luYWxUaXRsZSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIsIHRoaXMub3JpZ2luYWxUaXRsZSApO1xuXHRcdH1cblxuXHRcdG5leHQgPSBvcmlnaW5hbFBvc2l0aW9uLnBhcmVudC5jaGlsZHJlbigpLmVxKCBvcmlnaW5hbFBvc2l0aW9uLmluZGV4ICk7XG5cblx0XHQvLyBEb24ndCB0cnkgdG8gcGxhY2UgdGhlIGRpYWxvZyBuZXh0IHRvIGl0c2VsZiAoIzg2MTMpXG5cdFx0aWYgKCBuZXh0Lmxlbmd0aCAmJiBuZXh0WyAwIF0gIT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0bmV4dC5iZWZvcmUoIHRoaXMuZWxlbWVudCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRvcmlnaW5hbFBvc2l0aW9uLnBhcmVudC5hcHBlbmQoIHRoaXMuZWxlbWVudCApO1xuXHRcdH1cblx0fSxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnVpRGlhbG9nO1xuXHR9LFxuXG5cdGRpc2FibGU6ICQubm9vcCxcblx0ZW5hYmxlOiAkLm5vb3AsXG5cblx0Y2xvc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHRpZiAoICF0aGlzLl9pc09wZW4gfHwgdGhpcy5fdHJpZ2dlciggXCJiZWZvcmVDbG9zZVwiLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9pc09wZW4gPSBmYWxzZTtcblx0XHR0aGlzLl9mb2N1c2VkRWxlbWVudCA9IG51bGw7XG5cdFx0dGhpcy5fZGVzdHJveU92ZXJsYXkoKTtcblx0XHR0aGlzLl91bnRyYWNrSW5zdGFuY2UoKTtcblxuXHRcdGlmICggIXRoaXMub3BlbmVyLmZpbHRlciggXCI6Zm9jdXNhYmxlXCIgKS50cmlnZ2VyKCBcImZvY3VzXCIgKS5sZW5ndGggKSB7XG5cblx0XHRcdC8vIEhpZGluZyBhIGZvY3VzZWQgZWxlbWVudCBkb2Vzbid0IHRyaWdnZXIgYmx1ciBpbiBXZWJLaXRcblx0XHRcdC8vIHNvIGluIGNhc2Ugd2UgaGF2ZSBub3RoaW5nIHRvIGZvY3VzIG9uLCBleHBsaWNpdGx5IGJsdXIgdGhlIGFjdGl2ZSBlbGVtZW50XG5cdFx0XHQvLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9NDcxODJcblx0XHRcdCQudWkuc2FmZUJsdXIoICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5faGlkZSggdGhpcy51aURpYWxvZywgdGhpcy5vcHRpb25zLmhpZGUsIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhhdC5fdHJpZ2dlciggXCJjbG9zZVwiLCBldmVudCApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRpc09wZW46IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLl9pc09wZW47XG5cdH0sXG5cblx0bW92ZVRvVG9wOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9tb3ZlVG9Ub3AoKTtcblx0fSxcblxuXHRfbW92ZVRvVG9wOiBmdW5jdGlvbiggZXZlbnQsIHNpbGVudCApIHtcblx0XHR2YXIgbW92ZWQgPSBmYWxzZSxcblx0XHRcdHpJbmRpY2VzID0gdGhpcy51aURpYWxvZy5zaWJsaW5ncyggXCIudWktZnJvbnQ6dmlzaWJsZVwiICkubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICskKCB0aGlzICkuY3NzKCBcInotaW5kZXhcIiApO1xuXHRcdFx0fSApLmdldCgpLFxuXHRcdFx0ekluZGV4TWF4ID0gTWF0aC5tYXguYXBwbHkoIG51bGwsIHpJbmRpY2VzICk7XG5cblx0XHRpZiAoIHpJbmRleE1heCA+PSArdGhpcy51aURpYWxvZy5jc3MoIFwiei1pbmRleFwiICkgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLmNzcyggXCJ6LWluZGV4XCIsIHpJbmRleE1heCArIDEgKTtcblx0XHRcdG1vdmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRpZiAoIG1vdmVkICYmICFzaWxlbnQgKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImZvY3VzXCIsIGV2ZW50ICk7XG5cdFx0fVxuXHRcdHJldHVybiBtb3ZlZDtcblx0fSxcblxuXHRvcGVuOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0aWYgKCB0aGlzLl9pc09wZW4gKSB7XG5cdFx0XHRpZiAoIHRoaXMuX21vdmVUb1RvcCgpICkge1xuXHRcdFx0XHR0aGlzLl9mb2N1c1RhYmJhYmxlKCk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5faXNPcGVuID0gdHJ1ZTtcblx0XHR0aGlzLm9wZW5lciA9ICQoICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICk7XG5cblx0XHR0aGlzLl9zaXplKCk7XG5cdFx0dGhpcy5fcG9zaXRpb24oKTtcblx0XHR0aGlzLl9jcmVhdGVPdmVybGF5KCk7XG5cdFx0dGhpcy5fbW92ZVRvVG9wKCBudWxsLCB0cnVlICk7XG5cblx0XHQvLyBFbnN1cmUgdGhlIG92ZXJsYXkgaXMgbW92ZWQgdG8gdGhlIHRvcCB3aXRoIHRoZSBkaWFsb2csIGJ1dCBvbmx5IHdoZW5cblx0XHQvLyBvcGVuaW5nLiBUaGUgb3ZlcmxheSBzaG91bGRuJ3QgbW92ZSBhZnRlciB0aGUgZGlhbG9nIGlzIG9wZW4gc28gdGhhdFxuXHRcdC8vIG1vZGVsZXNzIGRpYWxvZ3Mgb3BlbmVkIGFmdGVyIHRoZSBtb2RhbCBkaWFsb2cgc3RhY2sgcHJvcGVybHkuXG5cdFx0aWYgKCB0aGlzLm92ZXJsYXkgKSB7XG5cdFx0XHR0aGlzLm92ZXJsYXkuY3NzKCBcInotaW5kZXhcIiwgdGhpcy51aURpYWxvZy5jc3MoIFwiei1pbmRleFwiICkgLSAxICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2hvdyggdGhpcy51aURpYWxvZywgdGhpcy5vcHRpb25zLnNob3csIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhhdC5fZm9jdXNUYWJiYWJsZSgpO1xuXHRcdFx0dGhhdC5fdHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gVHJhY2sgdGhlIGRpYWxvZyBpbW1lZGlhdGVseSB1cG9uIG9wZW5lbmluZyBpbiBjYXNlIGEgZm9jdXMgZXZlbnRcblx0XHQvLyBzb21laG93IG9jY3VycyBvdXRzaWRlIG9mIHRoZSBkaWFsb2cgYmVmb3JlIGFuIGVsZW1lbnQgaW5zaWRlIHRoZVxuXHRcdC8vIGRpYWxvZyBpcyBmb2N1c2VkICgjMTAxNTIpXG5cdFx0dGhpcy5fbWFrZUZvY3VzVGFyZ2V0KCk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcIm9wZW5cIiApO1xuXHR9LFxuXG5cdF9mb2N1c1RhYmJhYmxlOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIFNldCBmb2N1cyB0byB0aGUgZmlyc3QgbWF0Y2g6XG5cdFx0Ly8gMS4gQW4gZWxlbWVudCB0aGF0IHdhcyBmb2N1c2VkIHByZXZpb3VzbHlcblx0XHQvLyAyLiBGaXJzdCBlbGVtZW50IGluc2lkZSB0aGUgZGlhbG9nIG1hdGNoaW5nIFthdXRvZm9jdXNdXG5cdFx0Ly8gMy4gVGFiYmFibGUgZWxlbWVudCBpbnNpZGUgdGhlIGNvbnRlbnQgZWxlbWVudFxuXHRcdC8vIDQuIFRhYmJhYmxlIGVsZW1lbnQgaW5zaWRlIHRoZSBidXR0b25wYW5lXG5cdFx0Ly8gNS4gVGhlIGNsb3NlIGJ1dHRvblxuXHRcdC8vIDYuIFRoZSBkaWFsb2cgaXRzZWxmXG5cdFx0dmFyIGhhc0ZvY3VzID0gdGhpcy5fZm9jdXNlZEVsZW1lbnQ7XG5cdFx0aWYgKCAhaGFzRm9jdXMgKSB7XG5cdFx0XHRoYXNGb2N1cyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIlthdXRvZm9jdXNdXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAhaGFzRm9jdXMubGVuZ3RoICkge1xuXHRcdFx0aGFzRm9jdXMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCI6dGFiYmFibGVcIiApO1xuXHRcdH1cblx0XHRpZiAoICFoYXNGb2N1cy5sZW5ndGggKSB7XG5cdFx0XHRoYXNGb2N1cyA9IHRoaXMudWlEaWFsb2dCdXR0b25QYW5lLmZpbmQoIFwiOnRhYmJhYmxlXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAhaGFzRm9jdXMubGVuZ3RoICkge1xuXHRcdFx0aGFzRm9jdXMgPSB0aGlzLnVpRGlhbG9nVGl0bGViYXJDbG9zZS5maWx0ZXIoIFwiOnRhYmJhYmxlXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAhaGFzRm9jdXMubGVuZ3RoICkge1xuXHRcdFx0aGFzRm9jdXMgPSB0aGlzLnVpRGlhbG9nO1xuXHRcdH1cblx0XHRoYXNGb2N1cy5lcSggMCApLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHR9LFxuXG5cdF9rZWVwRm9jdXM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRmdW5jdGlvbiBjaGVja0ZvY3VzKCkge1xuXHRcdFx0dmFyIGFjdGl2ZUVsZW1lbnQgPSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSxcblx0XHRcdFx0aXNBY3RpdmUgPSB0aGlzLnVpRGlhbG9nWyAwIF0gPT09IGFjdGl2ZUVsZW1lbnQgfHxcblx0XHRcdFx0XHQkLmNvbnRhaW5zKCB0aGlzLnVpRGlhbG9nWyAwIF0sIGFjdGl2ZUVsZW1lbnQgKTtcblx0XHRcdGlmICggIWlzQWN0aXZlICkge1xuXHRcdFx0XHR0aGlzLl9mb2N1c1RhYmJhYmxlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0Y2hlY2tGb2N1cy5jYWxsKCB0aGlzICk7XG5cblx0XHQvLyBzdXBwb3J0OiBJRVxuXHRcdC8vIElFIDw9IDggZG9lc24ndCBwcmV2ZW50IG1vdmluZyBmb2N1cyBldmVuIHdpdGggZXZlbnQucHJldmVudERlZmF1bHQoKVxuXHRcdC8vIHNvIHdlIGNoZWNrIGFnYWluIGxhdGVyXG5cdFx0dGhpcy5fZGVsYXkoIGNoZWNrRm9jdXMgKTtcblx0fSxcblxuXHRfY3JlYXRlV3JhcHBlcjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy51aURpYWxvZyA9ICQoIFwiPGRpdj5cIiApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYXR0cigge1xuXG5cdFx0XHRcdC8vIFNldHRpbmcgdGFiSW5kZXggbWFrZXMgdGhlIGRpdiBmb2N1c2FibGVcblx0XHRcdFx0dGFiSW5kZXg6IC0xLFxuXHRcdFx0XHRyb2xlOiBcImRpYWxvZ1wiXG5cdFx0XHR9IClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlEaWFsb2csIFwidWktZGlhbG9nXCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50IHVpLWZyb250XCIgKTtcblx0XHR0aGlzLl9vbiggdGhpcy51aURpYWxvZywge1xuXHRcdFx0a2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5jbG9zZU9uRXNjYXBlICYmICFldmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSAmJiBldmVudC5rZXlDb2RlICYmXG5cdFx0XHRcdFx0XHRldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuRVNDQVBFICkge1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBQcmV2ZW50IHRhYmJpbmcgb3V0IG9mIGRpYWxvZ3Ncblx0XHRcdFx0aWYgKCBldmVudC5rZXlDb2RlICE9PSAkLnVpLmtleUNvZGUuVEFCIHx8IGV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHR2YXIgdGFiYmFibGVzID0gdGhpcy51aURpYWxvZy5maW5kKCBcIjp0YWJiYWJsZVwiICksXG5cdFx0XHRcdFx0Zmlyc3QgPSB0YWJiYWJsZXMuZmlsdGVyKCBcIjpmaXJzdFwiICksXG5cdFx0XHRcdFx0bGFzdCA9IHRhYmJhYmxlcy5maWx0ZXIoIFwiOmxhc3RcIiApO1xuXG5cdFx0XHRcdGlmICggKCBldmVudC50YXJnZXQgPT09IGxhc3RbIDAgXSB8fCBldmVudC50YXJnZXQgPT09IHRoaXMudWlEaWFsb2dbIDAgXSApICYmXG5cdFx0XHRcdFx0XHQhZXZlbnQuc2hpZnRLZXkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0Zmlyc3QudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoICggZXZlbnQudGFyZ2V0ID09PSBmaXJzdFsgMCBdIHx8XG5cdFx0XHRcdFx0XHRldmVudC50YXJnZXQgPT09IHRoaXMudWlEaWFsb2dbIDAgXSApICYmIGV2ZW50LnNoaWZ0S2V5ICkge1xuXHRcdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGxhc3QudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRtb3VzZWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLl9tb3ZlVG9Ub3AoIGV2ZW50ICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fZm9jdXNUYWJiYWJsZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0Ly8gV2UgYXNzdW1lIHRoYXQgYW55IGV4aXN0aW5nIGFyaWEtZGVzY3JpYmVkYnkgYXR0cmlidXRlIG1lYW5zXG5cdFx0Ly8gdGhhdCB0aGUgZGlhbG9nIGNvbnRlbnQgaXMgbWFya2VkIHVwIHByb3Blcmx5XG5cdFx0Ly8gb3RoZXJ3aXNlIHdlIGJydXRlIGZvcmNlIHRoZSBjb250ZW50IGFzIHRoZSBkZXNjcmlwdGlvblxuXHRcdGlmICggIXRoaXMuZWxlbWVudC5maW5kKCBcIlthcmlhLWRlc2NyaWJlZGJ5XVwiICkubGVuZ3RoICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5hdHRyKCB7XG5cdFx0XHRcdFwiYXJpYS1kZXNjcmliZWRieVwiOiB0aGlzLmVsZW1lbnQudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKVxuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfY3JlYXRlVGl0bGViYXI6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB1aURpYWxvZ1RpdGxlO1xuXG5cdFx0dGhpcy51aURpYWxvZ1RpdGxlYmFyID0gJCggXCI8ZGl2PlwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlEaWFsb2dUaXRsZWJhcixcblx0XHRcdFwidWktZGlhbG9nLXRpdGxlYmFyXCIsIFwidWktd2lkZ2V0LWhlYWRlciB1aS1oZWxwZXItY2xlYXJmaXhcIiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLnVpRGlhbG9nVGl0bGViYXIsIHtcblx0XHRcdG1vdXNlZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHRcdC8vIERvbid0IHByZXZlbnQgY2xpY2sgb24gY2xvc2UgYnV0dG9uICgjODgzOClcblx0XHRcdFx0Ly8gRm9jdXNpbmcgYSBkaWFsb2cgdGhhdCBpcyBwYXJ0aWFsbHkgc2Nyb2xsZWQgb3V0IG9mIHZpZXdcblx0XHRcdFx0Ly8gY2F1c2VzIHRoZSBicm93c2VyIHRvIHNjcm9sbCBpdCBpbnRvIHZpZXcsIHByZXZlbnRpbmcgdGhlIGNsaWNrIGV2ZW50XG5cdFx0XHRcdGlmICggISQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLWRpYWxvZy10aXRsZWJhci1jbG9zZVwiICkgKSB7XG5cblx0XHRcdFx0XHQvLyBEaWFsb2cgaXNuJ3QgZ2V0dGluZyBmb2N1cyB3aGVuIGRyYWdnaW5nICgjODA2Mylcblx0XHRcdFx0XHR0aGlzLnVpRGlhbG9nLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0Ly8gU3VwcG9ydDogSUVcblx0XHQvLyBVc2UgdHlwZT1cImJ1dHRvblwiIHRvIHByZXZlbnQgZW50ZXIga2V5cHJlc3NlcyBpbiB0ZXh0Ym94ZXMgZnJvbSBjbG9zaW5nIHRoZVxuXHRcdC8vIGRpYWxvZyBpbiBJRSAoIzkzMTIpXG5cdFx0dGhpcy51aURpYWxvZ1RpdGxlYmFyQ2xvc2UgPSAkKCBcIjxidXR0b24gdHlwZT0nYnV0dG9uJz48L2J1dHRvbj5cIiApXG5cdFx0XHQuYnV0dG9uKCB7XG5cdFx0XHRcdGxhYmVsOiAkKCBcIjxhPlwiICkudGV4dCggdGhpcy5vcHRpb25zLmNsb3NlVGV4dCApLmh0bWwoKSxcblx0XHRcdFx0aWNvbjogXCJ1aS1pY29uLWNsb3NldGhpY2tcIixcblx0XHRcdFx0c2hvd0xhYmVsOiBmYWxzZVxuXHRcdFx0fSApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMudWlEaWFsb2dUaXRsZWJhciApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlEaWFsb2dUaXRsZWJhckNsb3NlLCBcInVpLWRpYWxvZy10aXRsZWJhci1jbG9zZVwiICk7XG5cdFx0dGhpcy5fb24oIHRoaXMudWlEaWFsb2dUaXRsZWJhckNsb3NlLCB7XG5cdFx0XHRjbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHVpRGlhbG9nVGl0bGUgPSAkKCBcIjxzcGFuPlwiICkudW5pcXVlSWQoKS5wcmVwZW5kVG8oIHRoaXMudWlEaWFsb2dUaXRsZWJhciApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB1aURpYWxvZ1RpdGxlLCBcInVpLWRpYWxvZy10aXRsZVwiICk7XG5cdFx0dGhpcy5fdGl0bGUoIHVpRGlhbG9nVGl0bGUgKTtcblxuXHRcdHRoaXMudWlEaWFsb2dUaXRsZWJhci5wcmVwZW5kVG8oIHRoaXMudWlEaWFsb2cgKTtcblxuXHRcdHRoaXMudWlEaWFsb2cuYXR0cigge1xuXHRcdFx0XCJhcmlhLWxhYmVsbGVkYnlcIjogdWlEaWFsb2dUaXRsZS5hdHRyKCBcImlkXCIgKVxuXHRcdH0gKTtcblx0fSxcblxuXHRfdGl0bGU6IGZ1bmN0aW9uKCB0aXRsZSApIHtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy50aXRsZSApIHtcblx0XHRcdHRpdGxlLnRleHQoIHRoaXMub3B0aW9ucy50aXRsZSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aXRsZS5odG1sKCBcIiYjMTYwO1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9jcmVhdGVCdXR0b25QYW5lOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZSA9ICQoIFwiPGRpdj5cIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZSwgXCJ1aS1kaWFsb2ctYnV0dG9ucGFuZVwiLFxuXHRcdFx0XCJ1aS13aWRnZXQtY29udGVudCB1aS1oZWxwZXItY2xlYXJmaXhcIiApO1xuXG5cdFx0dGhpcy51aUJ1dHRvblNldCA9ICQoIFwiPGRpdj5cIiApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMudWlEaWFsb2dCdXR0b25QYW5lICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlCdXR0b25TZXQsIFwidWktZGlhbG9nLWJ1dHRvbnNldFwiICk7XG5cblx0XHR0aGlzLl9jcmVhdGVCdXR0b25zKCk7XG5cdH0sXG5cblx0X2NyZWF0ZUJ1dHRvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGJ1dHRvbnMgPSB0aGlzLm9wdGlvbnMuYnV0dG9ucztcblxuXHRcdC8vIElmIHdlIGFscmVhZHkgaGF2ZSBhIGJ1dHRvbiBwYW5lLCByZW1vdmUgaXRcblx0XHR0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZS5yZW1vdmUoKTtcblx0XHR0aGlzLnVpQnV0dG9uU2V0LmVtcHR5KCk7XG5cblx0XHRpZiAoICQuaXNFbXB0eU9iamVjdCggYnV0dG9ucyApIHx8ICggJC5pc0FycmF5KCBidXR0b25zICkgJiYgIWJ1dHRvbnMubGVuZ3RoICkgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy51aURpYWxvZywgXCJ1aS1kaWFsb2ctYnV0dG9uc1wiICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0JC5lYWNoKCBidXR0b25zLCBmdW5jdGlvbiggbmFtZSwgcHJvcHMgKSB7XG5cdFx0XHR2YXIgY2xpY2ssIGJ1dHRvbk9wdGlvbnM7XG5cdFx0XHRwcm9wcyA9ICQuaXNGdW5jdGlvbiggcHJvcHMgKSA/XG5cdFx0XHRcdHsgY2xpY2s6IHByb3BzLCB0ZXh0OiBuYW1lIH0gOlxuXHRcdFx0XHRwcm9wcztcblxuXHRcdFx0Ly8gRGVmYXVsdCB0byBhIG5vbi1zdWJtaXR0aW5nIGJ1dHRvblxuXHRcdFx0cHJvcHMgPSAkLmV4dGVuZCggeyB0eXBlOiBcImJ1dHRvblwiIH0sIHByb3BzICk7XG5cblx0XHRcdC8vIENoYW5nZSB0aGUgY29udGV4dCBmb3IgdGhlIGNsaWNrIGNhbGxiYWNrIHRvIGJlIHRoZSBtYWluIGVsZW1lbnRcblx0XHRcdGNsaWNrID0gcHJvcHMuY2xpY2s7XG5cdFx0XHRidXR0b25PcHRpb25zID0ge1xuXHRcdFx0XHRpY29uOiBwcm9wcy5pY29uLFxuXHRcdFx0XHRpY29uUG9zaXRpb246IHByb3BzLmljb25Qb3NpdGlvbixcblx0XHRcdFx0c2hvd0xhYmVsOiBwcm9wcy5zaG93TGFiZWwsXG5cblx0XHRcdFx0Ly8gRGVwcmVjYXRlZCBvcHRpb25zXG5cdFx0XHRcdGljb25zOiBwcm9wcy5pY29ucyxcblx0XHRcdFx0dGV4dDogcHJvcHMudGV4dFxuXHRcdFx0fTtcblxuXHRcdFx0ZGVsZXRlIHByb3BzLmNsaWNrO1xuXHRcdFx0ZGVsZXRlIHByb3BzLmljb247XG5cdFx0XHRkZWxldGUgcHJvcHMuaWNvblBvc2l0aW9uO1xuXHRcdFx0ZGVsZXRlIHByb3BzLnNob3dMYWJlbDtcblxuXHRcdFx0Ly8gRGVwcmVjYXRlZCBvcHRpb25zXG5cdFx0XHRkZWxldGUgcHJvcHMuaWNvbnM7XG5cdFx0XHRpZiAoIHR5cGVvZiBwcm9wcy50ZXh0ID09PSBcImJvb2xlYW5cIiApIHtcblx0XHRcdFx0ZGVsZXRlIHByb3BzLnRleHQ7XG5cdFx0XHR9XG5cblx0XHRcdCQoIFwiPGJ1dHRvbj48L2J1dHRvbj5cIiwgcHJvcHMgKVxuXHRcdFx0XHQuYnV0dG9uKCBidXR0b25PcHRpb25zIClcblx0XHRcdFx0LmFwcGVuZFRvKCB0aGF0LnVpQnV0dG9uU2V0IClcblx0XHRcdFx0Lm9uKCBcImNsaWNrXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGNsaWNrLmFwcGx5KCB0aGF0LmVsZW1lbnRbIDAgXSwgYXJndW1lbnRzICk7XG5cdFx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlEaWFsb2csIFwidWktZGlhbG9nLWJ1dHRvbnNcIiApO1xuXHRcdHRoaXMudWlEaWFsb2dCdXR0b25QYW5lLmFwcGVuZFRvKCB0aGlzLnVpRGlhbG9nICk7XG5cdH0sXG5cblx0X21ha2VEcmFnZ2FibGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRmdW5jdGlvbiBmaWx0ZXJlZFVpKCB1aSApIHtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdHBvc2l0aW9uOiB1aS5wb3NpdGlvbixcblx0XHRcdFx0b2Zmc2V0OiB1aS5vZmZzZXRcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0dGhpcy51aURpYWxvZy5kcmFnZ2FibGUoIHtcblx0XHRcdGNhbmNlbDogXCIudWktZGlhbG9nLWNvbnRlbnQsIC51aS1kaWFsb2ctdGl0bGViYXItY2xvc2VcIixcblx0XHRcdGhhbmRsZTogXCIudWktZGlhbG9nLXRpdGxlYmFyXCIsXG5cdFx0XHRjb250YWlubWVudDogXCJkb2N1bWVudFwiLFxuXHRcdFx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCAkKCB0aGlzICksIFwidWktZGlhbG9nLWRyYWdnaW5nXCIgKTtcblx0XHRcdFx0dGhhdC5fYmxvY2tGcmFtZXMoKTtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJkcmFnU3RhcnRcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH0sXG5cdFx0XHRkcmFnOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImRyYWdcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH0sXG5cdFx0XHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR2YXIgbGVmdCA9IHVpLm9mZnNldC5sZWZ0IC0gdGhhdC5kb2N1bWVudC5zY3JvbGxMZWZ0KCksXG5cdFx0XHRcdFx0dG9wID0gdWkub2Zmc2V0LnRvcCAtIHRoYXQuZG9jdW1lbnQuc2Nyb2xsVG9wKCk7XG5cblx0XHRcdFx0b3B0aW9ucy5wb3NpdGlvbiA9IHtcblx0XHRcdFx0XHRteTogXCJsZWZ0IHRvcFwiLFxuXHRcdFx0XHRcdGF0OiBcImxlZnRcIiArICggbGVmdCA+PSAwID8gXCIrXCIgOiBcIlwiICkgKyBsZWZ0ICsgXCIgXCIgK1xuXHRcdFx0XHRcdFx0XCJ0b3BcIiArICggdG9wID49IDAgPyBcIitcIiA6IFwiXCIgKSArIHRvcCxcblx0XHRcdFx0XHRvZjogdGhhdC53aW5kb3dcblx0XHRcdFx0fTtcblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoICQoIHRoaXMgKSwgXCJ1aS1kaWFsb2ctZHJhZ2dpbmdcIiApO1xuXHRcdFx0XHR0aGF0Ll91bmJsb2NrRnJhbWVzKCk7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiZHJhZ1N0b3BcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X21ha2VSZXNpemFibGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRoYW5kbGVzID0gb3B0aW9ucy5yZXNpemFibGUsXG5cblx0XHRcdC8vIC51aS1yZXNpemFibGUgaGFzIHBvc2l0aW9uOiByZWxhdGl2ZSBkZWZpbmVkIGluIHRoZSBzdHlsZXNoZWV0XG5cdFx0XHQvLyBidXQgZGlhbG9ncyBoYXZlIHRvIHVzZSBhYnNvbHV0ZSBvciBmaXhlZCBwb3NpdGlvbmluZ1xuXHRcdFx0cG9zaXRpb24gPSB0aGlzLnVpRGlhbG9nLmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRyZXNpemVIYW5kbGVzID0gdHlwZW9mIGhhbmRsZXMgPT09IFwic3RyaW5nXCIgP1xuXHRcdFx0XHRoYW5kbGVzIDpcblx0XHRcdFx0XCJuLGUscyx3LHNlLHN3LG5lLG53XCI7XG5cblx0XHRmdW5jdGlvbiBmaWx0ZXJlZFVpKCB1aSApIHtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdG9yaWdpbmFsUG9zaXRpb246IHVpLm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRcdG9yaWdpbmFsU2l6ZTogdWkub3JpZ2luYWxTaXplLFxuXHRcdFx0XHRwb3NpdGlvbjogdWkucG9zaXRpb24sXG5cdFx0XHRcdHNpemU6IHVpLnNpemVcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0dGhpcy51aURpYWxvZy5yZXNpemFibGUoIHtcblx0XHRcdGNhbmNlbDogXCIudWktZGlhbG9nLWNvbnRlbnRcIixcblx0XHRcdGNvbnRhaW5tZW50OiBcImRvY3VtZW50XCIsXG5cdFx0XHRhbHNvUmVzaXplOiB0aGlzLmVsZW1lbnQsXG5cdFx0XHRtYXhXaWR0aDogb3B0aW9ucy5tYXhXaWR0aCxcblx0XHRcdG1heEhlaWdodDogb3B0aW9ucy5tYXhIZWlnaHQsXG5cdFx0XHRtaW5XaWR0aDogb3B0aW9ucy5taW5XaWR0aCxcblx0XHRcdG1pbkhlaWdodDogdGhpcy5fbWluSGVpZ2h0KCksXG5cdFx0XHRoYW5kbGVzOiByZXNpemVIYW5kbGVzLFxuXHRcdFx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCAkKCB0aGlzICksIFwidWktZGlhbG9nLXJlc2l6aW5nXCIgKTtcblx0XHRcdFx0dGhhdC5fYmxvY2tGcmFtZXMoKTtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJyZXNpemVTdGFydFwiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fSxcblx0XHRcdHJlc2l6ZTogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJyZXNpemVcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH0sXG5cdFx0XHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR2YXIgb2Zmc2V0ID0gdGhhdC51aURpYWxvZy5vZmZzZXQoKSxcblx0XHRcdFx0XHRsZWZ0ID0gb2Zmc2V0LmxlZnQgLSB0aGF0LmRvY3VtZW50LnNjcm9sbExlZnQoKSxcblx0XHRcdFx0XHR0b3AgPSBvZmZzZXQudG9wIC0gdGhhdC5kb2N1bWVudC5zY3JvbGxUb3AoKTtcblxuXHRcdFx0XHRvcHRpb25zLmhlaWdodCA9IHRoYXQudWlEaWFsb2cuaGVpZ2h0KCk7XG5cdFx0XHRcdG9wdGlvbnMud2lkdGggPSB0aGF0LnVpRGlhbG9nLndpZHRoKCk7XG5cdFx0XHRcdG9wdGlvbnMucG9zaXRpb24gPSB7XG5cdFx0XHRcdFx0bXk6IFwibGVmdCB0b3BcIixcblx0XHRcdFx0XHRhdDogXCJsZWZ0XCIgKyAoIGxlZnQgPj0gMCA/IFwiK1wiIDogXCJcIiApICsgbGVmdCArIFwiIFwiICtcblx0XHRcdFx0XHRcdFwidG9wXCIgKyAoIHRvcCA+PSAwID8gXCIrXCIgOiBcIlwiICkgKyB0b3AsXG5cdFx0XHRcdFx0b2Y6IHRoYXQud2luZG93XG5cdFx0XHRcdH07XG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCAkKCB0aGlzICksIFwidWktZGlhbG9nLXJlc2l6aW5nXCIgKTtcblx0XHRcdFx0dGhhdC5fdW5ibG9ja0ZyYW1lcygpO1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInJlc2l6ZVN0b3BcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH1cblx0XHR9IClcblx0XHRcdC5jc3MoIFwicG9zaXRpb25cIiwgcG9zaXRpb24gKTtcblx0fSxcblxuXHRfdHJhY2tGb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fb24oIHRoaXMud2lkZ2V0KCksIHtcblx0XHRcdGZvY3VzaW46IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fbWFrZUZvY3VzVGFyZ2V0KCk7XG5cdFx0XHRcdHRoaXMuX2ZvY3VzZWRFbGVtZW50ID0gJCggZXZlbnQudGFyZ2V0ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9tYWtlRm9jdXNUYXJnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3VudHJhY2tJbnN0YW5jZSgpO1xuXHRcdHRoaXMuX3RyYWNraW5nSW5zdGFuY2VzKCkudW5zaGlmdCggdGhpcyApO1xuXHR9LFxuXG5cdF91bnRyYWNrSW5zdGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpbnN0YW5jZXMgPSB0aGlzLl90cmFja2luZ0luc3RhbmNlcygpLFxuXHRcdFx0ZXhpc3RzID0gJC5pbkFycmF5KCB0aGlzLCBpbnN0YW5jZXMgKTtcblx0XHRpZiAoIGV4aXN0cyAhPT0gLTEgKSB7XG5cdFx0XHRpbnN0YW5jZXMuc3BsaWNlKCBleGlzdHMsIDEgKTtcblx0XHR9XG5cdH0sXG5cblx0X3RyYWNraW5nSW5zdGFuY2VzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaW5zdGFuY2VzID0gdGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1pbnN0YW5jZXNcIiApO1xuXHRcdGlmICggIWluc3RhbmNlcyApIHtcblx0XHRcdGluc3RhbmNlcyA9IFtdO1xuXHRcdFx0dGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1pbnN0YW5jZXNcIiwgaW5zdGFuY2VzICk7XG5cdFx0fVxuXHRcdHJldHVybiBpbnN0YW5jZXM7XG5cdH0sXG5cblx0X21pbkhlaWdodDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRyZXR1cm4gb3B0aW9ucy5oZWlnaHQgPT09IFwiYXV0b1wiID9cblx0XHRcdG9wdGlvbnMubWluSGVpZ2h0IDpcblx0XHRcdE1hdGgubWluKCBvcHRpb25zLm1pbkhlaWdodCwgb3B0aW9ucy5oZWlnaHQgKTtcblx0fSxcblxuXHRfcG9zaXRpb246IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gTmVlZCB0byBzaG93IHRoZSBkaWFsb2cgdG8gZ2V0IHRoZSBhY3R1YWwgb2Zmc2V0IGluIHRoZSBwb3NpdGlvbiBwbHVnaW5cblx0XHR2YXIgaXNWaXNpYmxlID0gdGhpcy51aURpYWxvZy5pcyggXCI6dmlzaWJsZVwiICk7XG5cdFx0aWYgKCAhaXNWaXNpYmxlICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5zaG93KCk7XG5cdFx0fVxuXHRcdHRoaXMudWlEaWFsb2cucG9zaXRpb24oIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApO1xuXHRcdGlmICggIWlzVmlzaWJsZSApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cuaGlkZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0cmVzaXplID0gZmFsc2UsXG5cdFx0XHRyZXNpemFibGVPcHRpb25zID0ge307XG5cblx0XHQkLmVhY2goIG9wdGlvbnMsIGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdFx0dGhhdC5fc2V0T3B0aW9uKCBrZXksIHZhbHVlICk7XG5cblx0XHRcdGlmICgga2V5IGluIHRoYXQuc2l6ZVJlbGF0ZWRPcHRpb25zICkge1xuXHRcdFx0XHRyZXNpemUgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBrZXkgaW4gdGhhdC5yZXNpemFibGVSZWxhdGVkT3B0aW9ucyApIHtcblx0XHRcdFx0cmVzaXphYmxlT3B0aW9uc1sga2V5IF0gPSB2YWx1ZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRpZiAoIHJlc2l6ZSApIHtcblx0XHRcdHRoaXMuX3NpemUoKTtcblx0XHRcdHRoaXMuX3Bvc2l0aW9uKCk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy51aURpYWxvZy5pcyggXCI6ZGF0YSh1aS1yZXNpemFibGUpXCIgKSApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cucmVzaXphYmxlKCBcIm9wdGlvblwiLCByZXNpemFibGVPcHRpb25zICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBpc0RyYWdnYWJsZSwgaXNSZXNpemFibGUsXG5cdFx0XHR1aURpYWxvZyA9IHRoaXMudWlEaWFsb2c7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJhcHBlbmRUb1wiICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImJ1dHRvbnNcIiApIHtcblx0XHRcdHRoaXMuX2NyZWF0ZUJ1dHRvbnMoKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJjbG9zZVRleHRcIiApIHtcblx0XHRcdHRoaXMudWlEaWFsb2dUaXRsZWJhckNsb3NlLmJ1dHRvbigge1xuXG5cdFx0XHRcdC8vIEVuc3VyZSB0aGF0IHdlIGFsd2F5cyBwYXNzIGEgc3RyaW5nXG5cdFx0XHRcdGxhYmVsOiAkKCBcIjxhPlwiICkudGV4dCggXCJcIiArIHRoaXMub3B0aW9ucy5jbG9zZVRleHQgKS5odG1sKClcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJkcmFnZ2FibGVcIiApIHtcblx0XHRcdGlzRHJhZ2dhYmxlID0gdWlEaWFsb2cuaXMoIFwiOmRhdGEodWktZHJhZ2dhYmxlKVwiICk7XG5cdFx0XHRpZiAoIGlzRHJhZ2dhYmxlICYmICF2YWx1ZSApIHtcblx0XHRcdFx0dWlEaWFsb2cuZHJhZ2dhYmxlKCBcImRlc3Ryb3lcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFpc0RyYWdnYWJsZSAmJiB2YWx1ZSApIHtcblx0XHRcdFx0dGhpcy5fbWFrZURyYWdnYWJsZSgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcInBvc2l0aW9uXCIgKSB7XG5cdFx0XHR0aGlzLl9wb3NpdGlvbigpO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcInJlc2l6YWJsZVwiICkge1xuXG5cdFx0XHQvLyBjdXJyZW50bHkgcmVzaXphYmxlLCBiZWNvbWluZyBub24tcmVzaXphYmxlXG5cdFx0XHRpc1Jlc2l6YWJsZSA9IHVpRGlhbG9nLmlzKCBcIjpkYXRhKHVpLXJlc2l6YWJsZSlcIiApO1xuXHRcdFx0aWYgKCBpc1Jlc2l6YWJsZSAmJiAhdmFsdWUgKSB7XG5cdFx0XHRcdHVpRGlhbG9nLnJlc2l6YWJsZSggXCJkZXN0cm95XCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3VycmVudGx5IHJlc2l6YWJsZSwgY2hhbmdpbmcgaGFuZGxlc1xuXHRcdFx0aWYgKCBpc1Jlc2l6YWJsZSAmJiB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdHVpRGlhbG9nLnJlc2l6YWJsZSggXCJvcHRpb25cIiwgXCJoYW5kbGVzXCIsIHZhbHVlICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEN1cnJlbnRseSBub24tcmVzaXphYmxlLCBiZWNvbWluZyByZXNpemFibGVcblx0XHRcdGlmICggIWlzUmVzaXphYmxlICYmIHZhbHVlICE9PSBmYWxzZSApIHtcblx0XHRcdFx0dGhpcy5fbWFrZVJlc2l6YWJsZSgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcInRpdGxlXCIgKSB7XG5cdFx0XHR0aGlzLl90aXRsZSggdGhpcy51aURpYWxvZ1RpdGxlYmFyLmZpbmQoIFwiLnVpLWRpYWxvZy10aXRsZVwiICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X3NpemU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gSWYgdGhlIHVzZXIgaGFzIHJlc2l6ZWQgdGhlIGRpYWxvZywgdGhlIC51aS1kaWFsb2cgYW5kIC51aS1kaWFsb2ctY29udGVudFxuXHRcdC8vIGRpdnMgd2lsbCBib3RoIGhhdmUgd2lkdGggYW5kIGhlaWdodCBzZXQsIHNvIHdlIG5lZWQgdG8gcmVzZXQgdGhlbVxuXHRcdHZhciBub25Db250ZW50SGVpZ2h0LCBtaW5Db250ZW50SGVpZ2h0LCBtYXhDb250ZW50SGVpZ2h0LFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdC8vIFJlc2V0IGNvbnRlbnQgc2l6aW5nXG5cdFx0dGhpcy5lbGVtZW50LnNob3coKS5jc3MoIHtcblx0XHRcdHdpZHRoOiBcImF1dG9cIixcblx0XHRcdG1pbkhlaWdodDogMCxcblx0XHRcdG1heEhlaWdodDogXCJub25lXCIsXG5cdFx0XHRoZWlnaHQ6IDBcblx0XHR9ICk7XG5cblx0XHRpZiAoIG9wdGlvbnMubWluV2lkdGggPiBvcHRpb25zLndpZHRoICkge1xuXHRcdFx0b3B0aW9ucy53aWR0aCA9IG9wdGlvbnMubWluV2lkdGg7XG5cdFx0fVxuXG5cdFx0Ly8gUmVzZXQgd3JhcHBlciBzaXppbmdcblx0XHQvLyBkZXRlcm1pbmUgdGhlIGhlaWdodCBvZiBhbGwgdGhlIG5vbi1jb250ZW50IGVsZW1lbnRzXG5cdFx0bm9uQ29udGVudEhlaWdodCA9IHRoaXMudWlEaWFsb2cuY3NzKCB7XG5cdFx0XHRoZWlnaHQ6IFwiYXV0b1wiLFxuXHRcdFx0d2lkdGg6IG9wdGlvbnMud2lkdGhcblx0XHR9IClcblx0XHRcdC5vdXRlckhlaWdodCgpO1xuXHRcdG1pbkNvbnRlbnRIZWlnaHQgPSBNYXRoLm1heCggMCwgb3B0aW9ucy5taW5IZWlnaHQgLSBub25Db250ZW50SGVpZ2h0ICk7XG5cdFx0bWF4Q29udGVudEhlaWdodCA9IHR5cGVvZiBvcHRpb25zLm1heEhlaWdodCA9PT0gXCJudW1iZXJcIiA/XG5cdFx0XHRNYXRoLm1heCggMCwgb3B0aW9ucy5tYXhIZWlnaHQgLSBub25Db250ZW50SGVpZ2h0ICkgOlxuXHRcdFx0XCJub25lXCI7XG5cblx0XHRpZiAoIG9wdGlvbnMuaGVpZ2h0ID09PSBcImF1dG9cIiApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5jc3MoIHtcblx0XHRcdFx0bWluSGVpZ2h0OiBtaW5Db250ZW50SGVpZ2h0LFxuXHRcdFx0XHRtYXhIZWlnaHQ6IG1heENvbnRlbnRIZWlnaHQsXG5cdFx0XHRcdGhlaWdodDogXCJhdXRvXCJcblx0XHRcdH0gKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5lbGVtZW50LmhlaWdodCggTWF0aC5tYXgoIDAsIG9wdGlvbnMuaGVpZ2h0IC0gbm9uQ29udGVudEhlaWdodCApICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnVpRGlhbG9nLmlzKCBcIjpkYXRhKHVpLXJlc2l6YWJsZSlcIiApICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5yZXNpemFibGUoIFwib3B0aW9uXCIsIFwibWluSGVpZ2h0XCIsIHRoaXMuX21pbkhlaWdodCgpICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9ibG9ja0ZyYW1lczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5pZnJhbWVCbG9ja3MgPSB0aGlzLmRvY3VtZW50LmZpbmQoIFwiaWZyYW1lXCIgKS5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGlmcmFtZSA9ICQoIHRoaXMgKTtcblxuXHRcdFx0cmV0dXJuICQoIFwiPGRpdj5cIiApXG5cdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLFxuXHRcdFx0XHRcdHdpZHRoOiBpZnJhbWUub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRcdGhlaWdodDogaWZyYW1lLm91dGVySGVpZ2h0KClcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5hcHBlbmRUbyggaWZyYW1lLnBhcmVudCgpIClcblx0XHRcdFx0Lm9mZnNldCggaWZyYW1lLm9mZnNldCgpIClbIDAgXTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X3VuYmxvY2tGcmFtZXM6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcy5pZnJhbWVCbG9ja3MgKSB7XG5cdFx0XHR0aGlzLmlmcmFtZUJsb2Nrcy5yZW1vdmUoKTtcblx0XHRcdGRlbGV0ZSB0aGlzLmlmcmFtZUJsb2Nrcztcblx0XHR9XG5cdH0sXG5cblx0X2FsbG93SW50ZXJhY3Rpb246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLWRpYWxvZ1wiICkubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0Ly8gVE9ETzogUmVtb3ZlIGhhY2sgd2hlbiBkYXRlcGlja2VyIGltcGxlbWVudHNcblx0XHQvLyB0aGUgLnVpLWZyb250IGxvZ2ljICgjODk4OSlcblx0XHRyZXR1cm4gISEkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1kYXRlcGlja2VyXCIgKS5sZW5ndGg7XG5cdH0sXG5cblx0X2NyZWF0ZU92ZXJsYXk6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXMub3B0aW9ucy5tb2RhbCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBXZSB1c2UgYSBkZWxheSBpbiBjYXNlIHRoZSBvdmVybGF5IGlzIGNyZWF0ZWQgZnJvbSBhblxuXHRcdC8vIGV2ZW50IHRoYXQgd2UncmUgZ29pbmcgdG8gYmUgY2FuY2VsbGluZyAoIzI4MDQpXG5cdFx0dmFyIGlzT3BlbmluZyA9IHRydWU7XG5cdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0aXNPcGVuaW5nID0gZmFsc2U7XG5cdFx0fSApO1xuXG5cdFx0aWYgKCAhdGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiICkgKSB7XG5cblx0XHRcdC8vIFByZXZlbnQgdXNlIG9mIGFuY2hvcnMgYW5kIGlucHV0c1xuXHRcdFx0Ly8gVXNpbmcgX29uKCkgZm9yIGFuIGV2ZW50IGhhbmRsZXIgc2hhcmVkIGFjcm9zcyBtYW55IGluc3RhbmNlcyBpc1xuXHRcdFx0Ly8gc2FmZSBiZWNhdXNlIHRoZSBkaWFsb2dzIHN0YWNrIGFuZCBtdXN0IGJlIGNsb3NlZCBpbiByZXZlcnNlIG9yZGVyXG5cdFx0XHR0aGlzLl9vbiggdGhpcy5kb2N1bWVudCwge1xuXHRcdFx0XHRmb2N1c2luOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0aWYgKCBpc09wZW5pbmcgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhdGhpcy5fYWxsb3dJbnRlcmFjdGlvbiggZXZlbnQgKSApIHtcblx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHR0aGlzLl90cmFja2luZ0luc3RhbmNlcygpWyAwIF0uX2ZvY3VzVGFiYmFibGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLm92ZXJsYXkgPSAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5vdmVybGF5LCBudWxsLCBcInVpLXdpZGdldC1vdmVybGF5IHVpLWZyb250XCIgKTtcblx0XHR0aGlzLl9vbiggdGhpcy5vdmVybGF5LCB7XG5cdFx0XHRtb3VzZWRvd246IFwiX2tlZXBGb2N1c1wiXG5cdFx0fSApO1xuXHRcdHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIixcblx0XHRcdCggdGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiICkgfHwgMCApICsgMSApO1xuXHR9LFxuXG5cdF9kZXN0cm95T3ZlcmxheTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLm1vZGFsICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vdmVybGF5ICkge1xuXHRcdFx0dmFyIG92ZXJsYXlzID0gdGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiICkgLSAxO1xuXG5cdFx0XHRpZiAoICFvdmVybGF5cyApIHtcblx0XHRcdFx0dGhpcy5fb2ZmKCB0aGlzLmRvY3VtZW50LCBcImZvY3VzaW5cIiApO1xuXHRcdFx0XHR0aGlzLmRvY3VtZW50LnJlbW92ZURhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIiwgb3ZlcmxheXMgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5vdmVybGF5LnJlbW92ZSgpO1xuXHRcdFx0dGhpcy5vdmVybGF5ID0gbnVsbDtcblx0XHR9XG5cdH1cbn0gKTtcblxuLy8gREVQUkVDQVRFRFxuLy8gVE9ETzogc3dpdGNoIHJldHVybiBiYWNrIHRvIHdpZGdldCBkZWNsYXJhdGlvbiBhdCB0b3Agb2YgZmlsZSB3aGVuIHRoaXMgaXMgcmVtb3ZlZFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gQmFja2NvbXBhdCBmb3IgZGlhbG9nQ2xhc3Mgb3B0aW9uXG5cdCQud2lkZ2V0KCBcInVpLmRpYWxvZ1wiLCAkLnVpLmRpYWxvZywge1xuXHRcdG9wdGlvbnM6IHtcblx0XHRcdGRpYWxvZ0NsYXNzOiBcIlwiXG5cdFx0fSxcblx0XHRfY3JlYXRlV3JhcHBlcjogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdFx0dGhpcy51aURpYWxvZy5hZGRDbGFzcyggdGhpcy5vcHRpb25zLmRpYWxvZ0NsYXNzICk7XG5cdFx0fSxcblx0XHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdGlmICgga2V5ID09PSBcImRpYWxvZ0NsYXNzXCIgKSB7XG5cdFx0XHRcdHRoaXMudWlEaWFsb2dcblx0XHRcdFx0XHQucmVtb3ZlQ2xhc3MoIHRoaXMub3B0aW9ucy5kaWFsb2dDbGFzcyApXG5cdFx0XHRcdFx0LmFkZENsYXNzKCB2YWx1ZSApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fc3VwZXJBcHBseSggYXJndW1lbnRzICk7XG5cdFx0fVxuXHR9ICk7XG59XG5cbnZhciB3aWRnZXRzRGlhbG9nID0gJC51aS5kaWFsb2c7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRHJvcHBhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBEcm9wcGFibGVcbi8vPj5ncm91cDogSW50ZXJhY3Rpb25zXG4vLz4+ZGVzY3JpcHRpb246IEVuYWJsZXMgZHJvcCB0YXJnZXRzIGZvciBkcmFnZ2FibGUgZWxlbWVudHMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZHJvcHBhYmxlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2Ryb3BwYWJsZS9cblxuXG5cbiQud2lkZ2V0KCBcInVpLmRyb3BwYWJsZVwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcImRyb3BcIixcblx0b3B0aW9uczoge1xuXHRcdGFjY2VwdDogXCIqXCIsXG5cdFx0YWRkQ2xhc3NlczogdHJ1ZSxcblx0XHRncmVlZHk6IGZhbHNlLFxuXHRcdHNjb3BlOiBcImRlZmF1bHRcIixcblx0XHR0b2xlcmFuY2U6IFwiaW50ZXJzZWN0XCIsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRhY3RpdmF0ZTogbnVsbCxcblx0XHRkZWFjdGl2YXRlOiBudWxsLFxuXHRcdGRyb3A6IG51bGwsXG5cdFx0b3V0OiBudWxsLFxuXHRcdG92ZXI6IG51bGxcblx0fSxcblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgcHJvcG9ydGlvbnMsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0YWNjZXB0ID0gby5hY2NlcHQ7XG5cblx0XHR0aGlzLmlzb3ZlciA9IGZhbHNlO1xuXHRcdHRoaXMuaXNvdXQgPSB0cnVlO1xuXG5cdFx0dGhpcy5hY2NlcHQgPSAkLmlzRnVuY3Rpb24oIGFjY2VwdCApID8gYWNjZXB0IDogZnVuY3Rpb24oIGQgKSB7XG5cdFx0XHRyZXR1cm4gZC5pcyggYWNjZXB0ICk7XG5cdFx0fTtcblxuXHRcdHRoaXMucHJvcG9ydGlvbnMgPSBmdW5jdGlvbiggLyogdmFsdWVUb1dyaXRlICovICkge1xuXHRcdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXG5cdFx0XHRcdC8vIFN0b3JlIHRoZSBkcm9wcGFibGUncyBwcm9wb3J0aW9uc1xuXHRcdFx0XHRwcm9wb3J0aW9ucyA9IGFyZ3VtZW50c1sgMCBdO1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBSZXRyaWV2ZSBvciBkZXJpdmUgdGhlIGRyb3BwYWJsZSdzIHByb3BvcnRpb25zXG5cdFx0XHRcdHJldHVybiBwcm9wb3J0aW9ucyA/XG5cdFx0XHRcdFx0cHJvcG9ydGlvbnMgOlxuXHRcdFx0XHRcdHByb3BvcnRpb25zID0ge1xuXHRcdFx0XHRcdFx0d2lkdGg6IHRoaXMuZWxlbWVudFsgMCBdLm9mZnNldFdpZHRoLFxuXHRcdFx0XHRcdFx0aGVpZ2h0OiB0aGlzLmVsZW1lbnRbIDAgXS5vZmZzZXRIZWlnaHRcblx0XHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHR0aGlzLl9hZGRUb01hbmFnZXIoIG8uc2NvcGUgKTtcblxuXHRcdG8uYWRkQ2xhc3NlcyAmJiB0aGlzLl9hZGRDbGFzcyggXCJ1aS1kcm9wcGFibGVcIiApO1xuXG5cdH0sXG5cblx0X2FkZFRvTWFuYWdlcjogZnVuY3Rpb24oIHNjb3BlICkge1xuXG5cdFx0Ly8gQWRkIHRoZSByZWZlcmVuY2UgYW5kIHBvc2l0aW9ucyB0byB0aGUgbWFuYWdlclxuXHRcdCQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHNjb3BlIF0gPSAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyBzY29wZSBdIHx8IFtdO1xuXHRcdCQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHNjb3BlIF0ucHVzaCggdGhpcyApO1xuXHR9LFxuXG5cdF9zcGxpY2U6IGZ1bmN0aW9uKCBkcm9wICkge1xuXHRcdHZhciBpID0gMDtcblx0XHRmb3IgKCA7IGkgPCBkcm9wLmxlbmd0aDsgaSsrICkge1xuXHRcdFx0aWYgKCBkcm9wWyBpIF0gPT09IHRoaXMgKSB7XG5cdFx0XHRcdGRyb3Auc3BsaWNlKCBpLCAxICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZHJvcCA9ICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHRoaXMub3B0aW9ucy5zY29wZSBdO1xuXG5cdFx0dGhpcy5fc3BsaWNlKCBkcm9wICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJhY2NlcHRcIiApIHtcblx0XHRcdHRoaXMuYWNjZXB0ID0gJC5pc0Z1bmN0aW9uKCB2YWx1ZSApID8gdmFsdWUgOiBmdW5jdGlvbiggZCApIHtcblx0XHRcdFx0cmV0dXJuIGQuaXMoIHZhbHVlICk7XG5cdFx0XHR9O1xuXHRcdH0gZWxzZSBpZiAoIGtleSA9PT0gXCJzY29wZVwiICkge1xuXHRcdFx0dmFyIGRyb3AgPSAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyB0aGlzLm9wdGlvbnMuc2NvcGUgXTtcblxuXHRcdFx0dGhpcy5fc3BsaWNlKCBkcm9wICk7XG5cdFx0XHR0aGlzLl9hZGRUb01hbmFnZXIoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0fSxcblxuXHRfYWN0aXZhdGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZHJhZ2dhYmxlID0gJC51aS5kZG1hbmFnZXIuY3VycmVudDtcblxuXHRcdHRoaXMuX2FkZEFjdGl2ZUNsYXNzKCk7XG5cdFx0aWYgKCBkcmFnZ2FibGUgKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImFjdGl2YXRlXCIsIGV2ZW50LCB0aGlzLnVpKCBkcmFnZ2FibGUgKSApO1xuXHRcdH1cblx0fSxcblxuXHRfZGVhY3RpdmF0ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBkcmFnZ2FibGUgPSAkLnVpLmRkbWFuYWdlci5jdXJyZW50O1xuXG5cdFx0dGhpcy5fcmVtb3ZlQWN0aXZlQ2xhc3MoKTtcblx0XHRpZiAoIGRyYWdnYWJsZSApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiZGVhY3RpdmF0ZVwiLCBldmVudCwgdGhpcy51aSggZHJhZ2dhYmxlICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X292ZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBkcmFnZ2FibGUgPSAkLnVpLmRkbWFuYWdlci5jdXJyZW50O1xuXG5cdFx0Ly8gQmFpbCBpZiBkcmFnZ2FibGUgYW5kIGRyb3BwYWJsZSBhcmUgc2FtZSBlbGVtZW50XG5cdFx0aWYgKCAhZHJhZ2dhYmxlIHx8ICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5lbGVtZW50IClbIDAgXSA9PT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFjY2VwdC5jYWxsKCB0aGlzLmVsZW1lbnRbIDAgXSwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLmVsZW1lbnQgKSApICkge1xuXHRcdFx0dGhpcy5fYWRkSG92ZXJDbGFzcygpO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJvdmVyXCIsIGV2ZW50LCB0aGlzLnVpKCBkcmFnZ2FibGUgKSApO1xuXHRcdH1cblxuXHR9LFxuXG5cdF9vdXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBkcmFnZ2FibGUgPSAkLnVpLmRkbWFuYWdlci5jdXJyZW50O1xuXG5cdFx0Ly8gQmFpbCBpZiBkcmFnZ2FibGUgYW5kIGRyb3BwYWJsZSBhcmUgc2FtZSBlbGVtZW50XG5cdFx0aWYgKCAhZHJhZ2dhYmxlIHx8ICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5lbGVtZW50IClbIDAgXSA9PT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFjY2VwdC5jYWxsKCB0aGlzLmVsZW1lbnRbIDAgXSwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLmVsZW1lbnQgKSApICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlSG92ZXJDbGFzcygpO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJvdXRcIiwgZXZlbnQsIHRoaXMudWkoIGRyYWdnYWJsZSApICk7XG5cdFx0fVxuXG5cdH0sXG5cblx0X2Ryb3A6IGZ1bmN0aW9uKCBldmVudCwgY3VzdG9tICkge1xuXG5cdFx0dmFyIGRyYWdnYWJsZSA9IGN1c3RvbSB8fCAkLnVpLmRkbWFuYWdlci5jdXJyZW50LFxuXHRcdFx0Y2hpbGRyZW5JbnRlcnNlY3Rpb24gPSBmYWxzZTtcblxuXHRcdC8vIEJhaWwgaWYgZHJhZ2dhYmxlIGFuZCBkcm9wcGFibGUgYXJlIHNhbWUgZWxlbWVudFxuXHRcdGlmICggIWRyYWdnYWJsZSB8fCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fFxuXHRcdFx0XHRkcmFnZ2FibGUuZWxlbWVudCApWyAwIF0gPT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LmZpbmQoIFwiOmRhdGEodWktZHJvcHBhYmxlKVwiIClcblx0XHRcdC5ub3QoIFwiLnVpLWRyYWdnYWJsZS1kcmFnZ2luZ1wiIClcblx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGluc3QgPSAkKCB0aGlzICkuZHJvcHBhYmxlKCBcImluc3RhbmNlXCIgKTtcblx0XHRcdFx0aWYgKFxuXHRcdFx0XHRcdGluc3Qub3B0aW9ucy5ncmVlZHkgJiZcblx0XHRcdFx0XHQhaW5zdC5vcHRpb25zLmRpc2FibGVkICYmXG5cdFx0XHRcdFx0aW5zdC5vcHRpb25zLnNjb3BlID09PSBkcmFnZ2FibGUub3B0aW9ucy5zY29wZSAmJlxuXHRcdFx0XHRcdGluc3QuYWNjZXB0LmNhbGwoXG5cdFx0XHRcdFx0XHRpbnN0LmVsZW1lbnRbIDAgXSwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHwgZHJhZ2dhYmxlLmVsZW1lbnQgKVxuXHRcdFx0XHRcdCkgJiZcblx0XHRcdFx0XHRpbnRlcnNlY3QoXG5cdFx0XHRcdFx0XHRkcmFnZ2FibGUsXG5cdFx0XHRcdFx0XHQkLmV4dGVuZCggaW5zdCwgeyBvZmZzZXQ6IGluc3QuZWxlbWVudC5vZmZzZXQoKSB9ICksXG5cdFx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMudG9sZXJhbmNlLCBldmVudFxuXHRcdFx0XHRcdClcblx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0Y2hpbGRyZW5JbnRlcnNlY3Rpb24gPSB0cnVlO1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTsgfVxuXHRcdFx0fSApO1xuXHRcdGlmICggY2hpbGRyZW5JbnRlcnNlY3Rpb24gKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFjY2VwdC5jYWxsKCB0aGlzLmVsZW1lbnRbIDAgXSxcblx0XHRcdFx0KCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHwgZHJhZ2dhYmxlLmVsZW1lbnQgKSApICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQWN0aXZlQ2xhc3MoKTtcblx0XHRcdHRoaXMuX3JlbW92ZUhvdmVyQ2xhc3MoKTtcblxuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJkcm9wXCIsIGV2ZW50LCB0aGlzLnVpKCBkcmFnZ2FibGUgKSApO1xuXHRcdFx0cmV0dXJuIHRoaXMuZWxlbWVudDtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fSxcblxuXHR1aTogZnVuY3Rpb24oIGMgKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGRyYWdnYWJsZTogKCBjLmN1cnJlbnRJdGVtIHx8IGMuZWxlbWVudCApLFxuXHRcdFx0aGVscGVyOiBjLmhlbHBlcixcblx0XHRcdHBvc2l0aW9uOiBjLnBvc2l0aW9uLFxuXHRcdFx0b2Zmc2V0OiBjLnBvc2l0aW9uQWJzXG5cdFx0fTtcblx0fSxcblxuXHQvLyBFeHRlbnNpb24gcG9pbnRzIGp1c3QgdG8gbWFrZSBiYWNrY29tcGF0IHNhbmUgYW5kIGF2b2lkIGR1cGxpY2F0aW5nIGxvZ2ljXG5cdC8vIFRPRE86IFJlbW92ZSBpbiAxLjEzIGFsb25nIHdpdGggY2FsbCB0byBpdCBiZWxvd1xuXHRfYWRkSG92ZXJDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktZHJvcHBhYmxlLWhvdmVyXCIgKTtcblx0fSxcblxuXHRfcmVtb3ZlSG92ZXJDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktZHJvcHBhYmxlLWhvdmVyXCIgKTtcblx0fSxcblxuXHRfYWRkQWN0aXZlQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWRyb3BwYWJsZS1hY3RpdmVcIiApO1xuXHR9LFxuXG5cdF9yZW1vdmVBY3RpdmVDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktZHJvcHBhYmxlLWFjdGl2ZVwiICk7XG5cdH1cbn0gKTtcblxudmFyIGludGVyc2VjdCA9ICQudWkuaW50ZXJzZWN0ID0gKCBmdW5jdGlvbigpIHtcblx0ZnVuY3Rpb24gaXNPdmVyQXhpcyggeCwgcmVmZXJlbmNlLCBzaXplICkge1xuXHRcdHJldHVybiAoIHggPj0gcmVmZXJlbmNlICkgJiYgKCB4IDwgKCByZWZlcmVuY2UgKyBzaXplICkgKTtcblx0fVxuXG5cdHJldHVybiBmdW5jdGlvbiggZHJhZ2dhYmxlLCBkcm9wcGFibGUsIHRvbGVyYW5jZU1vZGUsIGV2ZW50ICkge1xuXG5cdFx0aWYgKCAhZHJvcHBhYmxlLm9mZnNldCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR2YXIgeDEgPSAoIGRyYWdnYWJsZS5wb3NpdGlvbkFicyB8fFxuXHRcdFx0XHRkcmFnZ2FibGUucG9zaXRpb24uYWJzb2x1dGUgKS5sZWZ0ICsgZHJhZ2dhYmxlLm1hcmdpbnMubGVmdCxcblx0XHRcdHkxID0gKCBkcmFnZ2FibGUucG9zaXRpb25BYnMgfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLnBvc2l0aW9uLmFic29sdXRlICkudG9wICsgZHJhZ2dhYmxlLm1hcmdpbnMudG9wLFxuXHRcdFx0eDIgPSB4MSArIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCxcblx0XHRcdHkyID0geTEgKyBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0LFxuXHRcdFx0bCA9IGRyb3BwYWJsZS5vZmZzZXQubGVmdCxcblx0XHRcdHQgPSBkcm9wcGFibGUub2Zmc2V0LnRvcCxcblx0XHRcdHIgPSBsICsgZHJvcHBhYmxlLnByb3BvcnRpb25zKCkud2lkdGgsXG5cdFx0XHRiID0gdCArIGRyb3BwYWJsZS5wcm9wb3J0aW9ucygpLmhlaWdodDtcblxuXHRcdHN3aXRjaCAoIHRvbGVyYW5jZU1vZGUgKSB7XG5cdFx0Y2FzZSBcImZpdFwiOlxuXHRcdFx0cmV0dXJuICggbCA8PSB4MSAmJiB4MiA8PSByICYmIHQgPD0geTEgJiYgeTIgPD0gYiApO1xuXHRcdGNhc2UgXCJpbnRlcnNlY3RcIjpcblx0XHRcdHJldHVybiAoIGwgPCB4MSArICggZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC8gMiApICYmIC8vIFJpZ2h0IEhhbGZcblx0XHRcdFx0eDIgLSAoIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAvIDIgKSA8IHIgJiYgLy8gTGVmdCBIYWxmXG5cdFx0XHRcdHQgPCB5MSArICggZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAvIDIgKSAmJiAvLyBCb3R0b20gSGFsZlxuXHRcdFx0XHR5MiAtICggZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAvIDIgKSA8IGIgKTsgLy8gVG9wIEhhbGZcblx0XHRjYXNlIFwicG9pbnRlclwiOlxuXHRcdFx0cmV0dXJuIGlzT3ZlckF4aXMoIGV2ZW50LnBhZ2VZLCB0LCBkcm9wcGFibGUucHJvcG9ydGlvbnMoKS5oZWlnaHQgKSAmJlxuXHRcdFx0XHRpc092ZXJBeGlzKCBldmVudC5wYWdlWCwgbCwgZHJvcHBhYmxlLnByb3BvcnRpb25zKCkud2lkdGggKTtcblx0XHRjYXNlIFwidG91Y2hcIjpcblx0XHRcdHJldHVybiAoXG5cdFx0XHRcdCggeTEgPj0gdCAmJiB5MSA8PSBiICkgfHwgLy8gVG9wIGVkZ2UgdG91Y2hpbmdcblx0XHRcdFx0KCB5MiA+PSB0ICYmIHkyIDw9IGIgKSB8fCAvLyBCb3R0b20gZWRnZSB0b3VjaGluZ1xuXHRcdFx0XHQoIHkxIDwgdCAmJiB5MiA+IGIgKSAvLyBTdXJyb3VuZGVkIHZlcnRpY2FsbHlcblx0XHRcdCkgJiYgKFxuXHRcdFx0XHQoIHgxID49IGwgJiYgeDEgPD0gciApIHx8IC8vIExlZnQgZWRnZSB0b3VjaGluZ1xuXHRcdFx0XHQoIHgyID49IGwgJiYgeDIgPD0gciApIHx8IC8vIFJpZ2h0IGVkZ2UgdG91Y2hpbmdcblx0XHRcdFx0KCB4MSA8IGwgJiYgeDIgPiByICkgLy8gU3Vycm91bmRlZCBob3Jpem9udGFsbHlcblx0XHRcdCk7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdH07XG59ICkoKTtcblxuLypcblx0VGhpcyBtYW5hZ2VyIHRyYWNrcyBvZmZzZXRzIG9mIGRyYWdnYWJsZXMgYW5kIGRyb3BwYWJsZXNcbiovXG4kLnVpLmRkbWFuYWdlciA9IHtcblx0Y3VycmVudDogbnVsbCxcblx0ZHJvcHBhYmxlczogeyBcImRlZmF1bHRcIjogW10gfSxcblx0cHJlcGFyZU9mZnNldHM6IGZ1bmN0aW9uKCB0LCBldmVudCApIHtcblxuXHRcdHZhciBpLCBqLFxuXHRcdFx0bSA9ICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHQub3B0aW9ucy5zY29wZSBdIHx8IFtdLFxuXHRcdFx0dHlwZSA9IGV2ZW50ID8gZXZlbnQudHlwZSA6IG51bGwsIC8vIHdvcmthcm91bmQgZm9yICMyMzE3XG5cdFx0XHRsaXN0ID0gKCB0LmN1cnJlbnRJdGVtIHx8IHQuZWxlbWVudCApLmZpbmQoIFwiOmRhdGEodWktZHJvcHBhYmxlKVwiICkuYWRkQmFjaygpO1xuXG5cdFx0ZHJvcHBhYmxlc0xvb3A6IGZvciAoIGkgPSAwOyBpIDwgbS5sZW5ndGg7IGkrKyApIHtcblxuXHRcdFx0Ly8gTm8gZGlzYWJsZWQgYW5kIG5vbi1hY2NlcHRlZFxuXHRcdFx0aWYgKCBtWyBpIF0ub3B0aW9ucy5kaXNhYmxlZCB8fCAoIHQgJiYgIW1bIGkgXS5hY2NlcHQuY2FsbCggbVsgaSBdLmVsZW1lbnRbIDAgXSxcblx0XHRcdFx0XHQoIHQuY3VycmVudEl0ZW0gfHwgdC5lbGVtZW50ICkgKSApICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gRmlsdGVyIG91dCBlbGVtZW50cyBpbiB0aGUgY3VycmVudCBkcmFnZ2VkIGl0ZW1cblx0XHRcdGZvciAoIGogPSAwOyBqIDwgbGlzdC5sZW5ndGg7IGorKyApIHtcblx0XHRcdFx0aWYgKCBsaXN0WyBqIF0gPT09IG1bIGkgXS5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRcdFx0bVsgaSBdLnByb3BvcnRpb25zKCkuaGVpZ2h0ID0gMDtcblx0XHRcdFx0XHRjb250aW51ZSBkcm9wcGFibGVzTG9vcDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRtWyBpIF0udmlzaWJsZSA9IG1bIGkgXS5lbGVtZW50LmNzcyggXCJkaXNwbGF5XCIgKSAhPT0gXCJub25lXCI7XG5cdFx0XHRpZiAoICFtWyBpIF0udmlzaWJsZSApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFjdGl2YXRlIHRoZSBkcm9wcGFibGUgaWYgdXNlZCBkaXJlY3RseSBmcm9tIGRyYWdnYWJsZXNcblx0XHRcdGlmICggdHlwZSA9PT0gXCJtb3VzZWRvd25cIiApIHtcblx0XHRcdFx0bVsgaSBdLl9hY3RpdmF0ZS5jYWxsKCBtWyBpIF0sIGV2ZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdG1bIGkgXS5vZmZzZXQgPSBtWyBpIF0uZWxlbWVudC5vZmZzZXQoKTtcblx0XHRcdG1bIGkgXS5wcm9wb3J0aW9ucygge1xuXHRcdFx0XHR3aWR0aDogbVsgaSBdLmVsZW1lbnRbIDAgXS5vZmZzZXRXaWR0aCxcblx0XHRcdFx0aGVpZ2h0OiBtWyBpIF0uZWxlbWVudFsgMCBdLm9mZnNldEhlaWdodFxuXHRcdFx0fSApO1xuXG5cdFx0fVxuXG5cdH0sXG5cdGRyb3A6IGZ1bmN0aW9uKCBkcmFnZ2FibGUsIGV2ZW50ICkge1xuXG5cdFx0dmFyIGRyb3BwZWQgPSBmYWxzZTtcblxuXHRcdC8vIENyZWF0ZSBhIGNvcHkgb2YgdGhlIGRyb3BwYWJsZXMgaW4gY2FzZSB0aGUgbGlzdCBjaGFuZ2VzIGR1cmluZyB0aGUgZHJvcCAoIzkxMTYpXG5cdFx0JC5lYWNoKCAoICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIGRyYWdnYWJsZS5vcHRpb25zLnNjb3BlIF0gfHwgW10gKS5zbGljZSgpLCBmdW5jdGlvbigpIHtcblxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMuZGlzYWJsZWQgJiYgdGhpcy52aXNpYmxlICYmXG5cdFx0XHRcdFx0aW50ZXJzZWN0KCBkcmFnZ2FibGUsIHRoaXMsIHRoaXMub3B0aW9ucy50b2xlcmFuY2UsIGV2ZW50ICkgKSB7XG5cdFx0XHRcdGRyb3BwZWQgPSB0aGlzLl9kcm9wLmNhbGwoIHRoaXMsIGV2ZW50ICkgfHwgZHJvcHBlZDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zLmRpc2FibGVkICYmIHRoaXMudmlzaWJsZSAmJiB0aGlzLmFjY2VwdC5jYWxsKCB0aGlzLmVsZW1lbnRbIDAgXSxcblx0XHRcdFx0XHQoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fCBkcmFnZ2FibGUuZWxlbWVudCApICkgKSB7XG5cdFx0XHRcdHRoaXMuaXNvdXQgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLmlzb3ZlciA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLl9kZWFjdGl2YXRlLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cdFx0XHR9XG5cblx0XHR9ICk7XG5cdFx0cmV0dXJuIGRyb3BwZWQ7XG5cblx0fSxcblx0ZHJhZ1N0YXJ0OiBmdW5jdGlvbiggZHJhZ2dhYmxlLCBldmVudCApIHtcblxuXHRcdC8vIExpc3RlbiBmb3Igc2Nyb2xsaW5nIHNvIHRoYXQgaWYgdGhlIGRyYWdnaW5nIGNhdXNlcyBzY3JvbGxpbmcgdGhlIHBvc2l0aW9uIG9mIHRoZVxuXHRcdC8vIGRyb3BwYWJsZXMgY2FuIGJlIHJlY2FsY3VsYXRlZCAoc2VlICM1MDAzKVxuXHRcdGRyYWdnYWJsZS5lbGVtZW50LnBhcmVudHNVbnRpbCggXCJib2R5XCIgKS5vbiggXCJzY3JvbGwuZHJvcHBhYmxlXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAhZHJhZ2dhYmxlLm9wdGlvbnMucmVmcmVzaFBvc2l0aW9ucyApIHtcblx0XHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIGRyYWdnYWJsZSwgZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cdGRyYWc6IGZ1bmN0aW9uKCBkcmFnZ2FibGUsIGV2ZW50ICkge1xuXG5cdFx0Ly8gSWYgeW91IGhhdmUgYSBoaWdobHkgZHluYW1pYyBwYWdlLCB5b3UgbWlnaHQgdHJ5IHRoaXMgb3B0aW9uLiBJdCByZW5kZXJzIHBvc2l0aW9uc1xuXHRcdC8vIGV2ZXJ5IHRpbWUgeW91IG1vdmUgdGhlIG1vdXNlLlxuXHRcdGlmICggZHJhZ2dhYmxlLm9wdGlvbnMucmVmcmVzaFBvc2l0aW9ucyApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCBkcmFnZ2FibGUsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly8gUnVuIHRocm91Z2ggYWxsIGRyb3BwYWJsZXMgYW5kIGNoZWNrIHRoZWlyIHBvc2l0aW9ucyBiYXNlZCBvbiBzcGVjaWZpYyB0b2xlcmFuY2Ugb3B0aW9uc1xuXHRcdCQuZWFjaCggJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgZHJhZ2dhYmxlLm9wdGlvbnMuc2NvcGUgXSB8fCBbXSwgZnVuY3Rpb24oKSB7XG5cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkIHx8IHRoaXMuZ3JlZWR5Q2hpbGQgfHwgIXRoaXMudmlzaWJsZSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHR2YXIgcGFyZW50SW5zdGFuY2UsIHNjb3BlLCBwYXJlbnQsXG5cdFx0XHRcdGludGVyc2VjdHMgPSBpbnRlcnNlY3QoIGRyYWdnYWJsZSwgdGhpcywgdGhpcy5vcHRpb25zLnRvbGVyYW5jZSwgZXZlbnQgKSxcblx0XHRcdFx0YyA9ICFpbnRlcnNlY3RzICYmIHRoaXMuaXNvdmVyID9cblx0XHRcdFx0XHRcImlzb3V0XCIgOlxuXHRcdFx0XHRcdCggaW50ZXJzZWN0cyAmJiAhdGhpcy5pc292ZXIgPyBcImlzb3ZlclwiIDogbnVsbCApO1xuXHRcdFx0aWYgKCAhYyApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5ncmVlZHkgKSB7XG5cblx0XHRcdFx0Ly8gZmluZCBkcm9wcGFibGUgcGFyZW50cyB3aXRoIHNhbWUgc2NvcGVcblx0XHRcdFx0c2NvcGUgPSB0aGlzLm9wdGlvbnMuc2NvcGU7XG5cdFx0XHRcdHBhcmVudCA9IHRoaXMuZWxlbWVudC5wYXJlbnRzKCBcIjpkYXRhKHVpLWRyb3BwYWJsZSlcIiApLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0cmV0dXJuICQoIHRoaXMgKS5kcm9wcGFibGUoIFwiaW5zdGFuY2VcIiApLm9wdGlvbnMuc2NvcGUgPT09IHNjb3BlO1xuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0aWYgKCBwYXJlbnQubGVuZ3RoICkge1xuXHRcdFx0XHRcdHBhcmVudEluc3RhbmNlID0gJCggcGFyZW50WyAwIF0gKS5kcm9wcGFibGUoIFwiaW5zdGFuY2VcIiApO1xuXHRcdFx0XHRcdHBhcmVudEluc3RhbmNlLmdyZWVkeUNoaWxkID0gKCBjID09PSBcImlzb3ZlclwiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gV2UganVzdCBtb3ZlZCBpbnRvIGEgZ3JlZWR5IGNoaWxkXG5cdFx0XHRpZiAoIHBhcmVudEluc3RhbmNlICYmIGMgPT09IFwiaXNvdmVyXCIgKSB7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLmlzb3ZlciA9IGZhbHNlO1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5pc291dCA9IHRydWU7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLl9vdXQuY2FsbCggcGFyZW50SW5zdGFuY2UsIGV2ZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXNbIGMgXSA9IHRydWU7XG5cdFx0XHR0aGlzWyBjID09PSBcImlzb3V0XCIgPyBcImlzb3ZlclwiIDogXCJpc291dFwiIF0gPSBmYWxzZTtcblx0XHRcdHRoaXNbIGMgPT09IFwiaXNvdmVyXCIgPyBcIl9vdmVyXCIgOiBcIl9vdXRcIiBdLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cblx0XHRcdC8vIFdlIGp1c3QgbW92ZWQgb3V0IG9mIGEgZ3JlZWR5IGNoaWxkXG5cdFx0XHRpZiAoIHBhcmVudEluc3RhbmNlICYmIGMgPT09IFwiaXNvdXRcIiApIHtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuaXNvdXQgPSBmYWxzZTtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuaXNvdmVyID0gdHJ1ZTtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuX292ZXIuY2FsbCggcGFyZW50SW5zdGFuY2UsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdH0sXG5cdGRyYWdTdG9wOiBmdW5jdGlvbiggZHJhZ2dhYmxlLCBldmVudCApIHtcblx0XHRkcmFnZ2FibGUuZWxlbWVudC5wYXJlbnRzVW50aWwoIFwiYm9keVwiICkub2ZmKCBcInNjcm9sbC5kcm9wcGFibGVcIiApO1xuXG5cdFx0Ly8gQ2FsbCBwcmVwYXJlT2Zmc2V0cyBvbmUgZmluYWwgdGltZSBzaW5jZSBJRSBkb2VzIG5vdCBmaXJlIHJldHVybiBzY3JvbGwgZXZlbnRzIHdoZW5cblx0XHQvLyBvdmVyZmxvdyB3YXMgY2F1c2VkIGJ5IGRyYWcgKHNlZSAjNTAwMylcblx0XHRpZiAoICFkcmFnZ2FibGUub3B0aW9ucy5yZWZyZXNoUG9zaXRpb25zICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIGRyYWdnYWJsZSwgZXZlbnQgKTtcblx0XHR9XG5cdH1cbn07XG5cbi8vIERFUFJFQ0FURURcbi8vIFRPRE86IHN3aXRjaCByZXR1cm4gYmFjayB0byB3aWRnZXQgZGVjbGFyYXRpb24gYXQgdG9wIG9mIGZpbGUgd2hlbiB0aGlzIGlzIHJlbW92ZWRcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIEJhY2tjb21wYXQgZm9yIGFjdGl2ZUNsYXNzIGFuZCBob3ZlckNsYXNzIG9wdGlvbnNcblx0JC53aWRnZXQoIFwidWkuZHJvcHBhYmxlXCIsICQudWkuZHJvcHBhYmxlLCB7XG5cdFx0b3B0aW9uczoge1xuXHRcdFx0aG92ZXJDbGFzczogZmFsc2UsXG5cdFx0XHRhY3RpdmVDbGFzczogZmFsc2Vcblx0XHR9LFxuXHRcdF9hZGRBY3RpdmVDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuYWN0aXZlQ2xhc3MgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5hZGRDbGFzcyggdGhpcy5vcHRpb25zLmFjdGl2ZUNsYXNzICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRfcmVtb3ZlQWN0aXZlQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmFjdGl2ZUNsYXNzICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQ2xhc3MoIHRoaXMub3B0aW9ucy5hY3RpdmVDbGFzcyApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0X2FkZEhvdmVyQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhvdmVyQ2xhc3MgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5hZGRDbGFzcyggdGhpcy5vcHRpb25zLmhvdmVyQ2xhc3MgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdF9yZW1vdmVIb3ZlckNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5ob3ZlckNsYXNzICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQ2xhc3MoIHRoaXMub3B0aW9ucy5ob3ZlckNsYXNzICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9ICk7XG59XG5cbnZhciB3aWRnZXRzRHJvcHBhYmxlID0gJC51aS5kcm9wcGFibGU7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgUHJvZ3Jlc3NiYXIgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFByb2dyZXNzYmFyXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBhIHN0YXR1cyBpbmRpY2F0b3IgZm9yIGxvYWRpbmcgc3RhdGUsIHN0YW5kYXJkIHBlcmNlbnRhZ2UsIGFuZCBvdGhlciBwcm9ncmVzcyBpbmRpY2F0b3JzLlxuLy8ganNjczplbmFibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9wcm9ncmVzc2Jhci9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9wcm9ncmVzc2Jhci9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3Byb2dyZXNzYmFyLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c1Byb2dyZXNzYmFyID0gJC53aWRnZXQoIFwidWkucHJvZ3Jlc3NiYXJcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1wcm9ncmVzc2JhclwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktcHJvZ3Jlc3NiYXItdmFsdWVcIjogXCJ1aS1jb3JuZXItbGVmdFwiLFxuXHRcdFx0XCJ1aS1wcm9ncmVzc2Jhci1jb21wbGV0ZVwiOiBcInVpLWNvcm5lci1yaWdodFwiXG5cdFx0fSxcblx0XHRtYXg6IDEwMCxcblx0XHR2YWx1ZTogMCxcblxuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRjb21wbGV0ZTogbnVsbFxuXHR9LFxuXG5cdG1pbjogMCxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIENvbnN0cmFpbiBpbml0aWFsIHZhbHVlXG5cdFx0dGhpcy5vbGRWYWx1ZSA9IHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX2NvbnN0cmFpbmVkVmFsdWUoKTtcblxuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCB7XG5cblx0XHRcdC8vIE9ubHkgc2V0IHN0YXRpYyB2YWx1ZXM7IGFyaWEtdmFsdWVub3cgYW5kIGFyaWEtdmFsdWVtYXggYXJlXG5cdFx0XHQvLyBzZXQgaW5zaWRlIF9yZWZyZXNoVmFsdWUoKVxuXHRcdFx0cm9sZTogXCJwcm9ncmVzc2JhclwiLFxuXHRcdFx0XCJhcmlhLXZhbHVlbWluXCI6IHRoaXMubWluXG5cdFx0fSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXByb2dyZXNzYmFyXCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdHRoaXMudmFsdWVEaXYgPSAkKCBcIjxkaXY+XCIgKS5hcHBlbmRUbyggdGhpcy5lbGVtZW50ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudmFsdWVEaXYsIFwidWktcHJvZ3Jlc3NiYXItdmFsdWVcIiwgXCJ1aS13aWRnZXQtaGVhZGVyXCIgKTtcblx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwicm9sZSBhcmlhLXZhbHVlbWluIGFyaWEtdmFsdWVtYXggYXJpYS12YWx1ZW5vd1wiICk7XG5cblx0XHR0aGlzLnZhbHVlRGl2LnJlbW92ZSgpO1xuXHR9LFxuXG5cdHZhbHVlOiBmdW5jdGlvbiggbmV3VmFsdWUgKSB7XG5cdFx0aWYgKCBuZXdWYWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIHRoaXMub3B0aW9ucy52YWx1ZTtcblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl9jb25zdHJhaW5lZFZhbHVlKCBuZXdWYWx1ZSApO1xuXHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHR9LFxuXG5cdF9jb25zdHJhaW5lZFZhbHVlOiBmdW5jdGlvbiggbmV3VmFsdWUgKSB7XG5cdFx0aWYgKCBuZXdWYWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0bmV3VmFsdWUgPSB0aGlzLm9wdGlvbnMudmFsdWU7XG5cdFx0fVxuXG5cdFx0dGhpcy5pbmRldGVybWluYXRlID0gbmV3VmFsdWUgPT09IGZhbHNlO1xuXG5cdFx0Ly8gU2FuaXRpemUgdmFsdWVcblx0XHRpZiAoIHR5cGVvZiBuZXdWYWx1ZSAhPT0gXCJudW1iZXJcIiApIHtcblx0XHRcdG5ld1ZhbHVlID0gMDtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5pbmRldGVybWluYXRlID8gZmFsc2UgOlxuXHRcdFx0TWF0aC5taW4oIHRoaXMub3B0aW9ucy5tYXgsIE1hdGgubWF4KCB0aGlzLm1pbiwgbmV3VmFsdWUgKSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25zOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblxuXHRcdC8vIEVuc3VyZSBcInZhbHVlXCIgb3B0aW9uIGlzIHNldCBhZnRlciBvdGhlciB2YWx1ZXMgKGxpa2UgbWF4KVxuXHRcdHZhciB2YWx1ZSA9IG9wdGlvbnMudmFsdWU7XG5cdFx0ZGVsZXRlIG9wdGlvbnMudmFsdWU7XG5cblx0XHR0aGlzLl9zdXBlciggb3B0aW9ucyApO1xuXG5cdFx0dGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fY29uc3RyYWluZWRWYWx1ZSggdmFsdWUgKTtcblx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJtYXhcIiApIHtcblxuXHRcdFx0Ly8gRG9uJ3QgYWxsb3cgYSBtYXggbGVzcyB0aGFuIG1pblxuXHRcdFx0dmFsdWUgPSBNYXRoLm1heCggdGhpcy5taW4sIHZhbHVlICk7XG5cdFx0fVxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHR9LFxuXG5cdF9wZXJjZW50YWdlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5pbmRldGVybWluYXRlID9cblx0XHRcdDEwMCA6XG5cdFx0XHQxMDAgKiAoIHRoaXMub3B0aW9ucy52YWx1ZSAtIHRoaXMubWluICkgLyAoIHRoaXMub3B0aW9ucy5tYXggLSB0aGlzLm1pbiApO1xuXHR9LFxuXG5cdF9yZWZyZXNoVmFsdWU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB2YWx1ZSA9IHRoaXMub3B0aW9ucy52YWx1ZSxcblx0XHRcdHBlcmNlbnRhZ2UgPSB0aGlzLl9wZXJjZW50YWdlKCk7XG5cblx0XHR0aGlzLnZhbHVlRGl2XG5cdFx0XHQudG9nZ2xlKCB0aGlzLmluZGV0ZXJtaW5hdGUgfHwgdmFsdWUgPiB0aGlzLm1pbiApXG5cdFx0XHQud2lkdGgoIHBlcmNlbnRhZ2UudG9GaXhlZCggMCApICsgXCIlXCIgKTtcblxuXHRcdHRoaXNcblx0XHRcdC5fdG9nZ2xlQ2xhc3MoIHRoaXMudmFsdWVEaXYsIFwidWktcHJvZ3Jlc3NiYXItY29tcGxldGVcIiwgbnVsbCxcblx0XHRcdFx0dmFsdWUgPT09IHRoaXMub3B0aW9ucy5tYXggKVxuXHRcdFx0Ll90b2dnbGVDbGFzcyggXCJ1aS1wcm9ncmVzc2Jhci1pbmRldGVybWluYXRlXCIsIG51bGwsIHRoaXMuaW5kZXRlcm1pbmF0ZSApO1xuXG5cdFx0aWYgKCB0aGlzLmluZGV0ZXJtaW5hdGUgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJhcmlhLXZhbHVlbm93XCIgKTtcblx0XHRcdGlmICggIXRoaXMub3ZlcmxheURpdiApIHtcblx0XHRcdFx0dGhpcy5vdmVybGF5RGl2ID0gJCggXCI8ZGl2PlwiICkuYXBwZW5kVG8oIHRoaXMudmFsdWVEaXYgKTtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMub3ZlcmxheURpdiwgXCJ1aS1wcm9ncmVzc2Jhci1vdmVybGF5XCIgKTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoIHtcblx0XHRcdFx0XCJhcmlhLXZhbHVlbWF4XCI6IHRoaXMub3B0aW9ucy5tYXgsXG5cdFx0XHRcdFwiYXJpYS12YWx1ZW5vd1wiOiB2YWx1ZVxuXHRcdFx0fSApO1xuXHRcdFx0aWYgKCB0aGlzLm92ZXJsYXlEaXYgKSB7XG5cdFx0XHRcdHRoaXMub3ZlcmxheURpdi5yZW1vdmUoKTtcblx0XHRcdFx0dGhpcy5vdmVybGF5RGl2ID0gbnVsbDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub2xkVmFsdWUgIT09IHZhbHVlICkge1xuXHRcdFx0dGhpcy5vbGRWYWx1ZSA9IHZhbHVlO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiApO1xuXHRcdH1cblx0XHRpZiAoIHZhbHVlID09PSB0aGlzLm9wdGlvbnMubWF4ICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjb21wbGV0ZVwiICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU2VsZWN0YWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2VsZWN0YWJsZVxuLy8+Pmdyb3VwOiBJbnRlcmFjdGlvbnNcbi8vPj5kZXNjcmlwdGlvbjogQWxsb3dzIGdyb3VwcyBvZiBlbGVtZW50cyB0byBiZSBzZWxlY3RlZCB3aXRoIHRoZSBtb3VzZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zZWxlY3RhYmxlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3NlbGVjdGFibGUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2Uvc2VsZWN0YWJsZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzU2VsZWN0YWJsZSA9ICQud2lkZ2V0KCBcInVpLnNlbGVjdGFibGVcIiwgJC51aS5tb3VzZSwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YXBwZW5kVG86IFwiYm9keVwiLFxuXHRcdGF1dG9SZWZyZXNoOiB0cnVlLFxuXHRcdGRpc3RhbmNlOiAwLFxuXHRcdGZpbHRlcjogXCIqXCIsXG5cdFx0dG9sZXJhbmNlOiBcInRvdWNoXCIsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRzZWxlY3RlZDogbnVsbCxcblx0XHRzZWxlY3Rpbmc6IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbCxcblx0XHR1bnNlbGVjdGVkOiBudWxsLFxuXHRcdHVuc2VsZWN0aW5nOiBudWxsXG5cdH0sXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXNlbGVjdGFibGVcIiApO1xuXG5cdFx0dGhpcy5kcmFnZ2VkID0gZmFsc2U7XG5cblx0XHQvLyBDYWNoZSBzZWxlY3RlZSBjaGlsZHJlbiBiYXNlZCBvbiBmaWx0ZXJcblx0XHR0aGlzLnJlZnJlc2ggPSBmdW5jdGlvbigpIHtcblx0XHRcdHRoYXQuZWxlbWVudFBvcyA9ICQoIHRoYXQuZWxlbWVudFsgMCBdICkub2Zmc2V0KCk7XG5cdFx0XHR0aGF0LnNlbGVjdGVlcyA9ICQoIHRoYXQub3B0aW9ucy5maWx0ZXIsIHRoYXQuZWxlbWVudFsgMCBdICk7XG5cdFx0XHR0aGF0Ll9hZGRDbGFzcyggdGhhdC5zZWxlY3RlZXMsIFwidWktc2VsZWN0ZWVcIiApO1xuXHRcdFx0dGhhdC5zZWxlY3RlZXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciAkdGhpcyA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRzZWxlY3RlZU9mZnNldCA9ICR0aGlzLm9mZnNldCgpLFxuXHRcdFx0XHRcdHBvcyA9IHtcblx0XHRcdFx0XHRcdGxlZnQ6IHNlbGVjdGVlT2Zmc2V0LmxlZnQgLSB0aGF0LmVsZW1lbnRQb3MubGVmdCxcblx0XHRcdFx0XHRcdHRvcDogc2VsZWN0ZWVPZmZzZXQudG9wIC0gdGhhdC5lbGVtZW50UG9zLnRvcFxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdCQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiwge1xuXHRcdFx0XHRcdGVsZW1lbnQ6IHRoaXMsXG5cdFx0XHRcdFx0JGVsZW1lbnQ6ICR0aGlzLFxuXHRcdFx0XHRcdGxlZnQ6IHBvcy5sZWZ0LFxuXHRcdFx0XHRcdHRvcDogcG9zLnRvcCxcblx0XHRcdFx0XHRyaWdodDogcG9zLmxlZnQgKyAkdGhpcy5vdXRlcldpZHRoKCksXG5cdFx0XHRcdFx0Ym90dG9tOiBwb3MudG9wICsgJHRoaXMub3V0ZXJIZWlnaHQoKSxcblx0XHRcdFx0XHRzdGFydHNlbGVjdGVkOiBmYWxzZSxcblx0XHRcdFx0XHRzZWxlY3RlZDogJHRoaXMuaGFzQ2xhc3MoIFwidWktc2VsZWN0ZWRcIiApLFxuXHRcdFx0XHRcdHNlbGVjdGluZzogJHRoaXMuaGFzQ2xhc3MoIFwidWktc2VsZWN0aW5nXCIgKSxcblx0XHRcdFx0XHR1bnNlbGVjdGluZzogJHRoaXMuaGFzQ2xhc3MoIFwidWktdW5zZWxlY3RpbmdcIiApXG5cdFx0XHRcdH0gKTtcblx0XHRcdH0gKTtcblx0XHR9O1xuXHRcdHRoaXMucmVmcmVzaCgpO1xuXG5cdFx0dGhpcy5fbW91c2VJbml0KCk7XG5cblx0XHR0aGlzLmhlbHBlciA9ICQoIFwiPGRpdj5cIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhlbHBlciwgXCJ1aS1zZWxlY3RhYmxlLWhlbHBlclwiICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuc2VsZWN0ZWVzLnJlbW92ZURhdGEoIFwic2VsZWN0YWJsZS1pdGVtXCIgKTtcblx0XHR0aGlzLl9tb3VzZURlc3Ryb3koKTtcblx0fSxcblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLm9wb3MgPSBbIGV2ZW50LnBhZ2VYLCBldmVudC5wYWdlWSBdO1xuXHRcdHRoaXMuZWxlbWVudFBvcyA9ICQoIHRoaXMuZWxlbWVudFsgMCBdICkub2Zmc2V0KCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLnNlbGVjdGVlcyA9ICQoIG9wdGlvbnMuZmlsdGVyLCB0aGlzLmVsZW1lbnRbIDAgXSApO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzdGFydFwiLCBldmVudCApO1xuXG5cdFx0JCggb3B0aW9ucy5hcHBlbmRUbyApLmFwcGVuZCggdGhpcy5oZWxwZXIgKTtcblxuXHRcdC8vIHBvc2l0aW9uIGhlbHBlciAobGFzc28pXG5cdFx0dGhpcy5oZWxwZXIuY3NzKCB7XG5cdFx0XHRcImxlZnRcIjogZXZlbnQucGFnZVgsXG5cdFx0XHRcInRvcFwiOiBldmVudC5wYWdlWSxcblx0XHRcdFwid2lkdGhcIjogMCxcblx0XHRcdFwiaGVpZ2h0XCI6IDBcblx0XHR9ICk7XG5cblx0XHRpZiAoIG9wdGlvbnMuYXV0b1JlZnJlc2ggKSB7XG5cdFx0XHR0aGlzLnJlZnJlc2goKTtcblx0XHR9XG5cblx0XHR0aGlzLnNlbGVjdGVlcy5maWx0ZXIoIFwiLnVpLXNlbGVjdGVkXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxlY3RlZSA9ICQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiApO1xuXHRcdFx0c2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRpZiAoICFldmVudC5tZXRhS2V5ICYmICFldmVudC5jdHJsS2V5ICkge1xuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IGZhbHNlO1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9IHRydWU7XG5cblx0XHRcdFx0Ly8gc2VsZWN0YWJsZSBVTlNFTEVDVElORyBjYWxsYmFja1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInVuc2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0dW5zZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdCQoIGV2ZW50LnRhcmdldCApLnBhcmVudHMoKS5hZGRCYWNrKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZG9TZWxlY3QsXG5cdFx0XHRcdHNlbGVjdGVlID0gJC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiICk7XG5cdFx0XHRpZiAoIHNlbGVjdGVlICkge1xuXHRcdFx0XHRkb1NlbGVjdCA9ICggIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgKSB8fFxuXHRcdFx0XHRcdCFzZWxlY3RlZS4kZWxlbWVudC5oYXNDbGFzcyggXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgZG9TZWxlY3QgPyBcInVpLXVuc2VsZWN0aW5nXCIgOiBcInVpLXNlbGVjdGVkXCIgKVxuXHRcdFx0XHRcdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBkb1NlbGVjdCA/IFwidWktc2VsZWN0aW5nXCIgOiBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSAhZG9TZWxlY3Q7XG5cdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGluZyA9IGRvU2VsZWN0O1xuXHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IGRvU2VsZWN0O1xuXG5cdFx0XHRcdC8vIHNlbGVjdGFibGUgKFVOKVNFTEVDVElORyBjYWxsYmFja1xuXHRcdFx0XHRpZiAoIGRvU2VsZWN0ICkge1xuXHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwic2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0XHRzZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJ1bnNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdFx0dW5zZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHR9LFxuXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHRoaXMuZHJhZ2dlZCA9IHRydWU7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgdG1wLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0eDEgPSB0aGlzLm9wb3NbIDAgXSxcblx0XHRcdHkxID0gdGhpcy5vcG9zWyAxIF0sXG5cdFx0XHR4MiA9IGV2ZW50LnBhZ2VYLFxuXHRcdFx0eTIgPSBldmVudC5wYWdlWTtcblxuXHRcdGlmICggeDEgPiB4MiApIHsgdG1wID0geDI7IHgyID0geDE7IHgxID0gdG1wOyB9XG5cdFx0aWYgKCB5MSA+IHkyICkgeyB0bXAgPSB5MjsgeTIgPSB5MTsgeTEgPSB0bXA7IH1cblx0XHR0aGlzLmhlbHBlci5jc3MoIHsgbGVmdDogeDEsIHRvcDogeTEsIHdpZHRoOiB4MiAtIHgxLCBoZWlnaHQ6IHkyIC0geTEgfSApO1xuXG5cdFx0dGhpcy5zZWxlY3RlZXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZWN0ZWUgPSAkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIgKSxcblx0XHRcdFx0aGl0ID0gZmFsc2UsXG5cdFx0XHRcdG9mZnNldCA9IHt9O1xuXG5cdFx0XHQvL3ByZXZlbnQgaGVscGVyIGZyb20gYmVpbmcgc2VsZWN0ZWQgaWYgYXBwZW5kVG86IHNlbGVjdGFibGVcblx0XHRcdGlmICggIXNlbGVjdGVlIHx8IHNlbGVjdGVlLmVsZW1lbnQgPT09IHRoYXQuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdG9mZnNldC5sZWZ0ICAgPSBzZWxlY3RlZS5sZWZ0ICAgKyB0aGF0LmVsZW1lbnRQb3MubGVmdDtcblx0XHRcdG9mZnNldC5yaWdodCAgPSBzZWxlY3RlZS5yaWdodCAgKyB0aGF0LmVsZW1lbnRQb3MubGVmdDtcblx0XHRcdG9mZnNldC50b3AgICAgPSBzZWxlY3RlZS50b3AgICAgKyB0aGF0LmVsZW1lbnRQb3MudG9wO1xuXHRcdFx0b2Zmc2V0LmJvdHRvbSA9IHNlbGVjdGVlLmJvdHRvbSArIHRoYXQuZWxlbWVudFBvcy50b3A7XG5cblx0XHRcdGlmICggb3B0aW9ucy50b2xlcmFuY2UgPT09IFwidG91Y2hcIiApIHtcblx0XHRcdFx0aGl0ID0gKCAhKCBvZmZzZXQubGVmdCA+IHgyIHx8IG9mZnNldC5yaWdodCA8IHgxIHx8IG9mZnNldC50b3AgPiB5MiB8fFxuICAgICAgICAgICAgICAgICAgICBvZmZzZXQuYm90dG9tIDwgeTEgKSApO1xuXHRcdFx0fSBlbHNlIGlmICggb3B0aW9ucy50b2xlcmFuY2UgPT09IFwiZml0XCIgKSB7XG5cdFx0XHRcdGhpdCA9ICggb2Zmc2V0LmxlZnQgPiB4MSAmJiBvZmZzZXQucmlnaHQgPCB4MiAmJiBvZmZzZXQudG9wID4geTEgJiZcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0LmJvdHRvbSA8IHkyICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggaGl0ICkge1xuXG5cdFx0XHRcdC8vIFNFTEVDVFxuXHRcdFx0XHRpZiAoIHNlbGVjdGVlLnNlbGVjdGVkICkge1xuXHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHNlbGVjdGVlLnVuc2VsZWN0aW5nICkge1xuXHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoICFzZWxlY3RlZS5zZWxlY3RpbmcgKSB7XG5cdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHRcdC8vIHNlbGVjdGFibGUgU0VMRUNUSU5HIGNhbGxiYWNrXG5cdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJzZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHRcdHNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBVTlNFTEVDVFxuXHRcdFx0XHRpZiAoIHNlbGVjdGVlLnNlbGVjdGluZyApIHtcblx0XHRcdFx0XHRpZiAoICggZXZlbnQubWV0YUtleSB8fCBldmVudC5jdHJsS2V5ICkgJiYgc2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCApIHtcblx0XHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0aWYgKCBzZWxlY3RlZS5zdGFydHNlbGVjdGVkICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9IHRydWU7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIHNlbGVjdGFibGUgVU5TRUxFQ1RJTkcgY2FsbGJhY2tcblx0XHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwidW5zZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHRcdFx0dW5zZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBzZWxlY3RlZS5zZWxlY3RlZCApIHtcblx0XHRcdFx0XHRpZiAoICFldmVudC5tZXRhS2V5ICYmICFldmVudC5jdHJsS2V5ICYmICFzZWxlY3RlZS5zdGFydHNlbGVjdGVkICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gZmFsc2U7XG5cblx0XHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9IHRydWU7XG5cblx0XHRcdFx0XHRcdC8vIHNlbGVjdGFibGUgVU5TRUxFQ1RJTkcgY2FsbGJhY2tcblx0XHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwidW5zZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHRcdFx0dW5zZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuZHJhZ2dlZCA9IGZhbHNlO1xuXG5cdFx0JCggXCIudWktdW5zZWxlY3RpbmdcIiwgdGhpcy5lbGVtZW50WyAwIF0gKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxlY3RlZSA9ICQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiApO1xuXHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRzZWxlY3RlZS5zdGFydHNlbGVjdGVkID0gZmFsc2U7XG5cdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInVuc2VsZWN0ZWRcIiwgZXZlbnQsIHtcblx0XHRcdFx0dW5zZWxlY3RlZDogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0XHQkKCBcIi51aS1zZWxlY3RpbmdcIiwgdGhpcy5lbGVtZW50WyAwIF0gKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxlY3RlZSA9ICQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiApO1xuXHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGluZ1wiIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0c2VsZWN0ZWUuc2VsZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRzZWxlY3RlZS5zdGFydHNlbGVjdGVkID0gdHJ1ZTtcblx0XHRcdHRoYXQuX3RyaWdnZXIoIFwic2VsZWN0ZWRcIiwgZXZlbnQsIHtcblx0XHRcdFx0c2VsZWN0ZWQ6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50ICk7XG5cblx0XHR0aGlzLmhlbHBlci5yZW1vdmUoKTtcblxuXHRcdHJldHVybiBmYWxzZTtcblx0fVxuXG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU2VsZWN0bWVudSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2VsZWN0bWVudVxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kZXNjcmlwdGlvbjogRHVwbGljYXRlcyBhbmQgZXh0ZW5kcyB0aGUgZnVuY3Rpb25hbGl0eSBvZiBhIG5hdGl2ZSBIVE1MIHNlbGVjdCBlbGVtZW50LCBhbGxvd2luZyBpdCB0byBiZSBjdXN0b21pemFibGUgaW4gYmVoYXZpb3IgYW5kIGFwcGVhcmFuY2UgZmFyIGJleW9uZCB0aGUgbGltaXRhdGlvbnMgb2YgYSBuYXRpdmUgc2VsZWN0LlxuLy8ganNjczplbmFibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zZWxlY3RtZW51L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3NlbGVjdG1lbnUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9zZWxlY3RtZW51LmNzcywgLi4vLi4vdGhlbWVzL2Jhc2UvYnV0dG9uLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c1NlbGVjdG1lbnUgPSAkLndpZGdldCggXCJ1aS5zZWxlY3RtZW51XCIsIFsgJC51aS5mb3JtUmVzZXRNaXhpbiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8c2VsZWN0PlwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YXBwZW5kVG86IG51bGwsXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1vcGVuXCI6IFwidWktY29ybmVyLXRvcFwiLFxuXHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHR9LFxuXHRcdGRpc2FibGVkOiBudWxsLFxuXHRcdGljb25zOiB7XG5cdFx0XHRidXR0b246IFwidWktaWNvbi10cmlhbmdsZS0xLXNcIlxuXHRcdH0sXG5cdFx0cG9zaXRpb246IHtcblx0XHRcdG15OiBcImxlZnQgdG9wXCIsXG5cdFx0XHRhdDogXCJsZWZ0IGJvdHRvbVwiLFxuXHRcdFx0Y29sbGlzaW9uOiBcIm5vbmVcIlxuXHRcdH0sXG5cdFx0d2lkdGg6IGZhbHNlLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdGNsb3NlOiBudWxsLFxuXHRcdGZvY3VzOiBudWxsLFxuXHRcdG9wZW46IG51bGwsXG5cdFx0c2VsZWN0OiBudWxsXG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHNlbGVjdG1lbnVJZCA9IHRoaXMuZWxlbWVudC51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApO1xuXHRcdHRoaXMuaWRzID0ge1xuXHRcdFx0ZWxlbWVudDogc2VsZWN0bWVudUlkLFxuXHRcdFx0YnV0dG9uOiBzZWxlY3RtZW51SWQgKyBcIi1idXR0b25cIixcblx0XHRcdG1lbnU6IHNlbGVjdG1lbnVJZCArIFwiLW1lbnVcIlxuXHRcdH07XG5cblx0XHR0aGlzLl9kcmF3QnV0dG9uKCk7XG5cdFx0dGhpcy5fZHJhd01lbnUoKTtcblx0XHR0aGlzLl9iaW5kRm9ybVJlc2V0SGFuZGxlcigpO1xuXG5cdFx0dGhpcy5fcmVuZGVyZWQgPSBmYWxzZTtcblx0XHR0aGlzLm1lbnVJdGVtcyA9ICQoKTtcblx0fSxcblxuXHRfZHJhd0J1dHRvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGljb24sXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdGl0ZW0gPSB0aGlzLl9wYXJzZU9wdGlvbihcblx0XHRcdFx0dGhpcy5lbGVtZW50LmZpbmQoIFwib3B0aW9uOnNlbGVjdGVkXCIgKSxcblx0XHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uc2VsZWN0ZWRJbmRleFxuXHRcdFx0KTtcblxuXHRcdC8vIEFzc29jaWF0ZSBleGlzdGluZyBsYWJlbCB3aXRoIHRoZSBuZXcgYnV0dG9uXG5cdFx0dGhpcy5sYWJlbHMgPSB0aGlzLmVsZW1lbnQubGFiZWxzKCkuYXR0ciggXCJmb3JcIiwgdGhpcy5pZHMuYnV0dG9uICk7XG5cdFx0dGhpcy5fb24oIHRoaXMubGFiZWxzLCB7XG5cdFx0XHRjbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLmJ1dHRvbi5mb2N1cygpO1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIEhpZGUgb3JpZ2luYWwgc2VsZWN0IGVsZW1lbnRcblx0XHR0aGlzLmVsZW1lbnQuaGlkZSgpO1xuXG5cdFx0Ly8gQ3JlYXRlIGJ1dHRvblxuXHRcdHRoaXMuYnV0dG9uID0gJCggXCI8c3Bhbj5cIiwge1xuXHRcdFx0dGFiaW5kZXg6IHRoaXMub3B0aW9ucy5kaXNhYmxlZCA/IC0xIDogMCxcblx0XHRcdGlkOiB0aGlzLmlkcy5idXR0b24sXG5cdFx0XHRyb2xlOiBcImNvbWJvYm94XCIsXG5cdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XCJhcmlhLWF1dG9jb21wbGV0ZVwiOiBcImxpc3RcIixcblx0XHRcdFwiYXJpYS1vd25zXCI6IHRoaXMuaWRzLm1lbnUsXG5cdFx0XHRcImFyaWEtaGFzcG9wdXBcIjogXCJ0cnVlXCIsXG5cdFx0XHR0aXRsZTogdGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiApXG5cdFx0fSApXG5cdFx0XHQuaW5zZXJ0QWZ0ZXIoIHRoaXMuZWxlbWVudCApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYnV0dG9uLCBcInVpLXNlbGVjdG1lbnUtYnV0dG9uIHVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiLFxuXHRcdFx0XCJ1aS1idXR0b24gdWktd2lkZ2V0XCIgKTtcblxuXHRcdGljb24gPSAkKCBcIjxzcGFuPlwiICkuYXBwZW5kVG8oIHRoaXMuYnV0dG9uICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGljb24sIFwidWktc2VsZWN0bWVudS1pY29uXCIsIFwidWktaWNvbiBcIiArIHRoaXMub3B0aW9ucy5pY29ucy5idXR0b24gKTtcblx0XHR0aGlzLmJ1dHRvbkl0ZW0gPSB0aGlzLl9yZW5kZXJCdXR0b25JdGVtKCBpdGVtIClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5idXR0b24gKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLndpZHRoICE9PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuX3Jlc2l6ZUJ1dHRvbigpO1xuXHRcdH1cblxuXHRcdHRoaXMuX29uKCB0aGlzLmJ1dHRvbiwgdGhpcy5fYnV0dG9uRXZlbnRzICk7XG5cdFx0dGhpcy5idXR0b24ub25lKCBcImZvY3VzaW5cIiwgZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIERlbGF5IHJlbmRlcmluZyB0aGUgbWVudSBpdGVtcyB1bnRpbCB0aGUgYnV0dG9uIHJlY2VpdmVzIGZvY3VzLlxuXHRcdFx0Ly8gVGhlIG1lbnUgbWF5IGhhdmUgYWxyZWFkeSBiZWVuIHJlbmRlcmVkIHZpYSBhIHByb2dyYW1tYXRpYyBvcGVuLlxuXHRcdFx0aWYgKCAhdGhhdC5fcmVuZGVyZWQgKSB7XG5cdFx0XHRcdHRoYXQuX3JlZnJlc2hNZW51KCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9kcmF3TWVudTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0Ly8gQ3JlYXRlIG1lbnVcblx0XHR0aGlzLm1lbnUgPSAkKCBcIjx1bD5cIiwge1xuXHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcInRydWVcIixcblx0XHRcdFwiYXJpYS1sYWJlbGxlZGJ5XCI6IHRoaXMuaWRzLmJ1dHRvbixcblx0XHRcdGlkOiB0aGlzLmlkcy5tZW51XG5cdFx0fSApO1xuXG5cdFx0Ly8gV3JhcCBtZW51XG5cdFx0dGhpcy5tZW51V3JhcCA9ICQoIFwiPGRpdj5cIiApLmFwcGVuZCggdGhpcy5tZW51ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubWVudVdyYXAsIFwidWktc2VsZWN0bWVudS1tZW51XCIsIFwidWktZnJvbnRcIiApO1xuXHRcdHRoaXMubWVudVdyYXAuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblxuXHRcdC8vIEluaXRpYWxpemUgbWVudSB3aWRnZXRcblx0XHR0aGlzLm1lbnVJbnN0YW5jZSA9IHRoaXMubWVudVxuXHRcdFx0Lm1lbnUoIHtcblx0XHRcdFx0Y2xhc3Nlczoge1xuXHRcdFx0XHRcdFwidWktbWVudVwiOiBcInVpLWNvcm5lci1ib3R0b21cIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRyb2xlOiBcImxpc3Rib3hcIixcblx0XHRcdFx0c2VsZWN0OiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRThcblx0XHRcdFx0XHQvLyBJZiB0aGUgaXRlbSB3YXMgc2VsZWN0ZWQgdmlhIGEgY2xpY2ssIHRoZSB0ZXh0IHNlbGVjdGlvblxuXHRcdFx0XHRcdC8vIHdpbGwgYmUgZGVzdHJveWVkIGluIElFXG5cdFx0XHRcdFx0dGhhdC5fc2V0U2VsZWN0aW9uKCk7XG5cblx0XHRcdFx0XHR0aGF0Ll9zZWxlY3QoIHVpLml0ZW0uZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiApLCBldmVudCApO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRmb2N1czogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0XHR2YXIgaXRlbSA9IHVpLml0ZW0uZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiApO1xuXG5cdFx0XHRcdFx0Ly8gUHJldmVudCBpbml0YWwgZm9jdXMgZnJvbSBmaXJpbmcgYW5kIGNoZWNrIGlmIGl0cyBhIG5ld2x5IGZvY3VzZWQgaXRlbVxuXHRcdFx0XHRcdGlmICggdGhhdC5mb2N1c0luZGV4ICE9IG51bGwgJiYgaXRlbS5pbmRleCAhPT0gdGhhdC5mb2N1c0luZGV4ICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJmb2N1c1wiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKTtcblx0XHRcdFx0XHRcdGlmICggIXRoYXQuaXNPcGVuICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0Ll9zZWxlY3QoIGl0ZW0sIGV2ZW50ICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoYXQuZm9jdXNJbmRleCA9IGl0ZW0uaW5kZXg7XG5cblx0XHRcdFx0XHR0aGF0LmJ1dHRvbi5hdHRyKCBcImFyaWEtYWN0aXZlZGVzY2VuZGFudFwiLFxuXHRcdFx0XHRcdFx0dGhhdC5tZW51SXRlbXMuZXEoIGl0ZW0uaW5kZXggKS5hdHRyKCBcImlkXCIgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IClcblx0XHRcdC5tZW51KCBcImluc3RhbmNlXCIgKTtcblxuXHRcdC8vIERvbid0IGNsb3NlIHRoZSBtZW51IG9uIG1vdXNlbGVhdmVcblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5fb2ZmKCB0aGlzLm1lbnUsIFwibW91c2VsZWF2ZVwiICk7XG5cblx0XHQvLyBDYW5jZWwgdGhlIG1lbnUncyBjb2xsYXBzZUFsbCBvbiBkb2N1bWVudCBjbGlja1xuXHRcdHRoaXMubWVudUluc3RhbmNlLl9jbG9zZU9uRG9jdW1lbnRDbGljayA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH07XG5cblx0XHQvLyBTZWxlY3RzIG9mdGVuIGNvbnRhaW4gZW1wdHkgaXRlbXMsIGJ1dCBuZXZlciBjb250YWluIGRpdmlkZXJzXG5cdFx0dGhpcy5tZW51SW5zdGFuY2UuX2lzRGl2aWRlciA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH07XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVmcmVzaE1lbnUoKTtcblx0XHR0aGlzLmJ1dHRvbkl0ZW0ucmVwbGFjZVdpdGgoXG5cdFx0XHR0aGlzLmJ1dHRvbkl0ZW0gPSB0aGlzLl9yZW5kZXJCdXR0b25JdGVtKFxuXG5cdFx0XHRcdC8vIEZhbGwgYmFjayB0byBhbiBlbXB0eSBvYmplY3QgaW4gY2FzZSB0aGVyZSBhcmUgbm8gb3B0aW9uc1xuXHRcdFx0XHR0aGlzLl9nZXRTZWxlY3RlZEl0ZW0oKS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiICkgfHwge31cblx0XHRcdClcblx0XHQpO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLndpZHRoID09PSBudWxsICkge1xuXHRcdFx0dGhpcy5fcmVzaXplQnV0dG9uKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZWZyZXNoTWVudTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGl0ZW0sXG5cdFx0XHRvcHRpb25zID0gdGhpcy5lbGVtZW50LmZpbmQoIFwib3B0aW9uXCIgKTtcblxuXHRcdHRoaXMubWVudS5lbXB0eSgpO1xuXG5cdFx0dGhpcy5fcGFyc2VPcHRpb25zKCBvcHRpb25zICk7XG5cdFx0dGhpcy5fcmVuZGVyTWVudSggdGhpcy5tZW51LCB0aGlzLml0ZW1zICk7XG5cblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5yZWZyZXNoKCk7XG5cdFx0dGhpcy5tZW51SXRlbXMgPSB0aGlzLm1lbnUuZmluZCggXCJsaVwiIClcblx0XHRcdC5ub3QoIFwiLnVpLXNlbGVjdG1lbnUtb3B0Z3JvdXBcIiApXG5cdFx0XHRcdC5maW5kKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiICk7XG5cblx0XHR0aGlzLl9yZW5kZXJlZCA9IHRydWU7XG5cblx0XHRpZiAoICFvcHRpb25zLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpdGVtID0gdGhpcy5fZ2V0U2VsZWN0ZWRJdGVtKCk7XG5cblx0XHQvLyBVcGRhdGUgdGhlIG1lbnUgdG8gaGF2ZSB0aGUgY29ycmVjdCBpdGVtIGZvY3VzZWRcblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5mb2N1cyggbnVsbCwgaXRlbSApO1xuXHRcdHRoaXMuX3NldEFyaWEoIGl0ZW0uZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiApICk7XG5cblx0XHQvLyBTZXQgZGlzYWJsZWQgc3RhdGVcblx0XHR0aGlzLl9zZXRPcHRpb24oIFwiZGlzYWJsZWRcIiwgdGhpcy5lbGVtZW50LnByb3AoIFwiZGlzYWJsZWRcIiApICk7XG5cdH0sXG5cblx0b3BlbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUgdGhlIG1lbnUgaXMgYmVpbmcgb3BlbmVkLCByZW5kZXIgdGhlIGl0ZW1zXG5cdFx0aWYgKCAhdGhpcy5fcmVuZGVyZWQgKSB7XG5cdFx0XHR0aGlzLl9yZWZyZXNoTWVudSgpO1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIE1lbnUgY2xlYXJzIGZvY3VzIG9uIGNsb3NlLCByZXNldCBmb2N1cyB0byBzZWxlY3RlZCBpdGVtXG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5tZW51LmZpbmQoIFwiLnVpLXN0YXRlLWFjdGl2ZVwiICksIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdHRoaXMubWVudUluc3RhbmNlLmZvY3VzKCBudWxsLCB0aGlzLl9nZXRTZWxlY3RlZEl0ZW0oKSApO1xuXHRcdH1cblxuXHRcdC8vIElmIHRoZXJlIGFyZSBubyBvcHRpb25zLCBkb24ndCBvcGVuIHRoZSBtZW51XG5cdFx0aWYgKCAhdGhpcy5tZW51SXRlbXMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuaXNPcGVuID0gdHJ1ZTtcblx0XHR0aGlzLl90b2dnbGVBdHRyKCk7XG5cdFx0dGhpcy5fcmVzaXplTWVudSgpO1xuXHRcdHRoaXMuX3Bvc2l0aW9uKCk7XG5cblx0XHR0aGlzLl9vbiggdGhpcy5kb2N1bWVudCwgdGhpcy5fZG9jdW1lbnRDbGljayApO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJvcGVuXCIsIGV2ZW50ICk7XG5cdH0sXG5cblx0X3Bvc2l0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm1lbnVXcmFwLnBvc2l0aW9uKCAkLmV4dGVuZCggeyBvZjogdGhpcy5idXR0b24gfSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uICkgKTtcblx0fSxcblxuXHRjbG9zZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMuaXNPcGVuICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuaXNPcGVuID0gZmFsc2U7XG5cdFx0dGhpcy5fdG9nZ2xlQXR0cigpO1xuXG5cdFx0dGhpcy5yYW5nZSA9IG51bGw7XG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmRvY3VtZW50ICk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcImNsb3NlXCIsIGV2ZW50ICk7XG5cdH0sXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5idXR0b247XG5cdH0sXG5cblx0bWVudVdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubWVudTtcblx0fSxcblxuXHRfcmVuZGVyQnV0dG9uSXRlbTogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0dmFyIGJ1dHRvbkl0ZW0gPSAkKCBcIjxzcGFuPlwiICk7XG5cblx0XHR0aGlzLl9zZXRUZXh0KCBidXR0b25JdGVtLCBpdGVtLmxhYmVsICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGJ1dHRvbkl0ZW0sIFwidWktc2VsZWN0bWVudS10ZXh0XCIgKTtcblxuXHRcdHJldHVybiBidXR0b25JdGVtO1xuXHR9LFxuXG5cdF9yZW5kZXJNZW51OiBmdW5jdGlvbiggdWwsIGl0ZW1zICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGN1cnJlbnRPcHRncm91cCA9IFwiXCI7XG5cblx0XHQkLmVhY2goIGl0ZW1zLCBmdW5jdGlvbiggaW5kZXgsIGl0ZW0gKSB7XG5cdFx0XHR2YXIgbGk7XG5cblx0XHRcdGlmICggaXRlbS5vcHRncm91cCAhPT0gY3VycmVudE9wdGdyb3VwICkge1xuXHRcdFx0XHRsaSA9ICQoIFwiPGxpPlwiLCB7XG5cdFx0XHRcdFx0dGV4dDogaXRlbS5vcHRncm91cFxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBsaSwgXCJ1aS1zZWxlY3RtZW51LW9wdGdyb3VwXCIsIFwidWktbWVudS1kaXZpZGVyXCIgK1xuXHRcdFx0XHRcdCggaXRlbS5lbGVtZW50LnBhcmVudCggXCJvcHRncm91cFwiICkucHJvcCggXCJkaXNhYmxlZFwiICkgP1xuXHRcdFx0XHRcdFx0XCIgdWktc3RhdGUtZGlzYWJsZWRcIiA6XG5cdFx0XHRcdFx0XHRcIlwiICkgKTtcblxuXHRcdFx0XHRsaS5hcHBlbmRUbyggdWwgKTtcblxuXHRcdFx0XHRjdXJyZW50T3B0Z3JvdXAgPSBpdGVtLm9wdGdyb3VwO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGF0Ll9yZW5kZXJJdGVtRGF0YSggdWwsIGl0ZW0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X3JlbmRlckl0ZW1EYXRhOiBmdW5jdGlvbiggdWwsIGl0ZW0gKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JlbmRlckl0ZW0oIHVsLCBpdGVtICkuZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiwgaXRlbSApO1xuXHR9LFxuXG5cdF9yZW5kZXJJdGVtOiBmdW5jdGlvbiggdWwsIGl0ZW0gKSB7XG5cdFx0dmFyIGxpID0gJCggXCI8bGk+XCIgKSxcblx0XHRcdHdyYXBwZXIgPSAkKCBcIjxkaXY+XCIsIHtcblx0XHRcdFx0dGl0bGU6IGl0ZW0uZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKVxuXHRcdFx0fSApO1xuXG5cdFx0aWYgKCBpdGVtLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGxpLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKTtcblx0XHR9XG5cdFx0dGhpcy5fc2V0VGV4dCggd3JhcHBlciwgaXRlbS5sYWJlbCApO1xuXG5cdFx0cmV0dXJuIGxpLmFwcGVuZCggd3JhcHBlciApLmFwcGVuZFRvKCB1bCApO1xuXHR9LFxuXG5cdF9zZXRUZXh0OiBmdW5jdGlvbiggZWxlbWVudCwgdmFsdWUgKSB7XG5cdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdGVsZW1lbnQudGV4dCggdmFsdWUgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbWVudC5odG1sKCBcIiYjMTYwO1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9tb3ZlOiBmdW5jdGlvbiggZGlyZWN0aW9uLCBldmVudCApIHtcblx0XHR2YXIgaXRlbSwgbmV4dCxcblx0XHRcdGZpbHRlciA9IFwiLnVpLW1lbnUtaXRlbVwiO1xuXG5cdFx0aWYgKCB0aGlzLmlzT3BlbiApIHtcblx0XHRcdGl0ZW0gPSB0aGlzLm1lbnVJdGVtcy5lcSggdGhpcy5mb2N1c0luZGV4ICkucGFyZW50KCBcImxpXCIgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aXRlbSA9IHRoaXMubWVudUl0ZW1zLmVxKCB0aGlzLmVsZW1lbnRbIDAgXS5zZWxlY3RlZEluZGV4ICkucGFyZW50KCBcImxpXCIgKTtcblx0XHRcdGZpbHRlciArPSBcIjpub3QoLnVpLXN0YXRlLWRpc2FibGVkKVwiO1xuXHRcdH1cblxuXHRcdGlmICggZGlyZWN0aW9uID09PSBcImZpcnN0XCIgfHwgZGlyZWN0aW9uID09PSBcImxhc3RcIiApIHtcblx0XHRcdG5leHQgPSBpdGVtWyBkaXJlY3Rpb24gPT09IFwiZmlyc3RcIiA/IFwicHJldkFsbFwiIDogXCJuZXh0QWxsXCIgXSggZmlsdGVyICkuZXEoIC0xICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG5leHQgPSBpdGVtWyBkaXJlY3Rpb24gKyBcIkFsbFwiIF0oIGZpbHRlciApLmVxKCAwICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBuZXh0Lmxlbmd0aCApIHtcblx0XHRcdHRoaXMubWVudUluc3RhbmNlLmZvY3VzKCBldmVudCwgbmV4dCApO1xuXHRcdH1cblx0fSxcblxuXHRfZ2V0U2VsZWN0ZWRJdGVtOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tZW51SXRlbXMuZXEoIHRoaXMuZWxlbWVudFsgMCBdLnNlbGVjdGVkSW5kZXggKS5wYXJlbnQoIFwibGlcIiApO1xuXHR9LFxuXG5cdF90b2dnbGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzWyB0aGlzLmlzT3BlbiA/IFwiY2xvc2VcIiA6IFwib3BlblwiIF0oIGV2ZW50ICk7XG5cdH0sXG5cblx0X3NldFNlbGVjdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHNlbGVjdGlvbjtcblxuXHRcdGlmICggIXRoaXMucmFuZ2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB3aW5kb3cuZ2V0U2VsZWN0aW9uICkge1xuXHRcdFx0c2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuXHRcdFx0c2VsZWN0aW9uLnJlbW92ZUFsbFJhbmdlcygpO1xuXHRcdFx0c2VsZWN0aW9uLmFkZFJhbmdlKCB0aGlzLnJhbmdlICk7XG5cblx0XHQvLyBTdXBwb3J0OiBJRThcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5yYW5nZS5zZWxlY3QoKTtcblx0XHR9XG5cblx0XHQvLyBTdXBwb3J0OiBJRVxuXHRcdC8vIFNldHRpbmcgdGhlIHRleHQgc2VsZWN0aW9uIGtpbGxzIHRoZSBidXR0b24gZm9jdXMgaW4gSUUsIGJ1dFxuXHRcdC8vIHJlc3RvcmluZyB0aGUgZm9jdXMgZG9lc24ndCBraWxsIHRoZSBzZWxlY3Rpb24uXG5cdFx0dGhpcy5idXR0b24uZm9jdXMoKTtcblx0fSxcblxuXHRfZG9jdW1lbnRDbGljazoge1xuXHRcdG1vdXNlZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0aWYgKCAhdGhpcy5pc09wZW4gKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktc2VsZWN0bWVudS1tZW51LCAjXCIgK1xuXHRcdFx0XHRcdCQudWkuZXNjYXBlU2VsZWN0b3IoIHRoaXMuaWRzLmJ1dHRvbiApICkubGVuZ3RoICkge1xuXHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfYnV0dG9uRXZlbnRzOiB7XG5cblx0XHQvLyBQcmV2ZW50IHRleHQgc2VsZWN0aW9uIGZyb20gYmVpbmcgcmVzZXQgd2hlbiBpbnRlcmFjdGluZyB3aXRoIHRoZSBzZWxlY3RtZW51ICgjMTAxNDQpXG5cdFx0bW91c2Vkb3duOiBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxlY3Rpb247XG5cblx0XHRcdGlmICggd2luZG93LmdldFNlbGVjdGlvbiApIHtcblx0XHRcdFx0c2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbigpO1xuXHRcdFx0XHRpZiAoIHNlbGVjdGlvbi5yYW5nZUNvdW50ICkge1xuXHRcdFx0XHRcdHRoaXMucmFuZ2UgPSBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCggMCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOFxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5yYW5nZSA9IGRvY3VtZW50LnNlbGVjdGlvbi5jcmVhdGVSYW5nZSgpO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRjbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0dGhpcy5fc2V0U2VsZWN0aW9uKCk7XG5cdFx0XHR0aGlzLl90b2dnbGUoIGV2ZW50ICk7XG5cdFx0fSxcblxuXHRcdGtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciBwcmV2ZW50RGVmYXVsdCA9IHRydWU7XG5cdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuVEFCOlxuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRVNDQVBFOlxuXHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0XHRwcmV2ZW50RGVmYXVsdCA9IGZhbHNlO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkVOVEVSOlxuXHRcdFx0XHRpZiAoIHRoaXMuaXNPcGVuICkge1xuXHRcdFx0XHRcdHRoaXMuX3NlbGVjdEZvY3VzZWRJdGVtKCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuVVA6XG5cdFx0XHRcdGlmICggZXZlbnQuYWx0S2V5ICkge1xuXHRcdFx0XHRcdHRoaXMuX3RvZ2dsZSggZXZlbnQgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcInByZXZcIiwgZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkRPV046XG5cdFx0XHRcdGlmICggZXZlbnQuYWx0S2V5ICkge1xuXHRcdFx0XHRcdHRoaXMuX3RvZ2dsZSggZXZlbnQgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcIm5leHRcIiwgZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlNQQUNFOlxuXHRcdFx0XHRpZiAoIHRoaXMuaXNPcGVuICkge1xuXHRcdFx0XHRcdHRoaXMuX3NlbGVjdEZvY3VzZWRJdGVtKCBldmVudCApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX3RvZ2dsZSggZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkxFRlQ6XG5cdFx0XHRcdHRoaXMuX21vdmUoIFwicHJldlwiLCBldmVudCApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlJJR0hUOlxuXHRcdFx0XHR0aGlzLl9tb3ZlKCBcIm5leHRcIiwgZXZlbnQgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5IT01FOlxuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9VUDpcblx0XHRcdFx0dGhpcy5fbW92ZSggXCJmaXJzdFwiLCBldmVudCApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkVORDpcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdFx0dGhpcy5fbW92ZSggXCJsYXN0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0dGhpcy5tZW51LnRyaWdnZXIoIGV2ZW50ICk7XG5cdFx0XHRcdHByZXZlbnREZWZhdWx0ID0gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggcHJldmVudERlZmF1bHQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9zZWxlY3RGb2N1c2VkSXRlbTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpdGVtID0gdGhpcy5tZW51SXRlbXMuZXEoIHRoaXMuZm9jdXNJbmRleCApLnBhcmVudCggXCJsaVwiICk7XG5cdFx0aWYgKCAhaXRlbS5oYXNDbGFzcyggXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSB7XG5cdFx0XHR0aGlzLl9zZWxlY3QoIGl0ZW0uZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiApLCBldmVudCApO1xuXHRcdH1cblx0fSxcblxuXHRfc2VsZWN0OiBmdW5jdGlvbiggaXRlbSwgZXZlbnQgKSB7XG5cdFx0dmFyIG9sZEluZGV4ID0gdGhpcy5lbGVtZW50WyAwIF0uc2VsZWN0ZWRJbmRleDtcblxuXHRcdC8vIENoYW5nZSBuYXRpdmUgc2VsZWN0IGVsZW1lbnRcblx0XHR0aGlzLmVsZW1lbnRbIDAgXS5zZWxlY3RlZEluZGV4ID0gaXRlbS5pbmRleDtcblx0XHR0aGlzLmJ1dHRvbkl0ZW0ucmVwbGFjZVdpdGgoIHRoaXMuYnV0dG9uSXRlbSA9IHRoaXMuX3JlbmRlckJ1dHRvbkl0ZW0oIGl0ZW0gKSApO1xuXHRcdHRoaXMuX3NldEFyaWEoIGl0ZW0gKTtcblx0XHR0aGlzLl90cmlnZ2VyKCBcInNlbGVjdFwiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKTtcblxuXHRcdGlmICggaXRlbS5pbmRleCAhPT0gb2xkSW5kZXggKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHR9LFxuXG5cdF9zZXRBcmlhOiBmdW5jdGlvbiggaXRlbSApIHtcblx0XHR2YXIgaWQgPSB0aGlzLm1lbnVJdGVtcy5lcSggaXRlbS5pbmRleCApLmF0dHIoIFwiaWRcIiApO1xuXG5cdFx0dGhpcy5idXR0b24uYXR0cigge1xuXHRcdFx0XCJhcmlhLWxhYmVsbGVkYnlcIjogaWQsXG5cdFx0XHRcImFyaWEtYWN0aXZlZGVzY2VuZGFudFwiOiBpZFxuXHRcdH0gKTtcblx0XHR0aGlzLm1lbnUuYXR0ciggXCJhcmlhLWFjdGl2ZWRlc2NlbmRhbnRcIiwgaWQgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJpY29uc1wiICkge1xuXHRcdFx0dmFyIGljb24gPSB0aGlzLmJ1dHRvbi5maW5kKCBcInNwYW4udWktaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggaWNvbiwgbnVsbCwgdGhpcy5vcHRpb25zLmljb25zLmJ1dHRvbiApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIGljb24sIG51bGwsIHZhbHVlLmJ1dHRvbiApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJhcHBlbmRUb1wiICkge1xuXHRcdFx0dGhpcy5tZW51V3JhcC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcIndpZHRoXCIgKSB7XG5cdFx0XHR0aGlzLl9yZXNpemVCdXR0b24oKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5vcHRpb24oIFwiZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHR0aGlzLmJ1dHRvbi5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5idXR0b24sIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblxuXHRcdHRoaXMuZWxlbWVudC5wcm9wKCBcImRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdHRoaXMuYnV0dG9uLmF0dHIoIFwidGFiaW5kZXhcIiwgLTEgKTtcblx0XHRcdHRoaXMuY2xvc2UoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5idXR0b24uYXR0ciggXCJ0YWJpbmRleFwiLCAwICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hcHBlbmRUbzogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW1lbnQgPSB0aGlzLm9wdGlvbnMuYXBwZW5kVG87XG5cblx0XHRpZiAoIGVsZW1lbnQgKSB7XG5cdFx0XHRlbGVtZW50ID0gZWxlbWVudC5qcXVlcnkgfHwgZWxlbWVudC5ub2RlVHlwZSA/XG5cdFx0XHRcdCQoIGVsZW1lbnQgKSA6XG5cdFx0XHRcdHRoaXMuZG9jdW1lbnQuZmluZCggZWxlbWVudCApLmVxKCAwICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhZWxlbWVudCB8fCAhZWxlbWVudFsgMCBdICkge1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZWxlbWVudC5jbG9zZXN0KCBcIi51aS1mcm9udCwgZGlhbG9nXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoICFlbGVtZW50Lmxlbmd0aCApIHtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZWxlbWVudDtcblx0fSxcblxuXHRfdG9nZ2xlQXR0cjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5idXR0b24uYXR0ciggXCJhcmlhLWV4cGFuZGVkXCIsIHRoaXMuaXNPcGVuICk7XG5cblx0XHQvLyBXZSBjYW4ndCB1c2UgdHdvIF90b2dnbGVDbGFzcygpIGNhbGxzIGhlcmUsIGJlY2F1c2Ugd2UgbmVlZCB0byBtYWtlIHN1cmVcblx0XHQvLyB3ZSBhbHdheXMgcmVtb3ZlIGNsYXNzZXMgZmlyc3QgYW5kIGFkZCB0aGVtIHNlY29uZCwgb3RoZXJ3aXNlIGlmIGJvdGggY2xhc3NlcyBoYXZlIHRoZVxuXHRcdC8vIHNhbWUgdGhlbWUgY2xhc3MsIGl0IHdpbGwgYmUgcmVtb3ZlZCBhZnRlciB3ZSBhZGQgaXQuXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuYnV0dG9uLCBcInVpLXNlbGVjdG1lbnUtYnV0dG9uLVwiICtcblx0XHRcdCggdGhpcy5pc09wZW4gPyBcImNsb3NlZFwiIDogXCJvcGVuXCIgKSApXG5cdFx0XHQuX2FkZENsYXNzKCB0aGlzLmJ1dHRvbiwgXCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1cIiArXG5cdFx0XHRcdCggdGhpcy5pc09wZW4gPyBcIm9wZW5cIiA6IFwiY2xvc2VkXCIgKSApXG5cdFx0XHQuX3RvZ2dsZUNsYXNzKCB0aGlzLm1lbnVXcmFwLCBcInVpLXNlbGVjdG1lbnUtb3BlblwiLCBudWxsLCB0aGlzLmlzT3BlbiApO1xuXG5cdFx0dGhpcy5tZW51LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgIXRoaXMuaXNPcGVuICk7XG5cdH0sXG5cblx0X3Jlc2l6ZUJ1dHRvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHdpZHRoID0gdGhpcy5vcHRpb25zLndpZHRoO1xuXG5cdFx0Ly8gRm9yIGB3aWR0aDogZmFsc2VgLCBqdXN0IHJlbW92ZSBpbmxpbmUgc3R5bGUgYW5kIHN0b3Bcblx0XHRpZiAoIHdpZHRoID09PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuYnV0dG9uLmNzcyggXCJ3aWR0aFwiLCBcIlwiICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRm9yIGB3aWR0aDogbnVsbGAsIG1hdGNoIHRoZSB3aWR0aCBvZiB0aGUgb3JpZ2luYWwgZWxlbWVudFxuXHRcdGlmICggd2lkdGggPT09IG51bGwgKSB7XG5cdFx0XHR3aWR0aCA9IHRoaXMuZWxlbWVudC5zaG93KCkub3V0ZXJXaWR0aCgpO1xuXHRcdFx0dGhpcy5lbGVtZW50LmhpZGUoKTtcblx0XHR9XG5cblx0XHR0aGlzLmJ1dHRvbi5vdXRlcldpZHRoKCB3aWR0aCApO1xuXHR9LFxuXG5cdF9yZXNpemVNZW51OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm1lbnUub3V0ZXJXaWR0aCggTWF0aC5tYXgoXG5cdFx0XHR0aGlzLmJ1dHRvbi5vdXRlcldpZHRoKCksXG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFMTBcblx0XHRcdC8vIElFMTAgd3JhcHMgbG9uZyB0ZXh0IChwb3NzaWJseSBhIHJvdW5kaW5nIGJ1Zylcblx0XHRcdC8vIHNvIHdlIGFkZCAxcHggdG8gYXZvaWQgdGhlIHdyYXBwaW5nXG5cdFx0XHR0aGlzLm1lbnUud2lkdGgoIFwiXCIgKS5vdXRlcldpZHRoKCkgKyAxXG5cdFx0KSApO1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMuX3N1cGVyKCk7XG5cblx0XHRvcHRpb25zLmRpc2FibGVkID0gdGhpcy5lbGVtZW50LnByb3AoIFwiZGlzYWJsZWRcIiApO1xuXG5cdFx0cmV0dXJuIG9wdGlvbnM7XG5cdH0sXG5cblx0X3BhcnNlT3B0aW9uczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0ZGF0YSA9IFtdO1xuXHRcdG9wdGlvbnMuZWFjaCggZnVuY3Rpb24oIGluZGV4LCBpdGVtICkge1xuXHRcdFx0ZGF0YS5wdXNoKCB0aGF0Ll9wYXJzZU9wdGlvbiggJCggaXRlbSApLCBpbmRleCApICk7XG5cdFx0fSApO1xuXHRcdHRoaXMuaXRlbXMgPSBkYXRhO1xuXHR9LFxuXG5cdF9wYXJzZU9wdGlvbjogZnVuY3Rpb24oIG9wdGlvbiwgaW5kZXggKSB7XG5cdFx0dmFyIG9wdGdyb3VwID0gb3B0aW9uLnBhcmVudCggXCJvcHRncm91cFwiICk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0ZWxlbWVudDogb3B0aW9uLFxuXHRcdFx0aW5kZXg6IGluZGV4LFxuXHRcdFx0dmFsdWU6IG9wdGlvbi52YWwoKSxcblx0XHRcdGxhYmVsOiBvcHRpb24udGV4dCgpLFxuXHRcdFx0b3B0Z3JvdXA6IG9wdGdyb3VwLmF0dHIoIFwibGFiZWxcIiApIHx8IFwiXCIsXG5cdFx0XHRkaXNhYmxlZDogb3B0Z3JvdXAucHJvcCggXCJkaXNhYmxlZFwiICkgfHwgb3B0aW9uLnByb3AoIFwiZGlzYWJsZWRcIiApXG5cdFx0fTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fdW5iaW5kRm9ybVJlc2V0SGFuZGxlcigpO1xuXHRcdHRoaXMubWVudVdyYXAucmVtb3ZlKCk7XG5cdFx0dGhpcy5idXR0b24ucmVtb3ZlKCk7XG5cdFx0dGhpcy5lbGVtZW50LnNob3coKTtcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlVW5pcXVlSWQoKTtcblx0XHR0aGlzLmxhYmVscy5hdHRyKCBcImZvclwiLCB0aGlzLmlkcy5lbGVtZW50ICk7XG5cdH1cbn0gXSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNsaWRlciAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2xpZGVyXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgYSBmbGV4aWJsZSBzbGlkZXIgd2l0aCByYW5nZXMgYW5kIGFjY2Vzc2liaWxpdHkgdmlhIGtleWJvYXJkLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NsaWRlci9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9zbGlkZXIvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9zbGlkZXIuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzU2xpZGVyID0gJC53aWRnZXQoIFwidWkuc2xpZGVyXCIsICQudWkubW91c2UsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwic2xpZGVcIixcblxuXHRvcHRpb25zOiB7XG5cdFx0YW5pbWF0ZTogZmFsc2UsXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1zbGlkZXJcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLXNsaWRlci1oYW5kbGVcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cblx0XHRcdC8vIE5vdGU6IHVpLXdpZGdldC1oZWFkZXIgaXNuJ3QgdGhlIG1vc3QgZml0dGluZ2x5IHNlbWFudGljIGZyYW1ld29yayBjbGFzcyBmb3IgdGhpc1xuXHRcdFx0Ly8gZWxlbWVudCwgYnV0IHdvcmtlZCBiZXN0IHZpc3VhbGx5IHdpdGggYSB2YXJpZXR5IG9mIHRoZW1lc1xuXHRcdFx0XCJ1aS1zbGlkZXItcmFuZ2VcIjogXCJ1aS1jb3JuZXItYWxsIHVpLXdpZGdldC1oZWFkZXJcIlxuXHRcdH0sXG5cdFx0ZGlzdGFuY2U6IDAsXG5cdFx0bWF4OiAxMDAsXG5cdFx0bWluOiAwLFxuXHRcdG9yaWVudGF0aW9uOiBcImhvcml6b250YWxcIixcblx0XHRyYW5nZTogZmFsc2UsXG5cdFx0c3RlcDogMSxcblx0XHR2YWx1ZTogMCxcblx0XHR2YWx1ZXM6IG51bGwsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0c2xpZGU6IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbFxuXHR9LFxuXG5cdC8vIE51bWJlciBvZiBwYWdlcyBpbiBhIHNsaWRlclxuXHQvLyAoaG93IG1hbnkgdGltZXMgY2FuIHlvdSBwYWdlIHVwL2Rvd24gdG8gZ28gdGhyb3VnaCB0aGUgd2hvbGUgcmFuZ2UpXG5cdG51bVBhZ2VzOiA1LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2tleVNsaWRpbmcgPSBmYWxzZTtcblx0XHR0aGlzLl9tb3VzZVNsaWRpbmcgPSBmYWxzZTtcblx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHR0aGlzLl9oYW5kbGVJbmRleCA9IG51bGw7XG5cdFx0dGhpcy5fZGV0ZWN0T3JpZW50YXRpb24oKTtcblx0XHR0aGlzLl9tb3VzZUluaXQoKTtcblx0XHR0aGlzLl9jYWxjdWxhdGVOZXdNYXgoKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXNsaWRlciB1aS1zbGlkZXItXCIgKyB0aGlzLm9yaWVudGF0aW9uLFxuXHRcdFx0XCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXG5cdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXHR9LFxuXG5cdF9yZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9jcmVhdGVSYW5nZSgpO1xuXHRcdHRoaXMuX2NyZWF0ZUhhbmRsZXMoKTtcblx0XHR0aGlzLl9zZXR1cEV2ZW50cygpO1xuXHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHR9LFxuXG5cdF9jcmVhdGVIYW5kbGVzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaSwgaGFuZGxlQ291bnQsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0ZXhpc3RpbmdIYW5kbGVzID0gdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLXNsaWRlci1oYW5kbGVcIiApLFxuXHRcdFx0aGFuZGxlID0gXCI8c3BhbiB0YWJpbmRleD0nMCc+PC9zcGFuPlwiLFxuXHRcdFx0aGFuZGxlcyA9IFtdO1xuXG5cdFx0aGFuZGxlQ291bnQgPSAoIG9wdGlvbnMudmFsdWVzICYmIG9wdGlvbnMudmFsdWVzLmxlbmd0aCApIHx8IDE7XG5cblx0XHRpZiAoIGV4aXN0aW5nSGFuZGxlcy5sZW5ndGggPiBoYW5kbGVDb3VudCApIHtcblx0XHRcdGV4aXN0aW5nSGFuZGxlcy5zbGljZSggaGFuZGxlQ291bnQgKS5yZW1vdmUoKTtcblx0XHRcdGV4aXN0aW5nSGFuZGxlcyA9IGV4aXN0aW5nSGFuZGxlcy5zbGljZSggMCwgaGFuZGxlQ291bnQgKTtcblx0XHR9XG5cblx0XHRmb3IgKCBpID0gZXhpc3RpbmdIYW5kbGVzLmxlbmd0aDsgaSA8IGhhbmRsZUNvdW50OyBpKysgKSB7XG5cdFx0XHRoYW5kbGVzLnB1c2goIGhhbmRsZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuaGFuZGxlcyA9IGV4aXN0aW5nSGFuZGxlcy5hZGQoICQoIGhhbmRsZXMuam9pbiggXCJcIiApICkuYXBwZW5kVG8oIHRoaXMuZWxlbWVudCApICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oYW5kbGVzLCBcInVpLXNsaWRlci1oYW5kbGVcIiwgXCJ1aS1zdGF0ZS1kZWZhdWx0XCIgKTtcblxuXHRcdHRoaXMuaGFuZGxlID0gdGhpcy5oYW5kbGVzLmVxKCAwICk7XG5cblx0XHR0aGlzLmhhbmRsZXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHQkKCB0aGlzIClcblx0XHRcdFx0LmRhdGEoIFwidWktc2xpZGVyLWhhbmRsZS1pbmRleFwiLCBpIClcblx0XHRcdFx0LmF0dHIoIFwidGFiSW5kZXhcIiwgMCApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfY3JlYXRlUmFuZ2U6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0aWYgKCBvcHRpb25zLnJhbmdlICkge1xuXHRcdFx0aWYgKCBvcHRpb25zLnJhbmdlID09PSB0cnVlICkge1xuXHRcdFx0XHRpZiAoICFvcHRpb25zLnZhbHVlcyApIHtcblx0XHRcdFx0XHRvcHRpb25zLnZhbHVlcyA9IFsgdGhpcy5fdmFsdWVNaW4oKSwgdGhpcy5fdmFsdWVNaW4oKSBdO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBvcHRpb25zLnZhbHVlcy5sZW5ndGggJiYgb3B0aW9ucy52YWx1ZXMubGVuZ3RoICE9PSAyICkge1xuXHRcdFx0XHRcdG9wdGlvbnMudmFsdWVzID0gWyBvcHRpb25zLnZhbHVlc1sgMCBdLCBvcHRpb25zLnZhbHVlc1sgMCBdIF07XG5cdFx0XHRcdH0gZWxzZSBpZiAoICQuaXNBcnJheSggb3B0aW9ucy52YWx1ZXMgKSApIHtcblx0XHRcdFx0XHRvcHRpb25zLnZhbHVlcyA9IG9wdGlvbnMudmFsdWVzLnNsaWNlKCAwICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhdGhpcy5yYW5nZSB8fCAhdGhpcy5yYW5nZS5sZW5ndGggKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2UgPSAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0XHRcdC5hcHBlbmRUbyggdGhpcy5lbGVtZW50ICk7XG5cblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMucmFuZ2UsIFwidWktc2xpZGVyLXJhbmdlXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLnJhbmdlLCBcInVpLXNsaWRlci1yYW5nZS1taW4gdWktc2xpZGVyLXJhbmdlLW1heFwiICk7XG5cblx0XHRcdFx0Ly8gSGFuZGxlIHJhbmdlIHN3aXRjaGluZyBmcm9tIHRydWUgdG8gbWluL21heFxuXHRcdFx0XHR0aGlzLnJhbmdlLmNzcygge1xuXHRcdFx0XHRcdFwibGVmdFwiOiBcIlwiLFxuXHRcdFx0XHRcdFwiYm90dG9tXCI6IFwiXCJcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvcHRpb25zLnJhbmdlID09PSBcIm1pblwiIHx8IG9wdGlvbnMucmFuZ2UgPT09IFwibWF4XCIgKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnJhbmdlLCBcInVpLXNsaWRlci1yYW5nZS1cIiArIG9wdGlvbnMucmFuZ2UgKTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0aWYgKCB0aGlzLnJhbmdlICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlLnJlbW92ZSgpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5yYW5nZSA9IG51bGw7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXR1cEV2ZW50czogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmhhbmRsZXMgKTtcblx0XHR0aGlzLl9vbiggdGhpcy5oYW5kbGVzLCB0aGlzLl9oYW5kbGVFdmVudHMgKTtcblx0XHR0aGlzLl9ob3ZlcmFibGUoIHRoaXMuaGFuZGxlcyApO1xuXHRcdHRoaXMuX2ZvY3VzYWJsZSggdGhpcy5oYW5kbGVzICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuaGFuZGxlcy5yZW1vdmUoKTtcblx0XHRpZiAoIHRoaXMucmFuZ2UgKSB7XG5cdFx0XHR0aGlzLnJhbmdlLnJlbW92ZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX21vdXNlRGVzdHJveSgpO1xuXHR9LFxuXG5cdF9tb3VzZUNhcHR1cmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgcG9zaXRpb24sIG5vcm1WYWx1ZSwgZGlzdGFuY2UsIGNsb3Nlc3RIYW5kbGUsIGluZGV4LCBhbGxvd2VkLCBvZmZzZXQsIG1vdXNlT3ZlckhhbmRsZSxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucztcblxuXHRcdGlmICggby5kaXNhYmxlZCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR0aGlzLmVsZW1lbnRTaXplID0ge1xuXHRcdFx0d2lkdGg6IHRoaXMuZWxlbWVudC5vdXRlcldpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IHRoaXMuZWxlbWVudC5vdXRlckhlaWdodCgpXG5cdFx0fTtcblx0XHR0aGlzLmVsZW1lbnRPZmZzZXQgPSB0aGlzLmVsZW1lbnQub2Zmc2V0KCk7XG5cblx0XHRwb3NpdGlvbiA9IHsgeDogZXZlbnQucGFnZVgsIHk6IGV2ZW50LnBhZ2VZIH07XG5cdFx0bm9ybVZhbHVlID0gdGhpcy5fbm9ybVZhbHVlRnJvbU1vdXNlKCBwb3NpdGlvbiApO1xuXHRcdGRpc3RhbmNlID0gdGhpcy5fdmFsdWVNYXgoKSAtIHRoaXMuX3ZhbHVlTWluKCkgKyAxO1xuXHRcdHRoaXMuaGFuZGxlcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdHZhciB0aGlzRGlzdGFuY2UgPSBNYXRoLmFicyggbm9ybVZhbHVlIC0gdGhhdC52YWx1ZXMoIGkgKSApO1xuXHRcdFx0aWYgKCAoIGRpc3RhbmNlID4gdGhpc0Rpc3RhbmNlICkgfHxcblx0XHRcdFx0KCBkaXN0YW5jZSA9PT0gdGhpc0Rpc3RhbmNlICYmXG5cdFx0XHRcdFx0KCBpID09PSB0aGF0Ll9sYXN0Q2hhbmdlZFZhbHVlIHx8IHRoYXQudmFsdWVzKCBpICkgPT09IG8ubWluICkgKSApIHtcblx0XHRcdFx0ZGlzdGFuY2UgPSB0aGlzRGlzdGFuY2U7XG5cdFx0XHRcdGNsb3Nlc3RIYW5kbGUgPSAkKCB0aGlzICk7XG5cdFx0XHRcdGluZGV4ID0gaTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRhbGxvd2VkID0gdGhpcy5fc3RhcnQoIGV2ZW50LCBpbmRleCApO1xuXHRcdGlmICggYWxsb3dlZCA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdHRoaXMuX21vdXNlU2xpZGluZyA9IHRydWU7XG5cblx0XHR0aGlzLl9oYW5kbGVJbmRleCA9IGluZGV4O1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGNsb3Nlc3RIYW5kbGUsIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRjbG9zZXN0SGFuZGxlLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXG5cdFx0b2Zmc2V0ID0gY2xvc2VzdEhhbmRsZS5vZmZzZXQoKTtcblx0XHRtb3VzZU92ZXJIYW5kbGUgPSAhJCggZXZlbnQudGFyZ2V0ICkucGFyZW50cygpLmFkZEJhY2soKS5pcyggXCIudWktc2xpZGVyLWhhbmRsZVwiICk7XG5cdFx0dGhpcy5fY2xpY2tPZmZzZXQgPSBtb3VzZU92ZXJIYW5kbGUgPyB7IGxlZnQ6IDAsIHRvcDogMCB9IDoge1xuXHRcdFx0bGVmdDogZXZlbnQucGFnZVggLSBvZmZzZXQubGVmdCAtICggY2xvc2VzdEhhbmRsZS53aWR0aCgpIC8gMiApLFxuXHRcdFx0dG9wOiBldmVudC5wYWdlWSAtIG9mZnNldC50b3AgLVxuXHRcdFx0XHQoIGNsb3Nlc3RIYW5kbGUuaGVpZ2h0KCkgLyAyICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjbG9zZXN0SGFuZGxlLmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0KCBwYXJzZUludCggY2xvc2VzdEhhbmRsZS5jc3MoIFwiYm9yZGVyQm90dG9tV2lkdGhcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdCggcGFyc2VJbnQoIGNsb3Nlc3RIYW5kbGUuY3NzKCBcIm1hcmdpblRvcFwiICksIDEwICkgfHwgMCApXG5cdFx0fTtcblxuXHRcdGlmICggIXRoaXMuaGFuZGxlcy5oYXNDbGFzcyggXCJ1aS1zdGF0ZS1ob3ZlclwiICkgKSB7XG5cdFx0XHR0aGlzLl9zbGlkZSggZXZlbnQsIGluZGV4LCBub3JtVmFsdWUgKTtcblx0XHR9XG5cdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgcG9zaXRpb24gPSB7IHg6IGV2ZW50LnBhZ2VYLCB5OiBldmVudC5wYWdlWSB9LFxuXHRcdFx0bm9ybVZhbHVlID0gdGhpcy5fbm9ybVZhbHVlRnJvbU1vdXNlKCBwb3NpdGlvbiApO1xuXG5cdFx0dGhpcy5fc2xpZGUoIGV2ZW50LCB0aGlzLl9oYW5kbGVJbmRleCwgbm9ybVZhbHVlICk7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmhhbmRsZXMsIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHR0aGlzLl9tb3VzZVNsaWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuX3N0b3AoIGV2ZW50LCB0aGlzLl9oYW5kbGVJbmRleCApO1xuXHRcdHRoaXMuX2NoYW5nZSggZXZlbnQsIHRoaXMuX2hhbmRsZUluZGV4ICk7XG5cblx0XHR0aGlzLl9oYW5kbGVJbmRleCA9IG51bGw7XG5cdFx0dGhpcy5fY2xpY2tPZmZzZXQgPSBudWxsO1xuXHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfZGV0ZWN0T3JpZW50YXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMub3JpZW50YXRpb24gPSAoIHRoaXMub3B0aW9ucy5vcmllbnRhdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiICkgPyBcInZlcnRpY2FsXCIgOiBcImhvcml6b250YWxcIjtcblx0fSxcblxuXHRfbm9ybVZhbHVlRnJvbU1vdXNlOiBmdW5jdGlvbiggcG9zaXRpb24gKSB7XG5cdFx0dmFyIHBpeGVsVG90YWwsXG5cdFx0XHRwaXhlbE1vdXNlLFxuXHRcdFx0cGVyY2VudE1vdXNlLFxuXHRcdFx0dmFsdWVUb3RhbCxcblx0XHRcdHZhbHVlTW91c2U7XG5cblx0XHRpZiAoIHRoaXMub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0cGl4ZWxUb3RhbCA9IHRoaXMuZWxlbWVudFNpemUud2lkdGg7XG5cdFx0XHRwaXhlbE1vdXNlID0gcG9zaXRpb24ueCAtIHRoaXMuZWxlbWVudE9mZnNldC5sZWZ0IC1cblx0XHRcdFx0KCB0aGlzLl9jbGlja09mZnNldCA/IHRoaXMuX2NsaWNrT2Zmc2V0LmxlZnQgOiAwICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHBpeGVsVG90YWwgPSB0aGlzLmVsZW1lbnRTaXplLmhlaWdodDtcblx0XHRcdHBpeGVsTW91c2UgPSBwb3NpdGlvbi55IC0gdGhpcy5lbGVtZW50T2Zmc2V0LnRvcCAtXG5cdFx0XHRcdCggdGhpcy5fY2xpY2tPZmZzZXQgPyB0aGlzLl9jbGlja09mZnNldC50b3AgOiAwICk7XG5cdFx0fVxuXG5cdFx0cGVyY2VudE1vdXNlID0gKCBwaXhlbE1vdXNlIC8gcGl4ZWxUb3RhbCApO1xuXHRcdGlmICggcGVyY2VudE1vdXNlID4gMSApIHtcblx0XHRcdHBlcmNlbnRNb3VzZSA9IDE7XG5cdFx0fVxuXHRcdGlmICggcGVyY2VudE1vdXNlIDwgMCApIHtcblx0XHRcdHBlcmNlbnRNb3VzZSA9IDA7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiICkge1xuXHRcdFx0cGVyY2VudE1vdXNlID0gMSAtIHBlcmNlbnRNb3VzZTtcblx0XHR9XG5cblx0XHR2YWx1ZVRvdGFsID0gdGhpcy5fdmFsdWVNYXgoKSAtIHRoaXMuX3ZhbHVlTWluKCk7XG5cdFx0dmFsdWVNb3VzZSA9IHRoaXMuX3ZhbHVlTWluKCkgKyBwZXJjZW50TW91c2UgKiB2YWx1ZVRvdGFsO1xuXG5cdFx0cmV0dXJuIHRoaXMuX3RyaW1BbGlnblZhbHVlKCB2YWx1ZU1vdXNlICk7XG5cdH0sXG5cblx0X3VpSGFzaDogZnVuY3Rpb24oIGluZGV4LCB2YWx1ZSwgdmFsdWVzICkge1xuXHRcdHZhciB1aUhhc2ggPSB7XG5cdFx0XHRoYW5kbGU6IHRoaXMuaGFuZGxlc1sgaW5kZXggXSxcblx0XHRcdGhhbmRsZUluZGV4OiBpbmRleCxcblx0XHRcdHZhbHVlOiB2YWx1ZSAhPT0gdW5kZWZpbmVkID8gdmFsdWUgOiB0aGlzLnZhbHVlKClcblx0XHR9O1xuXG5cdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0dWlIYXNoLnZhbHVlID0gdmFsdWUgIT09IHVuZGVmaW5lZCA/IHZhbHVlIDogdGhpcy52YWx1ZXMoIGluZGV4ICk7XG5cdFx0XHR1aUhhc2gudmFsdWVzID0gdmFsdWVzIHx8IHRoaXMudmFsdWVzKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHVpSGFzaDtcblx0fSxcblxuXHRfaGFzTXVsdGlwbGVWYWx1ZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMudmFsdWVzICYmIHRoaXMub3B0aW9ucy52YWx1ZXMubGVuZ3RoO1xuXHR9LFxuXG5cdF9zdGFydDogZnVuY3Rpb24oIGV2ZW50LCBpbmRleCApIHtcblx0XHRyZXR1cm4gdGhpcy5fdHJpZ2dlciggXCJzdGFydFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCBpbmRleCApICk7XG5cdH0sXG5cblx0X3NsaWRlOiBmdW5jdGlvbiggZXZlbnQsIGluZGV4LCBuZXdWYWwgKSB7XG5cdFx0dmFyIGFsbG93ZWQsIG90aGVyVmFsLFxuXHRcdFx0Y3VycmVudFZhbHVlID0gdGhpcy52YWx1ZSgpLFxuXHRcdFx0bmV3VmFsdWVzID0gdGhpcy52YWx1ZXMoKTtcblxuXHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdG90aGVyVmFsID0gdGhpcy52YWx1ZXMoIGluZGV4ID8gMCA6IDEgKTtcblx0XHRcdGN1cnJlbnRWYWx1ZSA9IHRoaXMudmFsdWVzKCBpbmRleCApO1xuXG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy52YWx1ZXMubGVuZ3RoID09PSAyICYmIHRoaXMub3B0aW9ucy5yYW5nZSA9PT0gdHJ1ZSApIHtcblx0XHRcdFx0bmV3VmFsID0gIGluZGV4ID09PSAwID8gTWF0aC5taW4oIG90aGVyVmFsLCBuZXdWYWwgKSA6IE1hdGgubWF4KCBvdGhlclZhbCwgbmV3VmFsICk7XG5cdFx0XHR9XG5cblx0XHRcdG5ld1ZhbHVlc1sgaW5kZXggXSA9IG5ld1ZhbDtcblx0XHR9XG5cblx0XHRpZiAoIG5ld1ZhbCA9PT0gY3VycmVudFZhbHVlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGFsbG93ZWQgPSB0aGlzLl90cmlnZ2VyKCBcInNsaWRlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIGluZGV4LCBuZXdWYWwsIG5ld1ZhbHVlcyApICk7XG5cblx0XHQvLyBBIHNsaWRlIGNhbiBiZSBjYW5jZWxlZCBieSByZXR1cm5pbmcgZmFsc2UgZnJvbSB0aGUgc2xpZGUgY2FsbGJhY2tcblx0XHRpZiAoIGFsbG93ZWQgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdHRoaXMudmFsdWVzKCBpbmRleCwgbmV3VmFsICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMudmFsdWUoIG5ld1ZhbCApO1xuXHRcdH1cblx0fSxcblxuXHRfc3RvcDogZnVuY3Rpb24oIGV2ZW50LCBpbmRleCApIHtcblx0XHR0aGlzLl90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggaW5kZXggKSApO1xuXHR9LFxuXG5cdF9jaGFuZ2U6IGZ1bmN0aW9uKCBldmVudCwgaW5kZXggKSB7XG5cdFx0aWYgKCAhdGhpcy5fa2V5U2xpZGluZyAmJiAhdGhpcy5fbW91c2VTbGlkaW5nICkge1xuXG5cdFx0XHQvL3N0b3JlIHRoZSBsYXN0IGNoYW5nZWQgdmFsdWUgaW5kZXggZm9yIHJlZmVyZW5jZSB3aGVuIGhhbmRsZXMgb3ZlcmxhcFxuXHRcdFx0dGhpcy5fbGFzdENoYW5nZWRWYWx1ZSA9IGluZGV4O1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggaW5kZXggKSApO1xuXHRcdH1cblx0fSxcblxuXHR2YWx1ZTogZnVuY3Rpb24oIG5ld1ZhbHVlICkge1xuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCBuZXdWYWx1ZSApO1xuXHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHR0aGlzLl9jaGFuZ2UoIG51bGwsIDAgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5fdmFsdWUoKTtcblx0fSxcblxuXHR2YWx1ZXM6IGZ1bmN0aW9uKCBpbmRleCwgbmV3VmFsdWUgKSB7XG5cdFx0dmFyIHZhbHMsXG5cdFx0XHRuZXdWYWx1ZXMsXG5cdFx0XHRpO1xuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcblx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZXNbIGluZGV4IF0gPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggbmV3VmFsdWUgKTtcblx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0dGhpcy5fY2hhbmdlKCBudWxsLCBpbmRleCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdGlmICggJC5pc0FycmF5KCBhcmd1bWVudHNbIDAgXSApICkge1xuXHRcdFx0XHR2YWxzID0gdGhpcy5vcHRpb25zLnZhbHVlcztcblx0XHRcdFx0bmV3VmFsdWVzID0gYXJndW1lbnRzWyAwIF07XG5cdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgdmFscy5sZW5ndGg7IGkgKz0gMSApIHtcblx0XHRcdFx0XHR2YWxzWyBpIF0gPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggbmV3VmFsdWVzWyBpIF0gKTtcblx0XHRcdFx0XHR0aGlzLl9jaGFuZ2UoIG51bGwsIGkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5fdmFsdWVzKCBpbmRleCApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLnZhbHVlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3ZhbHVlcygpO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgaSxcblx0XHRcdHZhbHNMZW5ndGggPSAwO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwicmFuZ2VcIiAmJiB0aGlzLm9wdGlvbnMucmFuZ2UgPT09IHRydWUgKSB7XG5cdFx0XHRpZiAoIHZhbHVlID09PSBcIm1pblwiICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl92YWx1ZXMoIDAgKTtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlcyA9IG51bGw7XG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSA9PT0gXCJtYXhcIiApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fdmFsdWVzKCB0aGlzLm9wdGlvbnMudmFsdWVzLmxlbmd0aCAtIDEgKTtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlcyA9IG51bGw7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCAkLmlzQXJyYXkoIHRoaXMub3B0aW9ucy52YWx1ZXMgKSApIHtcblx0XHRcdHZhbHNMZW5ndGggPSB0aGlzLm9wdGlvbnMudmFsdWVzLmxlbmd0aDtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0c3dpdGNoICgga2V5ICkge1xuXHRcdFx0Y2FzZSBcIm9yaWVudGF0aW9uXCI6XG5cdFx0XHRcdHRoaXMuX2RldGVjdE9yaWVudGF0aW9uKCk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLXNsaWRlci1ob3Jpem9udGFsIHVpLXNsaWRlci12ZXJ0aWNhbFwiIClcblx0XHRcdFx0XHQuX2FkZENsYXNzKCBcInVpLXNsaWRlci1cIiArIHRoaXMub3JpZW50YXRpb24gKTtcblx0XHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHRcdGlmICggdGhpcy5vcHRpb25zLnJhbmdlICkge1xuXHRcdFx0XHRcdHRoaXMuX3JlZnJlc2hSYW5nZSggdmFsdWUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlc2V0IHBvc2l0aW9uaW5nIGZyb20gcHJldmlvdXMgb3JpZW50YXRpb25cblx0XHRcdFx0dGhpcy5oYW5kbGVzLmNzcyggdmFsdWUgPT09IFwiaG9yaXpvbnRhbFwiID8gXCJib3R0b21cIiA6IFwibGVmdFwiLCBcIlwiICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcInZhbHVlXCI6XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdFx0dGhpcy5fY2hhbmdlKCBudWxsLCAwICk7XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwidmFsdWVzXCI6XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblxuXHRcdFx0XHQvLyBTdGFydCBmcm9tIHRoZSBsYXN0IGhhbmRsZSB0byBwcmV2ZW50IHVucmVhY2hhYmxlIGhhbmRsZXMgKCM5MDQ2KVxuXHRcdFx0XHRmb3IgKCBpID0gdmFsc0xlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHRcdHRoaXMuX2NoYW5nZSggbnVsbCwgaSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwic3RlcFwiOlxuXHRcdFx0Y2FzZSBcIm1pblwiOlxuXHRcdFx0Y2FzZSBcIm1heFwiOlxuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fY2FsY3VsYXRlTmV3TWF4KCk7XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcInJhbmdlXCI6XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHR9LFxuXG5cdC8vaW50ZXJuYWwgdmFsdWUgZ2V0dGVyXG5cdC8vIF92YWx1ZSgpIHJldHVybnMgdmFsdWUgdHJpbW1lZCBieSBtaW4gYW5kIG1heCwgYWxpZ25lZCBieSBzdGVwXG5cdF92YWx1ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHZhbCA9IHRoaXMub3B0aW9ucy52YWx1ZTtcblx0XHR2YWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggdmFsICk7XG5cblx0XHRyZXR1cm4gdmFsO1xuXHR9LFxuXG5cdC8vaW50ZXJuYWwgdmFsdWVzIGdldHRlclxuXHQvLyBfdmFsdWVzKCkgcmV0dXJucyBhcnJheSBvZiB2YWx1ZXMgdHJpbW1lZCBieSBtaW4gYW5kIG1heCwgYWxpZ25lZCBieSBzdGVwXG5cdC8vIF92YWx1ZXMoIGluZGV4ICkgcmV0dXJucyBzaW5nbGUgdmFsdWUgdHJpbW1lZCBieSBtaW4gYW5kIG1heCwgYWxpZ25lZCBieSBzdGVwXG5cdF92YWx1ZXM6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHR2YXIgdmFsLFxuXHRcdFx0dmFscyxcblx0XHRcdGk7XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHR2YWwgPSB0aGlzLm9wdGlvbnMudmFsdWVzWyBpbmRleCBdO1xuXHRcdFx0dmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIHZhbCApO1xuXG5cdFx0XHRyZXR1cm4gdmFsO1xuXHRcdH0gZWxzZSBpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cblx0XHRcdC8vIC5zbGljZSgpIGNyZWF0ZXMgYSBjb3B5IG9mIHRoZSBhcnJheVxuXHRcdFx0Ly8gdGhpcyBjb3B5IGdldHMgdHJpbW1lZCBieSBtaW4gYW5kIG1heCBhbmQgdGhlbiByZXR1cm5lZFxuXHRcdFx0dmFscyA9IHRoaXMub3B0aW9ucy52YWx1ZXMuc2xpY2UoKTtcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgdmFscy5sZW5ndGg7IGkgKz0gMSApIHtcblx0XHRcdFx0dmFsc1sgaSBdID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIHZhbHNbIGkgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdmFscztcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIFtdO1xuXHRcdH1cblx0fSxcblxuXHQvLyBSZXR1cm5zIHRoZSBzdGVwLWFsaWduZWQgdmFsdWUgdGhhdCB2YWwgaXMgY2xvc2VzdCB0bywgYmV0d2VlbiAoaW5jbHVzaXZlKSBtaW4gYW5kIG1heFxuXHRfdHJpbUFsaWduVmFsdWU6IGZ1bmN0aW9uKCB2YWwgKSB7XG5cdFx0aWYgKCB2YWwgPD0gdGhpcy5fdmFsdWVNaW4oKSApIHtcblx0XHRcdHJldHVybiB0aGlzLl92YWx1ZU1pbigpO1xuXHRcdH1cblx0XHRpZiAoIHZhbCA+PSB0aGlzLl92YWx1ZU1heCgpICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3ZhbHVlTWF4KCk7XG5cdFx0fVxuXHRcdHZhciBzdGVwID0gKCB0aGlzLm9wdGlvbnMuc3RlcCA+IDAgKSA/IHRoaXMub3B0aW9ucy5zdGVwIDogMSxcblx0XHRcdHZhbE1vZFN0ZXAgPSAoIHZhbCAtIHRoaXMuX3ZhbHVlTWluKCkgKSAlIHN0ZXAsXG5cdFx0XHRhbGlnblZhbHVlID0gdmFsIC0gdmFsTW9kU3RlcDtcblxuXHRcdGlmICggTWF0aC5hYnMoIHZhbE1vZFN0ZXAgKSAqIDIgPj0gc3RlcCApIHtcblx0XHRcdGFsaWduVmFsdWUgKz0gKCB2YWxNb2RTdGVwID4gMCApID8gc3RlcCA6ICggLXN0ZXAgKTtcblx0XHR9XG5cblx0XHQvLyBTaW5jZSBKYXZhU2NyaXB0IGhhcyBwcm9ibGVtcyB3aXRoIGxhcmdlIGZsb2F0cywgcm91bmRcblx0XHQvLyB0aGUgZmluYWwgdmFsdWUgdG8gNSBkaWdpdHMgYWZ0ZXIgdGhlIGRlY2ltYWwgcG9pbnQgKHNlZSAjNDEyNClcblx0XHRyZXR1cm4gcGFyc2VGbG9hdCggYWxpZ25WYWx1ZS50b0ZpeGVkKCA1ICkgKTtcblx0fSxcblxuXHRfY2FsY3VsYXRlTmV3TWF4OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbWF4ID0gdGhpcy5vcHRpb25zLm1heCxcblx0XHRcdG1pbiA9IHRoaXMuX3ZhbHVlTWluKCksXG5cdFx0XHRzdGVwID0gdGhpcy5vcHRpb25zLnN0ZXAsXG5cdFx0XHRhYm92ZU1pbiA9IE1hdGgucm91bmQoICggbWF4IC0gbWluICkgLyBzdGVwICkgKiBzdGVwO1xuXHRcdG1heCA9IGFib3ZlTWluICsgbWluO1xuXHRcdGlmICggbWF4ID4gdGhpcy5vcHRpb25zLm1heCApIHtcblxuXHRcdFx0Ly9JZiBtYXggaXMgbm90IGRpdmlzaWJsZSBieSBzdGVwLCByb3VuZGluZyBvZmYgbWF5IGluY3JlYXNlIGl0cyB2YWx1ZVxuXHRcdFx0bWF4IC09IHN0ZXA7XG5cdFx0fVxuXHRcdHRoaXMubWF4ID0gcGFyc2VGbG9hdCggbWF4LnRvRml4ZWQoIHRoaXMuX3ByZWNpc2lvbigpICkgKTtcblx0fSxcblxuXHRfcHJlY2lzaW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJlY2lzaW9uID0gdGhpcy5fcHJlY2lzaW9uT2YoIHRoaXMub3B0aW9ucy5zdGVwICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMubWluICE9PSBudWxsICkge1xuXHRcdFx0cHJlY2lzaW9uID0gTWF0aC5tYXgoIHByZWNpc2lvbiwgdGhpcy5fcHJlY2lzaW9uT2YoIHRoaXMub3B0aW9ucy5taW4gKSApO1xuXHRcdH1cblx0XHRyZXR1cm4gcHJlY2lzaW9uO1xuXHR9LFxuXG5cdF9wcmVjaXNpb25PZjogZnVuY3Rpb24oIG51bSApIHtcblx0XHR2YXIgc3RyID0gbnVtLnRvU3RyaW5nKCksXG5cdFx0XHRkZWNpbWFsID0gc3RyLmluZGV4T2YoIFwiLlwiICk7XG5cdFx0cmV0dXJuIGRlY2ltYWwgPT09IC0xID8gMCA6IHN0ci5sZW5ndGggLSBkZWNpbWFsIC0gMTtcblx0fSxcblxuXHRfdmFsdWVNaW46IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMubWluO1xuXHR9LFxuXG5cdF92YWx1ZU1heDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubWF4O1xuXHR9LFxuXG5cdF9yZWZyZXNoUmFuZ2U6IGZ1bmN0aW9uKCBvcmllbnRhdGlvbiApIHtcblx0XHRpZiAoIG9yaWVudGF0aW9uID09PSBcInZlcnRpY2FsXCIgKSB7XG5cdFx0XHR0aGlzLnJhbmdlLmNzcyggeyBcIndpZHRoXCI6IFwiXCIsIFwibGVmdFwiOiBcIlwiIH0gKTtcblx0XHR9XG5cdFx0aWYgKCBvcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHR0aGlzLnJhbmdlLmNzcyggeyBcImhlaWdodFwiOiBcIlwiLCBcImJvdHRvbVwiOiBcIlwiIH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X3JlZnJlc2hWYWx1ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGxhc3RWYWxQZXJjZW50LCB2YWxQZXJjZW50LCB2YWx1ZSwgdmFsdWVNaW4sIHZhbHVlTWF4LFxuXHRcdFx0b1JhbmdlID0gdGhpcy5vcHRpb25zLnJhbmdlLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0YW5pbWF0ZSA9ICggIXRoaXMuX2FuaW1hdGVPZmYgKSA/IG8uYW5pbWF0ZSA6IGZhbHNlLFxuXHRcdFx0X3NldCA9IHt9O1xuXG5cdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0dGhpcy5oYW5kbGVzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHR2YWxQZXJjZW50ID0gKCB0aGF0LnZhbHVlcyggaSApIC0gdGhhdC5fdmFsdWVNaW4oKSApIC8gKCB0aGF0Ll92YWx1ZU1heCgpIC1cblx0XHRcdFx0XHR0aGF0Ll92YWx1ZU1pbigpICkgKiAxMDA7XG5cdFx0XHRcdF9zZXRbIHRoYXQub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiID8gXCJsZWZ0XCIgOiBcImJvdHRvbVwiIF0gPSB2YWxQZXJjZW50ICsgXCIlXCI7XG5cdFx0XHRcdCQoIHRoaXMgKS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSggX3NldCwgby5hbmltYXRlICk7XG5cdFx0XHRcdGlmICggdGhhdC5vcHRpb25zLnJhbmdlID09PSB0cnVlICkge1xuXHRcdFx0XHRcdGlmICggdGhhdC5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRcdFx0XHRsZWZ0OiB2YWxQZXJjZW50ICsgXCIlXCJcblx0XHRcdFx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDEgKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQucmFuZ2VbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdFx0XHRcdHdpZHRoOiAoIHZhbFBlcmNlbnQgLSBsYXN0VmFsUGVyY2VudCApICsgXCIlXCJcblx0XHRcdFx0XHRcdFx0fSwge1xuXHRcdFx0XHRcdFx0XHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0XHRkdXJhdGlvbjogby5hbmltYXRlXG5cdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0LnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0XHRcdFx0Ym90dG9tOiAoIHZhbFBlcmNlbnQgKSArIFwiJVwiXG5cdFx0XHRcdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKCBpID09PSAxICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0LnJhbmdlWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRcdFx0XHRoZWlnaHQ6ICggdmFsUGVyY2VudCAtIGxhc3RWYWxQZXJjZW50ICkgKyBcIiVcIlxuXHRcdFx0XHRcdFx0XHR9LCB7XG5cdFx0XHRcdFx0XHRcdFx0cXVldWU6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcdGR1cmF0aW9uOiBvLmFuaW1hdGVcblx0XHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRsYXN0VmFsUGVyY2VudCA9IHZhbFBlcmNlbnQ7XG5cdFx0XHR9ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHZhbHVlID0gdGhpcy52YWx1ZSgpO1xuXHRcdFx0dmFsdWVNaW4gPSB0aGlzLl92YWx1ZU1pbigpO1xuXHRcdFx0dmFsdWVNYXggPSB0aGlzLl92YWx1ZU1heCgpO1xuXHRcdFx0dmFsUGVyY2VudCA9ICggdmFsdWVNYXggIT09IHZhbHVlTWluICkgP1xuXHRcdFx0XHRcdCggdmFsdWUgLSB2YWx1ZU1pbiApIC8gKCB2YWx1ZU1heCAtIHZhbHVlTWluICkgKiAxMDAgOlxuXHRcdFx0XHRcdDA7XG5cdFx0XHRfc2V0WyB0aGlzLm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiA/IFwibGVmdFwiIDogXCJib3R0b21cIiBdID0gdmFsUGVyY2VudCArIFwiJVwiO1xuXHRcdFx0dGhpcy5oYW5kbGUuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIF9zZXQsIG8uYW5pbWF0ZSApO1xuXG5cdFx0XHRpZiAoIG9SYW5nZSA9PT0gXCJtaW5cIiAmJiB0aGlzLm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdFx0dGhpcy5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdHdpZHRoOiB2YWxQZXJjZW50ICsgXCIlXCJcblx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9SYW5nZSA9PT0gXCJtYXhcIiAmJiB0aGlzLm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdFx0dGhpcy5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdHdpZHRoOiAoIDEwMCAtIHZhbFBlcmNlbnQgKSArIFwiJVwiXG5cdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvUmFuZ2UgPT09IFwibWluXCIgJiYgdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0aGVpZ2h0OiB2YWxQZXJjZW50ICsgXCIlXCJcblx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9SYW5nZSA9PT0gXCJtYXhcIiAmJiB0aGlzLm9yaWVudGF0aW9uID09PSBcInZlcnRpY2FsXCIgKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRoZWlnaHQ6ICggMTAwIC0gdmFsUGVyY2VudCApICsgXCIlXCJcblx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9oYW5kbGVFdmVudHM6IHtcblx0XHRrZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgYWxsb3dlZCwgY3VyVmFsLCBuZXdWYWwsIHN0ZXAsXG5cdFx0XHRcdGluZGV4ID0gJCggZXZlbnQudGFyZ2V0ICkuZGF0YSggXCJ1aS1zbGlkZXItaGFuZGxlLWluZGV4XCIgKTtcblxuXHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuSE9NRTpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5EOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlVQOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5SSUdIVDpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRE9XTjpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuTEVGVDpcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdGlmICggIXRoaXMuX2tleVNsaWRpbmcgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLl9rZXlTbGlkaW5nID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHRoaXMuX2FkZENsYXNzKCAkKCBldmVudC50YXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0XHRcdFx0YWxsb3dlZCA9IHRoaXMuX3N0YXJ0KCBldmVudCwgaW5kZXggKTtcblx0XHRcdFx0XHRcdGlmICggYWxsb3dlZCA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdHN0ZXAgPSB0aGlzLm9wdGlvbnMuc3RlcDtcblx0XHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdFx0Y3VyVmFsID0gbmV3VmFsID0gdGhpcy52YWx1ZXMoIGluZGV4ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjdXJWYWwgPSBuZXdWYWwgPSB0aGlzLnZhbHVlKCk7XG5cdFx0XHR9XG5cblx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkhPTUU6XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdmFsdWVNaW4oKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5EOlxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3ZhbHVlTWF4KCk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoXG5cdFx0XHRcdFx0XHRjdXJWYWwgKyAoICggdGhpcy5fdmFsdWVNYXgoKSAtIHRoaXMuX3ZhbHVlTWluKCkgKSAvIHRoaXMubnVtUGFnZXMgKVxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZShcblx0XHRcdFx0XHRcdGN1clZhbCAtICggKCB0aGlzLl92YWx1ZU1heCgpIC0gdGhpcy5fdmFsdWVNaW4oKSApIC8gdGhpcy5udW1QYWdlcyApICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlVQOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5SSUdIVDpcblx0XHRcdFx0XHRpZiAoIGN1clZhbCA9PT0gdGhpcy5fdmFsdWVNYXgoKSApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIGN1clZhbCArIHN0ZXAgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRE9XTjpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuTEVGVDpcblx0XHRcdFx0XHRpZiAoIGN1clZhbCA9PT0gdGhpcy5fdmFsdWVNaW4oKSApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIGN1clZhbCAtIHN0ZXAgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fc2xpZGUoIGV2ZW50LCBpbmRleCwgbmV3VmFsICk7XG5cdFx0fSxcblx0XHRrZXl1cDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0dmFyIGluZGV4ID0gJCggZXZlbnQudGFyZ2V0ICkuZGF0YSggXCJ1aS1zbGlkZXItaGFuZGxlLWluZGV4XCIgKTtcblxuXHRcdFx0aWYgKCB0aGlzLl9rZXlTbGlkaW5nICkge1xuXHRcdFx0XHR0aGlzLl9rZXlTbGlkaW5nID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuX3N0b3AoIGV2ZW50LCBpbmRleCApO1xuXHRcdFx0XHR0aGlzLl9jaGFuZ2UoIGV2ZW50LCBpbmRleCApO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggJCggZXZlbnQudGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTb3J0YWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU29ydGFibGVcbi8vPj5ncm91cDogSW50ZXJhY3Rpb25zXG4vLz4+ZGVzY3JpcHRpb246IEVuYWJsZXMgaXRlbXMgaW4gYSBsaXN0IHRvIGJlIHNvcnRlZCB1c2luZyB0aGUgbW91c2UuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc29ydGFibGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vc29ydGFibGUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2Uvc29ydGFibGUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c1NvcnRhYmxlID0gJC53aWRnZXQoIFwidWkuc29ydGFibGVcIiwgJC51aS5tb3VzZSwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJzb3J0XCIsXG5cdHJlYWR5OiBmYWxzZSxcblx0b3B0aW9uczoge1xuXHRcdGFwcGVuZFRvOiBcInBhcmVudFwiLFxuXHRcdGF4aXM6IGZhbHNlLFxuXHRcdGNvbm5lY3RXaXRoOiBmYWxzZSxcblx0XHRjb250YWlubWVudDogZmFsc2UsXG5cdFx0Y3Vyc29yOiBcImF1dG9cIixcblx0XHRjdXJzb3JBdDogZmFsc2UsXG5cdFx0ZHJvcE9uRW1wdHk6IHRydWUsXG5cdFx0Zm9yY2VQbGFjZWhvbGRlclNpemU6IGZhbHNlLFxuXHRcdGZvcmNlSGVscGVyU2l6ZTogZmFsc2UsXG5cdFx0Z3JpZDogZmFsc2UsXG5cdFx0aGFuZGxlOiBmYWxzZSxcblx0XHRoZWxwZXI6IFwib3JpZ2luYWxcIixcblx0XHRpdGVtczogXCI+ICpcIixcblx0XHRvcGFjaXR5OiBmYWxzZSxcblx0XHRwbGFjZWhvbGRlcjogZmFsc2UsXG5cdFx0cmV2ZXJ0OiBmYWxzZSxcblx0XHRzY3JvbGw6IHRydWUsXG5cdFx0c2Nyb2xsU2Vuc2l0aXZpdHk6IDIwLFxuXHRcdHNjcm9sbFNwZWVkOiAyMCxcblx0XHRzY29wZTogXCJkZWZhdWx0XCIsXG5cdFx0dG9sZXJhbmNlOiBcImludGVyc2VjdFwiLFxuXHRcdHpJbmRleDogMTAwMCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGFjdGl2YXRlOiBudWxsLFxuXHRcdGJlZm9yZVN0b3A6IG51bGwsXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdGRlYWN0aXZhdGU6IG51bGwsXG5cdFx0b3V0OiBudWxsLFxuXHRcdG92ZXI6IG51bGwsXG5cdFx0cmVjZWl2ZTogbnVsbCxcblx0XHRyZW1vdmU6IG51bGwsXG5cdFx0c29ydDogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsLFxuXHRcdHVwZGF0ZTogbnVsbFxuXHR9LFxuXG5cdF9pc092ZXJBeGlzOiBmdW5jdGlvbiggeCwgcmVmZXJlbmNlLCBzaXplICkge1xuXHRcdHJldHVybiAoIHggPj0gcmVmZXJlbmNlICkgJiYgKCB4IDwgKCByZWZlcmVuY2UgKyBzaXplICkgKTtcblx0fSxcblxuXHRfaXNGbG9hdGluZzogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0cmV0dXJuICggL2xlZnR8cmlnaHQvICkudGVzdCggaXRlbS5jc3MoIFwiZmxvYXRcIiApICkgfHxcblx0XHRcdCggL2lubGluZXx0YWJsZS1jZWxsLyApLnRlc3QoIGl0ZW0uY3NzKCBcImRpc3BsYXlcIiApICk7XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5jb250YWluZXJDYWNoZSA9IHt9O1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXNvcnRhYmxlXCIgKTtcblxuXHRcdC8vR2V0IHRoZSBpdGVtc1xuXHRcdHRoaXMucmVmcmVzaCgpO1xuXG5cdFx0Ly9MZXQncyBkZXRlcm1pbmUgdGhlIHBhcmVudCdzIG9mZnNldFxuXHRcdHRoaXMub2Zmc2V0ID0gdGhpcy5lbGVtZW50Lm9mZnNldCgpO1xuXG5cdFx0Ly9Jbml0aWFsaXplIG1vdXNlIGV2ZW50cyBmb3IgaW50ZXJhY3Rpb25cblx0XHR0aGlzLl9tb3VzZUluaXQoKTtcblxuXHRcdHRoaXMuX3NldEhhbmRsZUNsYXNzTmFtZSgpO1xuXG5cdFx0Ly9XZSdyZSByZWFkeSB0byBnb1xuXHRcdHRoaXMucmVhZHkgPSB0cnVlO1xuXG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImhhbmRsZVwiICkge1xuXHRcdFx0dGhpcy5fc2V0SGFuZGxlQ2xhc3NOYW1lKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRIYW5kbGVDbGFzc05hbWU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLXNvcnRhYmxlLWhhbmRsZVwiICksIFwidWktc29ydGFibGUtaGFuZGxlXCIgKTtcblx0XHQkLmVhY2goIHRoaXMuaXRlbXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhhdC5fYWRkQ2xhc3MoXG5cdFx0XHRcdHRoaXMuaW5zdGFuY2Uub3B0aW9ucy5oYW5kbGUgP1xuXHRcdFx0XHRcdHRoaXMuaXRlbS5maW5kKCB0aGlzLmluc3RhbmNlLm9wdGlvbnMuaGFuZGxlICkgOlxuXHRcdFx0XHRcdHRoaXMuaXRlbSxcblx0XHRcdFx0XCJ1aS1zb3J0YWJsZS1oYW5kbGVcIlxuXHRcdFx0KTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX21vdXNlRGVzdHJveSgpO1xuXG5cdFx0Zm9yICggdmFyIGkgPSB0aGlzLml0ZW1zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0dGhpcy5pdGVtc1sgaSBdLml0ZW0ucmVtb3ZlRGF0YSggdGhpcy53aWRnZXROYW1lICsgXCItaXRlbVwiICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X21vdXNlQ2FwdHVyZTogZnVuY3Rpb24oIGV2ZW50LCBvdmVycmlkZUhhbmRsZSApIHtcblx0XHR2YXIgY3VycmVudEl0ZW0gPSBudWxsLFxuXHRcdFx0dmFsaWRIYW5kbGUgPSBmYWxzZSxcblx0XHRcdHRoYXQgPSB0aGlzO1xuXG5cdFx0aWYgKCB0aGlzLnJldmVydGluZyApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCB8fCB0aGlzLm9wdGlvbnMudHlwZSA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvL1dlIGhhdmUgdG8gcmVmcmVzaCB0aGUgaXRlbXMgZGF0YSBvbmNlIGZpcnN0XG5cdFx0dGhpcy5fcmVmcmVzaEl0ZW1zKCBldmVudCApO1xuXG5cdFx0Ly9GaW5kIG91dCBpZiB0aGUgY2xpY2tlZCBub2RlIChvciBvbmUgb2YgaXRzIHBhcmVudHMpIGlzIGEgYWN0dWFsIGl0ZW0gaW4gdGhpcy5pdGVtc1xuXHRcdCQoIGV2ZW50LnRhcmdldCApLnBhcmVudHMoKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggJC5kYXRhKCB0aGlzLCB0aGF0LndpZGdldE5hbWUgKyBcIi1pdGVtXCIgKSA9PT0gdGhhdCApIHtcblx0XHRcdFx0Y3VycmVudEl0ZW0gPSAkKCB0aGlzICk7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0aWYgKCAkLmRhdGEoIGV2ZW50LnRhcmdldCwgdGhhdC53aWRnZXROYW1lICsgXCItaXRlbVwiICkgPT09IHRoYXQgKSB7XG5cdFx0XHRjdXJyZW50SXRlbSA9ICQoIGV2ZW50LnRhcmdldCApO1xuXHRcdH1cblxuXHRcdGlmICggIWN1cnJlbnRJdGVtICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oYW5kbGUgJiYgIW92ZXJyaWRlSGFuZGxlICkge1xuXHRcdFx0JCggdGhpcy5vcHRpb25zLmhhbmRsZSwgY3VycmVudEl0ZW0gKS5maW5kKCBcIipcIiApLmFkZEJhY2soKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCB0aGlzID09PSBldmVudC50YXJnZXQgKSB7XG5cdFx0XHRcdFx0dmFsaWRIYW5kbGUgPSB0cnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0XHRpZiAoICF2YWxpZEhhbmRsZSApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuY3VycmVudEl0ZW0gPSBjdXJyZW50SXRlbTtcblx0XHR0aGlzLl9yZW1vdmVDdXJyZW50c0Zyb21JdGVtcygpO1xuXHRcdHJldHVybiB0cnVlO1xuXG5cdH0sXG5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgb3ZlcnJpZGVIYW5kbGUsIG5vQWN0aXZhdGlvbiApIHtcblxuXHRcdHZhciBpLCBib2R5LFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucztcblxuXHRcdHRoaXMuY3VycmVudENvbnRhaW5lciA9IHRoaXM7XG5cblx0XHQvL1dlIG9ubHkgbmVlZCB0byBjYWxsIHJlZnJlc2hQb3NpdGlvbnMsIGJlY2F1c2UgdGhlIHJlZnJlc2hJdGVtcyBjYWxsIGhhcyBiZWVuIG1vdmVkIHRvXG5cdFx0Ly8gbW91c2VDYXB0dXJlXG5cdFx0dGhpcy5yZWZyZXNoUG9zaXRpb25zKCk7XG5cblx0XHQvL0NyZWF0ZSBhbmQgYXBwZW5kIHRoZSB2aXNpYmxlIGhlbHBlclxuXHRcdHRoaXMuaGVscGVyID0gdGhpcy5fY3JlYXRlSGVscGVyKCBldmVudCApO1xuXG5cdFx0Ly9DYWNoZSB0aGUgaGVscGVyIHNpemVcblx0XHR0aGlzLl9jYWNoZUhlbHBlclByb3BvcnRpb25zKCk7XG5cblx0XHQvKlxuXHRcdCAqIC0gUG9zaXRpb24gZ2VuZXJhdGlvbiAtXG5cdFx0ICogVGhpcyBibG9jayBnZW5lcmF0ZXMgZXZlcnl0aGluZyBwb3NpdGlvbiByZWxhdGVkIC0gaXQncyB0aGUgY29yZSBvZiBkcmFnZ2FibGVzLlxuXHRcdCAqL1xuXG5cdFx0Ly9DYWNoZSB0aGUgbWFyZ2lucyBvZiB0aGUgb3JpZ2luYWwgZWxlbWVudFxuXHRcdHRoaXMuX2NhY2hlTWFyZ2lucygpO1xuXG5cdFx0Ly9HZXQgdGhlIG5leHQgc2Nyb2xsaW5nIHBhcmVudFxuXHRcdHRoaXMuc2Nyb2xsUGFyZW50ID0gdGhpcy5oZWxwZXIuc2Nyb2xsUGFyZW50KCk7XG5cblx0XHQvL1RoZSBlbGVtZW50J3MgYWJzb2x1dGUgcG9zaXRpb24gb24gdGhlIHBhZ2UgbWludXMgbWFyZ2luc1xuXHRcdHRoaXMub2Zmc2V0ID0gdGhpcy5jdXJyZW50SXRlbS5vZmZzZXQoKTtcblx0XHR0aGlzLm9mZnNldCA9IHtcblx0XHRcdHRvcDogdGhpcy5vZmZzZXQudG9wIC0gdGhpcy5tYXJnaW5zLnRvcCxcblx0XHRcdGxlZnQ6IHRoaXMub2Zmc2V0LmxlZnQgLSB0aGlzLm1hcmdpbnMubGVmdFxuXHRcdH07XG5cblx0XHQkLmV4dGVuZCggdGhpcy5vZmZzZXQsIHtcblx0XHRcdGNsaWNrOiB7IC8vV2hlcmUgdGhlIGNsaWNrIGhhcHBlbmVkLCByZWxhdGl2ZSB0byB0aGUgZWxlbWVudFxuXHRcdFx0XHRsZWZ0OiBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmxlZnQsXG5cdFx0XHRcdHRvcDogZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC50b3Bcblx0XHRcdH0sXG5cdFx0XHRwYXJlbnQ6IHRoaXMuX2dldFBhcmVudE9mZnNldCgpLFxuXG5cdFx0XHQvLyBUaGlzIGlzIGEgcmVsYXRpdmUgdG8gYWJzb2x1dGUgcG9zaXRpb24gbWludXMgdGhlIGFjdHVhbCBwb3NpdGlvbiBjYWxjdWxhdGlvbiAtXG5cdFx0XHQvLyBvbmx5IHVzZWQgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgaGVscGVyXG5cdFx0XHRyZWxhdGl2ZTogdGhpcy5fZ2V0UmVsYXRpdmVPZmZzZXQoKVxuXHRcdH0gKTtcblxuXHRcdC8vIE9ubHkgYWZ0ZXIgd2UgZ290IHRoZSBvZmZzZXQsIHdlIGNhbiBjaGFuZ2UgdGhlIGhlbHBlcidzIHBvc2l0aW9uIHRvIGFic29sdXRlXG5cdFx0Ly8gVE9ETzogU3RpbGwgbmVlZCB0byBmaWd1cmUgb3V0IGEgd2F5IHRvIG1ha2UgcmVsYXRpdmUgc29ydGluZyBwb3NzaWJsZVxuXHRcdHRoaXMuaGVscGVyLmNzcyggXCJwb3NpdGlvblwiLCBcImFic29sdXRlXCIgKTtcblx0XHR0aGlzLmNzc1Bvc2l0aW9uID0gdGhpcy5oZWxwZXIuY3NzKCBcInBvc2l0aW9uXCIgKTtcblxuXHRcdC8vR2VuZXJhdGUgdGhlIG9yaWdpbmFsIHBvc2l0aW9uXG5cdFx0dGhpcy5vcmlnaW5hbFBvc2l0aW9uID0gdGhpcy5fZ2VuZXJhdGVQb3NpdGlvbiggZXZlbnQgKTtcblx0XHR0aGlzLm9yaWdpbmFsUGFnZVggPSBldmVudC5wYWdlWDtcblx0XHR0aGlzLm9yaWdpbmFsUGFnZVkgPSBldmVudC5wYWdlWTtcblxuXHRcdC8vQWRqdXN0IHRoZSBtb3VzZSBvZmZzZXQgcmVsYXRpdmUgdG8gdGhlIGhlbHBlciBpZiBcImN1cnNvckF0XCIgaXMgc3VwcGxpZWRcblx0XHQoIG8uY3Vyc29yQXQgJiYgdGhpcy5fYWRqdXN0T2Zmc2V0RnJvbUhlbHBlciggby5jdXJzb3JBdCApICk7XG5cblx0XHQvL0NhY2hlIHRoZSBmb3JtZXIgRE9NIHBvc2l0aW9uXG5cdFx0dGhpcy5kb21Qb3NpdGlvbiA9IHtcblx0XHRcdHByZXY6IHRoaXMuY3VycmVudEl0ZW0ucHJldigpWyAwIF0sXG5cdFx0XHRwYXJlbnQ6IHRoaXMuY3VycmVudEl0ZW0ucGFyZW50KClbIDAgXVxuXHRcdH07XG5cblx0XHQvLyBJZiB0aGUgaGVscGVyIGlzIG5vdCB0aGUgb3JpZ2luYWwsIGhpZGUgdGhlIG9yaWdpbmFsIHNvIGl0J3Mgbm90IHBsYXlpbmcgYW55IHJvbGUgZHVyaW5nXG5cdFx0Ly8gdGhlIGRyYWcsIHdvbid0IGNhdXNlIGFueXRoaW5nIGJhZCB0aGlzIHdheVxuXHRcdGlmICggdGhpcy5oZWxwZXJbIDAgXSAhPT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0dGhpcy5jdXJyZW50SXRlbS5oaWRlKCk7XG5cdFx0fVxuXG5cdFx0Ly9DcmVhdGUgdGhlIHBsYWNlaG9sZGVyXG5cdFx0dGhpcy5fY3JlYXRlUGxhY2Vob2xkZXIoKTtcblxuXHRcdC8vU2V0IGEgY29udGFpbm1lbnQgaWYgZ2l2ZW4gaW4gdGhlIG9wdGlvbnNcblx0XHRpZiAoIG8uY29udGFpbm1lbnQgKSB7XG5cdFx0XHR0aGlzLl9zZXRDb250YWlubWVudCgpO1xuXHRcdH1cblxuXHRcdGlmICggby5jdXJzb3IgJiYgby5jdXJzb3IgIT09IFwiYXV0b1wiICkgeyAvLyBjdXJzb3Igb3B0aW9uXG5cdFx0XHRib2R5ID0gdGhpcy5kb2N1bWVudC5maW5kKCBcImJvZHlcIiApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRVxuXHRcdFx0dGhpcy5zdG9yZWRDdXJzb3IgPSBib2R5LmNzcyggXCJjdXJzb3JcIiApO1xuXHRcdFx0Ym9keS5jc3MoIFwiY3Vyc29yXCIsIG8uY3Vyc29yICk7XG5cblx0XHRcdHRoaXMuc3RvcmVkU3R5bGVzaGVldCA9XG5cdFx0XHRcdCQoIFwiPHN0eWxlPip7IGN1cnNvcjogXCIgKyBvLmN1cnNvciArIFwiICFpbXBvcnRhbnQ7IH08L3N0eWxlPlwiICkuYXBwZW5kVG8oIGJvZHkgKTtcblx0XHR9XG5cblx0XHRpZiAoIG8ub3BhY2l0eSApIHsgLy8gb3BhY2l0eSBvcHRpb25cblx0XHRcdGlmICggdGhpcy5oZWxwZXIuY3NzKCBcIm9wYWNpdHlcIiApICkge1xuXHRcdFx0XHR0aGlzLl9zdG9yZWRPcGFjaXR5ID0gdGhpcy5oZWxwZXIuY3NzKCBcIm9wYWNpdHlcIiApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5oZWxwZXIuY3NzKCBcIm9wYWNpdHlcIiwgby5vcGFjaXR5ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvLnpJbmRleCApIHsgLy8gekluZGV4IG9wdGlvblxuXHRcdFx0aWYgKCB0aGlzLmhlbHBlci5jc3MoIFwiekluZGV4XCIgKSApIHtcblx0XHRcdFx0dGhpcy5fc3RvcmVkWkluZGV4ID0gdGhpcy5oZWxwZXIuY3NzKCBcInpJbmRleFwiICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmhlbHBlci5jc3MoIFwiekluZGV4XCIsIG8uekluZGV4ICk7XG5cdFx0fVxuXG5cdFx0Ly9QcmVwYXJlIHNjcm9sbGluZ1xuXHRcdGlmICggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0udGFnTmFtZSAhPT0gXCJIVE1MXCIgKSB7XG5cdFx0XHR0aGlzLm92ZXJmbG93T2Zmc2V0ID0gdGhpcy5zY3JvbGxQYXJlbnQub2Zmc2V0KCk7XG5cdFx0fVxuXG5cdFx0Ly9DYWxsIGNhbGxiYWNrc1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic3RhcnRcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cblx0XHQvL1JlY2FjaGUgdGhlIGhlbHBlciBzaXplXG5cdFx0aWYgKCAhdGhpcy5fcHJlc2VydmVIZWxwZXJQcm9wb3J0aW9ucyApIHtcblx0XHRcdHRoaXMuX2NhY2hlSGVscGVyUHJvcG9ydGlvbnMoKTtcblx0XHR9XG5cblx0XHQvL1Bvc3QgXCJhY3RpdmF0ZVwiIGV2ZW50cyB0byBwb3NzaWJsZSBjb250YWluZXJzXG5cdFx0aWYgKCAhbm9BY3RpdmF0aW9uICkge1xuXHRcdFx0Zm9yICggaSA9IHRoaXMuY29udGFpbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uX3RyaWdnZXIoIFwiYWN0aXZhdGVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly9QcmVwYXJlIHBvc3NpYmxlIGRyb3BwYWJsZXNcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuY3VycmVudCA9IHRoaXM7XG5cdFx0fVxuXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciAmJiAhby5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5kcmFnZ2luZyA9IHRydWU7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oZWxwZXIsIFwidWktc29ydGFibGUtaGVscGVyXCIgKTtcblxuXHRcdC8vIEV4ZWN1dGUgdGhlIGRyYWcgb25jZSAtIHRoaXMgY2F1c2VzIHRoZSBoZWxwZXIgbm90IHRvIGJlIHZpc2libGViZWZvcmUgZ2V0dGluZyBpdHNcblx0XHQvLyBjb3JyZWN0IHBvc2l0aW9uXG5cdFx0dGhpcy5fbW91c2VEcmFnKCBldmVudCApO1xuXHRcdHJldHVybiB0cnVlO1xuXG5cdH0sXG5cblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpLCBpdGVtLCBpdGVtRWxlbWVudCwgaW50ZXJzZWN0aW9uLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHNjcm9sbGVkID0gZmFsc2U7XG5cblx0XHQvL0NvbXB1dGUgdGhlIGhlbHBlcnMgcG9zaXRpb25cblx0XHR0aGlzLnBvc2l0aW9uID0gdGhpcy5fZ2VuZXJhdGVQb3NpdGlvbiggZXZlbnQgKTtcblx0XHR0aGlzLnBvc2l0aW9uQWJzID0gdGhpcy5fY29udmVydFBvc2l0aW9uVG8oIFwiYWJzb2x1dGVcIiApO1xuXG5cdFx0aWYgKCAhdGhpcy5sYXN0UG9zaXRpb25BYnMgKSB7XG5cdFx0XHR0aGlzLmxhc3RQb3NpdGlvbkFicyA9IHRoaXMucG9zaXRpb25BYnM7XG5cdFx0fVxuXG5cdFx0Ly9EbyBzY3JvbGxpbmdcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5zY3JvbGwgKSB7XG5cdFx0XHRpZiAoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0udGFnTmFtZSAhPT0gXCJIVE1MXCIgKSB7XG5cblx0XHRcdFx0aWYgKCAoIHRoaXMub3ZlcmZsb3dPZmZzZXQudG9wICsgdGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5vZmZzZXRIZWlnaHQgKSAtXG5cdFx0XHRcdFx0XHRldmVudC5wYWdlWSA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxUb3AgPVxuXHRcdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbFRvcCArIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5vdmVyZmxvd09mZnNldC50b3AgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsVG9wID1cblx0XHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxUb3AgLSBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAoIHRoaXMub3ZlcmZsb3dPZmZzZXQubGVmdCArIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0ub2Zmc2V0V2lkdGggKSAtXG5cdFx0XHRcdFx0XHRldmVudC5wYWdlWCA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxMZWZ0ID0gc2Nyb2xsZWQgPVxuXHRcdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxMZWZ0ICsgby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fSBlbHNlIGlmICggZXZlbnQucGFnZVggLSB0aGlzLm92ZXJmbG93T2Zmc2V0LmxlZnQgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsTGVmdCA9IHNjcm9sbGVkID1cblx0XHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsTGVmdCAtIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoKSA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCggdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoKSAtIG8uc2Nyb2xsU3BlZWQgKTtcblx0XHRcdFx0fSBlbHNlIGlmICggdGhpcy53aW5kb3cuaGVpZ2h0KCkgLSAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoKSApIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCggdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoKSArIG8uc2Nyb2xsU3BlZWQgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSB0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoKSA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoXG5cdFx0XHRcdFx0XHR0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoKSAtIG8uc2Nyb2xsU3BlZWRcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aGlzLndpbmRvdy53aWR0aCgpIC0gKCBldmVudC5wYWdlWCAtIHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpICkgPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdChcblx0XHRcdFx0XHRcdHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpICsgby5zY3JvbGxTcGVlZFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHNjcm9sbGVkICE9PSBmYWxzZSAmJiAkLnVpLmRkbWFuYWdlciAmJiAhby5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggdGhpcywgZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL1JlZ2VuZXJhdGUgdGhlIGFic29sdXRlIHBvc2l0aW9uIHVzZWQgZm9yIHBvc2l0aW9uIGNoZWNrc1xuXHRcdHRoaXMucG9zaXRpb25BYnMgPSB0aGlzLl9jb252ZXJ0UG9zaXRpb25UbyggXCJhYnNvbHV0ZVwiICk7XG5cblx0XHQvL1NldCB0aGUgaGVscGVyIHBvc2l0aW9uXG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLmF4aXMgfHwgdGhpcy5vcHRpb25zLmF4aXMgIT09IFwieVwiICkge1xuXHRcdFx0dGhpcy5oZWxwZXJbIDAgXS5zdHlsZS5sZWZ0ID0gdGhpcy5wb3NpdGlvbi5sZWZ0ICsgXCJweFwiO1xuXHRcdH1cblx0XHRpZiAoICF0aGlzLm9wdGlvbnMuYXhpcyB8fCB0aGlzLm9wdGlvbnMuYXhpcyAhPT0gXCJ4XCIgKSB7XG5cdFx0XHR0aGlzLmhlbHBlclsgMCBdLnN0eWxlLnRvcCA9IHRoaXMucG9zaXRpb24udG9wICsgXCJweFwiO1xuXHRcdH1cblxuXHRcdC8vUmVhcnJhbmdlXG5cdFx0Zm9yICggaSA9IHRoaXMuaXRlbXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cblx0XHRcdC8vQ2FjaGUgdmFyaWFibGVzIGFuZCBpbnRlcnNlY3Rpb24sIGNvbnRpbnVlIGlmIG5vIGludGVyc2VjdGlvblxuXHRcdFx0aXRlbSA9IHRoaXMuaXRlbXNbIGkgXTtcblx0XHRcdGl0ZW1FbGVtZW50ID0gaXRlbS5pdGVtWyAwIF07XG5cdFx0XHRpbnRlcnNlY3Rpb24gPSB0aGlzLl9pbnRlcnNlY3RzV2l0aFBvaW50ZXIoIGl0ZW0gKTtcblx0XHRcdGlmICggIWludGVyc2VjdGlvbiApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIE9ubHkgcHV0IHRoZSBwbGFjZWhvbGRlciBpbnNpZGUgdGhlIGN1cnJlbnQgQ29udGFpbmVyLCBza2lwIGFsbFxuXHRcdFx0Ly8gaXRlbXMgZnJvbSBvdGhlciBjb250YWluZXJzLiBUaGlzIHdvcmtzIGJlY2F1c2Ugd2hlbiBtb3Zpbmdcblx0XHRcdC8vIGFuIGl0ZW0gZnJvbSBvbmUgY29udGFpbmVyIHRvIGFub3RoZXIgdGhlXG5cdFx0XHQvLyBjdXJyZW50Q29udGFpbmVyIGlzIHN3aXRjaGVkIGJlZm9yZSB0aGUgcGxhY2Vob2xkZXIgaXMgbW92ZWQuXG5cdFx0XHQvL1xuXHRcdFx0Ly8gV2l0aG91dCB0aGlzLCBtb3ZpbmcgaXRlbXMgaW4gXCJzdWItc29ydGFibGVzXCIgY2FuIGNhdXNlXG5cdFx0XHQvLyB0aGUgcGxhY2Vob2xkZXIgdG8gaml0dGVyIGJldHdlZW4gdGhlIG91dGVyIGFuZCBpbm5lciBjb250YWluZXIuXG5cdFx0XHRpZiAoIGl0ZW0uaW5zdGFuY2UgIT09IHRoaXMuY3VycmVudENvbnRhaW5lciApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENhbm5vdCBpbnRlcnNlY3Qgd2l0aCBpdHNlbGZcblx0XHRcdC8vIG5vIHVzZWxlc3MgYWN0aW9ucyB0aGF0IGhhdmUgYmVlbiBkb25lIGJlZm9yZVxuXHRcdFx0Ly8gbm8gYWN0aW9uIGlmIHRoZSBpdGVtIG1vdmVkIGlzIHRoZSBwYXJlbnQgb2YgdGhlIGl0ZW0gY2hlY2tlZFxuXHRcdFx0aWYgKCBpdGVtRWxlbWVudCAhPT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICYmXG5cdFx0XHRcdHRoaXMucGxhY2Vob2xkZXJbIGludGVyc2VjdGlvbiA9PT0gMSA/IFwibmV4dFwiIDogXCJwcmV2XCIgXSgpWyAwIF0gIT09IGl0ZW1FbGVtZW50ICYmXG5cdFx0XHRcdCEkLmNvbnRhaW5zKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0sIGl0ZW1FbGVtZW50ICkgJiZcblx0XHRcdFx0KCB0aGlzLm9wdGlvbnMudHlwZSA9PT0gXCJzZW1pLWR5bmFtaWNcIiA/XG5cdFx0XHRcdFx0ISQuY29udGFpbnMoIHRoaXMuZWxlbWVudFsgMCBdLCBpdGVtRWxlbWVudCApIDpcblx0XHRcdFx0XHR0cnVlXG5cdFx0XHRcdClcblx0XHRcdCkge1xuXG5cdFx0XHRcdHRoaXMuZGlyZWN0aW9uID0gaW50ZXJzZWN0aW9uID09PSAxID8gXCJkb3duXCIgOiBcInVwXCI7XG5cblx0XHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlID09PSBcInBvaW50ZXJcIiB8fCB0aGlzLl9pbnRlcnNlY3RzV2l0aFNpZGVzKCBpdGVtICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fcmVhcnJhbmdlKCBldmVudCwgaXRlbSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vUG9zdCBldmVudHMgdG8gY29udGFpbmVyc1xuXHRcdHRoaXMuX2NvbnRhY3RDb250YWluZXJzKCBldmVudCApO1xuXG5cdFx0Ly9JbnRlcmNvbm5lY3Qgd2l0aCBkcm9wcGFibGVzXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmRyYWcoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly9DYWxsIGNhbGxiYWNrc1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic29ydFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblxuXHRcdHRoaXMubGFzdFBvc2l0aW9uQWJzID0gdGhpcy5wb3NpdGlvbkFicztcblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fSxcblxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggZXZlbnQsIG5vUHJvcGFnYXRpb24gKSB7XG5cblx0XHRpZiAoICFldmVudCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvL0lmIHdlIGFyZSB1c2luZyBkcm9wcGFibGVzLCBpbmZvcm0gdGhlIG1hbmFnZXIgYWJvdXQgdGhlIGRyb3Bcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICYmICF0aGlzLm9wdGlvbnMuZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmRyb3AoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMucmV2ZXJ0ICkge1xuXHRcdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0XHRjdXIgPSB0aGlzLnBsYWNlaG9sZGVyLm9mZnNldCgpLFxuXHRcdFx0XHRheGlzID0gdGhpcy5vcHRpb25zLmF4aXMsXG5cdFx0XHRcdGFuaW1hdGlvbiA9IHt9O1xuXG5cdFx0XHRpZiAoICFheGlzIHx8IGF4aXMgPT09IFwieFwiICkge1xuXHRcdFx0XHRhbmltYXRpb24ubGVmdCA9IGN1ci5sZWZ0IC0gdGhpcy5vZmZzZXQucGFyZW50LmxlZnQgLSB0aGlzLm1hcmdpbnMubGVmdCArXG5cdFx0XHRcdFx0KCB0aGlzLm9mZnNldFBhcmVudFsgMCBdID09PSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keSA/XG5cdFx0XHRcdFx0XHQwIDpcblx0XHRcdFx0XHRcdHRoaXMub2Zmc2V0UGFyZW50WyAwIF0uc2Nyb2xsTGVmdFxuXHRcdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoICFheGlzIHx8IGF4aXMgPT09IFwieVwiICkge1xuXHRcdFx0XHRhbmltYXRpb24udG9wID0gY3VyLnRvcCAtIHRoaXMub2Zmc2V0LnBhcmVudC50b3AgLSB0aGlzLm1hcmdpbnMudG9wICtcblx0XHRcdFx0XHQoIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gPT09IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5ID9cblx0XHRcdFx0XHRcdDAgOlxuXHRcdFx0XHRcdFx0dGhpcy5vZmZzZXRQYXJlbnRbIDAgXS5zY3JvbGxUb3Bcblx0XHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5yZXZlcnRpbmcgPSB0cnVlO1xuXHRcdFx0JCggdGhpcy5oZWxwZXIgKS5hbmltYXRlKFxuXHRcdFx0XHRhbmltYXRpb24sXG5cdFx0XHRcdHBhcnNlSW50KCB0aGlzLm9wdGlvbnMucmV2ZXJ0LCAxMCApIHx8IDUwMCxcblx0XHRcdFx0ZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dGhhdC5fY2xlYXIoIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2NsZWFyKCBldmVudCwgbm9Qcm9wYWdhdGlvbiApO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9LFxuXG5cdGNhbmNlbDogZnVuY3Rpb24oKSB7XG5cblx0XHRpZiAoIHRoaXMuZHJhZ2dpbmcgKSB7XG5cblx0XHRcdHRoaXMuX21vdXNlVXAoIG5ldyAkLkV2ZW50KCBcIm1vdXNldXBcIiwgeyB0YXJnZXQ6IG51bGwgfSApICk7XG5cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhlbHBlciA9PT0gXCJvcmlnaW5hbFwiICkge1xuXHRcdFx0XHR0aGlzLmN1cnJlbnRJdGVtLmNzcyggdGhpcy5fc3RvcmVkQ1NTICk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmN1cnJlbnRJdGVtLCBcInVpLXNvcnRhYmxlLWhlbHBlclwiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLmN1cnJlbnRJdGVtLnNob3coKTtcblx0XHRcdH1cblxuXHRcdFx0Ly9Qb3N0IGRlYWN0aXZhdGluZyBldmVudHMgdG8gY29udGFpbmVyc1xuXHRcdFx0Zm9yICggdmFyIGkgPSB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLl90cmlnZ2VyKCBcImRlYWN0aXZhdGVcIiwgbnVsbCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0aWYgKCB0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyICkge1xuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLl90cmlnZ2VyKCBcIm91dFwiLCBudWxsLCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAwO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMucGxhY2Vob2xkZXIgKSB7XG5cblx0XHRcdC8vJCh0aGlzLnBsYWNlaG9sZGVyWzBdKS5yZW1vdmUoKTsgd291bGQgaGF2ZSBiZWVuIHRoZSBqUXVlcnkgd2F5IC0gdW5mb3J0dW5hdGVseSxcblx0XHRcdC8vIGl0IHVuYmluZHMgQUxMIGV2ZW50cyBmcm9tIHRoZSBvcmlnaW5hbCBub2RlIVxuXHRcdFx0aWYgKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0ucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0dGhpcy5wbGFjZWhvbGRlclsgMCBdLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIHRoaXMucGxhY2Vob2xkZXJbIDAgXSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGVscGVyICE9PSBcIm9yaWdpbmFsXCIgJiYgdGhpcy5oZWxwZXIgJiZcblx0XHRcdFx0XHR0aGlzLmhlbHBlclsgMCBdLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHRoaXMuaGVscGVyLnJlbW92ZSgpO1xuXHRcdFx0fVxuXG5cdFx0XHQkLmV4dGVuZCggdGhpcywge1xuXHRcdFx0XHRoZWxwZXI6IG51bGwsXG5cdFx0XHRcdGRyYWdnaW5nOiBmYWxzZSxcblx0XHRcdFx0cmV2ZXJ0aW5nOiBmYWxzZSxcblx0XHRcdFx0X25vRmluYWxTb3J0OiBudWxsXG5cdFx0XHR9ICk7XG5cblx0XHRcdGlmICggdGhpcy5kb21Qb3NpdGlvbi5wcmV2ICkge1xuXHRcdFx0XHQkKCB0aGlzLmRvbVBvc2l0aW9uLnByZXYgKS5hZnRlciggdGhpcy5jdXJyZW50SXRlbSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0JCggdGhpcy5kb21Qb3NpdGlvbi5wYXJlbnQgKS5wcmVwZW5kKCB0aGlzLmN1cnJlbnRJdGVtICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fSxcblxuXHRzZXJpYWxpemU6IGZ1bmN0aW9uKCBvICkge1xuXG5cdFx0dmFyIGl0ZW1zID0gdGhpcy5fZ2V0SXRlbXNBc2pRdWVyeSggbyAmJiBvLmNvbm5lY3RlZCApLFxuXHRcdFx0c3RyID0gW107XG5cdFx0byA9IG8gfHwge307XG5cblx0XHQkKCBpdGVtcyApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHJlcyA9ICggJCggby5pdGVtIHx8IHRoaXMgKS5hdHRyKCBvLmF0dHJpYnV0ZSB8fCBcImlkXCIgKSB8fCBcIlwiIClcblx0XHRcdFx0Lm1hdGNoKCBvLmV4cHJlc3Npb24gfHwgKCAvKC4rKVtcXC09X10oLispLyApICk7XG5cdFx0XHRpZiAoIHJlcyApIHtcblx0XHRcdFx0c3RyLnB1c2goXG5cdFx0XHRcdFx0KCBvLmtleSB8fCByZXNbIDEgXSArIFwiW11cIiApICtcblx0XHRcdFx0XHRcIj1cIiArICggby5rZXkgJiYgby5leHByZXNzaW9uID8gcmVzWyAxIF0gOiByZXNbIDIgXSApICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0aWYgKCAhc3RyLmxlbmd0aCAmJiBvLmtleSApIHtcblx0XHRcdHN0ci5wdXNoKCBvLmtleSArIFwiPVwiICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHN0ci5qb2luKCBcIiZcIiApO1xuXG5cdH0sXG5cblx0dG9BcnJheTogZnVuY3Rpb24oIG8gKSB7XG5cblx0XHR2YXIgaXRlbXMgPSB0aGlzLl9nZXRJdGVtc0FzalF1ZXJ5KCBvICYmIG8uY29ubmVjdGVkICksXG5cdFx0XHRyZXQgPSBbXTtcblxuXHRcdG8gPSBvIHx8IHt9O1xuXG5cdFx0aXRlbXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXQucHVzaCggJCggby5pdGVtIHx8IHRoaXMgKS5hdHRyKCBvLmF0dHJpYnV0ZSB8fCBcImlkXCIgKSB8fCBcIlwiICk7XG5cdFx0fSApO1xuXHRcdHJldHVybiByZXQ7XG5cblx0fSxcblxuXHQvKiBCZSBjYXJlZnVsIHdpdGggdGhlIGZvbGxvd2luZyBjb3JlIGZ1bmN0aW9ucyAqL1xuXHRfaW50ZXJzZWN0c1dpdGg6IGZ1bmN0aW9uKCBpdGVtICkge1xuXG5cdFx0dmFyIHgxID0gdGhpcy5wb3NpdGlvbkFicy5sZWZ0LFxuXHRcdFx0eDIgPSB4MSArIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGgsXG5cdFx0XHR5MSA9IHRoaXMucG9zaXRpb25BYnMudG9wLFxuXHRcdFx0eTIgPSB5MSArIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0LFxuXHRcdFx0bCA9IGl0ZW0ubGVmdCxcblx0XHRcdHIgPSBsICsgaXRlbS53aWR0aCxcblx0XHRcdHQgPSBpdGVtLnRvcCxcblx0XHRcdGIgPSB0ICsgaXRlbS5oZWlnaHQsXG5cdFx0XHRkeUNsaWNrID0gdGhpcy5vZmZzZXQuY2xpY2sudG9wLFxuXHRcdFx0ZHhDbGljayA9IHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQsXG5cdFx0XHRpc092ZXJFbGVtZW50SGVpZ2h0ID0gKCB0aGlzLm9wdGlvbnMuYXhpcyA9PT0gXCJ4XCIgKSB8fCAoICggeTEgKyBkeUNsaWNrICkgPiB0ICYmXG5cdFx0XHRcdCggeTEgKyBkeUNsaWNrICkgPCBiICksXG5cdFx0XHRpc092ZXJFbGVtZW50V2lkdGggPSAoIHRoaXMub3B0aW9ucy5heGlzID09PSBcInlcIiApIHx8ICggKCB4MSArIGR4Q2xpY2sgKSA+IGwgJiZcblx0XHRcdFx0KCB4MSArIGR4Q2xpY2sgKSA8IHIgKSxcblx0XHRcdGlzT3ZlckVsZW1lbnQgPSBpc092ZXJFbGVtZW50SGVpZ2h0ICYmIGlzT3ZlckVsZW1lbnRXaWR0aDtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLnRvbGVyYW5jZSA9PT0gXCJwb2ludGVyXCIgfHxcblx0XHRcdHRoaXMub3B0aW9ucy5mb3JjZVBvaW50ZXJGb3JDb250YWluZXJzIHx8XG5cdFx0XHQoIHRoaXMub3B0aW9ucy50b2xlcmFuY2UgIT09IFwicG9pbnRlclwiICYmXG5cdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnNbIHRoaXMuZmxvYXRpbmcgPyBcIndpZHRoXCIgOiBcImhlaWdodFwiIF0gPlxuXHRcdFx0XHRpdGVtWyB0aGlzLmZsb2F0aW5nID8gXCJ3aWR0aFwiIDogXCJoZWlnaHRcIiBdIClcblx0XHQpIHtcblx0XHRcdHJldHVybiBpc092ZXJFbGVtZW50O1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJldHVybiAoIGwgPCB4MSArICggdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAvIDIgKSAmJiAvLyBSaWdodCBIYWxmXG5cdFx0XHRcdHgyIC0gKCB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC8gMiApIDwgciAmJiAvLyBMZWZ0IEhhbGZcblx0XHRcdFx0dCA8IHkxICsgKCB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAvIDIgKSAmJiAvLyBCb3R0b20gSGFsZlxuXHRcdFx0XHR5MiAtICggdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLyAyICkgPCBiICk7IC8vIFRvcCBIYWxmXG5cblx0XHR9XG5cdH0sXG5cblx0X2ludGVyc2VjdHNXaXRoUG9pbnRlcjogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0dmFyIHZlcnRpY2FsRGlyZWN0aW9uLCBob3Jpem9udGFsRGlyZWN0aW9uLFxuXHRcdFx0aXNPdmVyRWxlbWVudEhlaWdodCA9ICggdGhpcy5vcHRpb25zLmF4aXMgPT09IFwieFwiICkgfHxcblx0XHRcdFx0dGhpcy5faXNPdmVyQXhpcyhcblx0XHRcdFx0XHR0aGlzLnBvc2l0aW9uQWJzLnRvcCArIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCwgaXRlbS50b3AsIGl0ZW0uaGVpZ2h0ICksXG5cdFx0XHRpc092ZXJFbGVtZW50V2lkdGggPSAoIHRoaXMub3B0aW9ucy5heGlzID09PSBcInlcIiApIHx8XG5cdFx0XHRcdHRoaXMuX2lzT3ZlckF4aXMoXG5cdFx0XHRcdFx0dGhpcy5wb3NpdGlvbkFicy5sZWZ0ICsgdGhpcy5vZmZzZXQuY2xpY2subGVmdCwgaXRlbS5sZWZ0LCBpdGVtLndpZHRoICksXG5cdFx0XHRpc092ZXJFbGVtZW50ID0gaXNPdmVyRWxlbWVudEhlaWdodCAmJiBpc092ZXJFbGVtZW50V2lkdGg7XG5cblx0XHRpZiAoICFpc092ZXJFbGVtZW50ICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZlcnRpY2FsRGlyZWN0aW9uID0gdGhpcy5fZ2V0RHJhZ1ZlcnRpY2FsRGlyZWN0aW9uKCk7XG5cdFx0aG9yaXpvbnRhbERpcmVjdGlvbiA9IHRoaXMuX2dldERyYWdIb3Jpem9udGFsRGlyZWN0aW9uKCk7XG5cblx0XHRyZXR1cm4gdGhpcy5mbG9hdGluZyA/XG5cdFx0XHQoICggaG9yaXpvbnRhbERpcmVjdGlvbiA9PT0gXCJyaWdodFwiIHx8IHZlcnRpY2FsRGlyZWN0aW9uID09PSBcImRvd25cIiApID8gMiA6IDEgKVxuXHRcdFx0OiAoIHZlcnRpY2FsRGlyZWN0aW9uICYmICggdmVydGljYWxEaXJlY3Rpb24gPT09IFwiZG93blwiID8gMiA6IDEgKSApO1xuXG5cdH0sXG5cblx0X2ludGVyc2VjdHNXaXRoU2lkZXM6IGZ1bmN0aW9uKCBpdGVtICkge1xuXG5cdFx0dmFyIGlzT3ZlckJvdHRvbUhhbGYgPSB0aGlzLl9pc092ZXJBeGlzKCB0aGlzLnBvc2l0aW9uQWJzLnRvcCArXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCwgaXRlbS50b3AgKyAoIGl0ZW0uaGVpZ2h0IC8gMiApLCBpdGVtLmhlaWdodCApLFxuXHRcdFx0aXNPdmVyUmlnaHRIYWxmID0gdGhpcy5faXNPdmVyQXhpcyggdGhpcy5wb3NpdGlvbkFicy5sZWZ0ICtcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCwgaXRlbS5sZWZ0ICsgKCBpdGVtLndpZHRoIC8gMiApLCBpdGVtLndpZHRoICksXG5cdFx0XHR2ZXJ0aWNhbERpcmVjdGlvbiA9IHRoaXMuX2dldERyYWdWZXJ0aWNhbERpcmVjdGlvbigpLFxuXHRcdFx0aG9yaXpvbnRhbERpcmVjdGlvbiA9IHRoaXMuX2dldERyYWdIb3Jpem9udGFsRGlyZWN0aW9uKCk7XG5cblx0XHRpZiAoIHRoaXMuZmxvYXRpbmcgJiYgaG9yaXpvbnRhbERpcmVjdGlvbiApIHtcblx0XHRcdHJldHVybiAoICggaG9yaXpvbnRhbERpcmVjdGlvbiA9PT0gXCJyaWdodFwiICYmIGlzT3ZlclJpZ2h0SGFsZiApIHx8XG5cdFx0XHRcdCggaG9yaXpvbnRhbERpcmVjdGlvbiA9PT0gXCJsZWZ0XCIgJiYgIWlzT3ZlclJpZ2h0SGFsZiApICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiB2ZXJ0aWNhbERpcmVjdGlvbiAmJiAoICggdmVydGljYWxEaXJlY3Rpb24gPT09IFwiZG93blwiICYmIGlzT3ZlckJvdHRvbUhhbGYgKSB8fFxuXHRcdFx0XHQoIHZlcnRpY2FsRGlyZWN0aW9uID09PSBcInVwXCIgJiYgIWlzT3ZlckJvdHRvbUhhbGYgKSApO1xuXHRcdH1cblxuXHR9LFxuXG5cdF9nZXREcmFnVmVydGljYWxEaXJlY3Rpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBkZWx0YSA9IHRoaXMucG9zaXRpb25BYnMudG9wIC0gdGhpcy5sYXN0UG9zaXRpb25BYnMudG9wO1xuXHRcdHJldHVybiBkZWx0YSAhPT0gMCAmJiAoIGRlbHRhID4gMCA/IFwiZG93blwiIDogXCJ1cFwiICk7XG5cdH0sXG5cblx0X2dldERyYWdIb3Jpem9udGFsRGlyZWN0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZGVsdGEgPSB0aGlzLnBvc2l0aW9uQWJzLmxlZnQgLSB0aGlzLmxhc3RQb3NpdGlvbkFicy5sZWZ0O1xuXHRcdHJldHVybiBkZWx0YSAhPT0gMCAmJiAoIGRlbHRhID4gMCA/IFwicmlnaHRcIiA6IFwibGVmdFwiICk7XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuX3JlZnJlc2hJdGVtcyggZXZlbnQgKTtcblx0XHR0aGlzLl9zZXRIYW5kbGVDbGFzc05hbWUoKTtcblx0XHR0aGlzLnJlZnJlc2hQb3NpdGlvbnMoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfY29ubmVjdFdpdGg6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXHRcdHJldHVybiBvcHRpb25zLmNvbm5lY3RXaXRoLmNvbnN0cnVjdG9yID09PSBTdHJpbmcgP1xuXHRcdFx0WyBvcHRpb25zLmNvbm5lY3RXaXRoIF0gOlxuXHRcdFx0b3B0aW9ucy5jb25uZWN0V2l0aDtcblx0fSxcblxuXHRfZ2V0SXRlbXNBc2pRdWVyeTogZnVuY3Rpb24oIGNvbm5lY3RlZCApIHtcblxuXHRcdHZhciBpLCBqLCBjdXIsIGluc3QsXG5cdFx0XHRpdGVtcyA9IFtdLFxuXHRcdFx0cXVlcmllcyA9IFtdLFxuXHRcdFx0Y29ubmVjdFdpdGggPSB0aGlzLl9jb25uZWN0V2l0aCgpO1xuXG5cdFx0aWYgKCBjb25uZWN0V2l0aCAmJiBjb25uZWN0ZWQgKSB7XG5cdFx0XHRmb3IgKCBpID0gY29ubmVjdFdpdGgubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdGN1ciA9ICQoIGNvbm5lY3RXaXRoWyBpIF0sIHRoaXMuZG9jdW1lbnRbIDAgXSApO1xuXHRcdFx0XHRmb3IgKCBqID0gY3VyLmxlbmd0aCAtIDE7IGogPj0gMDsgai0tICkge1xuXHRcdFx0XHRcdGluc3QgPSAkLmRhdGEoIGN1clsgaiBdLCB0aGlzLndpZGdldEZ1bGxOYW1lICk7XG5cdFx0XHRcdFx0aWYgKCBpbnN0ICYmIGluc3QgIT09IHRoaXMgJiYgIWluc3Qub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdFx0XHRcdHF1ZXJpZXMucHVzaCggWyAkLmlzRnVuY3Rpb24oIGluc3Qub3B0aW9ucy5pdGVtcyApID9cblx0XHRcdFx0XHRcdFx0aW5zdC5vcHRpb25zLml0ZW1zLmNhbGwoIGluc3QuZWxlbWVudCApIDpcblx0XHRcdFx0XHRcdFx0JCggaW5zdC5vcHRpb25zLml0ZW1zLCBpbnN0LmVsZW1lbnQgKVxuXHRcdFx0XHRcdFx0XHRcdC5ub3QoIFwiLnVpLXNvcnRhYmxlLWhlbHBlclwiIClcblx0XHRcdFx0XHRcdFx0XHQubm90KCBcIi51aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiICksIGluc3QgXSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHF1ZXJpZXMucHVzaCggWyAkLmlzRnVuY3Rpb24oIHRoaXMub3B0aW9ucy5pdGVtcyApID9cblx0XHRcdHRoaXMub3B0aW9ucy5pdGVtc1xuXHRcdFx0XHQuY2FsbCggdGhpcy5lbGVtZW50LCBudWxsLCB7IG9wdGlvbnM6IHRoaXMub3B0aW9ucywgaXRlbTogdGhpcy5jdXJyZW50SXRlbSB9ICkgOlxuXHRcdFx0JCggdGhpcy5vcHRpb25zLml0ZW1zLCB0aGlzLmVsZW1lbnQgKVxuXHRcdFx0XHQubm90KCBcIi51aS1zb3J0YWJsZS1oZWxwZXJcIiApXG5cdFx0XHRcdC5ub3QoIFwiLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyXCIgKSwgdGhpcyBdICk7XG5cblx0XHRmdW5jdGlvbiBhZGRJdGVtcygpIHtcblx0XHRcdGl0ZW1zLnB1c2goIHRoaXMgKTtcblx0XHR9XG5cdFx0Zm9yICggaSA9IHF1ZXJpZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRxdWVyaWVzWyBpIF1bIDAgXS5lYWNoKCBhZGRJdGVtcyApO1xuXHRcdH1cblxuXHRcdHJldHVybiAkKCBpdGVtcyApO1xuXG5cdH0sXG5cblx0X3JlbW92ZUN1cnJlbnRzRnJvbUl0ZW1zOiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBsaXN0ID0gdGhpcy5jdXJyZW50SXRlbS5maW5kKCBcIjpkYXRhKFwiICsgdGhpcy53aWRnZXROYW1lICsgXCItaXRlbSlcIiApO1xuXG5cdFx0dGhpcy5pdGVtcyA9ICQuZ3JlcCggdGhpcy5pdGVtcywgZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0XHRmb3IgKCB2YXIgaiA9IDA7IGogPCBsaXN0Lmxlbmd0aDsgaisrICkge1xuXHRcdFx0XHRpZiAoIGxpc3RbIGogXSA9PT0gaXRlbS5pdGVtWyAwIF0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9ICk7XG5cblx0fSxcblxuXHRfcmVmcmVzaEl0ZW1zOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR0aGlzLml0ZW1zID0gW107XG5cdFx0dGhpcy5jb250YWluZXJzID0gWyB0aGlzIF07XG5cblx0XHR2YXIgaSwgaiwgY3VyLCBpbnN0LCB0YXJnZXREYXRhLCBfcXVlcmllcywgaXRlbSwgcXVlcmllc0xlbmd0aCxcblx0XHRcdGl0ZW1zID0gdGhpcy5pdGVtcyxcblx0XHRcdHF1ZXJpZXMgPSBbIFsgJC5pc0Z1bmN0aW9uKCB0aGlzLm9wdGlvbnMuaXRlbXMgKSA/XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5pdGVtcy5jYWxsKCB0aGlzLmVsZW1lbnRbIDAgXSwgZXZlbnQsIHsgaXRlbTogdGhpcy5jdXJyZW50SXRlbSB9ICkgOlxuXHRcdFx0XHQkKCB0aGlzLm9wdGlvbnMuaXRlbXMsIHRoaXMuZWxlbWVudCApLCB0aGlzIF0gXSxcblx0XHRcdGNvbm5lY3RXaXRoID0gdGhpcy5fY29ubmVjdFdpdGgoKTtcblxuXHRcdC8vU2hvdWxkbid0IGJlIHJ1biB0aGUgZmlyc3QgdGltZSB0aHJvdWdoIGR1ZSB0byBtYXNzaXZlIHNsb3ctZG93blxuXHRcdGlmICggY29ubmVjdFdpdGggJiYgdGhpcy5yZWFkeSApIHtcblx0XHRcdGZvciAoIGkgPSBjb25uZWN0V2l0aC5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0Y3VyID0gJCggY29ubmVjdFdpdGhbIGkgXSwgdGhpcy5kb2N1bWVudFsgMCBdICk7XG5cdFx0XHRcdGZvciAoIGogPSBjdXIubGVuZ3RoIC0gMTsgaiA+PSAwOyBqLS0gKSB7XG5cdFx0XHRcdFx0aW5zdCA9ICQuZGF0YSggY3VyWyBqIF0sIHRoaXMud2lkZ2V0RnVsbE5hbWUgKTtcblx0XHRcdFx0XHRpZiAoIGluc3QgJiYgaW5zdCAhPT0gdGhpcyAmJiAhaW5zdC5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0XHRcdFx0cXVlcmllcy5wdXNoKCBbICQuaXNGdW5jdGlvbiggaW5zdC5vcHRpb25zLml0ZW1zICkgP1xuXHRcdFx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuaXRlbXNcblx0XHRcdFx0XHRcdFx0XHQuY2FsbCggaW5zdC5lbGVtZW50WyAwIF0sIGV2ZW50LCB7IGl0ZW06IHRoaXMuY3VycmVudEl0ZW0gfSApIDpcblx0XHRcdFx0XHRcdFx0JCggaW5zdC5vcHRpb25zLml0ZW1zLCBpbnN0LmVsZW1lbnQgKSwgaW5zdCBdICk7XG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnMucHVzaCggaW5zdCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZvciAoIGkgPSBxdWVyaWVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0dGFyZ2V0RGF0YSA9IHF1ZXJpZXNbIGkgXVsgMSBdO1xuXHRcdFx0X3F1ZXJpZXMgPSBxdWVyaWVzWyBpIF1bIDAgXTtcblxuXHRcdFx0Zm9yICggaiA9IDAsIHF1ZXJpZXNMZW5ndGggPSBfcXVlcmllcy5sZW5ndGg7IGogPCBxdWVyaWVzTGVuZ3RoOyBqKysgKSB7XG5cdFx0XHRcdGl0ZW0gPSAkKCBfcXVlcmllc1sgaiBdICk7XG5cblx0XHRcdFx0Ly8gRGF0YSBmb3IgdGFyZ2V0IGNoZWNraW5nIChtb3VzZSBtYW5hZ2VyKVxuXHRcdFx0XHRpdGVtLmRhdGEoIHRoaXMud2lkZ2V0TmFtZSArIFwiLWl0ZW1cIiwgdGFyZ2V0RGF0YSApO1xuXG5cdFx0XHRcdGl0ZW1zLnB1c2goIHtcblx0XHRcdFx0XHRpdGVtOiBpdGVtLFxuXHRcdFx0XHRcdGluc3RhbmNlOiB0YXJnZXREYXRhLFxuXHRcdFx0XHRcdHdpZHRoOiAwLCBoZWlnaHQ6IDAsXG5cdFx0XHRcdFx0bGVmdDogMCwgdG9wOiAwXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0fSxcblxuXHRyZWZyZXNoUG9zaXRpb25zOiBmdW5jdGlvbiggZmFzdCApIHtcblxuXHRcdC8vIERldGVybWluZSB3aGV0aGVyIGl0ZW1zIGFyZSBiZWluZyBkaXNwbGF5ZWQgaG9yaXpvbnRhbGx5XG5cdFx0dGhpcy5mbG9hdGluZyA9IHRoaXMuaXRlbXMubGVuZ3RoID9cblx0XHRcdHRoaXMub3B0aW9ucy5heGlzID09PSBcInhcIiB8fCB0aGlzLl9pc0Zsb2F0aW5nKCB0aGlzLml0ZW1zWyAwIF0uaXRlbSApIDpcblx0XHRcdGZhbHNlO1xuXG5cdFx0Ly9UaGlzIGhhcyB0byBiZSByZWRvbmUgYmVjYXVzZSBkdWUgdG8gdGhlIGl0ZW0gYmVpbmcgbW92ZWQgb3V0L2ludG8gdGhlIG9mZnNldFBhcmVudCxcblx0XHQvLyB0aGUgb2Zmc2V0UGFyZW50J3MgcG9zaXRpb24gd2lsbCBjaGFuZ2Vcblx0XHRpZiAoIHRoaXMub2Zmc2V0UGFyZW50ICYmIHRoaXMuaGVscGVyICkge1xuXHRcdFx0dGhpcy5vZmZzZXQucGFyZW50ID0gdGhpcy5fZ2V0UGFyZW50T2Zmc2V0KCk7XG5cdFx0fVxuXG5cdFx0dmFyIGksIGl0ZW0sIHQsIHA7XG5cblx0XHRmb3IgKCBpID0gdGhpcy5pdGVtcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdGl0ZW0gPSB0aGlzLml0ZW1zWyBpIF07XG5cblx0XHRcdC8vV2UgaWdub3JlIGNhbGN1bGF0aW5nIHBvc2l0aW9ucyBvZiBhbGwgY29ubmVjdGVkIGNvbnRhaW5lcnMgd2hlbiB3ZSdyZSBub3Qgb3ZlciB0aGVtXG5cdFx0XHRpZiAoIGl0ZW0uaW5zdGFuY2UgIT09IHRoaXMuY3VycmVudENvbnRhaW5lciAmJiB0aGlzLmN1cnJlbnRDb250YWluZXIgJiZcblx0XHRcdFx0XHRpdGVtLml0ZW1bIDAgXSAhPT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0dCA9IHRoaXMub3B0aW9ucy50b2xlcmFuY2VFbGVtZW50ID9cblx0XHRcdFx0JCggdGhpcy5vcHRpb25zLnRvbGVyYW5jZUVsZW1lbnQsIGl0ZW0uaXRlbSApIDpcblx0XHRcdFx0aXRlbS5pdGVtO1xuXG5cdFx0XHRpZiAoICFmYXN0ICkge1xuXHRcdFx0XHRpdGVtLndpZHRoID0gdC5vdXRlcldpZHRoKCk7XG5cdFx0XHRcdGl0ZW0uaGVpZ2h0ID0gdC5vdXRlckhlaWdodCgpO1xuXHRcdFx0fVxuXG5cdFx0XHRwID0gdC5vZmZzZXQoKTtcblx0XHRcdGl0ZW0ubGVmdCA9IHAubGVmdDtcblx0XHRcdGl0ZW0udG9wID0gcC50b3A7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuY3VzdG9tICYmIHRoaXMub3B0aW9ucy5jdXN0b20ucmVmcmVzaENvbnRhaW5lcnMgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuY3VzdG9tLnJlZnJlc2hDb250YWluZXJzLmNhbGwoIHRoaXMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yICggaSA9IHRoaXMuY29udGFpbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0cCA9IHRoaXMuY29udGFpbmVyc1sgaSBdLmVsZW1lbnQub2Zmc2V0KCk7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLmxlZnQgPSBwLmxlZnQ7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLnRvcCA9IHAudG9wO1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS53aWR0aCA9XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uZWxlbWVudC5vdXRlcldpZHRoKCk7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLmhlaWdodCA9XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uZWxlbWVudC5vdXRlckhlaWdodCgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9jcmVhdGVQbGFjZWhvbGRlcjogZnVuY3Rpb24oIHRoYXQgKSB7XG5cdFx0dGhhdCA9IHRoYXQgfHwgdGhpcztcblx0XHR2YXIgY2xhc3NOYW1lLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucztcblxuXHRcdGlmICggIW8ucGxhY2Vob2xkZXIgfHwgby5wbGFjZWhvbGRlci5jb25zdHJ1Y3RvciA9PT0gU3RyaW5nICkge1xuXHRcdFx0Y2xhc3NOYW1lID0gby5wbGFjZWhvbGRlcjtcblx0XHRcdG8ucGxhY2Vob2xkZXIgPSB7XG5cdFx0XHRcdGVsZW1lbnQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdFx0dmFyIG5vZGVOYW1lID0gdGhhdC5jdXJyZW50SXRlbVsgMCBdLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCksXG5cdFx0XHRcdFx0XHRlbGVtZW50ID0gJCggXCI8XCIgKyBub2RlTmFtZSArIFwiPlwiLCB0aGF0LmRvY3VtZW50WyAwIF0gKTtcblxuXHRcdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIGVsZW1lbnQsIFwidWktc29ydGFibGUtcGxhY2Vob2xkZXJcIixcblx0XHRcdFx0XHRcdFx0XHRjbGFzc05hbWUgfHwgdGhhdC5jdXJyZW50SXRlbVsgMCBdLmNsYXNzTmFtZSApXG5cdFx0XHRcdFx0XHRcdC5fcmVtb3ZlQ2xhc3MoIGVsZW1lbnQsIFwidWktc29ydGFibGUtaGVscGVyXCIgKTtcblxuXHRcdFx0XHRcdGlmICggbm9kZU5hbWUgPT09IFwidGJvZHlcIiApIHtcblx0XHRcdFx0XHRcdHRoYXQuX2NyZWF0ZVRyUGxhY2Vob2xkZXIoXG5cdFx0XHRcdFx0XHRcdHRoYXQuY3VycmVudEl0ZW0uZmluZCggXCJ0clwiICkuZXEoIDAgKSxcblx0XHRcdFx0XHRcdFx0JCggXCI8dHI+XCIsIHRoYXQuZG9jdW1lbnRbIDAgXSApLmFwcGVuZFRvKCBlbGVtZW50IClcblx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwidHJcIiApIHtcblx0XHRcdFx0XHRcdHRoYXQuX2NyZWF0ZVRyUGxhY2Vob2xkZXIoIHRoYXQuY3VycmVudEl0ZW0sIGVsZW1lbnQgKTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBub2RlTmFtZSA9PT0gXCJpbWdcIiApIHtcblx0XHRcdFx0XHRcdGVsZW1lbnQuYXR0ciggXCJzcmNcIiwgdGhhdC5jdXJyZW50SXRlbS5hdHRyKCBcInNyY1wiICkgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICFjbGFzc05hbWUgKSB7XG5cdFx0XHRcdFx0XHRlbGVtZW50LmNzcyggXCJ2aXNpYmlsaXR5XCIsIFwiaGlkZGVuXCIgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZXR1cm4gZWxlbWVudDtcblx0XHRcdFx0fSxcblx0XHRcdFx0dXBkYXRlOiBmdW5jdGlvbiggY29udGFpbmVyLCBwICkge1xuXG5cdFx0XHRcdFx0Ly8gMS4gSWYgYSBjbGFzc05hbWUgaXMgc2V0IGFzICdwbGFjZWhvbGRlciBvcHRpb24sIHdlIGRvbid0IGZvcmNlIHNpemVzIC1cblx0XHRcdFx0XHQvLyB0aGUgY2xhc3MgaXMgcmVzcG9uc2libGUgZm9yIHRoYXRcblx0XHRcdFx0XHQvLyAyLiBUaGUgb3B0aW9uICdmb3JjZVBsYWNlaG9sZGVyU2l6ZSBjYW4gYmUgZW5hYmxlZCB0byBmb3JjZSBpdCBldmVuIGlmIGFcblx0XHRcdFx0XHQvLyBjbGFzcyBuYW1lIGlzIHNwZWNpZmllZFxuXHRcdFx0XHRcdGlmICggY2xhc3NOYW1lICYmICFvLmZvcmNlUGxhY2Vob2xkZXJTaXplICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vSWYgdGhlIGVsZW1lbnQgZG9lc24ndCBoYXZlIGEgYWN0dWFsIGhlaWdodCBieSBpdHNlbGYgKHdpdGhvdXQgc3R5bGVzIGNvbWluZ1xuXHRcdFx0XHRcdC8vIGZyb20gYSBzdHlsZXNoZWV0KSwgaXQgcmVjZWl2ZXMgdGhlIGlubGluZSBoZWlnaHQgZnJvbSB0aGUgZHJhZ2dlZCBpdGVtXG5cdFx0XHRcdFx0aWYgKCAhcC5oZWlnaHQoKSApIHtcblx0XHRcdFx0XHRcdHAuaGVpZ2h0KFxuXHRcdFx0XHRcdFx0XHR0aGF0LmN1cnJlbnRJdGVtLmlubmVySGVpZ2h0KCkgLVxuXHRcdFx0XHRcdFx0XHRwYXJzZUludCggdGhhdC5jdXJyZW50SXRlbS5jc3MoIFwicGFkZGluZ1RvcFwiICkgfHwgMCwgMTAgKSAtXG5cdFx0XHRcdFx0XHRcdHBhcnNlSW50KCB0aGF0LmN1cnJlbnRJdGVtLmNzcyggXCJwYWRkaW5nQm90dG9tXCIgKSB8fCAwLCAxMCApICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggIXAud2lkdGgoKSApIHtcblx0XHRcdFx0XHRcdHAud2lkdGgoXG5cdFx0XHRcdFx0XHRcdHRoYXQuY3VycmVudEl0ZW0uaW5uZXJXaWR0aCgpIC1cblx0XHRcdFx0XHRcdFx0cGFyc2VJbnQoIHRoYXQuY3VycmVudEl0ZW0uY3NzKCBcInBhZGRpbmdMZWZ0XCIgKSB8fCAwLCAxMCApIC1cblx0XHRcdFx0XHRcdFx0cGFyc2VJbnQoIHRoYXQuY3VycmVudEl0ZW0uY3NzKCBcInBhZGRpbmdSaWdodFwiICkgfHwgMCwgMTAgKSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHQvL0NyZWF0ZSB0aGUgcGxhY2Vob2xkZXJcblx0XHR0aGF0LnBsYWNlaG9sZGVyID0gJCggby5wbGFjZWhvbGRlci5lbGVtZW50LmNhbGwoIHRoYXQuZWxlbWVudCwgdGhhdC5jdXJyZW50SXRlbSApICk7XG5cblx0XHQvL0FwcGVuZCBpdCBhZnRlciB0aGUgYWN0dWFsIGN1cnJlbnQgaXRlbVxuXHRcdHRoYXQuY3VycmVudEl0ZW0uYWZ0ZXIoIHRoYXQucGxhY2Vob2xkZXIgKTtcblxuXHRcdC8vVXBkYXRlIHRoZSBzaXplIG9mIHRoZSBwbGFjZWhvbGRlciAoVE9ETzogTG9naWMgdG8gZnV6enksIHNlZSBsaW5lIDMxNi8zMTcpXG5cdFx0by5wbGFjZWhvbGRlci51cGRhdGUoIHRoYXQsIHRoYXQucGxhY2Vob2xkZXIgKTtcblxuXHR9LFxuXG5cdF9jcmVhdGVUclBsYWNlaG9sZGVyOiBmdW5jdGlvbiggc291cmNlVHIsIHRhcmdldFRyICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHNvdXJjZVRyLmNoaWxkcmVuKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHQkKCBcIjx0ZD4mIzE2MDs8L3RkPlwiLCB0aGF0LmRvY3VtZW50WyAwIF0gKVxuXHRcdFx0XHQuYXR0ciggXCJjb2xzcGFuXCIsICQoIHRoaXMgKS5hdHRyKCBcImNvbHNwYW5cIiApIHx8IDEgKVxuXHRcdFx0XHQuYXBwZW5kVG8oIHRhcmdldFRyICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9jb250YWN0Q29udGFpbmVyczogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpLCBqLCBkaXN0LCBpdGVtV2l0aExlYXN0RGlzdGFuY2UsIHBvc1Byb3BlcnR5LCBzaXplUHJvcGVydHksIGN1ciwgbmVhckJvdHRvbSxcblx0XHRcdGZsb2F0aW5nLCBheGlzLFxuXHRcdFx0aW5uZXJtb3N0Q29udGFpbmVyID0gbnVsbCxcblx0XHRcdGlubmVybW9zdEluZGV4ID0gbnVsbDtcblxuXHRcdC8vIEdldCBpbm5lcm1vc3QgY29udGFpbmVyIHRoYXQgaW50ZXJzZWN0cyB3aXRoIGl0ZW1cblx0XHRmb3IgKCBpID0gdGhpcy5jb250YWluZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXG5cdFx0XHQvLyBOZXZlciBjb25zaWRlciBhIGNvbnRhaW5lciB0aGF0J3MgbG9jYXRlZCB3aXRoaW4gdGhlIGl0ZW0gaXRzZWxmXG5cdFx0XHRpZiAoICQuY29udGFpbnMoIHRoaXMuY3VycmVudEl0ZW1bIDAgXSwgdGhpcy5jb250YWluZXJzWyBpIF0uZWxlbWVudFsgMCBdICkgKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuX2ludGVyc2VjdHNXaXRoKCB0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZSApICkge1xuXG5cdFx0XHRcdC8vIElmIHdlJ3ZlIGFscmVhZHkgZm91bmQgYSBjb250YWluZXIgYW5kIGl0J3MgbW9yZSBcImlubmVyXCIgdGhhbiB0aGlzLCB0aGVuIGNvbnRpbnVlXG5cdFx0XHRcdGlmICggaW5uZXJtb3N0Q29udGFpbmVyICYmXG5cdFx0XHRcdFx0XHQkLmNvbnRhaW5zKFxuXHRcdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5lbGVtZW50WyAwIF0sXG5cdFx0XHRcdFx0XHRcdGlubmVybW9zdENvbnRhaW5lci5lbGVtZW50WyAwIF0gKSApIHtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlubmVybW9zdENvbnRhaW5lciA9IHRoaXMuY29udGFpbmVyc1sgaSBdO1xuXHRcdFx0XHRpbm5lcm1vc3RJbmRleCA9IGk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gY29udGFpbmVyIGRvZXNuJ3QgaW50ZXJzZWN0LiB0cmlnZ2VyIFwib3V0XCIgZXZlbnQgaWYgbmVjZXNzYXJ5XG5cdFx0XHRcdGlmICggdGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciApIHtcblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5fdHJpZ2dlciggXCJvdXRcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciA9IDA7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIElmIG5vIGludGVyc2VjdGluZyBjb250YWluZXJzIGZvdW5kLCByZXR1cm5cblx0XHRpZiAoICFpbm5lcm1vc3RDb250YWluZXIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gTW92ZSB0aGUgaXRlbSBpbnRvIHRoZSBjb250YWluZXIgaWYgaXQncyBub3QgdGhlcmUgYWxyZWFkeVxuXHRcdGlmICggdGhpcy5jb250YWluZXJzLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdGlmICggIXRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5jb250YWluZXJDYWNoZS5vdmVyICkge1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uX3RyaWdnZXIoIFwib3ZlclwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAxO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIFdoZW4gZW50ZXJpbmcgYSBuZXcgY29udGFpbmVyLCB3ZSB3aWxsIGZpbmQgdGhlIGl0ZW0gd2l0aCB0aGUgbGVhc3QgZGlzdGFuY2UgYW5kXG5cdFx0XHQvLyBhcHBlbmQgb3VyIGl0ZW0gbmVhciBpdFxuXHRcdFx0ZGlzdCA9IDEwMDAwO1xuXHRcdFx0aXRlbVdpdGhMZWFzdERpc3RhbmNlID0gbnVsbDtcblx0XHRcdGZsb2F0aW5nID0gaW5uZXJtb3N0Q29udGFpbmVyLmZsb2F0aW5nIHx8IHRoaXMuX2lzRmxvYXRpbmcoIHRoaXMuY3VycmVudEl0ZW0gKTtcblx0XHRcdHBvc1Byb3BlcnR5ID0gZmxvYXRpbmcgPyBcImxlZnRcIiA6IFwidG9wXCI7XG5cdFx0XHRzaXplUHJvcGVydHkgPSBmbG9hdGluZyA/IFwid2lkdGhcIiA6IFwiaGVpZ2h0XCI7XG5cdFx0XHRheGlzID0gZmxvYXRpbmcgPyBcInBhZ2VYXCIgOiBcInBhZ2VZXCI7XG5cblx0XHRcdGZvciAoIGogPSB0aGlzLml0ZW1zLmxlbmd0aCAtIDE7IGogPj0gMDsgai0tICkge1xuXHRcdFx0XHRpZiAoICEkLmNvbnRhaW5zKFxuXHRcdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLmVsZW1lbnRbIDAgXSwgdGhpcy5pdGVtc1sgaiBdLml0ZW1bIDAgXSApXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggdGhpcy5pdGVtc1sgaiBdLml0ZW1bIDAgXSA9PT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y3VyID0gdGhpcy5pdGVtc1sgaiBdLml0ZW0ub2Zmc2V0KClbIHBvc1Byb3BlcnR5IF07XG5cdFx0XHRcdG5lYXJCb3R0b20gPSBmYWxzZTtcblx0XHRcdFx0aWYgKCBldmVudFsgYXhpcyBdIC0gY3VyID4gdGhpcy5pdGVtc1sgaiBdWyBzaXplUHJvcGVydHkgXSAvIDIgKSB7XG5cdFx0XHRcdFx0bmVhckJvdHRvbSA9IHRydWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBldmVudFsgYXhpcyBdIC0gY3VyICkgPCBkaXN0ICkge1xuXHRcdFx0XHRcdGRpc3QgPSBNYXRoLmFicyggZXZlbnRbIGF4aXMgXSAtIGN1ciApO1xuXHRcdFx0XHRcdGl0ZW1XaXRoTGVhc3REaXN0YW5jZSA9IHRoaXMuaXRlbXNbIGogXTtcblx0XHRcdFx0XHR0aGlzLmRpcmVjdGlvbiA9IG5lYXJCb3R0b20gPyBcInVwXCIgOiBcImRvd25cIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvL0NoZWNrIGlmIGRyb3BPbkVtcHR5IGlzIGVuYWJsZWRcblx0XHRcdGlmICggIWl0ZW1XaXRoTGVhc3REaXN0YW5jZSAmJiAhdGhpcy5vcHRpb25zLmRyb3BPbkVtcHR5ICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5jdXJyZW50Q29udGFpbmVyID09PSB0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0gKSB7XG5cdFx0XHRcdGlmICggIXRoaXMuY3VycmVudENvbnRhaW5lci5jb250YWluZXJDYWNoZS5vdmVyICkge1xuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5fdHJpZ2dlciggXCJvdmVyXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdFx0XHRcdHRoaXMuY3VycmVudENvbnRhaW5lci5jb250YWluZXJDYWNoZS5vdmVyID0gMTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGl0ZW1XaXRoTGVhc3REaXN0YW5jZSA/XG5cdFx0XHRcdHRoaXMuX3JlYXJyYW5nZSggZXZlbnQsIGl0ZW1XaXRoTGVhc3REaXN0YW5jZSwgbnVsbCwgdHJ1ZSApIDpcblx0XHRcdFx0dGhpcy5fcmVhcnJhbmdlKCBldmVudCwgbnVsbCwgdGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLmVsZW1lbnQsIHRydWUgKTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdHRoaXMuY3VycmVudENvbnRhaW5lciA9IHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXTtcblxuXHRcdFx0Ly9VcGRhdGUgdGhlIHBsYWNlaG9sZGVyXG5cdFx0XHR0aGlzLm9wdGlvbnMucGxhY2Vob2xkZXIudXBkYXRlKCB0aGlzLmN1cnJlbnRDb250YWluZXIsIHRoaXMucGxhY2Vob2xkZXIgKTtcblxuXHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLl90cmlnZ2VyKCBcIm92ZXJcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uY29udGFpbmVyQ2FjaGUub3ZlciA9IDE7XG5cdFx0fVxuXG5cdH0sXG5cblx0X2NyZWF0ZUhlbHBlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRoZWxwZXIgPSAkLmlzRnVuY3Rpb24oIG8uaGVscGVyICkgP1xuXHRcdFx0XHQkKCBvLmhlbHBlci5hcHBseSggdGhpcy5lbGVtZW50WyAwIF0sIFsgZXZlbnQsIHRoaXMuY3VycmVudEl0ZW0gXSApICkgOlxuXHRcdFx0XHQoIG8uaGVscGVyID09PSBcImNsb25lXCIgPyB0aGlzLmN1cnJlbnRJdGVtLmNsb25lKCkgOiB0aGlzLmN1cnJlbnRJdGVtICk7XG5cblx0XHQvL0FkZCB0aGUgaGVscGVyIHRvIHRoZSBET00gaWYgdGhhdCBkaWRuJ3QgaGFwcGVuIGFscmVhZHlcblx0XHRpZiAoICFoZWxwZXIucGFyZW50cyggXCJib2R5XCIgKS5sZW5ndGggKSB7XG5cdFx0XHQkKCBvLmFwcGVuZFRvICE9PSBcInBhcmVudFwiID9cblx0XHRcdFx0by5hcHBlbmRUbyA6XG5cdFx0XHRcdHRoaXMuY3VycmVudEl0ZW1bIDAgXS5wYXJlbnROb2RlIClbIDAgXS5hcHBlbmRDaGlsZCggaGVscGVyWyAwIF0gKTtcblx0XHR9XG5cblx0XHRpZiAoIGhlbHBlclsgMCBdID09PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHR0aGlzLl9zdG9yZWRDU1MgPSB7XG5cdFx0XHRcdHdpZHRoOiB0aGlzLmN1cnJlbnRJdGVtWyAwIF0uc3R5bGUud2lkdGgsXG5cdFx0XHRcdGhlaWdodDogdGhpcy5jdXJyZW50SXRlbVsgMCBdLnN0eWxlLmhlaWdodCxcblx0XHRcdFx0cG9zaXRpb246IHRoaXMuY3VycmVudEl0ZW0uY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdFx0dG9wOiB0aGlzLmN1cnJlbnRJdGVtLmNzcyggXCJ0b3BcIiApLFxuXHRcdFx0XHRsZWZ0OiB0aGlzLmN1cnJlbnRJdGVtLmNzcyggXCJsZWZ0XCIgKVxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHRpZiAoICFoZWxwZXJbIDAgXS5zdHlsZS53aWR0aCB8fCBvLmZvcmNlSGVscGVyU2l6ZSApIHtcblx0XHRcdGhlbHBlci53aWR0aCggdGhpcy5jdXJyZW50SXRlbS53aWR0aCgpICk7XG5cdFx0fVxuXHRcdGlmICggIWhlbHBlclsgMCBdLnN0eWxlLmhlaWdodCB8fCBvLmZvcmNlSGVscGVyU2l6ZSApIHtcblx0XHRcdGhlbHBlci5oZWlnaHQoIHRoaXMuY3VycmVudEl0ZW0uaGVpZ2h0KCkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaGVscGVyO1xuXG5cdH0sXG5cblx0X2FkanVzdE9mZnNldEZyb21IZWxwZXI6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0aWYgKCB0eXBlb2Ygb2JqID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0b2JqID0gb2JqLnNwbGl0KCBcIiBcIiApO1xuXHRcdH1cblx0XHRpZiAoICQuaXNBcnJheSggb2JqICkgKSB7XG5cdFx0XHRvYmogPSB7IGxlZnQ6ICtvYmpbIDAgXSwgdG9wOiArb2JqWyAxIF0gfHwgMCB9O1xuXHRcdH1cblx0XHRpZiAoIFwibGVmdFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPSBvYmoubGVmdCArIHRoaXMubWFyZ2lucy5sZWZ0O1xuXHRcdH1cblx0XHRpZiAoIFwicmlnaHRcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0ID0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIG9iai5yaWdodCArIHRoaXMubWFyZ2lucy5sZWZ0O1xuXHRcdH1cblx0XHRpZiAoIFwidG9wXCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wID0gb2JqLnRvcCArIHRoaXMubWFyZ2lucy50b3A7XG5cdFx0fVxuXHRcdGlmICggXCJib3R0b21cIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgPSB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIG9iai5ib3R0b20gKyB0aGlzLm1hcmdpbnMudG9wO1xuXHRcdH1cblx0fSxcblxuXHRfZ2V0UGFyZW50T2Zmc2V0OiBmdW5jdGlvbigpIHtcblxuXHRcdC8vR2V0IHRoZSBvZmZzZXRQYXJlbnQgYW5kIGNhY2hlIGl0cyBwb3NpdGlvblxuXHRcdHRoaXMub2Zmc2V0UGFyZW50ID0gdGhpcy5oZWxwZXIub2Zmc2V0UGFyZW50KCk7XG5cdFx0dmFyIHBvID0gdGhpcy5vZmZzZXRQYXJlbnQub2Zmc2V0KCk7XG5cblx0XHQvLyBUaGlzIGlzIGEgc3BlY2lhbCBjYXNlIHdoZXJlIHdlIG5lZWQgdG8gbW9kaWZ5IGEgb2Zmc2V0IGNhbGN1bGF0ZWQgb24gc3RhcnQsIHNpbmNlIHRoZVxuXHRcdC8vIGZvbGxvd2luZyBoYXBwZW5lZDpcblx0XHQvLyAxLiBUaGUgcG9zaXRpb24gb2YgdGhlIGhlbHBlciBpcyBhYnNvbHV0ZSwgc28gaXQncyBwb3NpdGlvbiBpcyBjYWxjdWxhdGVkIGJhc2VkIG9uIHRoZVxuXHRcdC8vIG5leHQgcG9zaXRpb25lZCBwYXJlbnRcblx0XHQvLyAyLiBUaGUgYWN0dWFsIG9mZnNldCBwYXJlbnQgaXMgYSBjaGlsZCBvZiB0aGUgc2Nyb2xsIHBhcmVudCwgYW5kIHRoZSBzY3JvbGwgcGFyZW50IGlzbid0XG5cdFx0Ly8gdGhlIGRvY3VtZW50LCB3aGljaCBtZWFucyB0aGF0IHRoZSBzY3JvbGwgaXMgaW5jbHVkZWQgaW4gdGhlIGluaXRpYWwgY2FsY3VsYXRpb24gb2YgdGhlXG5cdFx0Ly8gb2Zmc2V0IG9mIHRoZSBwYXJlbnQsIGFuZCBuZXZlciByZWNhbGN1bGF0ZWQgdXBvbiBkcmFnXG5cdFx0aWYgKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImFic29sdXRlXCIgJiYgdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdCQuY29udGFpbnMoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0sIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApIHtcblx0XHRcdHBvLmxlZnQgKz0gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpO1xuXHRcdFx0cG8udG9wICs9IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpO1xuXHRcdH1cblxuXHRcdC8vIFRoaXMgbmVlZHMgdG8gYmUgYWN0dWFsbHkgZG9uZSBmb3IgYWxsIGJyb3dzZXJzLCBzaW5jZSBwYWdlWC9wYWdlWSBpbmNsdWRlcyB0aGlzXG5cdFx0Ly8gaW5mb3JtYXRpb24gd2l0aCBhbiB1Z2x5IElFIGZpeFxuXHRcdGlmICggdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSA9PT0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkgfHxcblx0XHRcdFx0KCB0aGlzLm9mZnNldFBhcmVudFsgMCBdLnRhZ05hbWUgJiZcblx0XHRcdFx0dGhpcy5vZmZzZXRQYXJlbnRbIDAgXS50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiaHRtbFwiICYmICQudWkuaWUgKSApIHtcblx0XHRcdHBvID0geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiBwby50b3AgKyAoIHBhcnNlSW50KCB0aGlzLm9mZnNldFBhcmVudC5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdGxlZnQ6IHBvLmxlZnQgKyAoIHBhcnNlSW50KCB0aGlzLm9mZnNldFBhcmVudC5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKSwgMTAgKSB8fCAwIClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2dldFJlbGF0aXZlT2Zmc2V0OiBmdW5jdGlvbigpIHtcblxuXHRcdGlmICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJyZWxhdGl2ZVwiICkge1xuXHRcdFx0dmFyIHAgPSB0aGlzLmN1cnJlbnRJdGVtLnBvc2l0aW9uKCk7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHR0b3A6IHAudG9wIC0gKCBwYXJzZUludCggdGhpcy5oZWxwZXIuY3NzKCBcInRvcFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKSxcblx0XHRcdFx0bGVmdDogcC5sZWZ0IC0gKCBwYXJzZUludCggdGhpcy5oZWxwZXIuY3NzKCBcImxlZnRcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpXG5cdFx0XHR9O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblx0XHR9XG5cblx0fSxcblxuXHRfY2FjaGVNYXJnaW5zOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm1hcmdpbnMgPSB7XG5cdFx0XHRsZWZ0OiAoIHBhcnNlSW50KCB0aGlzLmN1cnJlbnRJdGVtLmNzcyggXCJtYXJnaW5MZWZ0XCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHR0b3A6ICggcGFyc2VJbnQoIHRoaXMuY3VycmVudEl0ZW0uY3NzKCBcIm1hcmdpblRvcFwiICksIDEwICkgfHwgMCApXG5cdFx0fTtcblx0fSxcblxuXHRfY2FjaGVIZWxwZXJQcm9wb3J0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucyA9IHtcblx0XHRcdHdpZHRoOiB0aGlzLmhlbHBlci5vdXRlcldpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IHRoaXMuaGVscGVyLm91dGVySGVpZ2h0KClcblx0XHR9O1xuXHR9LFxuXG5cdF9zZXRDb250YWlubWVudDogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgY2UsIGNvLCBvdmVyLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucztcblx0XHRpZiAoIG8uY29udGFpbm1lbnQgPT09IFwicGFyZW50XCIgKSB7XG5cdFx0XHRvLmNvbnRhaW5tZW50ID0gdGhpcy5oZWxwZXJbIDAgXS5wYXJlbnROb2RlO1xuXHRcdH1cblx0XHRpZiAoIG8uY29udGFpbm1lbnQgPT09IFwiZG9jdW1lbnRcIiB8fCBvLmNvbnRhaW5tZW50ID09PSBcIndpbmRvd1wiICkge1xuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IFtcblx0XHRcdFx0MCAtIHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgLSB0aGlzLm9mZnNldC5wYXJlbnQubGVmdCxcblx0XHRcdFx0MCAtIHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAtIHRoaXMub2Zmc2V0LnBhcmVudC50b3AsXG5cdFx0XHRcdG8uY29udGFpbm1lbnQgPT09IFwiZG9jdW1lbnRcIiA/XG5cdFx0XHRcdFx0dGhpcy5kb2N1bWVudC53aWR0aCgpIDpcblx0XHRcdFx0XHR0aGlzLndpbmRvdy53aWR0aCgpIC0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0XHQoIG8uY29udGFpbm1lbnQgPT09IFwiZG9jdW1lbnRcIiA/XG5cdFx0XHRcdFx0KCB0aGlzLmRvY3VtZW50LmhlaWdodCgpIHx8IGRvY3VtZW50LmJvZHkucGFyZW50Tm9kZS5zY3JvbGxIZWlnaHQgKSA6XG5cdFx0XHRcdFx0dGhpcy53aW5kb3cuaGVpZ2h0KCkgfHwgdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkucGFyZW50Tm9kZS5zY3JvbGxIZWlnaHRcblx0XHRcdFx0KSAtIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gdGhpcy5tYXJnaW5zLnRvcFxuXHRcdFx0XTtcblx0XHR9XG5cblx0XHRpZiAoICEoIC9eKGRvY3VtZW50fHdpbmRvd3xwYXJlbnQpJC8gKS50ZXN0KCBvLmNvbnRhaW5tZW50ICkgKSB7XG5cdFx0XHRjZSA9ICQoIG8uY29udGFpbm1lbnQgKVsgMCBdO1xuXHRcdFx0Y28gPSAkKCBvLmNvbnRhaW5tZW50ICkub2Zmc2V0KCk7XG5cdFx0XHRvdmVyID0gKCAkKCBjZSApLmNzcyggXCJvdmVyZmxvd1wiICkgIT09IFwiaGlkZGVuXCIgKTtcblxuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IFtcblx0XHRcdFx0Y28ubGVmdCArICggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJwYWRkaW5nTGVmdFwiICksIDEwICkgfHwgMCApIC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRcdGNvLnRvcCArICggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcInBhZGRpbmdUb3BcIiApLCAxMCApIHx8IDAgKSAtIHRoaXMubWFyZ2lucy50b3AsXG5cdFx0XHRcdGNvLmxlZnQgKyAoIG92ZXIgPyBNYXRoLm1heCggY2Uuc2Nyb2xsV2lkdGgsIGNlLm9mZnNldFdpZHRoICkgOiBjZS5vZmZzZXRXaWR0aCApIC1cblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwicGFkZGluZ1JpZ2h0XCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdFx0Y28udG9wICsgKCBvdmVyID8gTWF0aC5tYXgoIGNlLnNjcm9sbEhlaWdodCwgY2Uub2Zmc2V0SGVpZ2h0ICkgOiBjZS5vZmZzZXRIZWlnaHQgKSAtXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwicGFkZGluZ0JvdHRvbVwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIHRoaXMubWFyZ2lucy50b3Bcblx0XHRcdF07XG5cdFx0fVxuXG5cdH0sXG5cblx0X2NvbnZlcnRQb3NpdGlvblRvOiBmdW5jdGlvbiggZCwgcG9zICkge1xuXG5cdFx0aWYgKCAhcG9zICkge1xuXHRcdFx0cG9zID0gdGhpcy5wb3NpdGlvbjtcblx0XHR9XG5cdFx0dmFyIG1vZCA9IGQgPT09IFwiYWJzb2x1dGVcIiA/IDEgOiAtMSxcblx0XHRcdHNjcm9sbCA9IHRoaXMuY3NzUG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiAmJlxuXHRcdFx0XHQhKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0JC5jb250YWlucyggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSwgdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkgP1xuXHRcdFx0XHRcdHRoaXMub2Zmc2V0UGFyZW50IDpcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudCxcblx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPSAoIC8oaHRtbHxib2R5KS9pICkudGVzdCggc2Nyb2xsWyAwIF0udGFnTmFtZSApO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwb3MudG9wXHQrXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAqIG1vZCArXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LnRvcCAqIG1vZCAtXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKSA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHNjcm9sbC5zY3JvbGxUb3AoKSApICkgKiBtb2QgKVxuXHRcdFx0KSxcblx0XHRcdGxlZnQ6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cG9zLmxlZnQgK1xuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0ICogbW9kICtcblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQubGVmdCAqIG1vZFx0LVxuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpIDogc2Nyb2xsSXNSb290Tm9kZSA/IDAgOlxuXHRcdFx0XHRcdHNjcm9sbC5zY3JvbGxMZWZ0KCkgKSAqIG1vZCApXG5cdFx0XHQpXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9nZW5lcmF0ZVBvc2l0aW9uOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgdG9wLCBsZWZ0LFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHBhZ2VYID0gZXZlbnQucGFnZVgsXG5cdFx0XHRwYWdlWSA9IGV2ZW50LnBhZ2VZLFxuXHRcdFx0c2Nyb2xsID0gdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiICYmXG5cdFx0XHRcdCEoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHQkLmNvbnRhaW5zKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLCB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSA/XG5cdFx0XHRcdFx0dGhpcy5vZmZzZXRQYXJlbnQgOlxuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50LFxuXHRcdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID0gKCAvKGh0bWx8Ym9keSkvaSApLnRlc3QoIHNjcm9sbFsgMCBdLnRhZ05hbWUgKTtcblxuXHRcdC8vIFRoaXMgaXMgYW5vdGhlciB2ZXJ5IHdlaXJkIHNwZWNpYWwgY2FzZSB0aGF0IG9ubHkgaGFwcGVucyBmb3IgcmVsYXRpdmUgZWxlbWVudHM6XG5cdFx0Ly8gMS4gSWYgdGhlIGNzcyBwb3NpdGlvbiBpcyByZWxhdGl2ZVxuXHRcdC8vIDIuIGFuZCB0aGUgc2Nyb2xsIHBhcmVudCBpcyB0aGUgZG9jdW1lbnQgb3Igc2ltaWxhciB0byB0aGUgb2Zmc2V0IHBhcmVudFxuXHRcdC8vIHdlIGhhdmUgdG8gcmVmcmVzaCB0aGUgcmVsYXRpdmUgb2Zmc2V0IGR1cmluZyB0aGUgc2Nyb2xsIHNvIHRoZXJlIGFyZSBubyBqdW1wc1xuXHRcdGlmICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJyZWxhdGl2ZVwiICYmICEoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZSA9IHRoaXMuX2dldFJlbGF0aXZlT2Zmc2V0KCk7XG5cdFx0fVxuXG5cdFx0Lypcblx0XHQgKiAtIFBvc2l0aW9uIGNvbnN0cmFpbmluZyAtXG5cdFx0ICogQ29uc3RyYWluIHRoZSBwb3NpdGlvbiB0byBhIG1peCBvZiBncmlkLCBjb250YWlubWVudC5cblx0XHQgKi9cblxuXHRcdGlmICggdGhpcy5vcmlnaW5hbFBvc2l0aW9uICkgeyAvL0lmIHdlIGFyZSBub3QgZHJhZ2dpbmcgeWV0LCB3ZSB3b24ndCBjaGVjayBmb3Igb3B0aW9uc1xuXG5cdFx0XHRpZiAoIHRoaXMuY29udGFpbm1lbnQgKSB7XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0IDwgdGhpcy5jb250YWlubWVudFsgMCBdICkge1xuXHRcdFx0XHRcdHBhZ2VYID0gdGhpcy5jb250YWlubWVudFsgMCBdICsgdGhpcy5vZmZzZXQuY2xpY2subGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wIDwgdGhpcy5jb250YWlubWVudFsgMSBdICkge1xuXHRcdFx0XHRcdHBhZ2VZID0gdGhpcy5jb250YWlubWVudFsgMSBdICsgdGhpcy5vZmZzZXQuY2xpY2sudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID4gdGhpcy5jb250YWlubWVudFsgMiBdICkge1xuXHRcdFx0XHRcdHBhZ2VYID0gdGhpcy5jb250YWlubWVudFsgMiBdICsgdGhpcy5vZmZzZXQuY2xpY2subGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID4gdGhpcy5jb250YWlubWVudFsgMyBdICkge1xuXHRcdFx0XHRcdHBhZ2VZID0gdGhpcy5jb250YWlubWVudFsgMyBdICsgdGhpcy5vZmZzZXQuY2xpY2sudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggby5ncmlkICkge1xuXHRcdFx0XHR0b3AgPSB0aGlzLm9yaWdpbmFsUGFnZVkgKyBNYXRoLnJvdW5kKCAoIHBhZ2VZIC0gdGhpcy5vcmlnaW5hbFBhZ2VZICkgL1xuXHRcdFx0XHRcdG8uZ3JpZFsgMSBdICkgKiBvLmdyaWRbIDEgXTtcblx0XHRcdFx0cGFnZVkgPSB0aGlzLmNvbnRhaW5tZW50ID9cblx0XHRcdFx0XHQoICggdG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID49IHRoaXMuY29udGFpbm1lbnRbIDEgXSAmJlxuXHRcdFx0XHRcdFx0dG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wIDw9IHRoaXMuY29udGFpbm1lbnRbIDMgXSApID9cblx0XHRcdFx0XHRcdFx0dG9wIDpcblx0XHRcdFx0XHRcdFx0KCAoIHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+PSB0aGlzLmNvbnRhaW5tZW50WyAxIF0gKSA/XG5cdFx0XHRcdFx0XHRcdFx0dG9wIC0gby5ncmlkWyAxIF0gOiB0b3AgKyBvLmdyaWRbIDEgXSApICkgOlxuXHRcdFx0XHRcdFx0XHRcdHRvcDtcblxuXHRcdFx0XHRsZWZ0ID0gdGhpcy5vcmlnaW5hbFBhZ2VYICsgTWF0aC5yb3VuZCggKCBwYWdlWCAtIHRoaXMub3JpZ2luYWxQYWdlWCApIC9cblx0XHRcdFx0XHRvLmdyaWRbIDAgXSApICogby5ncmlkWyAwIF07XG5cdFx0XHRcdHBhZ2VYID0gdGhpcy5jb250YWlubWVudCA/XG5cdFx0XHRcdFx0KCAoIGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID49IHRoaXMuY29udGFpbm1lbnRbIDAgXSAmJlxuXHRcdFx0XHRcdFx0bGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPD0gdGhpcy5jb250YWlubWVudFsgMiBdICkgP1xuXHRcdFx0XHRcdFx0XHRsZWZ0IDpcblx0XHRcdFx0XHRcdFx0KCAoIGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID49IHRoaXMuY29udGFpbm1lbnRbIDAgXSApID9cblx0XHRcdFx0XHRcdFx0XHRsZWZ0IC0gby5ncmlkWyAwIF0gOiBsZWZ0ICsgby5ncmlkWyAwIF0gKSApIDpcblx0XHRcdFx0XHRcdFx0XHRsZWZ0O1xuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwYWdlWSAtXG5cblx0XHRcdFx0Ly8gQ2xpY2sgb2Zmc2V0IChyZWxhdGl2ZSB0byB0aGUgZWxlbWVudClcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wIC1cblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUudG9wIC1cblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQudG9wICtcblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpIDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogc2Nyb2xsLnNjcm9sbFRvcCgpICkgKSApXG5cdFx0XHQpLFxuXHRcdFx0bGVmdDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwYWdlWCAtXG5cblx0XHRcdFx0Ly8gQ2xpY2sgb2Zmc2V0IChyZWxhdGl2ZSB0byB0aGUgZWxlbWVudClcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCAtXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgLVxuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0ICtcblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKSA6XG5cdFx0XHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA/IDAgOiBzY3JvbGwuc2Nyb2xsTGVmdCgpICkgKVxuXHRcdFx0KVxuXHRcdH07XG5cblx0fSxcblxuXHRfcmVhcnJhbmdlOiBmdW5jdGlvbiggZXZlbnQsIGksIGEsIGhhcmRSZWZyZXNoICkge1xuXG5cdFx0YSA/IGFbIDAgXS5hcHBlbmRDaGlsZCggdGhpcy5wbGFjZWhvbGRlclsgMCBdICkgOlxuXHRcdFx0aS5pdGVtWyAwIF0ucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoIHRoaXMucGxhY2Vob2xkZXJbIDAgXSxcblx0XHRcdFx0KCB0aGlzLmRpcmVjdGlvbiA9PT0gXCJkb3duXCIgPyBpLml0ZW1bIDAgXSA6IGkuaXRlbVsgMCBdLm5leHRTaWJsaW5nICkgKTtcblxuXHRcdC8vVmFyaW91cyB0aGluZ3MgZG9uZSBoZXJlIHRvIGltcHJvdmUgdGhlIHBlcmZvcm1hbmNlOlxuXHRcdC8vIDEuIHdlIGNyZWF0ZSBhIHNldFRpbWVvdXQsIHRoYXQgY2FsbHMgcmVmcmVzaFBvc2l0aW9uc1xuXHRcdC8vIDIuIG9uIHRoZSBpbnN0YW5jZSwgd2UgaGF2ZSBhIGNvdW50ZXIgdmFyaWFibGUsIHRoYXQgZ2V0J3MgaGlnaGVyIGFmdGVyIGV2ZXJ5IGFwcGVuZFxuXHRcdC8vIDMuIG9uIHRoZSBsb2NhbCBzY29wZSwgd2UgY29weSB0aGUgY291bnRlciB2YXJpYWJsZSwgYW5kIGNoZWNrIGluIHRoZSB0aW1lb3V0LFxuXHRcdC8vIGlmIGl0J3Mgc3RpbGwgdGhlIHNhbWVcblx0XHQvLyA0LiB0aGlzIGxldHMgb25seSB0aGUgbGFzdCBhZGRpdGlvbiB0byB0aGUgdGltZW91dCBzdGFjayB0aHJvdWdoXG5cdFx0dGhpcy5jb3VudGVyID0gdGhpcy5jb3VudGVyID8gKyt0aGlzLmNvdW50ZXIgOiAxO1xuXHRcdHZhciBjb3VudGVyID0gdGhpcy5jb3VudGVyO1xuXG5cdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCBjb3VudGVyID09PSB0aGlzLmNvdW50ZXIgKSB7XG5cblx0XHRcdFx0Ly9QcmVjb21wdXRlIGFmdGVyIGVhY2ggRE9NIGluc2VydGlvbiwgTk9UIG9uIG1vdXNlbW92ZVxuXHRcdFx0XHR0aGlzLnJlZnJlc2hQb3NpdGlvbnMoICFoYXJkUmVmcmVzaCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHR9LFxuXG5cdF9jbGVhcjogZnVuY3Rpb24oIGV2ZW50LCBub1Byb3BhZ2F0aW9uICkge1xuXG5cdFx0dGhpcy5yZXZlcnRpbmcgPSBmYWxzZTtcblxuXHRcdC8vIFdlIGRlbGF5IGFsbCBldmVudHMgdGhhdCBoYXZlIHRvIGJlIHRyaWdnZXJlZCB0byBhZnRlciB0aGUgcG9pbnQgd2hlcmUgdGhlIHBsYWNlaG9sZGVyXG5cdFx0Ly8gaGFzIGJlZW4gcmVtb3ZlZCBhbmQgZXZlcnl0aGluZyBlbHNlIG5vcm1hbGl6ZWQgYWdhaW5cblx0XHR2YXIgaSxcblx0XHRcdGRlbGF5ZWRUcmlnZ2VycyA9IFtdO1xuXG5cdFx0Ly8gV2UgZmlyc3QgaGF2ZSB0byB1cGRhdGUgdGhlIGRvbSBwb3NpdGlvbiBvZiB0aGUgYWN0dWFsIGN1cnJlbnRJdGVtXG5cdFx0Ly8gTm90ZTogZG9uJ3QgZG8gaXQgaWYgdGhlIGN1cnJlbnQgaXRlbSBpcyBhbHJlYWR5IHJlbW92ZWQgKGJ5IGEgdXNlciksIG9yIGl0IGdldHNcblx0XHQvLyByZWFwcGVuZGVkIChzZWUgIzQwODgpXG5cdFx0aWYgKCAhdGhpcy5fbm9GaW5hbFNvcnQgJiYgdGhpcy5jdXJyZW50SXRlbS5wYXJlbnQoKS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLnBsYWNlaG9sZGVyLmJlZm9yZSggdGhpcy5jdXJyZW50SXRlbSApO1xuXHRcdH1cblx0XHR0aGlzLl9ub0ZpbmFsU29ydCA9IG51bGw7XG5cblx0XHRpZiAoIHRoaXMuaGVscGVyWyAwIF0gPT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdGZvciAoIGkgaW4gdGhpcy5fc3RvcmVkQ1NTICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuX3N0b3JlZENTU1sgaSBdID09PSBcImF1dG9cIiB8fCB0aGlzLl9zdG9yZWRDU1NbIGkgXSA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdFx0XHR0aGlzLl9zdG9yZWRDU1NbIGkgXSA9IFwiXCI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuY3VycmVudEl0ZW0uY3NzKCB0aGlzLl9zdG9yZWRDU1MgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmN1cnJlbnRJdGVtLCBcInVpLXNvcnRhYmxlLWhlbHBlclwiICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuY3VycmVudEl0ZW0uc2hvdygpO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5mcm9tT3V0c2lkZSAmJiAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX3RyaWdnZXIoIFwicmVjZWl2ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzLmZyb21PdXRzaWRlICkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdFx0aWYgKCAoIHRoaXMuZnJvbU91dHNpZGUgfHxcblx0XHRcdFx0dGhpcy5kb21Qb3NpdGlvbi5wcmV2ICE9PVxuXHRcdFx0XHR0aGlzLmN1cnJlbnRJdGVtLnByZXYoKS5ub3QoIFwiLnVpLXNvcnRhYmxlLWhlbHBlclwiIClbIDAgXSB8fFxuXHRcdFx0XHR0aGlzLmRvbVBvc2l0aW9uLnBhcmVudCAhPT0gdGhpcy5jdXJyZW50SXRlbS5wYXJlbnQoKVsgMCBdICkgJiYgIW5vUHJvcGFnYXRpb24gKSB7XG5cblx0XHRcdC8vIFRyaWdnZXIgdXBkYXRlIGNhbGxiYWNrIGlmIHRoZSBET00gcG9zaXRpb24gaGFzIGNoYW5nZWRcblx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX3RyaWdnZXIoIFwidXBkYXRlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdC8vIENoZWNrIGlmIHRoZSBpdGVtcyBDb250YWluZXIgaGFzIENoYW5nZWQgYW5kIHRyaWdnZXIgYXBwcm9wcmlhdGVcblx0XHQvLyBldmVudHMuXG5cdFx0aWYgKCB0aGlzICE9PSB0aGlzLmN1cnJlbnRDb250YWluZXIgKSB7XG5cdFx0XHRpZiAoICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdHRoaXMuX3RyaWdnZXIoIFwicmVtb3ZlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCAoIGZ1bmN0aW9uKCBjICkge1xuXHRcdFx0XHRcdHJldHVybiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0XHRjLl90cmlnZ2VyKCBcInJlY2VpdmVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0fSApLmNhbGwoIHRoaXMsIHRoaXMuY3VycmVudENvbnRhaW5lciApICk7XG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCAoIGZ1bmN0aW9uKCBjICkge1xuXHRcdFx0XHRcdHJldHVybiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0XHRjLl90cmlnZ2VyKCBcInVwZGF0ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9ICkuY2FsbCggdGhpcywgdGhpcy5jdXJyZW50Q29udGFpbmVyICkgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL1Bvc3QgZXZlbnRzIHRvIGNvbnRhaW5lcnNcblx0XHRmdW5jdGlvbiBkZWxheUV2ZW50KCB0eXBlLCBpbnN0YW5jZSwgY29udGFpbmVyICkge1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0Y29udGFpbmVyLl90cmlnZ2VyKCB0eXBlLCBldmVudCwgaW5zdGFuY2UuX3VpSGFzaCggaW5zdGFuY2UgKSApO1xuXHRcdFx0fTtcblx0XHR9XG5cdFx0Zm9yICggaSA9IHRoaXMuY29udGFpbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdGlmICggIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCBkZWxheUV2ZW50KCBcImRlYWN0aXZhdGVcIiwgdGhpcywgdGhpcy5jb250YWluZXJzWyBpIF0gKSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCB0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyICkge1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggZGVsYXlFdmVudCggXCJvdXRcIiwgdGhpcywgdGhpcy5jb250YWluZXJzWyBpIF0gKSApO1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyID0gMDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL0RvIHdoYXQgd2FzIG9yaWdpbmFsbHkgaW4gcGx1Z2luc1xuXHRcdGlmICggdGhpcy5zdG9yZWRDdXJzb3IgKSB7XG5cdFx0XHR0aGlzLmRvY3VtZW50LmZpbmQoIFwiYm9keVwiICkuY3NzKCBcImN1cnNvclwiLCB0aGlzLnN0b3JlZEN1cnNvciApO1xuXHRcdFx0dGhpcy5zdG9yZWRTdHlsZXNoZWV0LnJlbW92ZSgpO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX3N0b3JlZE9wYWNpdHkgKSB7XG5cdFx0XHR0aGlzLmhlbHBlci5jc3MoIFwib3BhY2l0eVwiLCB0aGlzLl9zdG9yZWRPcGFjaXR5ICk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5fc3RvcmVkWkluZGV4ICkge1xuXHRcdFx0dGhpcy5oZWxwZXIuY3NzKCBcInpJbmRleFwiLCB0aGlzLl9zdG9yZWRaSW5kZXggPT09IFwiYXV0b1wiID8gXCJcIiA6IHRoaXMuX3N0b3JlZFpJbmRleCApO1xuXHRcdH1cblxuXHRcdHRoaXMuZHJhZ2dpbmcgPSBmYWxzZTtcblxuXHRcdGlmICggIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImJlZm9yZVN0b3BcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0fVxuXG5cdFx0Ly8kKHRoaXMucGxhY2Vob2xkZXJbMF0pLnJlbW92ZSgpOyB3b3VsZCBoYXZlIGJlZW4gdGhlIGpRdWVyeSB3YXkgLSB1bmZvcnR1bmF0ZWx5LFxuXHRcdC8vIGl0IHVuYmluZHMgQUxMIGV2ZW50cyBmcm9tIHRoZSBvcmlnaW5hbCBub2RlIVxuXHRcdHRoaXMucGxhY2Vob2xkZXJbIDAgXS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0gKTtcblxuXHRcdGlmICggIXRoaXMuY2FuY2VsSGVscGVyUmVtb3ZhbCApIHtcblx0XHRcdGlmICggdGhpcy5oZWxwZXJbIDAgXSAhPT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0XHR0aGlzLmhlbHBlci5yZW1vdmUoKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuaGVscGVyID0gbnVsbDtcblx0XHR9XG5cblx0XHRpZiAoICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0Zm9yICggaSA9IDA7IGkgPCBkZWxheWVkVHJpZ2dlcnMubGVuZ3RoOyBpKysgKSB7XG5cblx0XHRcdFx0Ly8gVHJpZ2dlciBhbGwgZGVsYXllZCBldmVudHNcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzWyBpIF0uY2FsbCggdGhpcywgZXZlbnQgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHR9XG5cblx0XHR0aGlzLmZyb21PdXRzaWRlID0gZmFsc2U7XG5cdFx0cmV0dXJuICF0aGlzLmNhbmNlbEhlbHBlclJlbW92YWw7XG5cblx0fSxcblxuXHRfdHJpZ2dlcjogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAkLldpZGdldC5wcm90b3R5cGUuX3RyaWdnZXIuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApID09PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuY2FuY2VsKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91aUhhc2g6IGZ1bmN0aW9uKCBfaW5zdCApIHtcblx0XHR2YXIgaW5zdCA9IF9pbnN0IHx8IHRoaXM7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGhlbHBlcjogaW5zdC5oZWxwZXIsXG5cdFx0XHRwbGFjZWhvbGRlcjogaW5zdC5wbGFjZWhvbGRlciB8fCAkKCBbXSApLFxuXHRcdFx0cG9zaXRpb246IGluc3QucG9zaXRpb24sXG5cdFx0XHRvcmlnaW5hbFBvc2l0aW9uOiBpbnN0Lm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRvZmZzZXQ6IGluc3QucG9zaXRpb25BYnMsXG5cdFx0XHRpdGVtOiBpbnN0LmN1cnJlbnRJdGVtLFxuXHRcdFx0c2VuZGVyOiBfaW5zdCA/IF9pbnN0LmVsZW1lbnQgOiBudWxsXG5cdFx0fTtcblx0fVxuXG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU3Bpbm5lciAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU3Bpbm5lclxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGJ1dHRvbnMgdG8gZWFzaWx5IGlucHV0IG51bWJlcnMgdmlhIHRoZSBrZXlib2FyZCBvciBtb3VzZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zcGlubmVyL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3NwaW5uZXIvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9zcGlubmVyLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG5mdW5jdGlvbiBzcGlubmVyTW9kaWZlciggZm4gKSB7XG5cdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJldmlvdXMgPSB0aGlzLmVsZW1lbnQudmFsKCk7XG5cdFx0Zm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdHRoaXMuX3JlZnJlc2goKTtcblx0XHRpZiAoIHByZXZpb3VzICE9PSB0aGlzLmVsZW1lbnQudmFsKCkgKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiICk7XG5cdFx0fVxuXHR9O1xufVxuXG4kLndpZGdldCggXCJ1aS5zcGlubmVyXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPGlucHV0PlwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJzcGluXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXNwaW5uZXJcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLXNwaW5uZXItZG93blwiOiBcInVpLWNvcm5lci1iclwiLFxuXHRcdFx0XCJ1aS1zcGlubmVyLXVwXCI6IFwidWktY29ybmVyLXRyXCJcblx0XHR9LFxuXHRcdGN1bHR1cmU6IG51bGwsXG5cdFx0aWNvbnM6IHtcblx0XHRcdGRvd246IFwidWktaWNvbi10cmlhbmdsZS0xLXNcIixcblx0XHRcdHVwOiBcInVpLWljb24tdHJpYW5nbGUtMS1uXCJcblx0XHR9LFxuXHRcdGluY3JlbWVudGFsOiB0cnVlLFxuXHRcdG1heDogbnVsbCxcblx0XHRtaW46IG51bGwsXG5cdFx0bnVtYmVyRm9ybWF0OiBudWxsLFxuXHRcdHBhZ2U6IDEwLFxuXHRcdHN0ZXA6IDEsXG5cblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0c3BpbjogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsXG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBoYW5kbGUgc3RyaW5nIHZhbHVlcyB0aGF0IG5lZWQgdG8gYmUgcGFyc2VkXG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcIm1heFwiLCB0aGlzLm9wdGlvbnMubWF4ICk7XG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcIm1pblwiLCB0aGlzLm9wdGlvbnMubWluICk7XG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcInN0ZXBcIiwgdGhpcy5vcHRpb25zLnN0ZXAgKTtcblxuXHRcdC8vIE9ubHkgZm9ybWF0IGlmIHRoZXJlIGlzIGEgdmFsdWUsIHByZXZlbnRzIHRoZSBmaWVsZCBmcm9tIGJlaW5nIG1hcmtlZFxuXHRcdC8vIGFzIGludmFsaWQgaW4gRmlyZWZveCwgc2VlICM5NTczLlxuXHRcdGlmICggdGhpcy52YWx1ZSgpICE9PSBcIlwiICkge1xuXG5cdFx0XHQvLyBGb3JtYXQgdGhlIHZhbHVlLCBidXQgZG9uJ3QgY29uc3RyYWluLlxuXHRcdFx0dGhpcy5fdmFsdWUoIHRoaXMuZWxlbWVudC52YWwoKSwgdHJ1ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX2RyYXcoKTtcblx0XHR0aGlzLl9vbiggdGhpcy5fZXZlbnRzICk7XG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXG5cdFx0Ly8gVHVybmluZyBvZmYgYXV0b2NvbXBsZXRlIHByZXZlbnRzIHRoZSBicm93c2VyIGZyb20gcmVtZW1iZXJpbmcgdGhlXG5cdFx0Ly8gdmFsdWUgd2hlbiBuYXZpZ2F0aW5nIHRocm91Z2ggaGlzdG9yeSwgc28gd2UgcmUtZW5hYmxlIGF1dG9jb21wbGV0ZVxuXHRcdC8vIGlmIHRoZSBwYWdlIGlzIHVubG9hZGVkIGJlZm9yZSB0aGUgd2lkZ2V0IGlzIGRlc3Ryb3llZC4gIzc3OTBcblx0XHR0aGlzLl9vbiggdGhpcy53aW5kb3csIHtcblx0XHRcdGJlZm9yZXVubG9hZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcImF1dG9jb21wbGV0ZVwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMuX3N1cGVyKCk7XG5cdFx0dmFyIGVsZW1lbnQgPSB0aGlzLmVsZW1lbnQ7XG5cblx0XHQkLmVhY2goIFsgXCJtaW5cIiwgXCJtYXhcIiwgXCJzdGVwXCIgXSwgZnVuY3Rpb24oIGksIG9wdGlvbiApIHtcblx0XHRcdHZhciB2YWx1ZSA9IGVsZW1lbnQuYXR0ciggb3B0aW9uICk7XG5cdFx0XHRpZiAoIHZhbHVlICE9IG51bGwgJiYgdmFsdWUubGVuZ3RoICkge1xuXHRcdFx0XHRvcHRpb25zWyBvcHRpb24gXSA9IHZhbHVlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHJldHVybiBvcHRpb25zO1xuXHR9LFxuXG5cdF9ldmVudHM6IHtcblx0XHRrZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRpZiAoIHRoaXMuX3N0YXJ0KCBldmVudCApICYmIHRoaXMuX2tleWRvd24oIGV2ZW50ICkgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRrZXl1cDogXCJfc3RvcFwiLFxuXHRcdGZvY3VzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMucHJldmlvdXMgPSB0aGlzLmVsZW1lbnQudmFsKCk7XG5cdFx0fSxcblx0XHRibHVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRpZiAoIHRoaXMuY2FuY2VsQmx1ciApIHtcblx0XHRcdFx0ZGVsZXRlIHRoaXMuY2FuY2VsQmx1cjtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9zdG9wKCk7XG5cdFx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdFx0XHRpZiAoIHRoaXMucHJldmlvdXMgIT09IHRoaXMuZWxlbWVudC52YWwoKSApIHtcblx0XHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdG1vdXNld2hlZWw6IGZ1bmN0aW9uKCBldmVudCwgZGVsdGEgKSB7XG5cdFx0XHRpZiAoICFkZWx0YSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhdGhpcy5zcGlubmluZyAmJiAhdGhpcy5fc3RhcnQoIGV2ZW50ICkgKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fc3BpbiggKCBkZWx0YSA+IDAgPyAxIDogLTEgKSAqIHRoaXMub3B0aW9ucy5zdGVwLCBldmVudCApO1xuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLm1vdXNld2hlZWxUaW1lciApO1xuXHRcdFx0dGhpcy5tb3VzZXdoZWVsVGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdGhpcy5zcGlubmluZyApIHtcblx0XHRcdFx0XHR0aGlzLl9zdG9wKCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LCAxMDAgKTtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fSxcblx0XHRcIm1vdXNlZG93biAudWktc3Bpbm5lci1idXR0b25cIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0dmFyIHByZXZpb3VzO1xuXG5cdFx0XHQvLyBXZSBuZXZlciB3YW50IHRoZSBidXR0b25zIHRvIGhhdmUgZm9jdXM7IHdoZW5ldmVyIHRoZSB1c2VyIGlzXG5cdFx0XHQvLyBpbnRlcmFjdGluZyB3aXRoIHRoZSBzcGlubmVyLCB0aGUgZm9jdXMgc2hvdWxkIGJlIG9uIHRoZSBpbnB1dC5cblx0XHRcdC8vIElmIHRoZSBpbnB1dCBpcyBmb2N1c2VkIHRoZW4gdGhpcy5wcmV2aW91cyBpcyBwcm9wZXJseSBzZXQgZnJvbVxuXHRcdFx0Ly8gd2hlbiB0aGUgaW5wdXQgZmlyc3QgcmVjZWl2ZWQgZm9jdXMuIElmIHRoZSBpbnB1dCBpcyBub3QgZm9jdXNlZFxuXHRcdFx0Ly8gdGhlbiB3ZSBuZWVkIHRvIHNldCB0aGlzLnByZXZpb3VzIGJhc2VkIG9uIHRoZSB2YWx1ZSBiZWZvcmUgc3Bpbm5pbmcuXG5cdFx0XHRwcmV2aW91cyA9IHRoaXMuZWxlbWVudFsgMCBdID09PSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSA/XG5cdFx0XHRcdHRoaXMucHJldmlvdXMgOiB0aGlzLmVsZW1lbnQudmFsKCk7XG5cdFx0XHRmdW5jdGlvbiBjaGVja0ZvY3VzKCkge1xuXHRcdFx0XHR2YXIgaXNBY3RpdmUgPSB0aGlzLmVsZW1lbnRbIDAgXSA9PT0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICk7XG5cdFx0XHRcdGlmICggIWlzQWN0aXZlICkge1xuXHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0XHR0aGlzLnByZXZpb3VzID0gcHJldmlvdXM7XG5cblx0XHRcdFx0XHQvLyBzdXBwb3J0OiBJRVxuXHRcdFx0XHRcdC8vIElFIHNldHMgZm9jdXMgYXN5bmNocm9ub3VzbHksIHNvIHdlIG5lZWQgdG8gY2hlY2sgaWYgZm9jdXNcblx0XHRcdFx0XHQvLyBtb3ZlZCBvZmYgb2YgdGhlIGlucHV0IGJlY2F1c2UgdGhlIHVzZXIgY2xpY2tlZCBvbiB0aGUgYnV0dG9uLlxuXHRcdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHRoaXMucHJldmlvdXMgPSBwcmV2aW91cztcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gRW5zdXJlIGZvY3VzIGlzIG9uIChvciBzdGF5cyBvbikgdGhlIHRleHQgZmllbGRcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRjaGVja0ZvY3VzLmNhbGwoIHRoaXMgKTtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUVcblx0XHRcdC8vIElFIGRvZXNuJ3QgcHJldmVudCBtb3ZpbmcgZm9jdXMgZXZlbiB3aXRoIGV2ZW50LnByZXZlbnREZWZhdWx0KClcblx0XHRcdC8vIHNvIHdlIHNldCBhIGZsYWcgdG8ga25vdyB3aGVuIHdlIHNob3VsZCBpZ25vcmUgdGhlIGJsdXIgZXZlbnRcblx0XHRcdC8vIGFuZCBjaGVjayAoYWdhaW4pIGlmIGZvY3VzIG1vdmVkIG9mZiBvZiB0aGUgaW5wdXQuXG5cdFx0XHR0aGlzLmNhbmNlbEJsdXIgPSB0cnVlO1xuXHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRkZWxldGUgdGhpcy5jYW5jZWxCbHVyO1xuXHRcdFx0XHRjaGVja0ZvY3VzLmNhbGwoIHRoaXMgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0aWYgKCB0aGlzLl9zdGFydCggZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCAkKCBldmVudC5jdXJyZW50VGFyZ2V0IClcblx0XHRcdFx0Lmhhc0NsYXNzKCBcInVpLXNwaW5uZXItdXBcIiApID8gMSA6IC0xLCBldmVudCApO1xuXHRcdH0sXG5cdFx0XCJtb3VzZXVwIC51aS1zcGlubmVyLWJ1dHRvblwiOiBcIl9zdG9wXCIsXG5cdFx0XCJtb3VzZWVudGVyIC51aS1zcGlubmVyLWJ1dHRvblwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdC8vIGJ1dHRvbiB3aWxsIGFkZCB1aS1zdGF0ZS1hY3RpdmUgaWYgbW91c2Ugd2FzIGRvd24gd2hpbGUgbW91c2VsZWF2ZSBhbmQga2VwdCBkb3duXG5cdFx0XHRpZiAoICEkKCBldmVudC5jdXJyZW50VGFyZ2V0ICkuaGFzQ2xhc3MoIFwidWktc3RhdGUtYWN0aXZlXCIgKSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuX3N0YXJ0KCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCAkKCBldmVudC5jdXJyZW50VGFyZ2V0IClcblx0XHRcdFx0Lmhhc0NsYXNzKCBcInVpLXNwaW5uZXItdXBcIiApID8gMSA6IC0xLCBldmVudCApO1xuXHRcdH0sXG5cblx0XHQvLyBUT0RPOiBkbyB3ZSByZWFsbHkgd2FudCB0byBjb25zaWRlciB0aGlzIGEgc3RvcD9cblx0XHQvLyBzaG91bGRuJ3Qgd2UganVzdCBzdG9wIHRoZSByZXBlYXRlciBhbmQgd2FpdCB1bnRpbCBtb3VzZXVwIGJlZm9yZVxuXHRcdC8vIHdlIHRyaWdnZXIgdGhlIHN0b3AgZXZlbnQ/XG5cdFx0XCJtb3VzZWxlYXZlIC51aS1zcGlubmVyLWJ1dHRvblwiOiBcIl9zdG9wXCJcblx0fSxcblxuXHQvLyBTdXBwb3J0IG1vYmlsZSBlbmhhbmNlZCBvcHRpb24gYW5kIG1ha2UgYmFja2NvbXBhdCBtb3JlIHNhbmVcblx0X2VuaGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMudWlTcGlubmVyID0gdGhpcy5lbGVtZW50XG5cdFx0XHQuYXR0ciggXCJhdXRvY29tcGxldGVcIiwgXCJvZmZcIiApXG5cdFx0XHQud3JhcCggXCI8c3Bhbj5cIiApXG5cdFx0XHQucGFyZW50KClcblxuXHRcdFx0XHQvLyBBZGQgYnV0dG9uc1xuXHRcdFx0XHQuYXBwZW5kKFxuXHRcdFx0XHRcdFwiPGE+PC9hPjxhPjwvYT5cIlxuXHRcdFx0XHQpO1xuXHR9LFxuXG5cdF9kcmF3OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9lbmhhbmNlKCk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aVNwaW5uZXIsIFwidWktc3Bpbm5lclwiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktc3Bpbm5lci1pbnB1dFwiICk7XG5cblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJyb2xlXCIsIFwic3BpbmJ1dHRvblwiICk7XG5cblx0XHQvLyBCdXR0b24gYmluZGluZ3Ncblx0XHR0aGlzLmJ1dHRvbnMgPSB0aGlzLnVpU3Bpbm5lci5jaGlsZHJlbiggXCJhXCIgKVxuXHRcdFx0LmF0dHIoIFwidGFiSW5kZXhcIiwgLTEgKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgdHJ1ZSApXG5cdFx0XHQuYnV0dG9uKCB7XG5cdFx0XHRcdGNsYXNzZXM6IHtcblx0XHRcdFx0XHRcInVpLWJ1dHRvblwiOiBcIlwiXG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHRcdC8vIFRPRE86IFJpZ2h0IG5vdyBidXR0b24gZG9lcyBub3Qgc3VwcG9ydCBjbGFzc2VzIHRoaXMgaXMgYWxyZWFkeSB1cGRhdGVkIGluIGJ1dHRvbiBQUlxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmJ1dHRvbnMsIFwidWktY29ybmVyLWFsbFwiICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5idXR0b25zLmZpcnN0KCksIFwidWktc3Bpbm5lci1idXR0b24gdWktc3Bpbm5lci11cFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYnV0dG9ucy5sYXN0KCksIFwidWktc3Bpbm5lci1idXR0b24gdWktc3Bpbm5lci1kb3duXCIgKTtcblx0XHR0aGlzLmJ1dHRvbnMuZmlyc3QoKS5idXR0b24oIHtcblx0XHRcdFwiaWNvblwiOiB0aGlzLm9wdGlvbnMuaWNvbnMudXAsXG5cdFx0XHRcInNob3dMYWJlbFwiOiBmYWxzZVxuXHRcdH0gKTtcblx0XHR0aGlzLmJ1dHRvbnMubGFzdCgpLmJ1dHRvbigge1xuXHRcdFx0XCJpY29uXCI6IHRoaXMub3B0aW9ucy5pY29ucy5kb3duLFxuXHRcdFx0XCJzaG93TGFiZWxcIjogZmFsc2Vcblx0XHR9ICk7XG5cblx0XHQvLyBJRSA2IGRvZXNuJ3QgdW5kZXJzdGFuZCBoZWlnaHQ6IDUwJSBmb3IgdGhlIGJ1dHRvbnNcblx0XHQvLyB1bmxlc3MgdGhlIHdyYXBwZXIgaGFzIGFuIGV4cGxpY2l0IGhlaWdodFxuXHRcdGlmICggdGhpcy5idXR0b25zLmhlaWdodCgpID4gTWF0aC5jZWlsKCB0aGlzLnVpU3Bpbm5lci5oZWlnaHQoKSAqIDAuNSApICYmXG5cdFx0XHRcdHRoaXMudWlTcGlubmVyLmhlaWdodCgpID4gMCApIHtcblx0XHRcdHRoaXMudWlTcGlubmVyLmhlaWdodCggdGhpcy51aVNwaW5uZXIuaGVpZ2h0KCkgKTtcblx0XHR9XG5cdH0sXG5cblx0X2tleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGtleUNvZGUgPSAkLnVpLmtleUNvZGU7XG5cblx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdGNhc2Uga2V5Q29kZS5VUDpcblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgMSwgZXZlbnQgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdGNhc2Uga2V5Q29kZS5ET1dOOlxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCAtMSwgZXZlbnQgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdGNhc2Uga2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCBvcHRpb25zLnBhZ2UsIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRjYXNlIGtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCAtb3B0aW9ucy5wYWdlLCBldmVudCApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9zdGFydDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMuc3Bpbm5pbmcgJiYgdGhpcy5fdHJpZ2dlciggXCJzdGFydFwiLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRpZiAoICF0aGlzLmNvdW50ZXIgKSB7XG5cdFx0XHR0aGlzLmNvdW50ZXIgPSAxO1xuXHRcdH1cblx0XHR0aGlzLnNwaW5uaW5nID0gdHJ1ZTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfcmVwZWF0OiBmdW5jdGlvbiggaSwgc3RlcHMsIGV2ZW50ICkge1xuXHRcdGkgPSBpIHx8IDUwMDtcblxuXHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdHRoaXMudGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9yZXBlYXQoIDQwLCBzdGVwcywgZXZlbnQgKTtcblx0XHR9LCBpICk7XG5cblx0XHR0aGlzLl9zcGluKCBzdGVwcyAqIHRoaXMub3B0aW9ucy5zdGVwLCBldmVudCApO1xuXHR9LFxuXG5cdF9zcGluOiBmdW5jdGlvbiggc3RlcCwgZXZlbnQgKSB7XG5cdFx0dmFyIHZhbHVlID0gdGhpcy52YWx1ZSgpIHx8IDA7XG5cblx0XHRpZiAoICF0aGlzLmNvdW50ZXIgKSB7XG5cdFx0XHR0aGlzLmNvdW50ZXIgPSAxO1xuXHRcdH1cblxuXHRcdHZhbHVlID0gdGhpcy5fYWRqdXN0VmFsdWUoIHZhbHVlICsgc3RlcCAqIHRoaXMuX2luY3JlbWVudCggdGhpcy5jb3VudGVyICkgKTtcblxuXHRcdGlmICggIXRoaXMuc3Bpbm5pbmcgfHwgdGhpcy5fdHJpZ2dlciggXCJzcGluXCIsIGV2ZW50LCB7IHZhbHVlOiB2YWx1ZSB9ICkgIT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5fdmFsdWUoIHZhbHVlICk7XG5cdFx0XHR0aGlzLmNvdW50ZXIrKztcblx0XHR9XG5cdH0sXG5cblx0X2luY3JlbWVudDogZnVuY3Rpb24oIGkgKSB7XG5cdFx0dmFyIGluY3JlbWVudGFsID0gdGhpcy5vcHRpb25zLmluY3JlbWVudGFsO1xuXG5cdFx0aWYgKCBpbmNyZW1lbnRhbCApIHtcblx0XHRcdHJldHVybiAkLmlzRnVuY3Rpb24oIGluY3JlbWVudGFsICkgP1xuXHRcdFx0XHRpbmNyZW1lbnRhbCggaSApIDpcblx0XHRcdFx0TWF0aC5mbG9vciggaSAqIGkgKiBpIC8gNTAwMDAgLSBpICogaSAvIDUwMCArIDE3ICogaSAvIDIwMCArIDEgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gMTtcblx0fSxcblxuXHRfcHJlY2lzaW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJlY2lzaW9uID0gdGhpcy5fcHJlY2lzaW9uT2YoIHRoaXMub3B0aW9ucy5zdGVwICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMubWluICE9PSBudWxsICkge1xuXHRcdFx0cHJlY2lzaW9uID0gTWF0aC5tYXgoIHByZWNpc2lvbiwgdGhpcy5fcHJlY2lzaW9uT2YoIHRoaXMub3B0aW9ucy5taW4gKSApO1xuXHRcdH1cblx0XHRyZXR1cm4gcHJlY2lzaW9uO1xuXHR9LFxuXG5cdF9wcmVjaXNpb25PZjogZnVuY3Rpb24oIG51bSApIHtcblx0XHR2YXIgc3RyID0gbnVtLnRvU3RyaW5nKCksXG5cdFx0XHRkZWNpbWFsID0gc3RyLmluZGV4T2YoIFwiLlwiICk7XG5cdFx0cmV0dXJuIGRlY2ltYWwgPT09IC0xID8gMCA6IHN0ci5sZW5ndGggLSBkZWNpbWFsIC0gMTtcblx0fSxcblxuXHRfYWRqdXN0VmFsdWU6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgYmFzZSwgYWJvdmVNaW4sXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIHdlJ3JlIGF0IGEgdmFsaWQgc3RlcFxuXHRcdC8vIC0gZmluZCBvdXQgd2hlcmUgd2UgYXJlIHJlbGF0aXZlIHRvIHRoZSBiYXNlIChtaW4gb3IgMClcblx0XHRiYXNlID0gb3B0aW9ucy5taW4gIT09IG51bGwgPyBvcHRpb25zLm1pbiA6IDA7XG5cdFx0YWJvdmVNaW4gPSB2YWx1ZSAtIGJhc2U7XG5cblx0XHQvLyAtIHJvdW5kIHRvIHRoZSBuZWFyZXN0IHN0ZXBcblx0XHRhYm92ZU1pbiA9IE1hdGgucm91bmQoIGFib3ZlTWluIC8gb3B0aW9ucy5zdGVwICkgKiBvcHRpb25zLnN0ZXA7XG5cblx0XHQvLyAtIHJvdW5kaW5nIGlzIGJhc2VkIG9uIDAsIHNvIGFkanVzdCBiYWNrIHRvIG91ciBiYXNlXG5cdFx0dmFsdWUgPSBiYXNlICsgYWJvdmVNaW47XG5cblx0XHQvLyBGaXggcHJlY2lzaW9uIGZyb20gYmFkIEpTIGZsb2F0aW5nIHBvaW50IG1hdGhcblx0XHR2YWx1ZSA9IHBhcnNlRmxvYXQoIHZhbHVlLnRvRml4ZWQoIHRoaXMuX3ByZWNpc2lvbigpICkgKTtcblxuXHRcdC8vIENsYW1wIHRoZSB2YWx1ZVxuXHRcdGlmICggb3B0aW9ucy5tYXggIT09IG51bGwgJiYgdmFsdWUgPiBvcHRpb25zLm1heCApIHtcblx0XHRcdHJldHVybiBvcHRpb25zLm1heDtcblx0XHR9XG5cdFx0aWYgKCBvcHRpb25zLm1pbiAhPT0gbnVsbCAmJiB2YWx1ZSA8IG9wdGlvbnMubWluICkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMubWluO1xuXHRcdH1cblxuXHRcdHJldHVybiB2YWx1ZTtcblx0fSxcblxuXHRfc3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMuc3Bpbm5pbmcgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLm1vdXNld2hlZWxUaW1lciApO1xuXHRcdHRoaXMuY291bnRlciA9IDA7XG5cdFx0dGhpcy5zcGlubmluZyA9IGZhbHNlO1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBwcmV2VmFsdWUsIGZpcnN0LCBsYXN0O1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiY3VsdHVyZVwiIHx8IGtleSA9PT0gXCJudW1iZXJGb3JtYXRcIiApIHtcblx0XHRcdHByZXZWYWx1ZSA9IHRoaXMuX3BhcnNlKCB0aGlzLmVsZW1lbnQudmFsKCkgKTtcblx0XHRcdHRoaXMub3B0aW9uc1sga2V5IF0gPSB2YWx1ZTtcblx0XHRcdHRoaXMuZWxlbWVudC52YWwoIHRoaXMuX2Zvcm1hdCggcHJldlZhbHVlICkgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJtYXhcIiB8fCBrZXkgPT09IFwibWluXCIgfHwga2V5ID09PSBcInN0ZXBcIiApIHtcblx0XHRcdGlmICggdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHR2YWx1ZSA9IHRoaXMuX3BhcnNlKCB2YWx1ZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAoIGtleSA9PT0gXCJpY29uc1wiICkge1xuXHRcdFx0Zmlyc3QgPSB0aGlzLmJ1dHRvbnMuZmlyc3QoKS5maW5kKCBcIi51aS1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBmaXJzdCwgbnVsbCwgdGhpcy5vcHRpb25zLmljb25zLnVwICk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggZmlyc3QsIG51bGwsIHZhbHVlLnVwICk7XG5cdFx0XHRsYXN0ID0gdGhpcy5idXR0b25zLmxhc3QoKS5maW5kKCBcIi51aS1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBsYXN0LCBudWxsLCB0aGlzLm9wdGlvbnMuaWNvbnMuZG93biApO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGxhc3QsIG51bGwsIHZhbHVlLmRvd24gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMudWlTcGlubmVyLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0XHR0aGlzLmVsZW1lbnQucHJvcCggXCJkaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdFx0dGhpcy5idXR0b25zLmJ1dHRvbiggdmFsdWUgPyBcImRpc2FibGVcIiA6IFwiZW5hYmxlXCIgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uczogc3Bpbm5lck1vZGlmZXIoIGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHRoaXMuX3N1cGVyKCBvcHRpb25zICk7XG5cdH0gKSxcblxuXHRfcGFyc2U6IGZ1bmN0aW9uKCB2YWwgKSB7XG5cdFx0aWYgKCB0eXBlb2YgdmFsID09PSBcInN0cmluZ1wiICYmIHZhbCAhPT0gXCJcIiApIHtcblx0XHRcdHZhbCA9IHdpbmRvdy5HbG9iYWxpemUgJiYgdGhpcy5vcHRpb25zLm51bWJlckZvcm1hdCA/XG5cdFx0XHRcdEdsb2JhbGl6ZS5wYXJzZUZsb2F0KCB2YWwsIDEwLCB0aGlzLm9wdGlvbnMuY3VsdHVyZSApIDogK3ZhbDtcblx0XHR9XG5cdFx0cmV0dXJuIHZhbCA9PT0gXCJcIiB8fCBpc05hTiggdmFsICkgPyBudWxsIDogdmFsO1xuXHR9LFxuXG5cdF9mb3JtYXQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRpZiAoIHZhbHVlID09PSBcIlwiICkge1xuXHRcdFx0cmV0dXJuIFwiXCI7XG5cdFx0fVxuXHRcdHJldHVybiB3aW5kb3cuR2xvYmFsaXplICYmIHRoaXMub3B0aW9ucy5udW1iZXJGb3JtYXQgP1xuXHRcdFx0R2xvYmFsaXplLmZvcm1hdCggdmFsdWUsIHRoaXMub3B0aW9ucy5udW1iZXJGb3JtYXQsIHRoaXMub3B0aW9ucy5jdWx0dXJlICkgOlxuXHRcdFx0dmFsdWU7XG5cdH0sXG5cblx0X3JlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCB7XG5cdFx0XHRcImFyaWEtdmFsdWVtaW5cIjogdGhpcy5vcHRpb25zLm1pbixcblx0XHRcdFwiYXJpYS12YWx1ZW1heFwiOiB0aGlzLm9wdGlvbnMubWF4LFxuXG5cdFx0XHQvLyBUT0RPOiB3aGF0IHNob3VsZCB3ZSBkbyB3aXRoIHZhbHVlcyB0aGF0IGNhbid0IGJlIHBhcnNlZD9cblx0XHRcdFwiYXJpYS12YWx1ZW5vd1wiOiB0aGlzLl9wYXJzZSggdGhpcy5lbGVtZW50LnZhbCgpIClcblx0XHR9ICk7XG5cdH0sXG5cblx0aXNWYWxpZDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHZhbHVlID0gdGhpcy52YWx1ZSgpO1xuXG5cdFx0Ly8gTnVsbCBpcyBpbnZhbGlkXG5cdFx0aWYgKCB2YWx1ZSA9PT0gbnVsbCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBJZiB2YWx1ZSBnZXRzIGFkanVzdGVkLCBpdCdzIGludmFsaWRcblx0XHRyZXR1cm4gdmFsdWUgPT09IHRoaXMuX2FkanVzdFZhbHVlKCB2YWx1ZSApO1xuXHR9LFxuXG5cdC8vIFVwZGF0ZSB0aGUgdmFsdWUgd2l0aG91dCB0cmlnZ2VyaW5nIGNoYW5nZVxuXHRfdmFsdWU6IGZ1bmN0aW9uKCB2YWx1ZSwgYWxsb3dBbnkgKSB7XG5cdFx0dmFyIHBhcnNlZDtcblx0XHRpZiAoIHZhbHVlICE9PSBcIlwiICkge1xuXHRcdFx0cGFyc2VkID0gdGhpcy5fcGFyc2UoIHZhbHVlICk7XG5cdFx0XHRpZiAoIHBhcnNlZCAhPT0gbnVsbCApIHtcblx0XHRcdFx0aWYgKCAhYWxsb3dBbnkgKSB7XG5cdFx0XHRcdFx0cGFyc2VkID0gdGhpcy5fYWRqdXN0VmFsdWUoIHBhcnNlZCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHZhbHVlID0gdGhpcy5fZm9ybWF0KCBwYXJzZWQgKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5lbGVtZW50LnZhbCggdmFsdWUgKTtcblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LnByb3AoIFwiZGlzYWJsZWRcIiwgZmFsc2UgKVxuXHRcdFx0LnJlbW92ZUF0dHIoIFwiYXV0b2NvbXBsZXRlIHJvbGUgYXJpYS12YWx1ZW1pbiBhcmlhLXZhbHVlbWF4IGFyaWEtdmFsdWVub3dcIiApO1xuXG5cdFx0dGhpcy51aVNwaW5uZXIucmVwbGFjZVdpdGgoIHRoaXMuZWxlbWVudCApO1xuXHR9LFxuXG5cdHN0ZXBVcDogc3Bpbm5lck1vZGlmZXIoIGZ1bmN0aW9uKCBzdGVwcyApIHtcblx0XHR0aGlzLl9zdGVwVXAoIHN0ZXBzICk7XG5cdH0gKSxcblx0X3N0ZXBVcDogZnVuY3Rpb24oIHN0ZXBzICkge1xuXHRcdGlmICggdGhpcy5fc3RhcnQoKSApIHtcblx0XHRcdHRoaXMuX3NwaW4oICggc3RlcHMgfHwgMSApICogdGhpcy5vcHRpb25zLnN0ZXAgKTtcblx0XHRcdHRoaXMuX3N0b3AoKTtcblx0XHR9XG5cdH0sXG5cblx0c3RlcERvd246IHNwaW5uZXJNb2RpZmVyKCBmdW5jdGlvbiggc3RlcHMgKSB7XG5cdFx0dGhpcy5fc3RlcERvd24oIHN0ZXBzICk7XG5cdH0gKSxcblx0X3N0ZXBEb3duOiBmdW5jdGlvbiggc3RlcHMgKSB7XG5cdFx0aWYgKCB0aGlzLl9zdGFydCgpICkge1xuXHRcdFx0dGhpcy5fc3BpbiggKCBzdGVwcyB8fCAxICkgKiAtdGhpcy5vcHRpb25zLnN0ZXAgKTtcblx0XHRcdHRoaXMuX3N0b3AoKTtcblx0XHR9XG5cdH0sXG5cblx0cGFnZVVwOiBzcGlubmVyTW9kaWZlciggZnVuY3Rpb24oIHBhZ2VzICkge1xuXHRcdHRoaXMuX3N0ZXBVcCggKCBwYWdlcyB8fCAxICkgKiB0aGlzLm9wdGlvbnMucGFnZSApO1xuXHR9ICksXG5cblx0cGFnZURvd246IHNwaW5uZXJNb2RpZmVyKCBmdW5jdGlvbiggcGFnZXMgKSB7XG5cdFx0dGhpcy5fc3RlcERvd24oICggcGFnZXMgfHwgMSApICogdGhpcy5vcHRpb25zLnBhZ2UgKTtcblx0fSApLFxuXG5cdHZhbHVlOiBmdW5jdGlvbiggbmV3VmFsICkge1xuXHRcdGlmICggIWFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fcGFyc2UoIHRoaXMuZWxlbWVudC52YWwoKSApO1xuXHRcdH1cblx0XHRzcGlubmVyTW9kaWZlciggdGhpcy5fdmFsdWUgKS5jYWxsKCB0aGlzLCBuZXdWYWwgKTtcblx0fSxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnVpU3Bpbm5lcjtcblx0fVxufSApO1xuXG4vLyBERVBSRUNBVEVEXG4vLyBUT0RPOiBzd2l0Y2ggcmV0dXJuIGJhY2sgdG8gd2lkZ2V0IGRlY2xhcmF0aW9uIGF0IHRvcCBvZiBmaWxlIHdoZW4gdGhpcyBpcyByZW1vdmVkXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBCYWNrY29tcGF0IGZvciBzcGlubmVyIGh0bWwgZXh0ZW5zaW9uIHBvaW50c1xuXHQkLndpZGdldCggXCJ1aS5zcGlubmVyXCIsICQudWkuc3Bpbm5lciwge1xuXHRcdF9lbmhhbmNlOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMudWlTcGlubmVyID0gdGhpcy5lbGVtZW50XG5cdFx0XHRcdC5hdHRyKCBcImF1dG9jb21wbGV0ZVwiLCBcIm9mZlwiIClcblx0XHRcdFx0LndyYXAoIHRoaXMuX3VpU3Bpbm5lckh0bWwoKSApXG5cdFx0XHRcdC5wYXJlbnQoKVxuXG5cdFx0XHRcdFx0Ly8gQWRkIGJ1dHRvbnNcblx0XHRcdFx0XHQuYXBwZW5kKCB0aGlzLl9idXR0b25IdG1sKCkgKTtcblx0XHR9LFxuXHRcdF91aVNwaW5uZXJIdG1sOiBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiBcIjxzcGFuPlwiO1xuXHRcdH0sXG5cblx0XHRfYnV0dG9uSHRtbDogZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gXCI8YT48L2E+PGE+PC9hPlwiO1xuXHRcdH1cblx0fSApO1xufVxuXG52YXIgd2lkZ2V0c1NwaW5uZXIgPSAkLnVpLnNwaW5uZXI7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgVGFicyAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogVGFic1xuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IFRyYW5zZm9ybXMgYSBzZXQgb2YgY29udGFpbmVyIGVsZW1lbnRzIGludG8gYSB0YWIgc3RydWN0dXJlLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3RhYnMvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vdGFicy9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3RhYnMuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLnRhYnNcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWxheTogMzAwLFxuXHRvcHRpb25zOiB7XG5cdFx0YWN0aXZlOiBudWxsLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktdGFic1wiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktdGFicy1uYXZcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLXRhYnMtcGFuZWxcIjogXCJ1aS1jb3JuZXItYm90dG9tXCIsXG5cdFx0XHRcInVpLXRhYnMtdGFiXCI6IFwidWktY29ybmVyLXRvcFwiXG5cdFx0fSxcblx0XHRjb2xsYXBzaWJsZTogZmFsc2UsXG5cdFx0ZXZlbnQ6IFwiY2xpY2tcIixcblx0XHRoZWlnaHRTdHlsZTogXCJjb250ZW50XCIsXG5cdFx0aGlkZTogbnVsbCxcblx0XHRzaG93OiBudWxsLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0YWN0aXZhdGU6IG51bGwsXG5cdFx0YmVmb3JlQWN0aXZhdGU6IG51bGwsXG5cdFx0YmVmb3JlTG9hZDogbnVsbCxcblx0XHRsb2FkOiBudWxsXG5cdH0sXG5cblx0X2lzTG9jYWw6ICggZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHJoYXNoID0gLyMuKiQvO1xuXG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBhbmNob3IgKSB7XG5cdFx0XHR2YXIgYW5jaG9yVXJsLCBsb2NhdGlvblVybDtcblxuXHRcdFx0YW5jaG9yVXJsID0gYW5jaG9yLmhyZWYucmVwbGFjZSggcmhhc2gsIFwiXCIgKTtcblx0XHRcdGxvY2F0aW9uVXJsID0gbG9jYXRpb24uaHJlZi5yZXBsYWNlKCByaGFzaCwgXCJcIiApO1xuXG5cdFx0XHQvLyBEZWNvZGluZyBtYXkgdGhyb3cgYW4gZXJyb3IgaWYgdGhlIFVSTCBpc24ndCBVVEYtOCAoIzk1MTgpXG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhbmNob3JVcmwgPSBkZWNvZGVVUklDb21wb25lbnQoIGFuY2hvclVybCApO1xuXHRcdFx0fSBjYXRjaCAoIGVycm9yICkge31cblx0XHRcdHRyeSB7XG5cdFx0XHRcdGxvY2F0aW9uVXJsID0gZGVjb2RlVVJJQ29tcG9uZW50KCBsb2NhdGlvblVybCApO1xuXHRcdFx0fSBjYXRjaCAoIGVycm9yICkge31cblxuXHRcdFx0cmV0dXJuIGFuY2hvci5oYXNoLmxlbmd0aCA+IDEgJiYgYW5jaG9yVXJsID09PSBsb2NhdGlvblVybDtcblx0XHR9O1xuXHR9ICkoKSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0dGhpcy5ydW5uaW5nID0gZmFsc2U7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS10YWJzXCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggXCJ1aS10YWJzLWNvbGxhcHNpYmxlXCIsIG51bGwsIG9wdGlvbnMuY29sbGFwc2libGUgKTtcblxuXHRcdHRoaXMuX3Byb2Nlc3NUYWJzKCk7XG5cdFx0b3B0aW9ucy5hY3RpdmUgPSB0aGlzLl9pbml0aWFsQWN0aXZlKCk7XG5cblx0XHQvLyBUYWtlIGRpc2FibGluZyB0YWJzIHZpYSBjbGFzcyBhdHRyaWJ1dGUgZnJvbSBIVE1MXG5cdFx0Ly8gaW50byBhY2NvdW50IGFuZCB1cGRhdGUgb3B0aW9uIHByb3Blcmx5LlxuXHRcdGlmICggJC5pc0FycmF5KCBvcHRpb25zLmRpc2FibGVkICkgKSB7XG5cdFx0XHRvcHRpb25zLmRpc2FibGVkID0gJC51bmlxdWUoIG9wdGlvbnMuZGlzYWJsZWQuY29uY2F0KFxuXHRcdFx0XHQkLm1hcCggdGhpcy50YWJzLmZpbHRlciggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApLCBmdW5jdGlvbiggbGkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoYXQudGFicy5pbmRleCggbGkgKTtcblx0XHRcdFx0fSApXG5cdFx0XHQpICkuc29ydCgpO1xuXHRcdH1cblxuXHRcdC8vIENoZWNrIGZvciBsZW5ndGggYXZvaWRzIGVycm9yIHdoZW4gaW5pdGlhbGl6aW5nIGVtcHR5IGxpc3Rcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5hY3RpdmUgIT09IGZhbHNlICYmIHRoaXMuYW5jaG9ycy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmFjdGl2ZSA9IHRoaXMuX2ZpbmRBY3RpdmUoIG9wdGlvbnMuYWN0aXZlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuYWN0aXZlID0gJCgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX3JlZnJlc2goKTtcblxuXHRcdGlmICggdGhpcy5hY3RpdmUubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5sb2FkKCBvcHRpb25zLmFjdGl2ZSApO1xuXHRcdH1cblx0fSxcblxuXHRfaW5pdGlhbEFjdGl2ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGFjdGl2ZSA9IHRoaXMub3B0aW9ucy5hY3RpdmUsXG5cdFx0XHRjb2xsYXBzaWJsZSA9IHRoaXMub3B0aW9ucy5jb2xsYXBzaWJsZSxcblx0XHRcdGxvY2F0aW9uSGFzaCA9IGxvY2F0aW9uLmhhc2guc3Vic3RyaW5nKCAxICk7XG5cblx0XHRpZiAoIGFjdGl2ZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0Ly8gY2hlY2sgdGhlIGZyYWdtZW50IGlkZW50aWZpZXIgaW4gdGhlIFVSTFxuXHRcdFx0aWYgKCBsb2NhdGlvbkhhc2ggKSB7XG5cdFx0XHRcdHRoaXMudGFicy5lYWNoKCBmdW5jdGlvbiggaSwgdGFiICkge1xuXHRcdFx0XHRcdGlmICggJCggdGFiICkuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIgKSA9PT0gbG9jYXRpb25IYXNoICkge1xuXHRcdFx0XHRcdFx0YWN0aXZlID0gaTtcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2hlY2sgZm9yIGEgdGFiIG1hcmtlZCBhY3RpdmUgdmlhIGEgY2xhc3Ncblx0XHRcdGlmICggYWN0aXZlID09PSBudWxsICkge1xuXHRcdFx0XHRhY3RpdmUgPSB0aGlzLnRhYnMuaW5kZXgoIHRoaXMudGFicy5maWx0ZXIoIFwiLnVpLXRhYnMtYWN0aXZlXCIgKSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBObyBhY3RpdmUgdGFiLCBzZXQgdG8gZmFsc2Vcblx0XHRcdGlmICggYWN0aXZlID09PSBudWxsIHx8IGFjdGl2ZSA9PT0gLTEgKSB7XG5cdFx0XHRcdGFjdGl2ZSA9IHRoaXMudGFicy5sZW5ndGggPyAwIDogZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gSGFuZGxlIG51bWJlcnM6IG5lZ2F0aXZlLCBvdXQgb2YgcmFuZ2Vcblx0XHRpZiAoIGFjdGl2ZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHRhY3RpdmUgPSB0aGlzLnRhYnMuaW5kZXgoIHRoaXMudGFicy5lcSggYWN0aXZlICkgKTtcblx0XHRcdGlmICggYWN0aXZlID09PSAtMSApIHtcblx0XHRcdFx0YWN0aXZlID0gY29sbGFwc2libGUgPyBmYWxzZSA6IDA7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gRG9uJ3QgYWxsb3cgY29sbGFwc2libGU6IGZhbHNlIGFuZCBhY3RpdmU6IGZhbHNlXG5cdFx0aWYgKCAhY29sbGFwc2libGUgJiYgYWN0aXZlID09PSBmYWxzZSAmJiB0aGlzLmFuY2hvcnMubGVuZ3RoICkge1xuXHRcdFx0YWN0aXZlID0gMDtcblx0XHR9XG5cblx0XHRyZXR1cm4gYWN0aXZlO1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVFdmVudERhdGE6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR0YWI6IHRoaXMuYWN0aXZlLFxuXHRcdFx0cGFuZWw6ICF0aGlzLmFjdGl2ZS5sZW5ndGggPyAkKCkgOiB0aGlzLl9nZXRQYW5lbEZvclRhYiggdGhpcy5hY3RpdmUgKVxuXHRcdH07XG5cdH0sXG5cblx0X3RhYktleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZm9jdXNlZFRhYiA9ICQoICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICkuY2xvc2VzdCggXCJsaVwiICksXG5cdFx0XHRzZWxlY3RlZEluZGV4ID0gdGhpcy50YWJzLmluZGV4KCBmb2N1c2VkVGFiICksXG5cdFx0XHRnb2luZ0ZvcndhcmQgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLl9oYW5kbGVQYWdlTmF2KCBldmVudCApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuUklHSFQ6XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRE9XTjpcblx0XHRcdHNlbGVjdGVkSW5kZXgrKztcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlVQOlxuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkxFRlQ6XG5cdFx0XHRnb2luZ0ZvcndhcmQgPSBmYWxzZTtcblx0XHRcdHNlbGVjdGVkSW5kZXgtLTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkVORDpcblx0XHRcdHNlbGVjdGVkSW5kZXggPSB0aGlzLmFuY2hvcnMubGVuZ3RoIC0gMTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkhPTUU6XG5cdFx0XHRzZWxlY3RlZEluZGV4ID0gMDtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlNQQUNFOlxuXG5cdFx0XHQvLyBBY3RpdmF0ZSBvbmx5LCBubyBjb2xsYXBzaW5nXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLmFjdGl2YXRpbmcgKTtcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCBzZWxlY3RlZEluZGV4ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5URVI6XG5cblx0XHRcdC8vIFRvZ2dsZSAoY2FuY2VsIGRlbGF5ZWQgYWN0aXZhdGlvbiwgYWxsb3cgY29sbGFwc2luZylcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMuYWN0aXZhdGluZyApO1xuXG5cdFx0XHQvLyBEZXRlcm1pbmUgaWYgd2Ugc2hvdWxkIGNvbGxhcHNlIG9yIGFjdGl2YXRlXG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggc2VsZWN0ZWRJbmRleCA9PT0gdGhpcy5vcHRpb25zLmFjdGl2ZSA/IGZhbHNlIDogc2VsZWN0ZWRJbmRleCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRm9jdXMgdGhlIGFwcHJvcHJpYXRlIHRhYiwgYmFzZWQgb24gd2hpY2gga2V5IHdhcyBwcmVzc2VkXG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMuYWN0aXZhdGluZyApO1xuXHRcdHNlbGVjdGVkSW5kZXggPSB0aGlzLl9mb2N1c05leHRUYWIoIHNlbGVjdGVkSW5kZXgsIGdvaW5nRm9yd2FyZCApO1xuXG5cdFx0Ly8gTmF2aWdhdGluZyB3aXRoIGNvbnRyb2wvY29tbWFuZCBrZXkgd2lsbCBwcmV2ZW50IGF1dG9tYXRpYyBhY3RpdmF0aW9uXG5cdFx0aWYgKCAhZXZlbnQuY3RybEtleSAmJiAhZXZlbnQubWV0YUtleSApIHtcblxuXHRcdFx0Ly8gVXBkYXRlIGFyaWEtc2VsZWN0ZWQgaW1tZWRpYXRlbHkgc28gdGhhdCBBVCB0aGluayB0aGUgdGFiIGlzIGFscmVhZHkgc2VsZWN0ZWQuXG5cdFx0XHQvLyBPdGhlcndpc2UgQVQgbWF5IGNvbmZ1c2UgdGhlIHVzZXIgYnkgc3RhdGluZyB0aGF0IHRoZXkgbmVlZCB0byBhY3RpdmF0ZSB0aGUgdGFiLFxuXHRcdFx0Ly8gYnV0IHRoZSB0YWIgd2lsbCBhbHJlYWR5IGJlIGFjdGl2YXRlZCBieSB0aGUgdGltZSB0aGUgYW5ub3VuY2VtZW50IGZpbmlzaGVzLlxuXHRcdFx0Zm9jdXNlZFRhYi5hdHRyKCBcImFyaWEtc2VsZWN0ZWRcIiwgXCJmYWxzZVwiICk7XG5cdFx0XHR0aGlzLnRhYnMuZXEoIHNlbGVjdGVkSW5kZXggKS5hdHRyKCBcImFyaWEtc2VsZWN0ZWRcIiwgXCJ0cnVlXCIgKTtcblxuXHRcdFx0dGhpcy5hY3RpdmF0aW5nID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbiggXCJhY3RpdmVcIiwgc2VsZWN0ZWRJbmRleCApO1xuXHRcdFx0fSwgdGhpcy5kZWxheSApO1xuXHRcdH1cblx0fSxcblxuXHRfcGFuZWxLZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCB0aGlzLl9oYW5kbGVQYWdlTmF2KCBldmVudCApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEN0cmwrdXAgbW92ZXMgZm9jdXMgdG8gdGhlIGN1cnJlbnQgdGFiXG5cdFx0aWYgKCBldmVudC5jdHJsS2V5ICYmIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5VUCApIHtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR0aGlzLmFjdGl2ZS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gQWx0K3BhZ2UgdXAvZG93biBtb3ZlcyBmb2N1cyB0byB0aGUgcHJldmlvdXMvbmV4dCB0YWIgKGFuZCBhY3RpdmF0ZXMpXG5cdF9oYW5kbGVQYWdlTmF2OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCBldmVudC5hbHRLZXkgJiYgZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLlBBR0VfVVAgKSB7XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggdGhpcy5fZm9jdXNOZXh0VGFiKCB0aGlzLm9wdGlvbnMuYWN0aXZlIC0gMSwgZmFsc2UgKSApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXHRcdGlmICggZXZlbnQuYWx0S2V5ICYmIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5QQUdFX0RPV04gKSB7XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggdGhpcy5fZm9jdXNOZXh0VGFiKCB0aGlzLm9wdGlvbnMuYWN0aXZlICsgMSwgdHJ1ZSApICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cdH0sXG5cblx0X2ZpbmROZXh0VGFiOiBmdW5jdGlvbiggaW5kZXgsIGdvaW5nRm9yd2FyZCApIHtcblx0XHR2YXIgbGFzdFRhYkluZGV4ID0gdGhpcy50YWJzLmxlbmd0aCAtIDE7XG5cblx0XHRmdW5jdGlvbiBjb25zdHJhaW4oKSB7XG5cdFx0XHRpZiAoIGluZGV4ID4gbGFzdFRhYkluZGV4ICkge1xuXHRcdFx0XHRpbmRleCA9IDA7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGluZGV4IDwgMCApIHtcblx0XHRcdFx0aW5kZXggPSBsYXN0VGFiSW5kZXg7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gaW5kZXg7XG5cdFx0fVxuXG5cdFx0d2hpbGUgKCAkLmluQXJyYXkoIGNvbnN0cmFpbigpLCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSAhPT0gLTEgKSB7XG5cdFx0XHRpbmRleCA9IGdvaW5nRm9yd2FyZCA/IGluZGV4ICsgMSA6IGluZGV4IC0gMTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaW5kZXg7XG5cdH0sXG5cblx0X2ZvY3VzTmV4dFRhYjogZnVuY3Rpb24oIGluZGV4LCBnb2luZ0ZvcndhcmQgKSB7XG5cdFx0aW5kZXggPSB0aGlzLl9maW5kTmV4dFRhYiggaW5kZXgsIGdvaW5nRm9yd2FyZCApO1xuXHRcdHRoaXMudGFicy5lcSggaW5kZXggKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRyZXR1cm4gaW5kZXg7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiYWN0aXZlXCIgKSB7XG5cblx0XHRcdC8vIF9hY3RpdmF0ZSgpIHdpbGwgaGFuZGxlIGludmFsaWQgdmFsdWVzIGFuZCB1cGRhdGUgdGhpcy5vcHRpb25zXG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggdmFsdWUgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiY29sbGFwc2libGVcIiApIHtcblx0XHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBcInVpLXRhYnMtY29sbGFwc2libGVcIiwgbnVsbCwgdmFsdWUgKTtcblxuXHRcdFx0Ly8gU2V0dGluZyBjb2xsYXBzaWJsZTogZmFsc2Ugd2hpbGUgY29sbGFwc2VkOyBvcGVuIGZpcnN0IHBhbmVsXG5cdFx0XHRpZiAoICF2YWx1ZSAmJiB0aGlzLm9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSApIHtcblx0XHRcdFx0dGhpcy5fYWN0aXZhdGUoIDAgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJldmVudFwiICkge1xuXHRcdFx0dGhpcy5fc2V0dXBFdmVudHMoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiaGVpZ2h0U3R5bGVcIiApIHtcblx0XHRcdHRoaXMuX3NldHVwSGVpZ2h0U3R5bGUoIHZhbHVlICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zYW5pdGl6ZVNlbGVjdG9yOiBmdW5jdGlvbiggaGFzaCApIHtcblx0XHRyZXR1cm4gaGFzaCA/IGhhc2gucmVwbGFjZSggL1shXCIkJSYnKCkqKywuXFwvOjs8PT4/QFxcW1xcXVxcXmB7fH1+XS9nLCBcIlxcXFwkJlwiICkgOiBcIlwiO1xuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0bGlzID0gdGhpcy50YWJsaXN0LmNoaWxkcmVuKCBcIjpoYXMoYVtocmVmXSlcIiApO1xuXG5cdFx0Ly8gR2V0IGRpc2FibGVkIHRhYnMgZnJvbSBjbGFzcyBhdHRyaWJ1dGUgZnJvbSBIVE1MXG5cdFx0Ly8gdGhpcyB3aWxsIGdldCBjb252ZXJ0ZWQgdG8gYSBib29sZWFuIGlmIG5lZWRlZCBpbiBfcmVmcmVzaCgpXG5cdFx0b3B0aW9ucy5kaXNhYmxlZCA9ICQubWFwKCBsaXMuZmlsdGVyKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICksIGZ1bmN0aW9uKCB0YWIgKSB7XG5cdFx0XHRyZXR1cm4gbGlzLmluZGV4KCB0YWIgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLl9wcm9jZXNzVGFicygpO1xuXG5cdFx0Ly8gV2FzIGNvbGxhcHNlZCBvciBubyB0YWJzXG5cdFx0aWYgKCBvcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgfHwgIXRoaXMuYW5jaG9ycy5sZW5ndGggKSB7XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSA9IGZhbHNlO1xuXHRcdFx0dGhpcy5hY3RpdmUgPSAkKCk7XG5cblx0XHQvLyB3YXMgYWN0aXZlLCBidXQgYWN0aXZlIHRhYiBpcyBnb25lXG5cdFx0fSBlbHNlIGlmICggdGhpcy5hY3RpdmUubGVuZ3RoICYmICEkLmNvbnRhaW5zKCB0aGlzLnRhYmxpc3RbIDAgXSwgdGhpcy5hY3RpdmVbIDAgXSApICkge1xuXG5cdFx0XHQvLyBhbGwgcmVtYWluaW5nIHRhYnMgYXJlIGRpc2FibGVkXG5cdFx0XHRpZiAoIHRoaXMudGFicy5sZW5ndGggPT09IG9wdGlvbnMuZGlzYWJsZWQubGVuZ3RoICkge1xuXHRcdFx0XHRvcHRpb25zLmFjdGl2ZSA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLmFjdGl2ZSA9ICQoKTtcblxuXHRcdFx0Ly8gYWN0aXZhdGUgcHJldmlvdXMgdGFiXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLl9hY3RpdmF0ZSggdGhpcy5fZmluZE5leHRUYWIoIE1hdGgubWF4KCAwLCBvcHRpb25zLmFjdGl2ZSAtIDEgKSwgZmFsc2UgKSApO1xuXHRcdFx0fVxuXG5cdFx0Ly8gd2FzIGFjdGl2ZSwgYWN0aXZlIHRhYiBzdGlsbCBleGlzdHNcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBtYWtlIHN1cmUgYWN0aXZlIGluZGV4IGlzIGNvcnJlY3Rcblx0XHRcdG9wdGlvbnMuYWN0aXZlID0gdGhpcy50YWJzLmluZGV4KCB0aGlzLmFjdGl2ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3JlZnJlc2goKTtcblx0fSxcblxuXHRfcmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fc2V0T3B0aW9uRGlzYWJsZWQoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApO1xuXHRcdHRoaXMuX3NldHVwRXZlbnRzKCB0aGlzLm9wdGlvbnMuZXZlbnQgKTtcblx0XHR0aGlzLl9zZXR1cEhlaWdodFN0eWxlKCB0aGlzLm9wdGlvbnMuaGVpZ2h0U3R5bGUgKTtcblxuXHRcdHRoaXMudGFicy5ub3QoIHRoaXMuYWN0aXZlICkuYXR0cigge1xuXHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHR0YWJJbmRleDogLTFcblx0XHR9ICk7XG5cdFx0dGhpcy5wYW5lbHMubm90KCB0aGlzLl9nZXRQYW5lbEZvclRhYiggdGhpcy5hY3RpdmUgKSApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwidHJ1ZVwiXG5cdFx0XHR9ICk7XG5cblx0XHQvLyBNYWtlIHN1cmUgb25lIHRhYiBpcyBpbiB0aGUgdGFiIG9yZGVyXG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUubGVuZ3RoICkge1xuXHRcdFx0dGhpcy50YWJzLmVxKCAwICkuYXR0ciggXCJ0YWJJbmRleFwiLCAwICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuYWN0aXZlXG5cdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcInRydWVcIixcblx0XHRcdFx0XHR0YWJJbmRleDogMFxuXHRcdFx0XHR9ICk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5hY3RpdmUsIFwidWktdGFicy1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0dGhpcy5fZ2V0UGFuZWxGb3JUYWIoIHRoaXMuYWN0aXZlIClcblx0XHRcdFx0LnNob3coKVxuXHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJmYWxzZVwiXG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X3Byb2Nlc3NUYWJzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRwcmV2VGFicyA9IHRoaXMudGFicyxcblx0XHRcdHByZXZBbmNob3JzID0gdGhpcy5hbmNob3JzLFxuXHRcdFx0cHJldlBhbmVscyA9IHRoaXMucGFuZWxzO1xuXG5cdFx0dGhpcy50YWJsaXN0ID0gdGhpcy5fZ2V0TGlzdCgpLmF0dHIoIFwicm9sZVwiLCBcInRhYmxpc3RcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnRhYmxpc3QsIFwidWktdGFicy1uYXZcIixcblx0XHRcdFwidWktaGVscGVyLXJlc2V0IHVpLWhlbHBlci1jbGVhcmZpeCB1aS13aWRnZXQtaGVhZGVyXCIgKTtcblxuXHRcdC8vIFByZXZlbnQgdXNlcnMgZnJvbSBmb2N1c2luZyBkaXNhYmxlZCB0YWJzIHZpYSBjbGlja1xuXHRcdHRoaXMudGFibGlzdFxuXHRcdFx0Lm9uKCBcIm1vdXNlZG93blwiICsgdGhpcy5ldmVudE5hbWVzcGFjZSwgXCI+IGxpXCIsIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCAkKCB0aGlzICkuaXMoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSApIHtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9IClcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUUgPDlcblx0XHRcdC8vIFByZXZlbnRpbmcgdGhlIGRlZmF1bHQgYWN0aW9uIGluIG1vdXNlZG93biBkb2Vzbid0IHByZXZlbnQgSUVcblx0XHRcdC8vIGZyb20gZm9jdXNpbmcgdGhlIGVsZW1lbnQsIHNvIGlmIHRoZSBhbmNob3IgZ2V0cyBmb2N1c2VkLCBibHVyLlxuXHRcdFx0Ly8gV2UgZG9uJ3QgaGF2ZSB0byB3b3JyeSBhYm91dCBmb2N1c2luZyB0aGUgcHJldmlvdXNseSBmb2N1c2VkXG5cdFx0XHQvLyBlbGVtZW50IHNpbmNlIGNsaWNraW5nIG9uIGEgbm9uLWZvY3VzYWJsZSBlbGVtZW50IHNob3VsZCBmb2N1c1xuXHRcdFx0Ly8gdGhlIGJvZHkgYW55d2F5LlxuXHRcdFx0Lm9uKCBcImZvY3VzXCIgKyB0aGlzLmV2ZW50TmFtZXNwYWNlLCBcIi51aS10YWJzLWFuY2hvclwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCAkKCB0aGlzICkuY2xvc2VzdCggXCJsaVwiICkuaXMoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSApIHtcblx0XHRcdFx0XHR0aGlzLmJsdXIoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXG5cdFx0dGhpcy50YWJzID0gdGhpcy50YWJsaXN0LmZpbmQoIFwiPiBsaTpoYXMoYVtocmVmXSlcIiApXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRyb2xlOiBcInRhYlwiLFxuXHRcdFx0XHR0YWJJbmRleDogLTFcblx0XHRcdH0gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy50YWJzLCBcInVpLXRhYnMtdGFiXCIsIFwidWktc3RhdGUtZGVmYXVsdFwiICk7XG5cblx0XHR0aGlzLmFuY2hvcnMgPSB0aGlzLnRhYnMubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiAkKCBcImFcIiwgdGhpcyApWyAwIF07XG5cdFx0fSApXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRyb2xlOiBcInByZXNlbnRhdGlvblwiLFxuXHRcdFx0XHR0YWJJbmRleDogLTFcblx0XHRcdH0gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5hbmNob3JzLCBcInVpLXRhYnMtYW5jaG9yXCIgKTtcblxuXHRcdHRoaXMucGFuZWxzID0gJCgpO1xuXG5cdFx0dGhpcy5hbmNob3JzLmVhY2goIGZ1bmN0aW9uKCBpLCBhbmNob3IgKSB7XG5cdFx0XHR2YXIgc2VsZWN0b3IsIHBhbmVsLCBwYW5lbElkLFxuXHRcdFx0XHRhbmNob3JJZCA9ICQoIGFuY2hvciApLnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiICksXG5cdFx0XHRcdHRhYiA9ICQoIGFuY2hvciApLmNsb3Nlc3QoIFwibGlcIiApLFxuXHRcdFx0XHRvcmlnaW5hbEFyaWFDb250cm9scyA9IHRhYi5hdHRyKCBcImFyaWEtY29udHJvbHNcIiApO1xuXG5cdFx0XHQvLyBJbmxpbmUgdGFiXG5cdFx0XHRpZiAoIHRoYXQuX2lzTG9jYWwoIGFuY2hvciApICkge1xuXHRcdFx0XHRzZWxlY3RvciA9IGFuY2hvci5oYXNoO1xuXHRcdFx0XHRwYW5lbElkID0gc2VsZWN0b3Iuc3Vic3RyaW5nKCAxICk7XG5cdFx0XHRcdHBhbmVsID0gdGhhdC5lbGVtZW50LmZpbmQoIHRoYXQuX3Nhbml0aXplU2VsZWN0b3IoIHNlbGVjdG9yICkgKTtcblxuXHRcdFx0Ly8gcmVtb3RlIHRhYlxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBJZiB0aGUgdGFiIGRvZXNuJ3QgYWxyZWFkeSBoYXZlIGFyaWEtY29udHJvbHMsXG5cdFx0XHRcdC8vIGdlbmVyYXRlIGFuIGlkIGJ5IHVzaW5nIGEgdGhyb3ctYXdheSBlbGVtZW50XG5cdFx0XHRcdHBhbmVsSWQgPSB0YWIuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIgKSB8fCAkKCB7fSApLnVuaXF1ZUlkKClbIDAgXS5pZDtcblx0XHRcdFx0c2VsZWN0b3IgPSBcIiNcIiArIHBhbmVsSWQ7XG5cdFx0XHRcdHBhbmVsID0gdGhhdC5lbGVtZW50LmZpbmQoIHNlbGVjdG9yICk7XG5cdFx0XHRcdGlmICggIXBhbmVsLmxlbmd0aCApIHtcblx0XHRcdFx0XHRwYW5lbCA9IHRoYXQuX2NyZWF0ZVBhbmVsKCBwYW5lbElkICk7XG5cdFx0XHRcdFx0cGFuZWwuaW5zZXJ0QWZ0ZXIoIHRoYXQucGFuZWxzWyBpIC0gMSBdIHx8IHRoYXQudGFibGlzdCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHBhbmVsLmF0dHIoIFwiYXJpYS1saXZlXCIsIFwicG9saXRlXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBwYW5lbC5sZW5ndGggKSB7XG5cdFx0XHRcdHRoYXQucGFuZWxzID0gdGhhdC5wYW5lbHMuYWRkKCBwYW5lbCApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvcmlnaW5hbEFyaWFDb250cm9scyApIHtcblx0XHRcdFx0dGFiLmRhdGEoIFwidWktdGFicy1hcmlhLWNvbnRyb2xzXCIsIG9yaWdpbmFsQXJpYUNvbnRyb2xzICk7XG5cdFx0XHR9XG5cdFx0XHR0YWIuYXR0cigge1xuXHRcdFx0XHRcImFyaWEtY29udHJvbHNcIjogcGFuZWxJZCxcblx0XHRcdFx0XCJhcmlhLWxhYmVsbGVkYnlcIjogYW5jaG9ySWRcblx0XHRcdH0gKTtcblx0XHRcdHBhbmVsLmF0dHIoIFwiYXJpYS1sYWJlbGxlZGJ5XCIsIGFuY2hvcklkICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5wYW5lbHMuYXR0ciggXCJyb2xlXCIsIFwidGFicGFuZWxcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnBhbmVscywgXCJ1aS10YWJzLXBhbmVsXCIsIFwidWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0Ly8gQXZvaWQgbWVtb3J5IGxlYWtzICgjMTAwNTYpXG5cdFx0aWYgKCBwcmV2VGFicyApIHtcblx0XHRcdHRoaXMuX29mZiggcHJldlRhYnMubm90KCB0aGlzLnRhYnMgKSApO1xuXHRcdFx0dGhpcy5fb2ZmKCBwcmV2QW5jaG9ycy5ub3QoIHRoaXMuYW5jaG9ycyApICk7XG5cdFx0XHR0aGlzLl9vZmYoIHByZXZQYW5lbHMubm90KCB0aGlzLnBhbmVscyApICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIEFsbG93IG92ZXJyaWRpbmcgaG93IHRvIGZpbmQgdGhlIGxpc3QgZm9yIHJhcmUgdXNhZ2Ugc2NlbmFyaW9zICgjNzcxNSlcblx0X2dldExpc3Q6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnRhYmxpc3QgfHwgdGhpcy5lbGVtZW50LmZpbmQoIFwib2wsIHVsXCIgKS5lcSggMCApO1xuXHR9LFxuXG5cdF9jcmVhdGVQYW5lbDogZnVuY3Rpb24oIGlkICkge1xuXHRcdHJldHVybiAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0LmF0dHIoIFwiaWRcIiwgaWQgKVxuXHRcdFx0LmRhdGEoIFwidWktdGFicy1kZXN0cm95XCIsIHRydWUgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCBkaXNhYmxlZCApIHtcblx0XHR2YXIgY3VycmVudEl0ZW0sIGxpLCBpO1xuXG5cdFx0aWYgKCAkLmlzQXJyYXkoIGRpc2FibGVkICkgKSB7XG5cdFx0XHRpZiAoICFkaXNhYmxlZC5sZW5ndGggKSB7XG5cdFx0XHRcdGRpc2FibGVkID0gZmFsc2U7XG5cdFx0XHR9IGVsc2UgaWYgKCBkaXNhYmxlZC5sZW5ndGggPT09IHRoaXMuYW5jaG9ycy5sZW5ndGggKSB7XG5cdFx0XHRcdGRpc2FibGVkID0gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBEaXNhYmxlIHRhYnNcblx0XHRmb3IgKCBpID0gMDsgKCBsaSA9IHRoaXMudGFic1sgaSBdICk7IGkrKyApIHtcblx0XHRcdGN1cnJlbnRJdGVtID0gJCggbGkgKTtcblx0XHRcdGlmICggZGlzYWJsZWQgPT09IHRydWUgfHwgJC5pbkFycmF5KCBpLCBkaXNhYmxlZCApICE9PSAtMSApIHtcblx0XHRcdFx0Y3VycmVudEl0ZW0uYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIFwidHJ1ZVwiICk7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCBjdXJyZW50SXRlbSwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjdXJyZW50SXRlbS5yZW1vdmVBdHRyKCBcImFyaWEtZGlzYWJsZWRcIiApO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY3VycmVudEl0ZW0sIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9IGRpc2FibGVkO1xuXG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMud2lkZ2V0KCksIHRoaXMud2lkZ2V0RnVsbE5hbWUgKyBcIi1kaXNhYmxlZFwiLCBudWxsLFxuXHRcdFx0ZGlzYWJsZWQgPT09IHRydWUgKTtcblx0fSxcblxuXHRfc2V0dXBFdmVudHM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZXZlbnRzID0ge307XG5cdFx0aWYgKCBldmVudCApIHtcblx0XHRcdCQuZWFjaCggZXZlbnQuc3BsaXQoIFwiIFwiICksIGZ1bmN0aW9uKCBpbmRleCwgZXZlbnROYW1lICkge1xuXHRcdFx0XHRldmVudHNbIGV2ZW50TmFtZSBdID0gXCJfZXZlbnRIYW5kbGVyXCI7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmFuY2hvcnMuYWRkKCB0aGlzLnRhYnMgKS5hZGQoIHRoaXMucGFuZWxzICkgKTtcblxuXHRcdC8vIEFsd2F5cyBwcmV2ZW50IHRoZSBkZWZhdWx0IGFjdGlvbiwgZXZlbiB3aGVuIGRpc2FibGVkXG5cdFx0dGhpcy5fb24oIHRydWUsIHRoaXMuYW5jaG9ycywge1xuXHRcdFx0Y2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0dGhpcy5fb24oIHRoaXMuYW5jaG9ycywgZXZlbnRzICk7XG5cdFx0dGhpcy5fb24oIHRoaXMudGFicywgeyBrZXlkb3duOiBcIl90YWJLZXlkb3duXCIgfSApO1xuXHRcdHRoaXMuX29uKCB0aGlzLnBhbmVscywgeyBrZXlkb3duOiBcIl9wYW5lbEtleWRvd25cIiB9ICk7XG5cblx0XHR0aGlzLl9mb2N1c2FibGUoIHRoaXMudGFicyApO1xuXHRcdHRoaXMuX2hvdmVyYWJsZSggdGhpcy50YWJzICk7XG5cdH0sXG5cblx0X3NldHVwSGVpZ2h0U3R5bGU6IGZ1bmN0aW9uKCBoZWlnaHRTdHlsZSApIHtcblx0XHR2YXIgbWF4SGVpZ2h0LFxuXHRcdFx0cGFyZW50ID0gdGhpcy5lbGVtZW50LnBhcmVudCgpO1xuXG5cdFx0aWYgKCBoZWlnaHRTdHlsZSA9PT0gXCJmaWxsXCIgKSB7XG5cdFx0XHRtYXhIZWlnaHQgPSBwYXJlbnQuaGVpZ2h0KCk7XG5cdFx0XHRtYXhIZWlnaHQgLT0gdGhpcy5lbGVtZW50Lm91dGVySGVpZ2h0KCkgLSB0aGlzLmVsZW1lbnQuaGVpZ2h0KCk7XG5cblx0XHRcdHRoaXMuZWxlbWVudC5zaWJsaW5ncyggXCI6dmlzaWJsZVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBlbGVtID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdHBvc2l0aW9uID0gZWxlbS5jc3MoIFwicG9zaXRpb25cIiApO1xuXG5cdFx0XHRcdGlmICggcG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiB8fCBwb3NpdGlvbiA9PT0gXCJmaXhlZFwiICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRtYXhIZWlnaHQgLT0gZWxlbS5vdXRlckhlaWdodCggdHJ1ZSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQuY2hpbGRyZW4oKS5ub3QoIHRoaXMucGFuZWxzICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdG1heEhlaWdodCAtPSAkKCB0aGlzICkub3V0ZXJIZWlnaHQoIHRydWUgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5wYW5lbHMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5oZWlnaHQoIE1hdGgubWF4KCAwLCBtYXhIZWlnaHQgLVxuXHRcdFx0XHRcdCQoIHRoaXMgKS5pbm5lckhlaWdodCgpICsgJCggdGhpcyApLmhlaWdodCgpICkgKTtcblx0XHRcdH0gKVxuXHRcdFx0XHQuY3NzKCBcIm92ZXJmbG93XCIsIFwiYXV0b1wiICk7XG5cdFx0fSBlbHNlIGlmICggaGVpZ2h0U3R5bGUgPT09IFwiYXV0b1wiICkge1xuXHRcdFx0bWF4SGVpZ2h0ID0gMDtcblx0XHRcdHRoaXMucGFuZWxzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRtYXhIZWlnaHQgPSBNYXRoLm1heCggbWF4SGVpZ2h0LCAkKCB0aGlzICkuaGVpZ2h0KCBcIlwiICkuaGVpZ2h0KCkgKTtcblx0XHRcdH0gKS5oZWlnaHQoIG1heEhlaWdodCApO1xuXHRcdH1cblx0fSxcblxuXHRfZXZlbnRIYW5kbGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRhY3RpdmUgPSB0aGlzLmFjdGl2ZSxcblx0XHRcdGFuY2hvciA9ICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSxcblx0XHRcdHRhYiA9IGFuY2hvci5jbG9zZXN0KCBcImxpXCIgKSxcblx0XHRcdGNsaWNrZWRJc0FjdGl2ZSA9IHRhYlsgMCBdID09PSBhY3RpdmVbIDAgXSxcblx0XHRcdGNvbGxhcHNpbmcgPSBjbGlja2VkSXNBY3RpdmUgJiYgb3B0aW9ucy5jb2xsYXBzaWJsZSxcblx0XHRcdHRvU2hvdyA9IGNvbGxhcHNpbmcgPyAkKCkgOiB0aGlzLl9nZXRQYW5lbEZvclRhYiggdGFiICksXG5cdFx0XHR0b0hpZGUgPSAhYWN0aXZlLmxlbmd0aCA/ICQoKSA6IHRoaXMuX2dldFBhbmVsRm9yVGFiKCBhY3RpdmUgKSxcblx0XHRcdGV2ZW50RGF0YSA9IHtcblx0XHRcdFx0b2xkVGFiOiBhY3RpdmUsXG5cdFx0XHRcdG9sZFBhbmVsOiB0b0hpZGUsXG5cdFx0XHRcdG5ld1RhYjogY29sbGFwc2luZyA/ICQoKSA6IHRhYixcblx0XHRcdFx0bmV3UGFuZWw6IHRvU2hvd1xuXHRcdFx0fTtcblxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRpZiAoIHRhYi5oYXNDbGFzcyggXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICkgfHxcblxuXHRcdFx0XHQvLyB0YWIgaXMgYWxyZWFkeSBsb2FkaW5nXG5cdFx0XHRcdHRhYi5oYXNDbGFzcyggXCJ1aS10YWJzLWxvYWRpbmdcIiApIHx8XG5cblx0XHRcdFx0Ly8gY2FuJ3Qgc3dpdGNoIGR1cm5pbmcgYW4gYW5pbWF0aW9uXG5cdFx0XHRcdHRoaXMucnVubmluZyB8fFxuXG5cdFx0XHRcdC8vIGNsaWNrIG9uIGFjdGl2ZSBoZWFkZXIsIGJ1dCBub3QgY29sbGFwc2libGVcblx0XHRcdFx0KCBjbGlja2VkSXNBY3RpdmUgJiYgIW9wdGlvbnMuY29sbGFwc2libGUgKSB8fFxuXG5cdFx0XHRcdC8vIGFsbG93IGNhbmNlbGluZyBhY3RpdmF0aW9uXG5cdFx0XHRcdCggdGhpcy5fdHJpZ2dlciggXCJiZWZvcmVBY3RpdmF0ZVwiLCBldmVudCwgZXZlbnREYXRhICkgPT09IGZhbHNlICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0b3B0aW9ucy5hY3RpdmUgPSBjb2xsYXBzaW5nID8gZmFsc2UgOiB0aGlzLnRhYnMuaW5kZXgoIHRhYiApO1xuXG5cdFx0dGhpcy5hY3RpdmUgPSBjbGlja2VkSXNBY3RpdmUgPyAkKCkgOiB0YWI7XG5cdFx0aWYgKCB0aGlzLnhociApIHtcblx0XHRcdHRoaXMueGhyLmFib3J0KCk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhdG9IaWRlLmxlbmd0aCAmJiAhdG9TaG93Lmxlbmd0aCApIHtcblx0XHRcdCQuZXJyb3IoIFwialF1ZXJ5IFVJIFRhYnM6IE1pc21hdGNoaW5nIGZyYWdtZW50IGlkZW50aWZpZXIuXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRvU2hvdy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmxvYWQoIHRoaXMudGFicy5pbmRleCggdGFiICksIGV2ZW50ICk7XG5cdFx0fVxuXHRcdHRoaXMuX3RvZ2dsZSggZXZlbnQsIGV2ZW50RGF0YSApO1xuXHR9LFxuXG5cdC8vIEhhbmRsZXMgc2hvdy9oaWRlIGZvciBzZWxlY3RpbmcgdGFic1xuXHRfdG9nZ2xlOiBmdW5jdGlvbiggZXZlbnQsIGV2ZW50RGF0YSApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHR0b1Nob3cgPSBldmVudERhdGEubmV3UGFuZWwsXG5cdFx0XHR0b0hpZGUgPSBldmVudERhdGEub2xkUGFuZWw7XG5cblx0XHR0aGlzLnJ1bm5pbmcgPSB0cnVlO1xuXG5cdFx0ZnVuY3Rpb24gY29tcGxldGUoKSB7XG5cdFx0XHR0aGF0LnJ1bm5pbmcgPSBmYWxzZTtcblx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiYWN0aXZhdGVcIiwgZXZlbnQsIGV2ZW50RGF0YSApO1xuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHNob3coKSB7XG5cdFx0XHR0aGF0Ll9hZGRDbGFzcyggZXZlbnREYXRhLm5ld1RhYi5jbG9zZXN0KCBcImxpXCIgKSwgXCJ1aS10YWJzLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cblx0XHRcdGlmICggdG9TaG93Lmxlbmd0aCAmJiB0aGF0Lm9wdGlvbnMuc2hvdyApIHtcblx0XHRcdFx0dGhhdC5fc2hvdyggdG9TaG93LCB0aGF0Lm9wdGlvbnMuc2hvdywgY29tcGxldGUgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRvU2hvdy5zaG93KCk7XG5cdFx0XHRcdGNvbXBsZXRlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gU3RhcnQgb3V0IGJ5IGhpZGluZywgdGhlbiBzaG93aW5nLCB0aGVuIGNvbXBsZXRpbmdcblx0XHRpZiAoIHRvSGlkZS5sZW5ndGggJiYgdGhpcy5vcHRpb25zLmhpZGUgKSB7XG5cdFx0XHR0aGlzLl9oaWRlKCB0b0hpZGUsIHRoaXMub3B0aW9ucy5oaWRlLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIGV2ZW50RGF0YS5vbGRUYWIuY2xvc2VzdCggXCJsaVwiICksXG5cdFx0XHRcdFx0XCJ1aS10YWJzLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRcdHNob3coKTtcblx0XHRcdH0gKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGV2ZW50RGF0YS5vbGRUYWIuY2xvc2VzdCggXCJsaVwiICksXG5cdFx0XHRcdFwidWktdGFicy1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0dG9IaWRlLmhpZGUoKTtcblx0XHRcdHNob3coKTtcblx0XHR9XG5cblx0XHR0b0hpZGUuYXR0ciggXCJhcmlhLWhpZGRlblwiLCBcInRydWVcIiApO1xuXHRcdGV2ZW50RGF0YS5vbGRUYWIuYXR0cigge1xuXHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCJcblx0XHR9ICk7XG5cblx0XHQvLyBJZiB3ZSdyZSBzd2l0Y2hpbmcgdGFicywgcmVtb3ZlIHRoZSBvbGQgdGFiIGZyb20gdGhlIHRhYiBvcmRlci5cblx0XHQvLyBJZiB3ZSdyZSBvcGVuaW5nIGZyb20gY29sbGFwc2VkIHN0YXRlLCByZW1vdmUgdGhlIHByZXZpb3VzIHRhYiBmcm9tIHRoZSB0YWIgb3JkZXIuXG5cdFx0Ly8gSWYgd2UncmUgY29sbGFwc2luZywgdGhlbiBrZWVwIHRoZSBjb2xsYXBzaW5nIHRhYiBpbiB0aGUgdGFiIG9yZGVyLlxuXHRcdGlmICggdG9TaG93Lmxlbmd0aCAmJiB0b0hpZGUubGVuZ3RoICkge1xuXHRcdFx0ZXZlbnREYXRhLm9sZFRhYi5hdHRyKCBcInRhYkluZGV4XCIsIC0xICk7XG5cdFx0fSBlbHNlIGlmICggdG9TaG93Lmxlbmd0aCApIHtcblx0XHRcdHRoaXMudGFicy5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gJCggdGhpcyApLmF0dHIoIFwidGFiSW5kZXhcIiApID09PSAwO1xuXHRcdFx0fSApXG5cdFx0XHRcdC5hdHRyKCBcInRhYkluZGV4XCIsIC0xICk7XG5cdFx0fVxuXG5cdFx0dG9TaG93LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgXCJmYWxzZVwiICk7XG5cdFx0ZXZlbnREYXRhLm5ld1RhYi5hdHRyKCB7XG5cdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHR0YWJJbmRleDogMFxuXHRcdH0gKTtcblx0fSxcblxuXHRfYWN0aXZhdGU6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHR2YXIgYW5jaG9yLFxuXHRcdFx0YWN0aXZlID0gdGhpcy5fZmluZEFjdGl2ZSggaW5kZXggKTtcblxuXHRcdC8vIFRyeWluZyB0byBhY3RpdmF0ZSB0aGUgYWxyZWFkeSBhY3RpdmUgcGFuZWxcblx0XHRpZiAoIGFjdGl2ZVsgMCBdID09PSB0aGlzLmFjdGl2ZVsgMCBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIFRyeWluZyB0byBjb2xsYXBzZSwgc2ltdWxhdGUgYSBjbGljayBvbiB0aGUgY3VycmVudCBhY3RpdmUgaGVhZGVyXG5cdFx0aWYgKCAhYWN0aXZlLmxlbmd0aCApIHtcblx0XHRcdGFjdGl2ZSA9IHRoaXMuYWN0aXZlO1xuXHRcdH1cblxuXHRcdGFuY2hvciA9IGFjdGl2ZS5maW5kKCBcIi51aS10YWJzLWFuY2hvclwiIClbIDAgXTtcblx0XHR0aGlzLl9ldmVudEhhbmRsZXIoIHtcblx0XHRcdHRhcmdldDogYW5jaG9yLFxuXHRcdFx0Y3VycmVudFRhcmdldDogYW5jaG9yLFxuXHRcdFx0cHJldmVudERlZmF1bHQ6ICQubm9vcFxuXHRcdH0gKTtcblx0fSxcblxuXHRfZmluZEFjdGl2ZTogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHJldHVybiBpbmRleCA9PT0gZmFsc2UgPyAkKCkgOiB0aGlzLnRhYnMuZXEoIGluZGV4ICk7XG5cdH0sXG5cblx0X2dldEluZGV4OiBmdW5jdGlvbiggaW5kZXggKSB7XG5cblx0XHQvLyBtZXRhLWZ1bmN0aW9uIHRvIGdpdmUgdXNlcnMgb3B0aW9uIHRvIHByb3ZpZGUgYSBocmVmIHN0cmluZyBpbnN0ZWFkIG9mIGEgbnVtZXJpY2FsIGluZGV4LlxuXHRcdGlmICggdHlwZW9mIGluZGV4ID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0aW5kZXggPSB0aGlzLmFuY2hvcnMuaW5kZXgoIHRoaXMuYW5jaG9ycy5maWx0ZXIoIFwiW2hyZWYkPSdcIiArXG5cdFx0XHRcdCQudWkuZXNjYXBlU2VsZWN0b3IoIGluZGV4ICkgKyBcIiddXCIgKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBpbmRleDtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCB0aGlzLnhociApIHtcblx0XHRcdHRoaXMueGhyLmFib3J0KCk7XG5cdFx0fVxuXG5cdFx0dGhpcy50YWJsaXN0XG5cdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlXCIgKVxuXHRcdFx0Lm9mZiggdGhpcy5ldmVudE5hbWVzcGFjZSApO1xuXG5cdFx0dGhpcy5hbmNob3JzXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlIHRhYkluZGV4XCIgKVxuXHRcdFx0LnJlbW92ZVVuaXF1ZUlkKCk7XG5cblx0XHR0aGlzLnRhYnMuYWRkKCB0aGlzLnBhbmVscyApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAkLmRhdGEoIHRoaXMsIFwidWktdGFicy1kZXN0cm95XCIgKSApIHtcblx0XHRcdFx0JCggdGhpcyApLnJlbW92ZSgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0JCggdGhpcyApLnJlbW92ZUF0dHIoIFwicm9sZSB0YWJJbmRleCBcIiArXG5cdFx0XHRcdFx0XCJhcmlhLWxpdmUgYXJpYS1idXN5IGFyaWEtc2VsZWN0ZWQgYXJpYS1sYWJlbGxlZGJ5IGFyaWEtaGlkZGVuIGFyaWEtZXhwYW5kZWRcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMudGFicy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBsaSA9ICQoIHRoaXMgKSxcblx0XHRcdFx0cHJldiA9IGxpLmRhdGEoIFwidWktdGFicy1hcmlhLWNvbnRyb2xzXCIgKTtcblx0XHRcdGlmICggcHJldiApIHtcblx0XHRcdFx0bGlcblx0XHRcdFx0XHQuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIsIHByZXYgKVxuXHRcdFx0XHRcdC5yZW1vdmVEYXRhKCBcInVpLXRhYnMtYXJpYS1jb250cm9sc1wiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRsaS5yZW1vdmVBdHRyKCBcImFyaWEtY29udHJvbHNcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMucGFuZWxzLnNob3coKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhlaWdodFN0eWxlICE9PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdHRoaXMucGFuZWxzLmNzcyggXCJoZWlnaHRcIiwgXCJcIiApO1xuXHRcdH1cblx0fSxcblxuXHRlbmFibGU6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHR2YXIgZGlzYWJsZWQgPSB0aGlzLm9wdGlvbnMuZGlzYWJsZWQ7XG5cdFx0aWYgKCBkaXNhYmxlZCA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBpbmRleCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0ZGlzYWJsZWQgPSBmYWxzZTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aW5kZXggPSB0aGlzLl9nZXRJbmRleCggaW5kZXggKTtcblx0XHRcdGlmICggJC5pc0FycmF5KCBkaXNhYmxlZCApICkge1xuXHRcdFx0XHRkaXNhYmxlZCA9ICQubWFwKCBkaXNhYmxlZCwgZnVuY3Rpb24oIG51bSApIHtcblx0XHRcdFx0XHRyZXR1cm4gbnVtICE9PSBpbmRleCA/IG51bSA6IG51bGw7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRpc2FibGVkID0gJC5tYXAoIHRoaXMudGFicywgZnVuY3Rpb24oIGxpLCBudW0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIG51bSAhPT0gaW5kZXggPyBudW0gOiBudWxsO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMuX3NldE9wdGlvbkRpc2FibGVkKCBkaXNhYmxlZCApO1xuXHR9LFxuXG5cdGRpc2FibGU6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHR2YXIgZGlzYWJsZWQgPSB0aGlzLm9wdGlvbnMuZGlzYWJsZWQ7XG5cdFx0aWYgKCBkaXNhYmxlZCA9PT0gdHJ1ZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIGluZGV4ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRkaXNhYmxlZCA9IHRydWU7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGluZGV4ID0gdGhpcy5fZ2V0SW5kZXgoIGluZGV4ICk7XG5cdFx0XHRpZiAoICQuaW5BcnJheSggaW5kZXgsIGRpc2FibGVkICkgIT09IC0xICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRpZiAoICQuaXNBcnJheSggZGlzYWJsZWQgKSApIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSAkLm1lcmdlKCBbIGluZGV4IF0sIGRpc2FibGVkICkuc29ydCgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSBbIGluZGV4IF07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMuX3NldE9wdGlvbkRpc2FibGVkKCBkaXNhYmxlZCApO1xuXHR9LFxuXG5cdGxvYWQ6IGZ1bmN0aW9uKCBpbmRleCwgZXZlbnQgKSB7XG5cdFx0aW5kZXggPSB0aGlzLl9nZXRJbmRleCggaW5kZXggKTtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHR0YWIgPSB0aGlzLnRhYnMuZXEoIGluZGV4ICksXG5cdFx0XHRhbmNob3IgPSB0YWIuZmluZCggXCIudWktdGFicy1hbmNob3JcIiApLFxuXHRcdFx0cGFuZWwgPSB0aGlzLl9nZXRQYW5lbEZvclRhYiggdGFiICksXG5cdFx0XHRldmVudERhdGEgPSB7XG5cdFx0XHRcdHRhYjogdGFiLFxuXHRcdFx0XHRwYW5lbDogcGFuZWxcblx0XHRcdH0sXG5cdFx0XHRjb21wbGV0ZSA9IGZ1bmN0aW9uKCBqcVhIUiwgc3RhdHVzICkge1xuXHRcdFx0XHRpZiAoIHN0YXR1cyA9PT0gXCJhYm9ydFwiICkge1xuXHRcdFx0XHRcdHRoYXQucGFuZWxzLnN0b3AoIGZhbHNlLCB0cnVlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggdGFiLCBcInVpLXRhYnMtbG9hZGluZ1wiICk7XG5cdFx0XHRcdHBhbmVsLnJlbW92ZUF0dHIoIFwiYXJpYS1idXN5XCIgKTtcblxuXHRcdFx0XHRpZiAoIGpxWEhSID09PSB0aGF0LnhociApIHtcblx0XHRcdFx0XHRkZWxldGUgdGhhdC54aHI7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHQvLyBOb3QgcmVtb3RlXG5cdFx0aWYgKCB0aGlzLl9pc0xvY2FsKCBhbmNob3JbIDAgXSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMueGhyID0gJC5hamF4KCB0aGlzLl9hamF4U2V0dGluZ3MoIGFuY2hvciwgZXZlbnQsIGV2ZW50RGF0YSApICk7XG5cblx0XHQvLyBTdXBwb3J0OiBqUXVlcnkgPDEuOFxuXHRcdC8vIGpRdWVyeSA8MS44IHJldHVybnMgZmFsc2UgaWYgdGhlIHJlcXVlc3QgaXMgY2FuY2VsZWQgaW4gYmVmb3JlU2VuZCxcblx0XHQvLyBidXQgYXMgb2YgMS44LCAkLmFqYXgoKSBhbHdheXMgcmV0dXJucyBhIGpxWEhSIG9iamVjdC5cblx0XHRpZiAoIHRoaXMueGhyICYmIHRoaXMueGhyLnN0YXR1c1RleHQgIT09IFwiY2FuY2VsZWRcIiApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0YWIsIFwidWktdGFicy1sb2FkaW5nXCIgKTtcblx0XHRcdHBhbmVsLmF0dHIoIFwiYXJpYS1idXN5XCIsIFwidHJ1ZVwiICk7XG5cblx0XHRcdHRoaXMueGhyXG5cdFx0XHRcdC5kb25lKCBmdW5jdGlvbiggcmVzcG9uc2UsIHN0YXR1cywganFYSFIgKSB7XG5cblx0XHRcdFx0XHQvLyBzdXBwb3J0OiBqUXVlcnkgPDEuOFxuXHRcdFx0XHRcdC8vIGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzExNzc4XG5cdFx0XHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRwYW5lbC5odG1sKCByZXNwb25zZSApO1xuXHRcdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJsb2FkXCIsIGV2ZW50LCBldmVudERhdGEgKTtcblxuXHRcdFx0XHRcdFx0Y29tcGxldGUoIGpxWEhSLCBzdGF0dXMgKTtcblx0XHRcdFx0XHR9LCAxICk7XG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQuZmFpbCggZnVuY3Rpb24oIGpxWEhSLCBzdGF0dXMgKSB7XG5cblx0XHRcdFx0XHQvLyBzdXBwb3J0OiBqUXVlcnkgPDEuOFxuXHRcdFx0XHRcdC8vIGh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzExNzc4XG5cdFx0XHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRjb21wbGV0ZSgganFYSFIsIHN0YXR1cyApO1xuXHRcdFx0XHRcdH0sIDEgKTtcblx0XHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfYWpheFNldHRpbmdzOiBmdW5jdGlvbiggYW5jaG9yLCBldmVudCwgZXZlbnREYXRhICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHRyZXR1cm4ge1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSA8MTEgb25seVxuXHRcdFx0Ly8gU3RyaXAgYW55IGhhc2ggdGhhdCBleGlzdHMgdG8gcHJldmVudCBlcnJvcnMgd2l0aCB0aGUgQWpheCByZXF1ZXN0XG5cdFx0XHR1cmw6IGFuY2hvci5hdHRyKCBcImhyZWZcIiApLnJlcGxhY2UoIC8jLiokLywgXCJcIiApLFxuXHRcdFx0YmVmb3JlU2VuZDogZnVuY3Rpb24oIGpxWEhSLCBzZXR0aW5ncyApIHtcblx0XHRcdFx0cmV0dXJuIHRoYXQuX3RyaWdnZXIoIFwiYmVmb3JlTG9hZFwiLCBldmVudCxcblx0XHRcdFx0XHQkLmV4dGVuZCggeyBqcVhIUjoganFYSFIsIGFqYXhTZXR0aW5nczogc2V0dGluZ3MgfSwgZXZlbnREYXRhICkgKTtcblx0XHRcdH1cblx0XHR9O1xuXHR9LFxuXG5cdF9nZXRQYW5lbEZvclRhYjogZnVuY3Rpb24oIHRhYiApIHtcblx0XHR2YXIgaWQgPSAkKCB0YWIgKS5hdHRyKCBcImFyaWEtY29udHJvbHNcIiApO1xuXHRcdHJldHVybiB0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5fc2FuaXRpemVTZWxlY3RvciggXCIjXCIgKyBpZCApICk7XG5cdH1cbn0gKTtcblxuLy8gREVQUkVDQVRFRFxuLy8gVE9ETzogU3dpdGNoIHJldHVybiBiYWNrIHRvIHdpZGdldCBkZWNsYXJhdGlvbiBhdCB0b3Agb2YgZmlsZSB3aGVuIHRoaXMgaXMgcmVtb3ZlZFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gQmFja2NvbXBhdCBmb3IgdWktdGFiIGNsYXNzIChub3cgdWktdGFicy10YWIpXG5cdCQud2lkZ2V0KCBcInVpLnRhYnNcIiwgJC51aS50YWJzLCB7XG5cdFx0X3Byb2Nlc3NUYWJzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyQXBwbHkoIGFyZ3VtZW50cyApO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudGFicywgXCJ1aS10YWJcIiApO1xuXHRcdH1cblx0fSApO1xufVxuXG52YXIgd2lkZ2V0c1RhYnMgPSAkLnVpLnRhYnM7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgVG9vbHRpcCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogVG9vbHRpcFxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IFNob3dzIGFkZGl0aW9uYWwgaW5mb3JtYXRpb24gZm9yIGFueSBlbGVtZW50IG9uIGhvdmVyIG9yIGZvY3VzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Rvb2x0aXAvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vdG9vbHRpcC9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3Rvb2x0aXAuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLnRvb2x0aXBcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS10b29sdGlwXCI6IFwidWktY29ybmVyLWFsbCB1aS13aWRnZXQtc2hhZG93XCJcblx0XHR9LFxuXHRcdGNvbnRlbnQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBzdXBwb3J0OiBJRTw5LCBPcGVyYSBpbiBqUXVlcnkgPDEuN1xuXHRcdFx0Ly8gLnRleHQoKSBjYW4ndCBhY2NlcHQgdW5kZWZpbmVkLCBzbyBjb2VyY2UgdG8gYSBzdHJpbmdcblx0XHRcdHZhciB0aXRsZSA9ICQoIHRoaXMgKS5hdHRyKCBcInRpdGxlXCIgKSB8fCBcIlwiO1xuXG5cdFx0XHQvLyBFc2NhcGUgdGl0bGUsIHNpbmNlIHdlJ3JlIGdvaW5nIGZyb20gYW4gYXR0cmlidXRlIHRvIHJhdyBIVE1MXG5cdFx0XHRyZXR1cm4gJCggXCI8YT5cIiApLnRleHQoIHRpdGxlICkuaHRtbCgpO1xuXHRcdH0sXG5cdFx0aGlkZTogdHJ1ZSxcblxuXHRcdC8vIERpc2FibGVkIGVsZW1lbnRzIGhhdmUgaW5jb25zaXN0ZW50IGJlaGF2aW9yIGFjcm9zcyBicm93c2VycyAoIzg2NjEpXG5cdFx0aXRlbXM6IFwiW3RpdGxlXTpub3QoW2Rpc2FibGVkXSlcIixcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0bXk6IFwibGVmdCB0b3ArMTVcIixcblx0XHRcdGF0OiBcImxlZnQgYm90dG9tXCIsXG5cdFx0XHRjb2xsaXNpb246IFwiZmxpcGZpdCBmbGlwXCJcblx0XHR9LFxuXHRcdHNob3c6IHRydWUsXG5cdFx0dHJhY2s6IGZhbHNlLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Y2xvc2U6IG51bGwsXG5cdFx0b3BlbjogbnVsbFxuXHR9LFxuXG5cdF9hZGREZXNjcmliZWRCeTogZnVuY3Rpb24oIGVsZW0sIGlkICkge1xuXHRcdHZhciBkZXNjcmliZWRieSA9ICggZWxlbS5hdHRyKCBcImFyaWEtZGVzY3JpYmVkYnlcIiApIHx8IFwiXCIgKS5zcGxpdCggL1xccysvICk7XG5cdFx0ZGVzY3JpYmVkYnkucHVzaCggaWQgKTtcblx0XHRlbGVtXG5cdFx0XHQuZGF0YSggXCJ1aS10b29sdGlwLWlkXCIsIGlkIClcblx0XHRcdC5hdHRyKCBcImFyaWEtZGVzY3JpYmVkYnlcIiwgJC50cmltKCBkZXNjcmliZWRieS5qb2luKCBcIiBcIiApICkgKTtcblx0fSxcblxuXHRfcmVtb3ZlRGVzY3JpYmVkQnk6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHZhciBpZCA9IGVsZW0uZGF0YSggXCJ1aS10b29sdGlwLWlkXCIgKSxcblx0XHRcdGRlc2NyaWJlZGJ5ID0gKCBlbGVtLmF0dHIoIFwiYXJpYS1kZXNjcmliZWRieVwiICkgfHwgXCJcIiApLnNwbGl0KCAvXFxzKy8gKSxcblx0XHRcdGluZGV4ID0gJC5pbkFycmF5KCBpZCwgZGVzY3JpYmVkYnkgKTtcblxuXHRcdGlmICggaW5kZXggIT09IC0xICkge1xuXHRcdFx0ZGVzY3JpYmVkYnkuc3BsaWNlKCBpbmRleCwgMSApO1xuXHRcdH1cblxuXHRcdGVsZW0ucmVtb3ZlRGF0YSggXCJ1aS10b29sdGlwLWlkXCIgKTtcblx0XHRkZXNjcmliZWRieSA9ICQudHJpbSggZGVzY3JpYmVkYnkuam9pbiggXCIgXCIgKSApO1xuXHRcdGlmICggZGVzY3JpYmVkYnkgKSB7XG5cdFx0XHRlbGVtLmF0dHIoIFwiYXJpYS1kZXNjcmliZWRieVwiLCBkZXNjcmliZWRieSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtLnJlbW92ZUF0dHIoIFwiYXJpYS1kZXNjcmliZWRieVwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX29uKCB7XG5cdFx0XHRtb3VzZW92ZXI6IFwib3BlblwiLFxuXHRcdFx0Zm9jdXNpbjogXCJvcGVuXCJcblx0XHR9ICk7XG5cblx0XHQvLyBJRHMgb2YgZ2VuZXJhdGVkIHRvb2x0aXBzLCBuZWVkZWQgZm9yIGRlc3Ryb3lcblx0XHR0aGlzLnRvb2x0aXBzID0ge307XG5cblx0XHQvLyBJRHMgb2YgcGFyZW50IHRvb2x0aXBzIHdoZXJlIHdlIHJlbW92ZWQgdGhlIHRpdGxlIGF0dHJpYnV0ZVxuXHRcdHRoaXMucGFyZW50cyA9IHt9O1xuXG5cdFx0Ly8gQXBwZW5kIHRoZSBhcmlhLWxpdmUgcmVnaW9uIHNvIHRvb2x0aXBzIGFubm91bmNlIGNvcnJlY3RseVxuXHRcdHRoaXMubGl2ZVJlZ2lvbiA9ICQoIFwiPGRpdj5cIiApXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRyb2xlOiBcImxvZ1wiLFxuXHRcdFx0XHRcImFyaWEtbGl2ZVwiOiBcImFzc2VydGl2ZVwiLFxuXHRcdFx0XHRcImFyaWEtcmVsZXZhbnRcIjogXCJhZGRpdGlvbnNcIlxuXHRcdFx0fSApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGl2ZVJlZ2lvbiwgbnVsbCwgXCJ1aS1oZWxwZXItaGlkZGVuLWFjY2Vzc2libGVcIiApO1xuXG5cdFx0dGhpcy5kaXNhYmxlZFRpdGxlcyA9ICQoIFtdICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdCQuZWFjaCggdGhpcy50b29sdGlwcywgZnVuY3Rpb24oIGlkLCB0b29sdGlwRGF0YSApIHtcblx0XHRcdFx0dGhhdC5fdXBkYXRlQ29udGVudCggdG9vbHRpcERhdGEuZWxlbWVudCApO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzWyB2YWx1ZSA/IFwiX2Rpc2FibGVcIiA6IFwiX2VuYWJsZVwiIF0oKTtcblx0fSxcblxuXHRfZGlzYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0Ly8gQ2xvc2Ugb3BlbiB0b29sdGlwc1xuXHRcdCQuZWFjaCggdGhpcy50b29sdGlwcywgZnVuY3Rpb24oIGlkLCB0b29sdGlwRGF0YSApIHtcblx0XHRcdHZhciBldmVudCA9ICQuRXZlbnQoIFwiYmx1clwiICk7XG5cdFx0XHRldmVudC50YXJnZXQgPSBldmVudC5jdXJyZW50VGFyZ2V0ID0gdG9vbHRpcERhdGEuZWxlbWVudFsgMCBdO1xuXHRcdFx0dGhhdC5jbG9zZSggZXZlbnQsIHRydWUgKTtcblx0XHR9ICk7XG5cblx0XHQvLyBSZW1vdmUgdGl0bGUgYXR0cmlidXRlcyB0byBwcmV2ZW50IG5hdGl2ZSB0b29sdGlwc1xuXHRcdHRoaXMuZGlzYWJsZWRUaXRsZXMgPSB0aGlzLmRpc2FibGVkVGl0bGVzLmFkZChcblx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKS5hZGRCYWNrKClcblx0XHRcdFx0LmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICk7XG5cdFx0XHRcdFx0aWYgKCBlbGVtZW50LmlzKCBcIlt0aXRsZV1cIiApICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGVsZW1lbnRcblx0XHRcdFx0XHRcdFx0LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiLCBlbGVtZW50LmF0dHIoIFwidGl0bGVcIiApIClcblx0XHRcdFx0XHRcdFx0LnJlbW92ZUF0dHIoIFwidGl0bGVcIiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApXG5cdFx0KTtcblx0fSxcblxuXHRfZW5hYmxlOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIHJlc3RvcmUgdGl0bGUgYXR0cmlidXRlc1xuXHRcdHRoaXMuZGlzYWJsZWRUaXRsZXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKTtcblx0XHRcdGlmICggZWxlbWVudC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICkge1xuXHRcdFx0XHRlbGVtZW50LmF0dHIoIFwidGl0bGVcIiwgZWxlbWVudC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHRoaXMuZGlzYWJsZWRUaXRsZXMgPSAkKCBbXSApO1xuXHR9LFxuXG5cdG9wZW46IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHR0YXJnZXQgPSAkKCBldmVudCA/IGV2ZW50LnRhcmdldCA6IHRoaXMuZWxlbWVudCApXG5cblx0XHRcdFx0Ly8gd2UgbmVlZCBjbG9zZXN0IGhlcmUgZHVlIHRvIG1vdXNlb3ZlciBidWJibGluZyxcblx0XHRcdFx0Ly8gYnV0IGFsd2F5cyBwb2ludGluZyBhdCB0aGUgc2FtZSBldmVudCB0YXJnZXRcblx0XHRcdFx0LmNsb3Nlc3QoIHRoaXMub3B0aW9ucy5pdGVtcyApO1xuXG5cdFx0Ly8gTm8gZWxlbWVudCB0byBzaG93IGEgdG9vbHRpcCBmb3Igb3IgdGhlIHRvb2x0aXAgaXMgYWxyZWFkeSBvcGVuXG5cdFx0aWYgKCAhdGFyZ2V0Lmxlbmd0aCB8fCB0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLWlkXCIgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRhcmdldC5hdHRyKCBcInRpdGxlXCIgKSApIHtcblx0XHRcdHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiwgdGFyZ2V0LmF0dHIoIFwidGl0bGVcIiApICk7XG5cdFx0fVxuXG5cdFx0dGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC1vcGVuXCIsIHRydWUgKTtcblxuXHRcdC8vIEtpbGwgcGFyZW50IHRvb2x0aXBzLCBjdXN0b20gb3IgbmF0aXZlLCBmb3IgaG92ZXJcblx0XHRpZiAoIGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09IFwibW91c2VvdmVyXCIgKSB7XG5cdFx0XHR0YXJnZXQucGFyZW50cygpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgcGFyZW50ID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdGJsdXJFdmVudDtcblx0XHRcdFx0aWYgKCBwYXJlbnQuZGF0YSggXCJ1aS10b29sdGlwLW9wZW5cIiApICkge1xuXHRcdFx0XHRcdGJsdXJFdmVudCA9ICQuRXZlbnQoIFwiYmx1clwiICk7XG5cdFx0XHRcdFx0Ymx1ckV2ZW50LnRhcmdldCA9IGJsdXJFdmVudC5jdXJyZW50VGFyZ2V0ID0gdGhpcztcblx0XHRcdFx0XHR0aGF0LmNsb3NlKCBibHVyRXZlbnQsIHRydWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHBhcmVudC5hdHRyKCBcInRpdGxlXCIgKSApIHtcblx0XHRcdFx0XHRwYXJlbnQudW5pcXVlSWQoKTtcblx0XHRcdFx0XHR0aGF0LnBhcmVudHNbIHRoaXMuaWQgXSA9IHtcblx0XHRcdFx0XHRcdGVsZW1lbnQ6IHRoaXMsXG5cdFx0XHRcdFx0XHR0aXRsZTogcGFyZW50LmF0dHIoIFwidGl0bGVcIiApXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRwYXJlbnQuYXR0ciggXCJ0aXRsZVwiLCBcIlwiICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9yZWdpc3RlckNsb3NlSGFuZGxlcnMoIGV2ZW50LCB0YXJnZXQgKTtcblx0XHR0aGlzLl91cGRhdGVDb250ZW50KCB0YXJnZXQsIGV2ZW50ICk7XG5cdH0sXG5cblx0X3VwZGF0ZUNvbnRlbnQ6IGZ1bmN0aW9uKCB0YXJnZXQsIGV2ZW50ICkge1xuXHRcdHZhciBjb250ZW50LFxuXHRcdFx0Y29udGVudE9wdGlvbiA9IHRoaXMub3B0aW9ucy5jb250ZW50LFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRldmVudFR5cGUgPSBldmVudCA/IGV2ZW50LnR5cGUgOiBudWxsO1xuXG5cdFx0aWYgKCB0eXBlb2YgY29udGVudE9wdGlvbiA9PT0gXCJzdHJpbmdcIiB8fCBjb250ZW50T3B0aW9uLm5vZGVUeXBlIHx8XG5cdFx0XHRcdGNvbnRlbnRPcHRpb24uanF1ZXJ5ICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX29wZW4oIGV2ZW50LCB0YXJnZXQsIGNvbnRlbnRPcHRpb24gKTtcblx0XHR9XG5cblx0XHRjb250ZW50ID0gY29udGVudE9wdGlvbi5jYWxsKCB0YXJnZXRbIDAgXSwgZnVuY3Rpb24oIHJlc3BvbnNlICkge1xuXG5cdFx0XHQvLyBJRSBtYXkgaW5zdGFudGx5IHNlcnZlIGEgY2FjaGVkIHJlc3BvbnNlIGZvciBhamF4IHJlcXVlc3RzXG5cdFx0XHQvLyBkZWxheSB0aGlzIGNhbGwgdG8gX29wZW4gc28gdGhlIG90aGVyIGNhbGwgdG8gX29wZW4gcnVucyBmaXJzdFxuXHRcdFx0dGhhdC5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdC8vIElnbm9yZSBhc3luYyByZXNwb25zZSBpZiB0b29sdGlwIHdhcyBjbG9zZWQgYWxyZWFkeVxuXHRcdFx0XHRpZiAoICF0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLW9wZW5cIiApICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEpRdWVyeSBjcmVhdGVzIGEgc3BlY2lhbCBldmVudCBmb3IgZm9jdXNpbiB3aGVuIGl0IGRvZXNuJ3Rcblx0XHRcdFx0Ly8gZXhpc3QgbmF0aXZlbHkuIFRvIGltcHJvdmUgcGVyZm9ybWFuY2UsIHRoZSBuYXRpdmUgZXZlbnRcblx0XHRcdFx0Ly8gb2JqZWN0IGlzIHJldXNlZCBhbmQgdGhlIHR5cGUgaXMgY2hhbmdlZC4gVGhlcmVmb3JlLCB3ZSBjYW4ndFxuXHRcdFx0XHQvLyByZWx5IG9uIHRoZSB0eXBlIGJlaW5nIGNvcnJlY3QgYWZ0ZXIgdGhlIGV2ZW50IGZpbmlzaGVkXG5cdFx0XHRcdC8vIGJ1YmJsaW5nLCBzbyB3ZSBzZXQgaXQgYmFjayB0byB0aGUgcHJldmlvdXMgdmFsdWUuICgjODc0MClcblx0XHRcdFx0aWYgKCBldmVudCApIHtcblx0XHRcdFx0XHRldmVudC50eXBlID0gZXZlbnRUeXBlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoaXMuX29wZW4oIGV2ZW50LCB0YXJnZXQsIHJlc3BvbnNlICk7XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHRcdGlmICggY29udGVudCApIHtcblx0XHRcdHRoaXMuX29wZW4oIGV2ZW50LCB0YXJnZXQsIGNvbnRlbnQgKTtcblx0XHR9XG5cdH0sXG5cblx0X29wZW46IGZ1bmN0aW9uKCBldmVudCwgdGFyZ2V0LCBjb250ZW50ICkge1xuXHRcdHZhciB0b29sdGlwRGF0YSwgdG9vbHRpcCwgZGVsYXllZFNob3csIGExMXlDb250ZW50LFxuXHRcdFx0cG9zaXRpb25PcHRpb24gPSAkLmV4dGVuZCgge30sIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApO1xuXG5cdFx0aWYgKCAhY29udGVudCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBDb250ZW50IGNhbiBiZSB1cGRhdGVkIG11bHRpcGxlIHRpbWVzLiBJZiB0aGUgdG9vbHRpcCBhbHJlYWR5XG5cdFx0Ly8gZXhpc3RzLCB0aGVuIGp1c3QgdXBkYXRlIHRoZSBjb250ZW50IGFuZCBiYWlsLlxuXHRcdHRvb2x0aXBEYXRhID0gdGhpcy5fZmluZCggdGFyZ2V0ICk7XG5cdFx0aWYgKCB0b29sdGlwRGF0YSApIHtcblx0XHRcdHRvb2x0aXBEYXRhLnRvb2x0aXAuZmluZCggXCIudWktdG9vbHRpcC1jb250ZW50XCIgKS5odG1sKCBjb250ZW50ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gSWYgd2UgaGF2ZSBhIHRpdGxlLCBjbGVhciBpdCB0byBwcmV2ZW50IHRoZSBuYXRpdmUgdG9vbHRpcFxuXHRcdC8vIHdlIGhhdmUgdG8gY2hlY2sgZmlyc3QgdG8gYXZvaWQgZGVmaW5pbmcgYSB0aXRsZSBpZiBub25lIGV4aXN0c1xuXHRcdC8vICh3ZSBkb24ndCB3YW50IHRvIGNhdXNlIGFuIGVsZW1lbnQgdG8gc3RhcnQgbWF0Y2hpbmcgW3RpdGxlXSlcblx0XHQvL1xuXHRcdC8vIFdlIHVzZSByZW1vdmVBdHRyIG9ubHkgZm9yIGtleSBldmVudHMsIHRvIGFsbG93IElFIHRvIGV4cG9ydCB0aGUgY29ycmVjdFxuXHRcdC8vIGFjY2Vzc2libGUgYXR0cmlidXRlcy4gRm9yIG1vdXNlIGV2ZW50cywgc2V0IHRvIGVtcHR5IHN0cmluZyB0byBhdm9pZFxuXHRcdC8vIG5hdGl2ZSB0b29sdGlwIHNob3dpbmcgdXAgKGhhcHBlbnMgb25seSB3aGVuIHJlbW92aW5nIGluc2lkZSBtb3VzZW92ZXIpLlxuXHRcdGlmICggdGFyZ2V0LmlzKCBcIlt0aXRsZV1cIiApICkge1xuXHRcdFx0aWYgKCBldmVudCAmJiBldmVudC50eXBlID09PSBcIm1vdXNlb3ZlclwiICkge1xuXHRcdFx0XHR0YXJnZXQuYXR0ciggXCJ0aXRsZVwiLCBcIlwiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0YXJnZXQucmVtb3ZlQXR0ciggXCJ0aXRsZVwiICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dG9vbHRpcERhdGEgPSB0aGlzLl90b29sdGlwKCB0YXJnZXQgKTtcblx0XHR0b29sdGlwID0gdG9vbHRpcERhdGEudG9vbHRpcDtcblx0XHR0aGlzLl9hZGREZXNjcmliZWRCeSggdGFyZ2V0LCB0b29sdGlwLmF0dHIoIFwiaWRcIiApICk7XG5cdFx0dG9vbHRpcC5maW5kKCBcIi51aS10b29sdGlwLWNvbnRlbnRcIiApLmh0bWwoIGNvbnRlbnQgKTtcblxuXHRcdC8vIFN1cHBvcnQ6IFZvaWNlb3ZlciBvbiBPUyBYLCBKQVdTIG9uIElFIDw9IDlcblx0XHQvLyBKQVdTIGFubm91bmNlcyBkZWxldGlvbnMgZXZlbiB3aGVuIGFyaWEtcmVsZXZhbnQ9XCJhZGRpdGlvbnNcIlxuXHRcdC8vIFZvaWNlb3ZlciB3aWxsIHNvbWV0aW1lcyByZS1yZWFkIHRoZSBlbnRpcmUgbG9nIHJlZ2lvbidzIGNvbnRlbnRzIGZyb20gdGhlIGJlZ2lubmluZ1xuXHRcdHRoaXMubGl2ZVJlZ2lvbi5jaGlsZHJlbigpLmhpZGUoKTtcblx0XHRhMTF5Q29udGVudCA9ICQoIFwiPGRpdj5cIiApLmh0bWwoIHRvb2x0aXAuZmluZCggXCIudWktdG9vbHRpcC1jb250ZW50XCIgKS5odG1sKCkgKTtcblx0XHRhMTF5Q29udGVudC5yZW1vdmVBdHRyKCBcIm5hbWVcIiApLmZpbmQoIFwiW25hbWVdXCIgKS5yZW1vdmVBdHRyKCBcIm5hbWVcIiApO1xuXHRcdGExMXlDb250ZW50LnJlbW92ZUF0dHIoIFwiaWRcIiApLmZpbmQoIFwiW2lkXVwiICkucmVtb3ZlQXR0ciggXCJpZFwiICk7XG5cdFx0YTExeUNvbnRlbnQuYXBwZW5kVG8oIHRoaXMubGl2ZVJlZ2lvbiApO1xuXG5cdFx0ZnVuY3Rpb24gcG9zaXRpb24oIGV2ZW50ICkge1xuXHRcdFx0cG9zaXRpb25PcHRpb24ub2YgPSBldmVudDtcblx0XHRcdGlmICggdG9vbHRpcC5pcyggXCI6aGlkZGVuXCIgKSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0dG9vbHRpcC5wb3NpdGlvbiggcG9zaXRpb25PcHRpb24gKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMudHJhY2sgJiYgZXZlbnQgJiYgL15tb3VzZS8udGVzdCggZXZlbnQudHlwZSApICkge1xuXHRcdFx0dGhpcy5fb24oIHRoaXMuZG9jdW1lbnQsIHtcblx0XHRcdFx0bW91c2Vtb3ZlOiBwb3NpdGlvblxuXHRcdFx0fSApO1xuXG5cdFx0XHQvLyB0cmlnZ2VyIG9uY2UgdG8gb3ZlcnJpZGUgZWxlbWVudC1yZWxhdGl2ZSBwb3NpdGlvbmluZ1xuXHRcdFx0cG9zaXRpb24oIGV2ZW50ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRvb2x0aXAucG9zaXRpb24oICQuZXh0ZW5kKCB7XG5cdFx0XHRcdG9mOiB0YXJnZXRcblx0XHRcdH0sIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApICk7XG5cdFx0fVxuXG5cdFx0dG9vbHRpcC5oaWRlKCk7XG5cblx0XHR0aGlzLl9zaG93KCB0b29sdGlwLCB0aGlzLm9wdGlvbnMuc2hvdyApO1xuXG5cdFx0Ly8gSGFuZGxlIHRyYWNraW5nIHRvb2x0aXBzIHRoYXQgYXJlIHNob3duIHdpdGggYSBkZWxheSAoIzg2NDQpLiBBcyBzb29uXG5cdFx0Ly8gYXMgdGhlIHRvb2x0aXAgaXMgdmlzaWJsZSwgcG9zaXRpb24gdGhlIHRvb2x0aXAgdXNpbmcgdGhlIG1vc3QgcmVjZW50XG5cdFx0Ly8gZXZlbnQuXG5cdFx0Ly8gQWRkcyB0aGUgY2hlY2sgdG8gYWRkIHRoZSB0aW1lcnMgb25seSB3aGVuIGJvdGggZGVsYXkgYW5kIHRyYWNrIG9wdGlvbnMgYXJlIHNldCAoIzE0NjgyKVxuXHRcdGlmICggdGhpcy5vcHRpb25zLnRyYWNrICYmIHRoaXMub3B0aW9ucy5zaG93ICYmIHRoaXMub3B0aW9ucy5zaG93LmRlbGF5ICkge1xuXHRcdFx0ZGVsYXllZFNob3cgPSB0aGlzLmRlbGF5ZWRTaG93ID0gc2V0SW50ZXJ2YWwoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHRvb2x0aXAuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uKCBwb3NpdGlvbk9wdGlvbi5vZiApO1xuXHRcdFx0XHRcdGNsZWFySW50ZXJ2YWwoIGRlbGF5ZWRTaG93ICk7XG5cdFx0XHRcdH1cblx0XHRcdH0sICQuZnguaW50ZXJ2YWwgKTtcblx0XHR9XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcIm9wZW5cIiwgZXZlbnQsIHsgdG9vbHRpcDogdG9vbHRpcCB9ICk7XG5cdH0sXG5cblx0X3JlZ2lzdGVyQ2xvc2VIYW5kbGVyczogZnVuY3Rpb24oIGV2ZW50LCB0YXJnZXQgKSB7XG5cdFx0dmFyIGV2ZW50cyA9IHtcblx0XHRcdGtleXVwOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLkVTQ0FQRSApIHtcblx0XHRcdFx0XHR2YXIgZmFrZUV2ZW50ID0gJC5FdmVudCggZXZlbnQgKTtcblx0XHRcdFx0XHRmYWtlRXZlbnQuY3VycmVudFRhcmdldCA9IHRhcmdldFsgMCBdO1xuXHRcdFx0XHRcdHRoaXMuY2xvc2UoIGZha2VFdmVudCwgdHJ1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdC8vIE9ubHkgYmluZCByZW1vdmUgaGFuZGxlciBmb3IgZGVsZWdhdGVkIHRhcmdldHMuIE5vbi1kZWxlZ2F0ZWRcblx0XHQvLyB0b29sdGlwcyB3aWxsIGhhbmRsZSB0aGlzIGluIGRlc3Ryb3kuXG5cdFx0aWYgKCB0YXJnZXRbIDAgXSAhPT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRldmVudHMucmVtb3ZlID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZVRvb2x0aXAoIHRoaXMuX2ZpbmQoIHRhcmdldCApLnRvb2x0aXAgKTtcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0aWYgKCAhZXZlbnQgfHwgZXZlbnQudHlwZSA9PT0gXCJtb3VzZW92ZXJcIiApIHtcblx0XHRcdGV2ZW50cy5tb3VzZWxlYXZlID0gXCJjbG9zZVwiO1xuXHRcdH1cblx0XHRpZiAoICFldmVudCB8fCBldmVudC50eXBlID09PSBcImZvY3VzaW5cIiApIHtcblx0XHRcdGV2ZW50cy5mb2N1c291dCA9IFwiY2xvc2VcIjtcblx0XHR9XG5cdFx0dGhpcy5fb24oIHRydWUsIHRhcmdldCwgZXZlbnRzICk7XG5cdH0sXG5cblx0Y2xvc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdG9vbHRpcCxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0dGFyZ2V0ID0gJCggZXZlbnQgPyBldmVudC5jdXJyZW50VGFyZ2V0IDogdGhpcy5lbGVtZW50ICksXG5cdFx0XHR0b29sdGlwRGF0YSA9IHRoaXMuX2ZpbmQoIHRhcmdldCApO1xuXG5cdFx0Ly8gVGhlIHRvb2x0aXAgbWF5IGFscmVhZHkgYmUgY2xvc2VkXG5cdFx0aWYgKCAhdG9vbHRpcERhdGEgKSB7XG5cblx0XHRcdC8vIFdlIHNldCB1aS10b29sdGlwLW9wZW4gaW1tZWRpYXRlbHkgdXBvbiBvcGVuIChpbiBvcGVuKCkpLCBidXQgb25seSBzZXQgdGhlXG5cdFx0XHQvLyBhZGRpdGlvbmFsIGRhdGEgb25jZSB0aGVyZSdzIGFjdHVhbGx5IGNvbnRlbnQgdG8gc2hvdyAoaW4gX29wZW4oKSkuIFNvIGV2ZW4gaWYgdGhlXG5cdFx0XHQvLyB0b29sdGlwIGRvZXNuJ3QgaGF2ZSBmdWxsIGRhdGEsIHdlIGFsd2F5cyByZW1vdmUgdWktdG9vbHRpcC1vcGVuIGluIGNhc2Ugd2UncmUgaW5cblx0XHRcdC8vIHRoZSBwZXJpb2QgYmV0d2VlbiBvcGVuKCkgYW5kIF9vcGVuKCkuXG5cdFx0XHR0YXJnZXQucmVtb3ZlRGF0YSggXCJ1aS10b29sdGlwLW9wZW5cIiApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRvb2x0aXAgPSB0b29sdGlwRGF0YS50b29sdGlwO1xuXG5cdFx0Ly8gRGlzYWJsaW5nIGNsb3NlcyB0aGUgdG9vbHRpcCwgc28gd2UgbmVlZCB0byB0cmFjayB3aGVuIHdlJ3JlIGNsb3Npbmdcblx0XHQvLyB0byBhdm9pZCBhbiBpbmZpbml0ZSBsb29wIGluIGNhc2UgdGhlIHRvb2x0aXAgYmVjb21lcyBkaXNhYmxlZCBvbiBjbG9zZVxuXHRcdGlmICggdG9vbHRpcERhdGEuY2xvc2luZyApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBDbGVhciB0aGUgaW50ZXJ2YWwgZm9yIGRlbGF5ZWQgdHJhY2tpbmcgdG9vbHRpcHNcblx0XHRjbGVhckludGVydmFsKCB0aGlzLmRlbGF5ZWRTaG93ICk7XG5cblx0XHQvLyBPbmx5IHNldCB0aXRsZSBpZiB3ZSBoYWQgb25lIGJlZm9yZSAoc2VlIGNvbW1lbnQgaW4gX29wZW4oKSlcblx0XHQvLyBJZiB0aGUgdGl0bGUgYXR0cmlidXRlIGhhcyBjaGFuZ2VkIHNpbmNlIG9wZW4oKSwgZG9uJ3QgcmVzdG9yZVxuXHRcdGlmICggdGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgJiYgIXRhcmdldC5hdHRyKCBcInRpdGxlXCIgKSApIHtcblx0XHRcdHRhcmdldC5hdHRyKCBcInRpdGxlXCIsIHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVtb3ZlRGVzY3JpYmVkQnkoIHRhcmdldCApO1xuXG5cdFx0dG9vbHRpcERhdGEuaGlkaW5nID0gdHJ1ZTtcblx0XHR0b29sdGlwLnN0b3AoIHRydWUgKTtcblx0XHR0aGlzLl9oaWRlKCB0b29sdGlwLCB0aGlzLm9wdGlvbnMuaGlkZSwgZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGF0Ll9yZW1vdmVUb29sdGlwKCAkKCB0aGlzICkgKTtcblx0XHR9ICk7XG5cblx0XHR0YXJnZXQucmVtb3ZlRGF0YSggXCJ1aS10b29sdGlwLW9wZW5cIiApO1xuXHRcdHRoaXMuX29mZiggdGFyZ2V0LCBcIm1vdXNlbGVhdmUgZm9jdXNvdXQga2V5dXBcIiApO1xuXG5cdFx0Ly8gUmVtb3ZlICdyZW1vdmUnIGJpbmRpbmcgb25seSBvbiBkZWxlZ2F0ZWQgdGFyZ2V0c1xuXHRcdGlmICggdGFyZ2V0WyAwIF0gIT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0dGhpcy5fb2ZmKCB0YXJnZXQsIFwicmVtb3ZlXCIgKTtcblx0XHR9XG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmRvY3VtZW50LCBcIm1vdXNlbW92ZVwiICk7XG5cblx0XHRpZiAoIGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09IFwibW91c2VsZWF2ZVwiICkge1xuXHRcdFx0JC5lYWNoKCB0aGlzLnBhcmVudHMsIGZ1bmN0aW9uKCBpZCwgcGFyZW50ICkge1xuXHRcdFx0XHQkKCBwYXJlbnQuZWxlbWVudCApLmF0dHIoIFwidGl0bGVcIiwgcGFyZW50LnRpdGxlICk7XG5cdFx0XHRcdGRlbGV0ZSB0aGF0LnBhcmVudHNbIGlkIF07XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dG9vbHRpcERhdGEuY2xvc2luZyA9IHRydWU7XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJjbG9zZVwiLCBldmVudCwgeyB0b29sdGlwOiB0b29sdGlwIH0gKTtcblx0XHRpZiAoICF0b29sdGlwRGF0YS5oaWRpbmcgKSB7XG5cdFx0XHR0b29sdGlwRGF0YS5jbG9zaW5nID0gZmFsc2U7XG5cdFx0fVxuXHR9LFxuXG5cdF90b29sdGlwOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgdG9vbHRpcCA9ICQoIFwiPGRpdj5cIiApLmF0dHIoIFwicm9sZVwiLCBcInRvb2x0aXBcIiApLFxuXHRcdFx0Y29udGVudCA9ICQoIFwiPGRpdj5cIiApLmFwcGVuZFRvKCB0b29sdGlwICksXG5cdFx0XHRpZCA9IHRvb2x0aXAudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBjb250ZW50LCBcInVpLXRvb2x0aXAtY29udGVudFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRvb2x0aXAsIFwidWktdG9vbHRpcFwiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHR0b29sdGlwLmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbyggZWxlbWVudCApICk7XG5cblx0XHRyZXR1cm4gdGhpcy50b29sdGlwc1sgaWQgXSA9IHtcblx0XHRcdGVsZW1lbnQ6IGVsZW1lbnQsXG5cdFx0XHR0b29sdGlwOiB0b29sdGlwXG5cdFx0fTtcblx0fSxcblxuXHRfZmluZDogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgaWQgPSB0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLWlkXCIgKTtcblx0XHRyZXR1cm4gaWQgPyB0aGlzLnRvb2x0aXBzWyBpZCBdIDogbnVsbDtcblx0fSxcblxuXHRfcmVtb3ZlVG9vbHRpcDogZnVuY3Rpb24oIHRvb2x0aXAgKSB7XG5cdFx0dG9vbHRpcC5yZW1vdmUoKTtcblx0XHRkZWxldGUgdGhpcy50b29sdGlwc1sgdG9vbHRpcC5hdHRyKCBcImlkXCIgKSBdO1xuXHR9LFxuXG5cdF9hcHBlbmRUbzogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgZWxlbWVudCA9IHRhcmdldC5jbG9zZXN0KCBcIi51aS1mcm9udCwgZGlhbG9nXCIgKTtcblxuXHRcdGlmICggIWVsZW1lbnQubGVuZ3RoICkge1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5O1xuXHRcdH1cblxuXHRcdHJldHVybiBlbGVtZW50O1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHQvLyBDbG9zZSBvcGVuIHRvb2x0aXBzXG5cdFx0JC5lYWNoKCB0aGlzLnRvb2x0aXBzLCBmdW5jdGlvbiggaWQsIHRvb2x0aXBEYXRhICkge1xuXG5cdFx0XHQvLyBEZWxlZ2F0ZSB0byBjbG9zZSBtZXRob2QgdG8gaGFuZGxlIGNvbW1vbiBjbGVhbnVwXG5cdFx0XHR2YXIgZXZlbnQgPSAkLkV2ZW50KCBcImJsdXJcIiApLFxuXHRcdFx0XHRlbGVtZW50ID0gdG9vbHRpcERhdGEuZWxlbWVudDtcblx0XHRcdGV2ZW50LnRhcmdldCA9IGV2ZW50LmN1cnJlbnRUYXJnZXQgPSBlbGVtZW50WyAwIF07XG5cdFx0XHR0aGF0LmNsb3NlKCBldmVudCwgdHJ1ZSApO1xuXG5cdFx0XHQvLyBSZW1vdmUgaW1tZWRpYXRlbHk7IGRlc3Ryb3lpbmcgYW4gb3BlbiB0b29sdGlwIGRvZXNuJ3QgdXNlIHRoZVxuXHRcdFx0Ly8gaGlkZSBhbmltYXRpb25cblx0XHRcdCQoIFwiI1wiICsgaWQgKS5yZW1vdmUoKTtcblxuXHRcdFx0Ly8gUmVzdG9yZSB0aGUgdGl0bGVcblx0XHRcdGlmICggZWxlbWVudC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICkge1xuXG5cdFx0XHRcdC8vIElmIHRoZSB0aXRsZSBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQgc2luY2Ugb3BlbigpLCBkb24ndCByZXN0b3JlXG5cdFx0XHRcdGlmICggIWVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiICkgKSB7XG5cdFx0XHRcdFx0ZWxlbWVudC5hdHRyKCBcInRpdGxlXCIsIGVsZW1lbnQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGVsZW1lbnQucmVtb3ZlRGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0dGhpcy5saXZlUmVnaW9uLnJlbW92ZSgpO1xuXHR9XG59ICk7XG5cbi8vIERFUFJFQ0FURURcbi8vIFRPRE86IFN3aXRjaCByZXR1cm4gYmFjayB0byB3aWRnZXQgZGVjbGFyYXRpb24gYXQgdG9wIG9mIGZpbGUgd2hlbiB0aGlzIGlzIHJlbW92ZWRcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIEJhY2tjb21wYXQgZm9yIHRvb2x0aXBDbGFzcyBvcHRpb25cblx0JC53aWRnZXQoIFwidWkudG9vbHRpcFwiLCAkLnVpLnRvb2x0aXAsIHtcblx0XHRvcHRpb25zOiB7XG5cdFx0XHR0b29sdGlwQ2xhc3M6IG51bGxcblx0XHR9LFxuXHRcdF90b29sdGlwOiBmdW5jdGlvbigpIHtcblx0XHRcdHZhciB0b29sdGlwRGF0YSA9IHRoaXMuX3N1cGVyQXBwbHkoIGFyZ3VtZW50cyApO1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMudG9vbHRpcENsYXNzICkge1xuXHRcdFx0XHR0b29sdGlwRGF0YS50b29sdGlwLmFkZENsYXNzKCB0aGlzLm9wdGlvbnMudG9vbHRpcENsYXNzICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdG9vbHRpcERhdGE7XG5cdFx0fVxuXHR9ICk7XG59XG5cbnZhciB3aWRnZXRzVG9vbHRpcCA9ICQudWkudG9vbHRpcDtcblxuXG5cblxufSkpOyIsIihmdW5jdGlvbiBkZWZpbmVNdXN0YWNoZShnbG9iYWwsZmFjdG9yeSl7aWYodHlwZW9mIGV4cG9ydHM9PT1cIm9iamVjdFwiJiZleHBvcnRzJiZ0eXBlb2YgZXhwb3J0cy5ub2RlTmFtZSE9PVwic3RyaW5nXCIpe2ZhY3RvcnkoZXhwb3J0cyl9ZWxzZSBpZih0eXBlb2YgZGVmaW5lPT09XCJmdW5jdGlvblwiJiZkZWZpbmUuYW1kKXtkZWZpbmUoW1wiZXhwb3J0c1wiXSxmYWN0b3J5KX1lbHNle2dsb2JhbC5NdXN0YWNoZT17fTtmYWN0b3J5KGdsb2JhbC5NdXN0YWNoZSl9fSkodGhpcyxmdW5jdGlvbiBtdXN0YWNoZUZhY3RvcnkobXVzdGFjaGUpe3ZhciBvYmplY3RUb1N0cmluZz1PYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO3ZhciBpc0FycmF5PUFycmF5LmlzQXJyYXl8fGZ1bmN0aW9uIGlzQXJyYXlQb2x5ZmlsbChvYmplY3Qpe3JldHVybiBvYmplY3RUb1N0cmluZy5jYWxsKG9iamVjdCk9PT1cIltvYmplY3QgQXJyYXldXCJ9O2Z1bmN0aW9uIGlzRnVuY3Rpb24ob2JqZWN0KXtyZXR1cm4gdHlwZW9mIG9iamVjdD09PVwiZnVuY3Rpb25cIn1mdW5jdGlvbiB0eXBlU3RyKG9iail7cmV0dXJuIGlzQXJyYXkob2JqKT9cImFycmF5XCI6dHlwZW9mIG9ian1mdW5jdGlvbiBlc2NhcGVSZWdFeHAoc3RyaW5nKXtyZXR1cm4gc3RyaW5nLnJlcGxhY2UoL1tcXC1cXFtcXF17fSgpKis/LixcXFxcXFxeJHwjXFxzXS9nLFwiXFxcXCQmXCIpfWZ1bmN0aW9uIGhhc1Byb3BlcnR5KG9iaixwcm9wTmFtZSl7cmV0dXJuIG9iaiE9bnVsbCYmdHlwZW9mIG9iaj09PVwib2JqZWN0XCImJnByb3BOYW1lIGluIG9ian12YXIgcmVnRXhwVGVzdD1SZWdFeHAucHJvdG90eXBlLnRlc3Q7ZnVuY3Rpb24gdGVzdFJlZ0V4cChyZSxzdHJpbmcpe3JldHVybiByZWdFeHBUZXN0LmNhbGwocmUsc3RyaW5nKX12YXIgbm9uU3BhY2VSZT0vXFxTLztmdW5jdGlvbiBpc1doaXRlc3BhY2Uoc3RyaW5nKXtyZXR1cm4hdGVzdFJlZ0V4cChub25TcGFjZVJlLHN0cmluZyl9dmFyIGVudGl0eU1hcD17XCImXCI6XCImYW1wO1wiLFwiPFwiOlwiJmx0O1wiLFwiPlwiOlwiJmd0O1wiLCdcIic6XCImcXVvdDtcIixcIidcIjpcIiYjMzk7XCIsXCIvXCI6XCImI3gyRjtcIixcImBcIjpcIiYjeDYwO1wiLFwiPVwiOlwiJiN4M0Q7XCJ9O2Z1bmN0aW9uIGVzY2FwZUh0bWwoc3RyaW5nKXtyZXR1cm4gU3RyaW5nKHN0cmluZykucmVwbGFjZSgvWyY8PlwiJ2A9XFwvXS9nLGZ1bmN0aW9uIGZyb21FbnRpdHlNYXAocyl7cmV0dXJuIGVudGl0eU1hcFtzXX0pfXZhciB3aGl0ZVJlPS9cXHMqLzt2YXIgc3BhY2VSZT0vXFxzKy87dmFyIGVxdWFsc1JlPS9cXHMqPS87dmFyIGN1cmx5UmU9L1xccypcXH0vO3ZhciB0YWdSZT0vI3xcXF58XFwvfD58XFx7fCZ8PXwhLztmdW5jdGlvbiBwYXJzZVRlbXBsYXRlKHRlbXBsYXRlLHRhZ3Mpe2lmKCF0ZW1wbGF0ZSlyZXR1cm5bXTt2YXIgc2VjdGlvbnM9W107dmFyIHRva2Vucz1bXTt2YXIgc3BhY2VzPVtdO3ZhciBoYXNUYWc9ZmFsc2U7dmFyIG5vblNwYWNlPWZhbHNlO2Z1bmN0aW9uIHN0cmlwU3BhY2UoKXtpZihoYXNUYWcmJiFub25TcGFjZSl7d2hpbGUoc3BhY2VzLmxlbmd0aClkZWxldGUgdG9rZW5zW3NwYWNlcy5wb3AoKV19ZWxzZXtzcGFjZXM9W119aGFzVGFnPWZhbHNlO25vblNwYWNlPWZhbHNlfXZhciBvcGVuaW5nVGFnUmUsY2xvc2luZ1RhZ1JlLGNsb3NpbmdDdXJseVJlO2Z1bmN0aW9uIGNvbXBpbGVUYWdzKHRhZ3NUb0NvbXBpbGUpe2lmKHR5cGVvZiB0YWdzVG9Db21waWxlPT09XCJzdHJpbmdcIil0YWdzVG9Db21waWxlPXRhZ3NUb0NvbXBpbGUuc3BsaXQoc3BhY2VSZSwyKTtpZighaXNBcnJheSh0YWdzVG9Db21waWxlKXx8dGFnc1RvQ29tcGlsZS5sZW5ndGghPT0yKXRocm93IG5ldyBFcnJvcihcIkludmFsaWQgdGFnczogXCIrdGFnc1RvQ29tcGlsZSk7b3BlbmluZ1RhZ1JlPW5ldyBSZWdFeHAoZXNjYXBlUmVnRXhwKHRhZ3NUb0NvbXBpbGVbMF0pK1wiXFxcXHMqXCIpO2Nsb3NpbmdUYWdSZT1uZXcgUmVnRXhwKFwiXFxcXHMqXCIrZXNjYXBlUmVnRXhwKHRhZ3NUb0NvbXBpbGVbMV0pKTtjbG9zaW5nQ3VybHlSZT1uZXcgUmVnRXhwKFwiXFxcXHMqXCIrZXNjYXBlUmVnRXhwKFwifVwiK3RhZ3NUb0NvbXBpbGVbMV0pKX1jb21waWxlVGFncyh0YWdzfHxtdXN0YWNoZS50YWdzKTt2YXIgc2Nhbm5lcj1uZXcgU2Nhbm5lcih0ZW1wbGF0ZSk7dmFyIHN0YXJ0LHR5cGUsdmFsdWUsY2hyLHRva2VuLG9wZW5TZWN0aW9uO3doaWxlKCFzY2FubmVyLmVvcygpKXtzdGFydD1zY2FubmVyLnBvczt2YWx1ZT1zY2FubmVyLnNjYW5VbnRpbChvcGVuaW5nVGFnUmUpO2lmKHZhbHVlKXtmb3IodmFyIGk9MCx2YWx1ZUxlbmd0aD12YWx1ZS5sZW5ndGg7aTx2YWx1ZUxlbmd0aDsrK2kpe2Nocj12YWx1ZS5jaGFyQXQoaSk7aWYoaXNXaGl0ZXNwYWNlKGNocikpe3NwYWNlcy5wdXNoKHRva2Vucy5sZW5ndGgpfWVsc2V7bm9uU3BhY2U9dHJ1ZX10b2tlbnMucHVzaChbXCJ0ZXh0XCIsY2hyLHN0YXJ0LHN0YXJ0KzFdKTtzdGFydCs9MTtpZihjaHI9PT1cIlxcblwiKXN0cmlwU3BhY2UoKX19aWYoIXNjYW5uZXIuc2NhbihvcGVuaW5nVGFnUmUpKWJyZWFrO2hhc1RhZz10cnVlO3R5cGU9c2Nhbm5lci5zY2FuKHRhZ1JlKXx8XCJuYW1lXCI7c2Nhbm5lci5zY2FuKHdoaXRlUmUpO2lmKHR5cGU9PT1cIj1cIil7dmFsdWU9c2Nhbm5lci5zY2FuVW50aWwoZXF1YWxzUmUpO3NjYW5uZXIuc2NhbihlcXVhbHNSZSk7c2Nhbm5lci5zY2FuVW50aWwoY2xvc2luZ1RhZ1JlKX1lbHNlIGlmKHR5cGU9PT1cIntcIil7dmFsdWU9c2Nhbm5lci5zY2FuVW50aWwoY2xvc2luZ0N1cmx5UmUpO3NjYW5uZXIuc2NhbihjdXJseVJlKTtzY2FubmVyLnNjYW5VbnRpbChjbG9zaW5nVGFnUmUpO3R5cGU9XCImXCJ9ZWxzZXt2YWx1ZT1zY2FubmVyLnNjYW5VbnRpbChjbG9zaW5nVGFnUmUpfWlmKCFzY2FubmVyLnNjYW4oY2xvc2luZ1RhZ1JlKSl0aHJvdyBuZXcgRXJyb3IoXCJVbmNsb3NlZCB0YWcgYXQgXCIrc2Nhbm5lci5wb3MpO3Rva2VuPVt0eXBlLHZhbHVlLHN0YXJ0LHNjYW5uZXIucG9zXTt0b2tlbnMucHVzaCh0b2tlbik7aWYodHlwZT09PVwiI1wifHx0eXBlPT09XCJeXCIpe3NlY3Rpb25zLnB1c2godG9rZW4pfWVsc2UgaWYodHlwZT09PVwiL1wiKXtvcGVuU2VjdGlvbj1zZWN0aW9ucy5wb3AoKTtpZighb3BlblNlY3Rpb24pdGhyb3cgbmV3IEVycm9yKCdVbm9wZW5lZCBzZWN0aW9uIFwiJyt2YWx1ZSsnXCIgYXQgJytzdGFydCk7aWYob3BlblNlY3Rpb25bMV0hPT12YWx1ZSl0aHJvdyBuZXcgRXJyb3IoJ1VuY2xvc2VkIHNlY3Rpb24gXCInK29wZW5TZWN0aW9uWzFdKydcIiBhdCAnK3N0YXJ0KX1lbHNlIGlmKHR5cGU9PT1cIm5hbWVcInx8dHlwZT09PVwie1wifHx0eXBlPT09XCImXCIpe25vblNwYWNlPXRydWV9ZWxzZSBpZih0eXBlPT09XCI9XCIpe2NvbXBpbGVUYWdzKHZhbHVlKX19b3BlblNlY3Rpb249c2VjdGlvbnMucG9wKCk7aWYob3BlblNlY3Rpb24pdGhyb3cgbmV3IEVycm9yKCdVbmNsb3NlZCBzZWN0aW9uIFwiJytvcGVuU2VjdGlvblsxXSsnXCIgYXQgJytzY2FubmVyLnBvcyk7cmV0dXJuIG5lc3RUb2tlbnMoc3F1YXNoVG9rZW5zKHRva2VucykpfWZ1bmN0aW9uIHNxdWFzaFRva2Vucyh0b2tlbnMpe3ZhciBzcXVhc2hlZFRva2Vucz1bXTt2YXIgdG9rZW4sbGFzdFRva2VuO2Zvcih2YXIgaT0wLG51bVRva2Vucz10b2tlbnMubGVuZ3RoO2k8bnVtVG9rZW5zOysraSl7dG9rZW49dG9rZW5zW2ldO2lmKHRva2VuKXtpZih0b2tlblswXT09PVwidGV4dFwiJiZsYXN0VG9rZW4mJmxhc3RUb2tlblswXT09PVwidGV4dFwiKXtsYXN0VG9rZW5bMV0rPXRva2VuWzFdO2xhc3RUb2tlblszXT10b2tlblszXX1lbHNle3NxdWFzaGVkVG9rZW5zLnB1c2godG9rZW4pO2xhc3RUb2tlbj10b2tlbn19fXJldHVybiBzcXVhc2hlZFRva2Vuc31mdW5jdGlvbiBuZXN0VG9rZW5zKHRva2Vucyl7dmFyIG5lc3RlZFRva2Vucz1bXTt2YXIgY29sbGVjdG9yPW5lc3RlZFRva2Vuczt2YXIgc2VjdGlvbnM9W107dmFyIHRva2VuLHNlY3Rpb247Zm9yKHZhciBpPTAsbnVtVG9rZW5zPXRva2Vucy5sZW5ndGg7aTxudW1Ub2tlbnM7KytpKXt0b2tlbj10b2tlbnNbaV07c3dpdGNoKHRva2VuWzBdKXtjYXNlXCIjXCI6Y2FzZVwiXlwiOmNvbGxlY3Rvci5wdXNoKHRva2VuKTtzZWN0aW9ucy5wdXNoKHRva2VuKTtjb2xsZWN0b3I9dG9rZW5bNF09W107YnJlYWs7Y2FzZVwiL1wiOnNlY3Rpb249c2VjdGlvbnMucG9wKCk7c2VjdGlvbls1XT10b2tlblsyXTtjb2xsZWN0b3I9c2VjdGlvbnMubGVuZ3RoPjA/c2VjdGlvbnNbc2VjdGlvbnMubGVuZ3RoLTFdWzRdOm5lc3RlZFRva2VuczticmVhaztkZWZhdWx0OmNvbGxlY3Rvci5wdXNoKHRva2VuKX19cmV0dXJuIG5lc3RlZFRva2Vuc31mdW5jdGlvbiBTY2FubmVyKHN0cmluZyl7dGhpcy5zdHJpbmc9c3RyaW5nO3RoaXMudGFpbD1zdHJpbmc7dGhpcy5wb3M9MH1TY2FubmVyLnByb3RvdHlwZS5lb3M9ZnVuY3Rpb24gZW9zKCl7cmV0dXJuIHRoaXMudGFpbD09PVwiXCJ9O1NjYW5uZXIucHJvdG90eXBlLnNjYW49ZnVuY3Rpb24gc2NhbihyZSl7dmFyIG1hdGNoPXRoaXMudGFpbC5tYXRjaChyZSk7aWYoIW1hdGNofHxtYXRjaC5pbmRleCE9PTApcmV0dXJuXCJcIjt2YXIgc3RyaW5nPW1hdGNoWzBdO3RoaXMudGFpbD10aGlzLnRhaWwuc3Vic3RyaW5nKHN0cmluZy5sZW5ndGgpO3RoaXMucG9zKz1zdHJpbmcubGVuZ3RoO3JldHVybiBzdHJpbmd9O1NjYW5uZXIucHJvdG90eXBlLnNjYW5VbnRpbD1mdW5jdGlvbiBzY2FuVW50aWwocmUpe3ZhciBpbmRleD10aGlzLnRhaWwuc2VhcmNoKHJlKSxtYXRjaDtzd2l0Y2goaW5kZXgpe2Nhc2UtMTptYXRjaD10aGlzLnRhaWw7dGhpcy50YWlsPVwiXCI7YnJlYWs7Y2FzZSAwOm1hdGNoPVwiXCI7YnJlYWs7ZGVmYXVsdDptYXRjaD10aGlzLnRhaWwuc3Vic3RyaW5nKDAsaW5kZXgpO3RoaXMudGFpbD10aGlzLnRhaWwuc3Vic3RyaW5nKGluZGV4KX10aGlzLnBvcys9bWF0Y2gubGVuZ3RoO3JldHVybiBtYXRjaH07ZnVuY3Rpb24gQ29udGV4dCh2aWV3LHBhcmVudENvbnRleHQpe3RoaXMudmlldz12aWV3O3RoaXMuY2FjaGU9e1wiLlwiOnRoaXMudmlld307dGhpcy5wYXJlbnQ9cGFyZW50Q29udGV4dH1Db250ZXh0LnByb3RvdHlwZS5wdXNoPWZ1bmN0aW9uIHB1c2godmlldyl7cmV0dXJuIG5ldyBDb250ZXh0KHZpZXcsdGhpcyl9O0NvbnRleHQucHJvdG90eXBlLmxvb2t1cD1mdW5jdGlvbiBsb29rdXAobmFtZSl7dmFyIGNhY2hlPXRoaXMuY2FjaGU7dmFyIHZhbHVlO2lmKGNhY2hlLmhhc093blByb3BlcnR5KG5hbWUpKXt2YWx1ZT1jYWNoZVtuYW1lXX1lbHNle3ZhciBjb250ZXh0PXRoaXMsbmFtZXMsaW5kZXgsbG9va3VwSGl0PWZhbHNlO3doaWxlKGNvbnRleHQpe2lmKG5hbWUuaW5kZXhPZihcIi5cIik+MCl7dmFsdWU9Y29udGV4dC52aWV3O25hbWVzPW5hbWUuc3BsaXQoXCIuXCIpO2luZGV4PTA7d2hpbGUodmFsdWUhPW51bGwmJmluZGV4PG5hbWVzLmxlbmd0aCl7aWYoaW5kZXg9PT1uYW1lcy5sZW5ndGgtMSlsb29rdXBIaXQ9aGFzUHJvcGVydHkodmFsdWUsbmFtZXNbaW5kZXhdKTt2YWx1ZT12YWx1ZVtuYW1lc1tpbmRleCsrXV19fWVsc2V7dmFsdWU9Y29udGV4dC52aWV3W25hbWVdO2xvb2t1cEhpdD1oYXNQcm9wZXJ0eShjb250ZXh0LnZpZXcsbmFtZSl9aWYobG9va3VwSGl0KWJyZWFrO2NvbnRleHQ9Y29udGV4dC5wYXJlbnR9Y2FjaGVbbmFtZV09dmFsdWV9aWYoaXNGdW5jdGlvbih2YWx1ZSkpdmFsdWU9dmFsdWUuY2FsbCh0aGlzLnZpZXcpO3JldHVybiB2YWx1ZX07ZnVuY3Rpb24gV3JpdGVyKCl7dGhpcy5jYWNoZT17fX1Xcml0ZXIucHJvdG90eXBlLmNsZWFyQ2FjaGU9ZnVuY3Rpb24gY2xlYXJDYWNoZSgpe3RoaXMuY2FjaGU9e319O1dyaXRlci5wcm90b3R5cGUucGFyc2U9ZnVuY3Rpb24gcGFyc2UodGVtcGxhdGUsdGFncyl7dmFyIGNhY2hlPXRoaXMuY2FjaGU7dmFyIHRva2Vucz1jYWNoZVt0ZW1wbGF0ZV07aWYodG9rZW5zPT1udWxsKXRva2Vucz1jYWNoZVt0ZW1wbGF0ZV09cGFyc2VUZW1wbGF0ZSh0ZW1wbGF0ZSx0YWdzKTtyZXR1cm4gdG9rZW5zfTtXcml0ZXIucHJvdG90eXBlLnJlbmRlcj1mdW5jdGlvbiByZW5kZXIodGVtcGxhdGUsdmlldyxwYXJ0aWFscyl7dmFyIHRva2Vucz10aGlzLnBhcnNlKHRlbXBsYXRlKTt2YXIgY29udGV4dD12aWV3IGluc3RhbmNlb2YgQ29udGV4dD92aWV3Om5ldyBDb250ZXh0KHZpZXcpO3JldHVybiB0aGlzLnJlbmRlclRva2Vucyh0b2tlbnMsY29udGV4dCxwYXJ0aWFscyx0ZW1wbGF0ZSl9O1dyaXRlci5wcm90b3R5cGUucmVuZGVyVG9rZW5zPWZ1bmN0aW9uIHJlbmRlclRva2Vucyh0b2tlbnMsY29udGV4dCxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKXt2YXIgYnVmZmVyPVwiXCI7dmFyIHRva2VuLHN5bWJvbCx2YWx1ZTtmb3IodmFyIGk9MCxudW1Ub2tlbnM9dG9rZW5zLmxlbmd0aDtpPG51bVRva2VuczsrK2kpe3ZhbHVlPXVuZGVmaW5lZDt0b2tlbj10b2tlbnNbaV07c3ltYm9sPXRva2VuWzBdO2lmKHN5bWJvbD09PVwiI1wiKXZhbHVlPXRoaXMucmVuZGVyU2VjdGlvbih0b2tlbixjb250ZXh0LHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpO2Vsc2UgaWYoc3ltYm9sPT09XCJeXCIpdmFsdWU9dGhpcy5yZW5kZXJJbnZlcnRlZCh0b2tlbixjb250ZXh0LHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpO2Vsc2UgaWYoc3ltYm9sPT09XCI+XCIpdmFsdWU9dGhpcy5yZW5kZXJQYXJ0aWFsKHRva2VuLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSk7ZWxzZSBpZihzeW1ib2w9PT1cIiZcIil2YWx1ZT10aGlzLnVuZXNjYXBlZFZhbHVlKHRva2VuLGNvbnRleHQpO2Vsc2UgaWYoc3ltYm9sPT09XCJuYW1lXCIpdmFsdWU9dGhpcy5lc2NhcGVkVmFsdWUodG9rZW4sY29udGV4dCk7ZWxzZSBpZihzeW1ib2w9PT1cInRleHRcIil2YWx1ZT10aGlzLnJhd1ZhbHVlKHRva2VuKTtpZih2YWx1ZSE9PXVuZGVmaW5lZClidWZmZXIrPXZhbHVlfXJldHVybiBidWZmZXJ9O1dyaXRlci5wcm90b3R5cGUucmVuZGVyU2VjdGlvbj1mdW5jdGlvbiByZW5kZXJTZWN0aW9uKHRva2VuLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSl7dmFyIHNlbGY9dGhpczt2YXIgYnVmZmVyPVwiXCI7dmFyIHZhbHVlPWNvbnRleHQubG9va3VwKHRva2VuWzFdKTtmdW5jdGlvbiBzdWJSZW5kZXIodGVtcGxhdGUpe3JldHVybiBzZWxmLnJlbmRlcih0ZW1wbGF0ZSxjb250ZXh0LHBhcnRpYWxzKX1pZighdmFsdWUpcmV0dXJuO2lmKGlzQXJyYXkodmFsdWUpKXtmb3IodmFyIGo9MCx2YWx1ZUxlbmd0aD12YWx1ZS5sZW5ndGg7ajx2YWx1ZUxlbmd0aDsrK2ope2J1ZmZlcis9dGhpcy5yZW5kZXJUb2tlbnModG9rZW5bNF0sY29udGV4dC5wdXNoKHZhbHVlW2pdKSxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKX19ZWxzZSBpZih0eXBlb2YgdmFsdWU9PT1cIm9iamVjdFwifHx0eXBlb2YgdmFsdWU9PT1cInN0cmluZ1wifHx0eXBlb2YgdmFsdWU9PT1cIm51bWJlclwiKXtidWZmZXIrPXRoaXMucmVuZGVyVG9rZW5zKHRva2VuWzRdLGNvbnRleHQucHVzaCh2YWx1ZSkscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSl9ZWxzZSBpZihpc0Z1bmN0aW9uKHZhbHVlKSl7aWYodHlwZW9mIG9yaWdpbmFsVGVtcGxhdGUhPT1cInN0cmluZ1wiKXRocm93IG5ldyBFcnJvcihcIkNhbm5vdCB1c2UgaGlnaGVyLW9yZGVyIHNlY3Rpb25zIHdpdGhvdXQgdGhlIG9yaWdpbmFsIHRlbXBsYXRlXCIpO3ZhbHVlPXZhbHVlLmNhbGwoY29udGV4dC52aWV3LG9yaWdpbmFsVGVtcGxhdGUuc2xpY2UodG9rZW5bM10sdG9rZW5bNV0pLHN1YlJlbmRlcik7aWYodmFsdWUhPW51bGwpYnVmZmVyKz12YWx1ZX1lbHNle2J1ZmZlcis9dGhpcy5yZW5kZXJUb2tlbnModG9rZW5bNF0sY29udGV4dCxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKX1yZXR1cm4gYnVmZmVyfTtXcml0ZXIucHJvdG90eXBlLnJlbmRlckludmVydGVkPWZ1bmN0aW9uIHJlbmRlckludmVydGVkKHRva2VuLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSl7dmFyIHZhbHVlPWNvbnRleHQubG9va3VwKHRva2VuWzFdKTtpZighdmFsdWV8fGlzQXJyYXkodmFsdWUpJiZ2YWx1ZS5sZW5ndGg9PT0wKXJldHVybiB0aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSxjb250ZXh0LHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpfTtXcml0ZXIucHJvdG90eXBlLnJlbmRlclBhcnRpYWw9ZnVuY3Rpb24gcmVuZGVyUGFydGlhbCh0b2tlbixjb250ZXh0LHBhcnRpYWxzKXtpZighcGFydGlhbHMpcmV0dXJuO3ZhciB2YWx1ZT1pc0Z1bmN0aW9uKHBhcnRpYWxzKT9wYXJ0aWFscyh0b2tlblsxXSk6cGFydGlhbHNbdG9rZW5bMV1dO2lmKHZhbHVlIT1udWxsKXJldHVybiB0aGlzLnJlbmRlclRva2Vucyh0aGlzLnBhcnNlKHZhbHVlKSxjb250ZXh0LHBhcnRpYWxzLHZhbHVlKX07V3JpdGVyLnByb3RvdHlwZS51bmVzY2FwZWRWYWx1ZT1mdW5jdGlvbiB1bmVzY2FwZWRWYWx1ZSh0b2tlbixjb250ZXh0KXt2YXIgdmFsdWU9Y29udGV4dC5sb29rdXAodG9rZW5bMV0pO2lmKHZhbHVlIT1udWxsKXJldHVybiB2YWx1ZX07V3JpdGVyLnByb3RvdHlwZS5lc2NhcGVkVmFsdWU9ZnVuY3Rpb24gZXNjYXBlZFZhbHVlKHRva2VuLGNvbnRleHQpe3ZhciB2YWx1ZT1jb250ZXh0Lmxvb2t1cCh0b2tlblsxXSk7aWYodmFsdWUhPW51bGwpcmV0dXJuIG11c3RhY2hlLmVzY2FwZSh2YWx1ZSl9O1dyaXRlci5wcm90b3R5cGUucmF3VmFsdWU9ZnVuY3Rpb24gcmF3VmFsdWUodG9rZW4pe3JldHVybiB0b2tlblsxXX07bXVzdGFjaGUubmFtZT1cIm11c3RhY2hlLmpzXCI7bXVzdGFjaGUudmVyc2lvbj1cIjIuMy4yXCI7bXVzdGFjaGUudGFncz1bXCJ7e1wiLFwifX1cIl07dmFyIGRlZmF1bHRXcml0ZXI9bmV3IFdyaXRlcjttdXN0YWNoZS5jbGVhckNhY2hlPWZ1bmN0aW9uIGNsZWFyQ2FjaGUoKXtyZXR1cm4gZGVmYXVsdFdyaXRlci5jbGVhckNhY2hlKCl9O211c3RhY2hlLnBhcnNlPWZ1bmN0aW9uIHBhcnNlKHRlbXBsYXRlLHRhZ3Mpe3JldHVybiBkZWZhdWx0V3JpdGVyLnBhcnNlKHRlbXBsYXRlLHRhZ3MpfTttdXN0YWNoZS5yZW5kZXI9ZnVuY3Rpb24gcmVuZGVyKHRlbXBsYXRlLHZpZXcscGFydGlhbHMpe2lmKHR5cGVvZiB0ZW1wbGF0ZSE9PVwic3RyaW5nXCIpe3Rocm93IG5ldyBUeXBlRXJyb3IoJ0ludmFsaWQgdGVtcGxhdGUhIFRlbXBsYXRlIHNob3VsZCBiZSBhIFwic3RyaW5nXCIgJysnYnV0IFwiJyt0eXBlU3RyKHRlbXBsYXRlKSsnXCIgd2FzIGdpdmVuIGFzIHRoZSBmaXJzdCAnK1wiYXJndW1lbnQgZm9yIG11c3RhY2hlI3JlbmRlcih0ZW1wbGF0ZSwgdmlldywgcGFydGlhbHMpXCIpfXJldHVybiBkZWZhdWx0V3JpdGVyLnJlbmRlcih0ZW1wbGF0ZSx2aWV3LHBhcnRpYWxzKX07bXVzdGFjaGUudG9faHRtbD1mdW5jdGlvbiB0b19odG1sKHRlbXBsYXRlLHZpZXcscGFydGlhbHMsc2VuZCl7dmFyIHJlc3VsdD1tdXN0YWNoZS5yZW5kZXIodGVtcGxhdGUsdmlldyxwYXJ0aWFscyk7aWYoaXNGdW5jdGlvbihzZW5kKSl7c2VuZChyZXN1bHQpfWVsc2V7cmV0dXJuIHJlc3VsdH19O211c3RhY2hlLmVzY2FwZT1lc2NhcGVIdG1sO211c3RhY2hlLlNjYW5uZXI9U2Nhbm5lcjttdXN0YWNoZS5Db250ZXh0PUNvbnRleHQ7bXVzdGFjaGUuV3JpdGVyPVdyaXRlcjtyZXR1cm4gbXVzdGFjaGV9KTtcbiJdfQ==